Related
When I was trying to get elevated rights for my batch script, when I found two related SO questions
How to request Administrator access inside a batch file
How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
...that led to answers that worked partially. For some reason, I had issues with command line passing for file path arguments containing spaces within the VBS script, so I tried to break the solution into 3 parts and concentrated on the inner (VBS) step, then adding the last step by calling a batch from that VBS which could not be found, despite in the same folder as the VBS script. I found that drag & drop isn't "that easy" and that it's different when using .vbs instead of .bat or .exe as drop targets.
Here is my actual question:
If I drag a file and drop it onto an executable (exe) or batch file (bat, cmd), The current working directory is determined by the source of the dragged item. Its directory is set as the working directory for the program or script that processes it.
If I drop a file onto a VBS script, it's different. On Windows 8.1 x64 I observe it to be C:\Windows\System32 even if the argument resides in the same folder as the VBS.
I can simply use a batch file (as drag'n'drop relay) like this
my.vbs %*
to get "the normal" .bat behaviour (drop source dictates CWD), but I also want to understand it.
Is it a bug or a feature? Is it consistent over all Windows versions?
edit: added the background (on top) for the question showing how I got there (+minor corrections)
After some API monitoring, this is what I see
When you drop a file over a .exe file the explorer.exe uses CreateProcess API function to start the process, passing the executable as lpApplicationName, and the executable and dropped file as lpCommandLine. The lpCurrentDirectory is set in the function call by the caller process to the folder containing the dropped file[1].
When you drop a file over a .cmd file the explorer.exe also uses CreateProcess API, but in this case the lpApplicationName is null and the lplCommandLine contains the batch file and the dropped file. lpCurrentDirectory is also set to the parent folder of the dropped file[1].
When you drop a file over a .vbs file, ShellExecuteEx is used and the lpDirectory field of the SHELLEXECUTEINFO structure is null, so, the process created inherits the current active directory of the parent process. By default the current active directory of the explorer.exe process is %systemroot%\system32, but it is possible to start a explorer instance with a different current active directory that will be inherited in this kind of drop operations.
[1] If we drop more than one file, the path of the file passed as first argument is used
note just for information: to test the active directory inherit the process followed was:
Open a cmd instance and change the current active directory to c:\temp
Kill all explorer.exe instances
From the cmd instance call explorer.exe. This explorer instance has the active directory in the cmd window as its current active directory.
The Arguments property holds the full paths to all items dropped on the script, so you can determine the directory of each dropped item like this:
Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
WScript.Echo fso.GetParentFolderName(item)
Next
Assuming that the working directory would be defined by what is dropped onto a script is a misguided approach. If you require that logic you can implement it in the script yourself, though, e.g. like this:
Set fso = CreateObject("Scripting.FileSystemObject")
Set sh = CreateObject("WScript.Shell")
For Each item In WScript.Arguments
sh.CurrentDirectory = fso.GetParentFolderName(item)
'working directory is now the parent folder of the current item
'...
Next
If you need the working directory to be the parent directory of the VBScript file you can derive that from the ScriptFullName property:
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetParentFolderName(WScript.ScriptFullName)
If I lookup the file types in the Windows registry, I see the following in their Shell\Open\Command values:
batfile: "%1" %*
cmdfile: "%1" %*
exefile: "%1" %*
VBSFile: "%SystemRoot%\System32\WScript.exe" "%1" %*
This seems to suggest that bat, cmd, exe are treated as executable on their own, maybe for historical reasons, whereas VBS is considered an ordinary script, that is only executable because its extension is registered with some executable to be called to interpret it. Pretty much the same as Python or Perl.
[Update] Indeed I proved that a Python script shows exactly the same behaviour as my VBS script: calling it from the command line providing arguments keeps the CWD, dropping a file on it causes the CWD to be C:\Windows\System32. So my question seems to be sort of wrong, but finally it helped people to point me into the right direction for further research...
c:\windows\system32\CScript.exe or c:\windows\system32\Wscript.exe are the programs that run vbscript. As you can see they are in system32.
Windows uses ShellExecuteEx to start programs - see it's rules at MSDN: ShellExecuteEx function (Windows)
ShellExecuteEx uses CreateProcess (CreateProcessEx) to actually start a program. CreateProcess function (Windows)
Edit
CMD doesn't use the registry for it's own stuff. Those registry entries are for programs other than CMD.
CMD main goal is to be MS Dos 5 compatible while enhancing it, it will correctly run most DOS batch files. It was written by IBM engineers working on OS/2 NOT Windows.
Edit 2
The core of your problem is that you are attempting to write programs as if you are a user typing to operate a computer.
As a programmer you don't make assumptions. The easiest way to not take assumptions is to specify full paths to what you want. Your batch file shouldn't care what the current directory is. EG In CMD there is a current directory per drive for compatibility with MSDos 5 (and programs in a console tend to share them but don't have to). In Windows there is one current directory per program. The default current directory has changed over the years.
The only time you should work with the current directory is if you are writing a batchfile for a user to use. EG If you type dir it does the current directory, a batchfile meant to be a general command should work the same way.
I'm writing myself a GUI utility for use in a CMD window to navigate between folders,
rather in the style of the old Norton Change Directory utility for DOS.
When run, the app pops up a folder tree to allow the user to select a folder to which
to navigate and then closes and returns to the CMD prompt. At the moment, the way it
works is that it is run as the first command in a "main" batch file. It writes a secondary batch
file, in my app's folder under AppData, containing the commands to change drive and
directory to the folder the user selected, and the main batch file then invokes this
second batch file using CALL.
It works fine, but this way of actually changing the CMD window's current directory
strikes me as inelegant both from the point of view of needing to be run from a batch file
(so that the user's selection can be acted upon after my app has closed) and of
needing the secondary batch file to do the actual navigation.
So, my question is, how can my app send the instructions to the instance of CMD
that owns the window in which the app is run to the folder the user selected? I've tried doing a ShellExecute
of "CMD /K ..." but although that does indeed navigate to the
selected folder, it does so in a new CMD window, not the one my app is run in. The
conceptual gap I have is how to get the current CMD to act on my app's instructions
after my app has terminated.
Fwiw, I thought of trying to write the user's folder selection into an environment variable in the CMD window's environment for the CMD processor to
act upon from there, but this seems to require that the CMD window be opened via "Run as Administrator", which I definitely don't want.
Your program cannot influence the environment variables of the command interpreter because they're separate processes. Your program cannot change the directory of the command interpreter directly, either, because, again, they're separate processes.
You need to use a batch file because the command interpreter executes batch files internally. Since it's all the same process, the batch file has the power to change the current directory, and for that change to remain in effect after the batch file finishes running.
Therefore, you need some way for your interactive program to communicate the directory selection back to the batch file so that it can act on it.
Instead of writing the instructions to another batch file, you could write the result to standard output. Have the batch file capture that output into a variable, and then execute cd on that variable. The batch code would look something like this:
for /f "tokens=*" %%a in ('[select_dir.exe]') do (
set DIRSELECTION=%%a
)
cd /d %DIRSELECTION%
Your Delphi code would look like this:
writeln(selected_dir);
To allow that command to work, you'll need to make sure your program is marked as a console program, as with {$APPTYPE CONSOLE}. If it's not, then the batch file won't receive any output, and probably won't even wait for your program to finish running before proceeding. It's OK for a console program to display a TForm, just like a GUI program.
I am writing a batch file to setup a small program that I have written for a couple of user's machines. As the batch file will be also writing to the user's registry it will be run in admin mode. The issue I have is when running in administrator mode when it gets to the COPY (I have also tested with the MOVE command) it outputs that the system cannot find the file. However if i run the program without the admin privileges the files copy/move as expected. I have tested the file without the registry command as well as that seems to have no effect on the situation. The initial files are all located in a folder on the users desktop but I have hard-coded the path names in to ensure that there is no confusion. I do have admin rights onto the machine as do all users for their respective computers.
The contents of the batch file is listed below:
REM This program needs to be run as administrator for it to add to the registry
REM Adds a registry value that allows the user to right click a document and run the program
#echo off
MD %UserProfile%\AppData\Roaming\Microsoft\AddIns\ComparisonAddin
COPY C:\Users\MyUser\Desktop\Launch Files\Compare.xlsm %UserProfile%\AppData\Roaming\Microsoft\AddIns\ComparisonAddin
COPY C:\Users\MyUser\Desktop\Launch Files\launchCompare.bat %UserProfile%\AppData\Roaming\Microsoft\AddIns\ComparisonAddin
REG ADD "HKCR\*\shell\Get Word Difference\command" /v "" /t REG_EXPAND_SZ /d "\"%USERPROFILE%\AppData\Roaming\Microsoft\AddIns\ComparisonAddin\launchCompare.bat\" \"%%1\""
pause
The directory is created as normal in both admin mode and non admin mode. Is there any reason why the COPY/MOVE command does not work in admin mode?
Thanks.
COPY "C:\Users\MyUser\Desktop\Launch Files\Compare.xlsm" "%UserProfile%\AppData\Roaming\Microsoft\AddIns\ComparisonAddin\"
Any source or target that contains separator characters like space, comma, tab etc. must be "quoted".
I use the trailing backslash at the end of directory name as a matter of habit so that if the directory does not exist, the copy won't try to create a destination file with that name.
I am a beginner in VBScript. I googled it & got to know that we can run VBScript from command line by executing below command:
For Example my vbscript name is Converter.vbs & it's present in folder D:\VBS.
I can run it through following methods:
CScript "D:\VBS\Converter.vbs"
OR
WScript "D:\VBS\Converter.vbs"
Now I would like to execute above VBScript without Cscript or Wscript command by simply typing the name of VBscript name i.e. Converter.
I DON'T WANT TO SPECIFY THE FULL PATH OF VBSCRIPT EVERYTIME.
Can anyone please guide me on how to do that ?
I'll break this down in to several distinct parts, as each part can be done individually. (I see the similar answer, but I'm going to give a more detailed explanation here..)
First part, in order to avoid typing "CScript" (or "WScript"), you need to tell Windows how to launch a * .vbs script file. In My Windows 8 (I cannot be sure all these commands work exactly as shown here in older Windows, but the process is the same, even if you have to change the commands slightly), launch a console window (aka "command prompt", or aka [incorrectly] "dos prompt") and type "assoc .vbs". That should result in a response such as:
C:\Windows\System32>assoc .vbs
.vbs=VBSFile
Using that, you then type "ftype VBSFile", which should result in a response of:
C:\Windows\System32>ftype VBSFile
vbsfile="%SystemRoot%\System32\WScript.exe" "%1" %*
-OR-
C:\Windows\System32>ftype VBSFile
vbsfile="%SystemRoot%\System32\CScript.exe" "%1" %*
If these two are already defined as above, your Windows' is already set up to know how to launch a * .vbs file. (BTW, WScript and CScript are the same program, using different names. WScript launches the script as if it were a GUI program, and CScript launches it as if it were a command line program. See other sites and/or documentation for these details and caveats.)
If either of the commands did not respond as above (or similar responses, if the file type reported by assoc and/or the command executed as reported by ftype have different names or locations), you can enter them yourself:
C:\Windows\System32>assoc .vbs=VBSFile
-and/or-
C:\Windows\System32>ftype vbsfile="%SystemRoot%\System32\WScript.exe" "%1" %*
You can also type "help assoc" or "help ftype" for additional information on these commands, which are often handy when you want to automatically run certain programs by simply typing a filename with a specific extension. (Be careful though, as some file extensions are specially set up by Windows or programs you may have installed so they operate correctly. Always check the currently assigned values reported by assoc/ftype and save them in a text file somewhere in case you have to restore them.)
Second part, avoiding typing the file extension when typing the command from the console window.. Understanding how Windows (and the CMD.EXE program) finds commands you type is useful for this (and the next) part. When you type a command, let's use "querty" as an example command, the system will first try to find the command in it's internal list of commands (via settings in the Windows' registry for the system itself, or programmed in in the case of CMD.EXE). Since there is no such command, it will then try to find the command in the current %PATH% environment variable. In older versions of DOS/Windows, CMD.EXE (and/or COMMAND.COM) would automatically add the file extensions ".bat", ".exe", ".com" and possibly ".cmd" to the command name you typed, unless you explicitly typed an extension (such as "querty.bat" to avoid running "querty.exe" by mistake). In more modern Windows, it will try the extensions listed in the %PATHEXT% environment variable. So all you have to do is add .vbs to %PATHEXT%. For example, here's my %PATHEXT%:
C:\Windows\System32>set pathext
PATHEXT=.PLX;.PLW;.PL;.BAT;.CMD;.VBS;.COM;.EXE;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY
Notice that the extensions MUST include the ".", are separated by ";", and that .VBS is listed AFTER .CMD, but BEFORE .COM. This means that if the command processor (CMD.EXE) finds more than one match, it'll use the first one listed. That is, if I have query.cmd, querty.vbs and querty.com, it'll use querty.cmd.
Now, if you want to do this all the time without having to keep setting %PATHEXT%, you'll have to modify the system environment. Typing it in a console window only changes it for that console window session. I'll leave this process as an exercise for the reader. :-P
Third part, getting the script to run without always typing the full path. This part, in relation to the second part, has been around since the days of DOS. Simply make sure the file is in one of the directories (folders, for you Windows' folk!) listed in the %PATH% environment variable. My suggestion is to make your own directory to store various files and programs you create or use often from the console window/command prompt (that is, don't worry about doing this for programs you run from the start menu or any other method.. only the console window. Don't mess with programs that are installed by Windows or an automated installer unless you know what you're doing).
Personally, I always create a "C:\sys\bat" directory for batch files, a "C:\sys\bin" directory for * .exe and * .com files (for example, if you download something like "md5sum", a MD5 checksum utility), a "C:\sys\wsh" directory for VBScripts (and JScripts, named "wsh" because both are executed using the "Windows Scripting Host", or "wsh" program), and so on. I then add these to my system %PATH% variable (Control Panel -> Advanced System Settings -> Advanced tab -> Environment Variables button), so Windows can always find them when I type them.
Combining all three parts will result in configuring your Windows system so that anywhere you can type in a command-line command, you can launch your VBScript by just typing it's base file name. You can do the same for just about any file type/extension; As you probably saw in my %PATHEXT% output, my system is set up to run Perl scripts (.PLX;.PLW;.PL) and Python (.PY) scripts as well. (I also put "C:\sys\bat;C:\sys\scripts;C:\sys\wsh;C:\sys\bin" at the front of my %PATH%, and put various batch files, script files, et cetera, in these directories, so Windows can always find them. This is also handy if you want to "override" some commands: Putting the * .bat files first in the path makes the system find them before the * .exe files, for example, and then the * .bat file can launch the actual program by giving the full path to the actual *. exe file. Check out the various sites on "batch file programming" for details and other examples of the power of the command line.. It isn't dead yet!)
One final note: DO check out some of the other sites for various warnings and caveats. This question posed a script named "converter.vbs", which is dangerously close to the command "convert.exe", which is a Windows program to convert your hard drive from a FAT file system to a NTFS file system.. Something that can clobber your hard drive if you make a typing mistake!
On the other hand, using the above techniques you can insulate yourself from such mistakes, too. Using CONVERT.EXE as an example.. Rename it to something like "REAL_CONVERT.EXE", then create a file like "C:\sys\bat\convert.bat" which contains:
#ECHO OFF
ECHO !DANGER! !DANGER! !DANGER! !DANGER, WILL ROBINSON!
ECHO This command will convert your hard drive to NTFS! DO YOU REALLY WANT TO DO THIS?!
ECHO PRESS CONTROL-C TO ABORT, otherwise..
REM "PAUSE" will pause the batch file with the message "Press any key to continue...",
REM and also allow the user to press CONTROL-C which will prompt the user to abort or
REM continue running the batch file.
PAUSE
ECHO Okay, if you're really determined to do this, type this command:
ECHO. %SystemRoot%\SYSTEM32\REAL_CONVERT.EXE
ECHO to run the real CONVERT.EXE program. Have a nice day!
You can also use CHOICE.EXE in modern Windows to make the user type "y" or "n" if they really want to continue, and so on.. Again, the power of batch (and scripting) files!
Here's some links to some good resources on how to use all this power:
http://ss64.com/
http://www.computerhope.com/batch.htm
http://commandwindows.com/batch.htm
http://www.robvanderwoude.com/batchfiles.php
Most of these sites are geared towards batch files, but most of the information in them applies to running any kind of batch (* .bat) file, command (* .cmd) file, and scripting (* .vbs, * .js, * .pl, * .py, and so on) files.
When entering the script's full file spec or its filename on the command line, the shell will use information accessibly by
assoc | grep -i vbs
.vbs=VBSFile
ftype | grep -i vbs
VBSFile=%SystemRoot%\System32\CScript.exe "%1" %*
to decide which program to run for the script. In my case it's cscript.exe, in yours it will be wscript.exe - that explains why your WScript.Echos result in MsgBoxes.
As
cscript /?
Usage: CScript scriptname.extension [option...] [arguments...]
Options:
//B Batch mode: Suppresses script errors and prompts from displaying
//D Enable Active Debugging
//E:engine Use engine for executing script
//H:CScript Changes the default script host to CScript.exe
//H:WScript Changes the default script host to WScript.exe (default)
//I Interactive mode (default, opposite of //B)
//Job:xxxx Execute a WSF job
//Logo Display logo (default)
//Nologo Prevent logo display: No banner will be shown at execution time
//S Save current command line options for this user
//T:nn Time out in seconds: Maximum time a script is permitted to run
//X Execute script in debugger
//U Use Unicode for redirected I/O from the console
shows, you can use //E and //S to permanently switch your default host to cscript.exe.
If you are so lazy that you don't even want to type the extension, make sure that the PATHEXT environment variable
set | grep -i vbs
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.py;.pyw;.tcl;.PSC1
contains .VBS and there is no Converter.cmd (that converts your harddisk into a washing machine) in your path.
Update wrt comment:
If you 'don't want to specify the full path of my vbscript everytime' you may:
put your CONVERTER.VBS in a folder that is included in the PATH environment variable; the shell will then search all pathes - if necessary taking the PATHEXT and the ftype/assoc info into account - for a matching 'executable'.
put a CONVERTER.BAT/.CMD into a path directory that contains a line like cscript p:\ath\to\CONVERTER.VBS
In both cases I would type out the extension to avoid (nasty) surprises.
I am wondering why you cannot put this in a batch file. Example:
cd D:\VBS\
WSCript Converter.vbs
Put the above code in a text file and save the text file with .bat extension. Now you have to simply run this .bat file.
Why don't you just stash the vbscript in a batch/vbscript file hybrid. Name the batch hybrid Converter.bat and you can execute it directly as Converter from the cmd line. Sure you can default ALL scripts to run from Cscript or Wscript, but if you want to execute your vbs as a windows script rather than a console script, this could cause some confusion later on. So just set your code to a batch file and run it directly.
Check the answer -> Here
And here is an example:
Converter.bat
::' VBS/Batch Hybrid
::' --- Batch portion ---------
rem^ &#echo off
rem^ &call :'sub
rem^ &exit /b
:'sub
rem^ &echo begin batch
rem^ &cscript //nologo //e:vbscript "%~f0"
rem^ &echo end batch
rem^ &exit /b
'----- VBS portion -----
Dim tester
tester = "Convert data here"
Msgbox tester
You may follow the following steps:
Open your CMD(Command Prompt)
Type 'D:' and hit Enter. Example: C:\Users\[Your User Name]>D:
Type 'CD VBS' and hit Enter. Example: D:>CD VBS
Type 'Converter.vbs' or 'start Converter.vbs' and hit Enter. Example: D:\VBS>Converter.vbs Or D:\VBS>start Converter.vbs
I would like to know what are the approaches that you use to manage the executables in your system. For example I have almost everything accessible through the command line, but now I come to the limit of the path string, so i can't add any more dir.
So what do you recommend?
A long time ago, I tried to use softLinks of the executables in a Dir that belonged to the path, but that approach didn't work.
Throw the "executable only" to a known Dir,has the problems that almost any application require a set of files, so this also is bad.
Throw the executable and all his files to a known Dir, mmm this will work, but the possibility to get a conflict in the name of the files is very very high.
Create a HardLink? i don't know. What do you think?
This will parse your %PATH% environment variable and convert each directory to its shortname equivalent and then piece it all back together:
#echo off
SET MyPath=%PATH%
echo %MyPath%
echo --
setlocal EnableDelayedExpansion
SET TempPath="%MyPath:;=";"%"
SET var=
FOR %%a IN (%TempPath%) DO (
IF exist %%~sa (
SET "var=!var!;%%~sa"
) ELSE (
echo %%a does not exist
)
)
echo --
echo !var:~1!
Take the output and update the PATH variable in environment variables.
One way I can think of is to use other environment variables to store partial paths; for example, if you have
C:\this_is_a\long_path\that_appears\in_multiple_places\subdir1;
C:\this_is_a\long_path\that_appears\in_multiple_places\subdir2;
then you can create a new environment variable such as
SET P1=C:\this_is_a\long_path\that_appears\in_multiple_places
after which your original paths become
%P1%\subdir1;
%P1%\subdir2;
EDIT: Another option is to create a bin directory that holds .bat files that point to the appropriate .exe files.
EDIT 2: Ben Voigt's comment to another answer mentions that using other environment variables as suggested might not reduce the length of %PATH% because they would be expanded prior to being stored. This may be true and I have not tested for it. Another option though is to use 8dot3 forms for longer directory names, for example C:\Program Files is typically equivalent to C:\PROGRA~1. You can use dir /x to see the shorter names.
EDIT 3: This simple test leads me to believe Ben Voigt is right.
set test1=hello
set test2=%test1%hello
set test1=bye
echo %test2%
At the end of this, you see output hellohello rather than byehello.
EDIT 4: In case you decide to use batch files to eliminate certain paths from %PATH%, you might be concerned about how to pass on arguments from your batch file to your executable such that the process is transparent (i.e., you won't notice any difference between calling the batch file and calling the executable). I don't have a whole lot of experience writing batch files, but this seems to work fine.
#echo off
rem This batch file points to an executable of the same name
rem that is located in another directory. Specify the directory
rem here:
set actualdir=c:\this_is\an_example_path
rem You do not need to change anything that follows.
set actualfile=%0
set args=%1
:beginloop
if "%1" == "" goto endloop
shift
set args=%args% %1
goto beginloop
:endloop
%actualdir%\%actualfile% %args%
As a general rule, you should be careful about running batch files from the internet, since you can do all sorts of things with batch files such as formatting your hard drive. If you don't trust the code above (which I wrote), you can test it by replacing the line
%actualdir%\%actualfile% %args%
with
echo %actualdir%\%actualfile% %args%
Ideally you should know exactly what every line does before you run it.
if you are using windows vista or higher, you can make a symbolic link to the folder. for example:
mklink /d C:\pf "C:\Program Files"
would make a link so c:\pf would be your program files folder. I shaved off 300 characters from my path by using this trick.
In case anyone's interested...
I find I never really need all those paths at once, so I create a bunch of "initialization" batch files which modify the path accordingly.
For example, if I wanted to do some C++ development in Eclipse, I would do:
> initmingw
> initeclipse
> eclipse
This is also handy for avoiding conflicts between executables with the same name (such as the C++ and D compilers, which both have a make.exe).
My batch files typically look like this:
#echo off
set PATH=C:\Path\To\My\Stuff1;%PATH%
set PATH=C:\Path\To\My\Stuff2;%PATH%
I find this approach relatively clean and have yet to run into any problems with it.
I generally don't have to worry about this (I haven't run into a path size limit - I don't even know what that is on modern Windows systems), but here's what I might do to avoid putting a program's directory in the path:
most command line utilities get thrown into a c:\util directory that's on the path
otherwise, I'll add a simple cmd/batch file to the c:\util directory that looks something like:
#"c:\program files\whereever\foo.exe" %*
which essentially creates an alias for the command. It's not necessarily perfect. Some programs really insist on being in the path (that's pretty rare nowadays), and other programs that try to invoke it might not find it properly. But for most uses it works well.
But generally, I haven't had to worry about avoiding adding directories to the path.
Another idea: Use DIR /X to determine the short names generated for non-8dot3 file
names. Then use these in your %PATH%.
For example, 'C:\Program Files' becomes 'C:\PROGRA~1'.
USe the App Path registry key instead of the path variable for application-specific paths:
http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
I wrote and use on a every-time basis a standard stream (stdin/stderr/stdout) & exit code PROXY program (called dispatcher https://github.com/131/dispatcher)
All CLI program i use (node, php, python, git, svn, rsync, plink ...) i'm using are actually the same exe file (around 10kb, that i just name differently), that i put in the same directory. A dummy static clear text file do the "proxy file name to real exe mapping".
Dispatcher use low level Process management win32 API to be absolutly transparent.
Using this software, i only do have ONE additionnal directory set in my PATH for all programs i might use.
Creating a folder c:\bin adding to your path and hardlinking like you said could shorten the string. Maybe add a variable pf to system vars with value c:\Program Files then replace c:\Program Files with %pf% in path.
Edit:
Create a virtual drive.
subst p: "c:\program files"
I follow these steps to make the entries manageable:
Created different users for different combination of software packages usage.
Example: (a) Created a user web for making available all the web development software; (b) Created a user database for making available all the database and data warehousing software packages. Remember some software may create more than one entry. Or sometime I break this into oracle specific and MSSQL specific and oracle specific users. I put MySQL/PostgreSQL, tomcat, wamp, xamp all into the user account webr.
If possible install common packages like office, photoshop, .. as system specific available for all users and special packages as user specific. Of course I had to log into different users and install them. Not all software may provide this option. If "install for this user only" option is not available, install it for the whole system.
I avoid installing programs in to the folder Program File (x86) or in to Program File. I always install into the base directory. For example MySQL 64 bit goes into "C:\mysql64" and MySQL 32 bit goes into "C:\mysql" folder. I always assume adding a suffix 64 only for 64bit software. If no suffix, then it is a 32 bit. I follow the same thing to Java and others. This way my path will be shorter, not including "C:\Program File (x86)". For some software the configuration file may need to be edited to show where exactly the .exe file is. Only program that demands to be installed into "C:\Program File (x86)" will be installed into that folder. Always I remember to shorten the names. I avoid version number like tomcat/release/version-2.5.0.3 such details. If I need to the know version, I create a file by name version and put it into the tomcat folder. In general shorten the link as much as possible.
Include any batch to replace abbreviated link to the path, if all the above steps passed the Windows limit.
Then Log into usage specific (mobile application, or database/data warehousing or web-development.. ..) user and do the relevant tasks.
You can also create virtual windows within windows. As long as you have one licensed OS copy, creating multiple virtual windows with same key is possible. You can put packages specific for a particular task in that machine. You have to launch separate VM each time. Some memory intensive packages like 3D animation movie makers all should be put into the main machine, not into VM as VM will have only a part of the RAM available for its use. It is a pain to boot each VM though.
The solutions above only work if you can trim down your path. In my case, that wasn't really an option, and it was a hassle to have to run a script every time I opened a command prompt. So I wrote a simple script that runs automatically when opening the command prompt, and appends the contents of a text file to your path.
There are also some contexts where having this script run breaks things (say, in a github or cygwin shell), so I also added a file that contains a list of paths that, if the command prompt is started in them, the path variable isn't changed via the startup script that normally updates the path.
#echo off
:: Modify these to the actual paths of these two files
set dontSetupFile=C:\Users\Yams\Dontsetup.txt
set pathFile=C:\Users\Yams\Path.txt
:: Retrieve the current path (for determining whether or not we should append to our path)
set curDir=%cd%
:: Be done if the current path is listed in the dontSetupFile
SetLocal EnableDelayedExpansion
for /F "delims=" %%i in (%dontSetupFile%) do (
if "%%i"=="%curDir%" GOTO AllDone
)
:: Append the pathFile to our current PATH
set pathAppend=
for /F "delims=" %%i in (%pathFile%) do (set pathAppend=!pathAppend!%%i)
set PATH=%PATH%;%pathAppend%
:: The only way to actually modify a command prompt's path via a batch file is by starting
:: up another command prompt window. So we will do this, however, if this script is
:: automatically called on startup of any command prompt window, it will infinately
:: recurse and bad things will happen.
:: If we already ran, we are done
if "%yams%"=="onion" GOTO AllDone
:: Otherwise, flag that we just ran, and then start up a new command prompt window
:: with this flag set
set yams=onion
cmd \K set PATH=%PATH%;
:: When that command prompt exits, it will load back up this command prompt window, and
:: then the user will need to exit out of this as well. This causes this window to
:: automatically exit once the cmd it just spawned is closed.
exit()
:: Path is set up, we are done!
:AllDone
#echo on
And Path.txt will look something like
C:\Program Files (x86)\Google\google_appengine;
C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;
C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;
C:\Program Files\Microsoft SQL Server\110\Tools\Binn;
C:\Program Files\Microsoft DNX\Dnvm;
C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit;
While Dontsetup.txt will look something like
C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit
C:\Program Files (x86)\Git\cmd
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin
To make this run automatically on startup, open regedit, navigate to HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Command Processor, then right click on the right and press new -> Multi-String Value. Name it AutoRun. Set it's value to
C:\Users\Yams\setUpPath.bat
or wherever else you stored the batch file above.
Didn't try it, but will splitting PATH in parts work and joining them in final variable work?
Example initially let's say you have something like
PATH={LONGPATH1};{LONGPATH2};....{2048th char}....{LONGPATH_N-1};{LONGPATH_N}
Instead you create:
_PATH1 = {LONGPATH1};{LONGPATH2};....{2048 char}
_PATH2 = {2049th char}...{LONGPATH_N-1};{LONGPATH_N}
rem // may be more parts
PATH = %_PATH1%;%_PATH2%