cmd set env and run script - windows

I want to run from powershell a batch script that needs a environment variable before run.
This is what I tried.
cmd.exe /c SET ENV_BASE_DIR='C:\Program Files\XY\Z 12.3' "&" "C:\Users\Admin\Desktop\file.bat /d /p"

To avoid quoting headaches, consider (temporarily) setting the environment variable from PowerShell and then invoking the batch file directly:
$env:ENV_BASE_DIR = 'C:\Program Files\XY\Z 12.3'
C:\Users\Admin\Desktop\file.bat /d /p
$env:ENV_BASE_DIR = $null # remove the env. var again.
If you do want to solve this with a cmd.exe one-liner:
cmd.exe /c set ENV_BASE_DIR='C:\Program Files\XY\Z 12.3' `& C:\Users\Admin\Desktop\file.bat /d /p
The & metacharacter is more simply escaped with ` (backtick), PowerShell's escape character.
The batch file path and its arguments are passed as individual arguments.
As for what you tried:
Ultimately, the only problem with your command line was that you put double quotes around C:\Users\Admin\Desktop\file.bat /d /p as a whole, which caused cmd.exe to consider the entire string the executable path.

Related

quotes inside quotes with windows' cmd

I have the following command set as a custom URL protocol in windows registry:
cmd /V:ON /C "SET r=%1 & SET s=!r:jhvnc:=! & start C:\Program Files\uvnc bvba\UltraVNC\vncviewer.exe !s:_= !"
This is not working because the path to the exe file has a space.
Normally, I'd use quotes:
cmd /V:ON /C "SET r=%1 & SET s=!r:jhvnc:=! & start "C:\Program Files\uvnc bvba\UltraVNC\vncviewer.exe" !s:_= !"
but the command is already in quotes. I tried escaping the quotes with double quotes, but that did not work.
How can I achieve this?
Simplest work around is use the historic short folder name
That should be C:\PROGRA~1\UVNCBV~1\
check using dir /x /a:d C:\PROGRA~1\U*
cmd /V:ON /C "SET r=%1 & SET s=!r:jhvnc:=! & start C:\PROGRA~1\UVNCBV~1\UltraVNC\vncviewer.exe !s:_= !"

how to debug mixed cmd and powershell scripts to solve special character problems like ampersand &

I am creating a dos batch script (cmd.exe) .cmd which through powershell elevates itself as administrator.
But if it's stored in a folder that contains both spaces and ampersand in its name, it won't work.
I am not an expert so I searched the web, but I could not find a solution or documentation to solve the problem. So I would also like to know how to debug this particular situation and the possible solutions to the problem and where to find the documentation describing the solution or the steps to get there .. (if any).
To recreate the problem: I created a folder under the desktop named "Pie & tea" without quotes. And in the folder I created a script "test.cmd" inside which I put only the essential to reproduce the problem. This is the content of the script:
#echo off
pause
PowerShell start "%~f0" -verb runas
pause
goto: eof
I run the script by double clicking on it (this is the desired mode). An error is shown with this code (I translate from italian with a translator):
Press any key to continue. . .
In row: 1 car: 34
+ start C:\Users\fposc\Desktop\Pie & tea\test.cmd -verb runas
+ ~
Ampersand (&) not allowed. The & operator is reserved for future use. Use "&" to pass the ampersand as
string.
+ CategoryInfo: ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId: AmpersandNotAllowed
Press any key to continue. . .
And following some instructions I modified the line of code with powershell by tripling the double quotes:
PowerShell start """%~f0""" -verb runas
But the cmd window opens and after pressing the space the UAC starts and after giving the consent another window appears for a moment but it closes immediately and I could not see any errors.
I have seen on the web any solutions using single quotes ' or the powershell escape character ` or the caret ^ of the dos batch or the --% parameter of the powershell etc.
But i was unable to resolve.
I do not put the attempts made here because I copied in a stupid way (since I am not familiar with the mixed cmd / powershell operation) and I made numerous random attempts combining the various solutions. Without any positive outcome.
I have also seen solutions that I would like to evaluate, such as:
change directories and use relative paths.
prepare string variables and replace characters.
Use powershell -encodedcommand to pass parameters.
But the preferred solution is the one that explains how to escape characters on the single line of code PowerShell start "%~f0" -verb runas and how to get there and the reference documentation.
Some links visited:
VBS Shell.Application and PowerShell Start-Process do not escape ampersands internally
Quoting issues with PowerShell
Issues on windows when the username contains &
Executing PowerShell script via explorer context menu on items containing ampersands in their names
Stackoverflow: batch file deal with Ampersand (&) in folder name
Stackoverflow: How to access file paths in PowerShell containing special characters
Stackoverflow: How to pass strings to powershell from cmd with ampersands in values?
Debugging tips:
If something goes wrong on the PowerShell side, you'll see the error message in the calling cmd.exe session; to print the command line that PowerShell itself sees, prepend [Environment]::CommandLine; to the command(s) being passed.[1]
To make PowerShell's Start-Process cmdlet (whose built-in alias is start) launch the batch file in a cmd.exe process that keeps the session open, invoke cmd.exe explicitly, with cmd /k, and pass it the batch-file path. Once you're sure everything works as expected, replace /k with /c (to create a session that terminates when the batch file terminates).
The primary problem in your case:
Regrettably, if a batch-file path contains & characters, a bug in cmd.exe requires manual ^-escaping of the & as well as spaces, and possibly other cmd.exe metacharacters, even if the path is enclosed in "..." as a whole; additionally, it seems that the full batch-file path must be used on invocation (which %~f0 ensures):
For instance, to invoke C:\foo\a & b.cmd, cmd /k "C:\foo\a & b.cmd" is not enough - you must use cmd /k "C:\foo\a^ ^&^ b.cmd"
The command below uses a -replace operation to perform this ^-escaping in PowerShell code, on the value of %~f0, which cmd.exe expands to the batch file's full path.
The following solution:
uses aux. environment variables to make it work in most situations, even with paths containing other exotic characters, such as $, % and '.
also includes support for passing arguments through on invocation.
See the bottom section for the evolution of the solution, which includes detailed explanations.
#echo off
:: Save the full path of this batch file in an aux. environment variable.
set "__THISFILE=%~f0"
:: Save the arguments received in an aux. environment variable.
:: Note: The space after "=" is required for the PowerShell command
:: to also work if *no* arguments were passed.
set __ARGS= %*
:: Unless already elevated, relaunch this batch file,
:: with arguments passed through.
:: Note: Replace `exit /b` with just `exit` to
:: close the current console window after relaunching.
net session >NUL 2>NUL || (powershell.exe -noprofile -c "Start-Process -Verb RunAs cmd /k, ($env:__THISFILE -replace '[ &%%^]', '^$&'), $env:__ARGS" & exit /b)
:: Reset the aux. variables.
set __ARGS=
set __THISFILE=
echo Now running with elevation. Arguments received:
echo. %*
Evolution of the solution above:
If your batch-file paths do not contain ' characters:
Embedded '...' quoting is used in the PowerShell command below, so as to avoid having to escape embedded " quotes, which can get tricky; this assumes that the batch-file path itself contains no ' chars (see below if your paths do contain ' chars.)
#echo off
:: Unless already elevated, relaunch this batch file with elevation.
net session >NUL 2>NUL || (powershell.exe -c "Start-Process -Verb RunAs cmd /k, ('%~f0' -replace '[ &]', '^$&')" & goto :eof)
echo Now running with elevation.
Note:
net session >NUL 2>NUL is a simple trick to test if the current process is elevated (being run as admin) or not: it only succeeds in elevated sessions (reflected in exit code 0, which the || and && operators implicitly act on).
-c (-Command) makes it explicit that command(s) are being passed to powershell.exe; while not strictly necessary, it is a good habit to form, given that pwsh.exe, the PowerShell (Core) 7+ CLI, now requires it (see the linked CLI documentation below).
/k, ... creates an array of arguments, which are positionally passed to the -ArgumentList parameter of Start-Process - in essence, Start-Process builds a command line from the executable name, cmd, and all arguments by string concatenation with spaces behind the scenes - see this answer to your follow-up question for details.
If your batch-file paths contain ' chars., embedded "..." quoting must be used:
With powershell.exe, the Windows PowerShell CLI, the most robust approach - which is indeed required here - is to use "^"" (sic) to escape each embedded ", as shown below.
(By contrast, pwsh.exe, the PowerShell (Core) 7+ CLI now fortunately accepts "".)
net session >NUL 2>NUL || (powershell.exe -nop -c "Start-Process -Verb RunAs cmd /k, ("^""%~f0"^"" -replace '[ &]', '^$&')" & goto :eof)
If your batch-file paths contain $ chars. and ' chars., an aux. environment variable must be used:
$ chars. alone wouldn't be a problem if you used embedded '...' quoting, but if ' are also present, embedded "..." quoting isn't an option, because PowerShell would treat the $ chars. as the start of a variable reference.
See the solution at the top.
If you additionally want to support passing arguments to the batch file:
Note: The solution at the top now incorporates this approach, while also handling a wider array of exotic batch-file paths.
To prevent further quoting headaches, an aux. environment variable, __ARGS is used in the code below to store all arguments that the batch file received (%*), which the PowerShell code can then access via $env:__ARGS on re-invocation.
#echo off
:: Save the arguments received in an aux. environment variable.
:: Note: The space after "=" is required for the PowerShell command
:: to also work if *no* arguments were passed.
set __ARGS= %*
:: Unless already elevated, relaunch this batch file,
:: with arguments passed through.
net session >NUL 2>NUL || (powershell.exe -nop -c "Start-Process -Verb RunAs cmd /k, ("^""%~f0"^"" -replace '[ &]', '^$&'), $env:__ARGS" & goto :eof)
:: Reset the aux. variable.
set __ARGS=
echo Now running with elevation. Arguments received:
echo. %*
[1] A simple example (call from cmd.exe): powershell -c "[Environment]::CommandLine; '%OS%'"

cmd /c and the & symbol in file path

I ran into a problem, where I have a batch file located in a directory that has the and symbol in it.
When I try to run the cmd /c on the batch file the and symbol messes up the cmd program even though the path is double quoted.
C:\>cmd /c "C:\This & That\batch.bat"
'C:\This' is not recognized as an internal or external command,
operable program or batch file.
The system cannot find the path specified.
I'm not sure what to do. I tried escaping the & , using ^& but that doesn't seem to work as I'm all-ready in double quotes.
If I run the same command line from a directory that does not have an & symbol it works fine.
C:\>cmd /c "C:\This and That\batch.bat"
C:\>echo "Hi There"
"Hi There"
Thanks for any help.
so this would be the best way.
You also need to escape the & with ^ and run double double quotes.
cmd /c ""C:\This ^& That\batch.bat""
or you can set a location variable and use && to run the set and cmd /c after each other.
set "location=C:\This ^& That" && cmd /c ""%location%\batch.bat""

How do I emulate a "wrapper script" on Windows?

On Linux, when I want to prepare the environment of a program before starting it, I'm using a wrapper script:
export JAVA_HOME=...
cd /some/folder
exec ./tool "$#"
How would I do the last line, especially the "$#", on Windows?
Note: I'm wrapping commands which take a lot of arguments (like java or mvn), so I need a solution which works for > 10 arguments.
Being able to exec would be nice but is only a minor concern.
Probably something like:
#echo off
setlocal enableextensions
set JAVA_HOME=...
cd ...
start "" .\sometool %*
endlocal
Setlocal localizes environment changes to the script (see setlocal /? for details), and %* means 'all script parameters'. The start command is a cmd.exe command that spawns an executable.
The start command has odd parsing rules; the first quoted string on its command line is considered to be a console window title, which is superfluous if you are not spawning a console window. This means that a command like this won't work as expected:
start "C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"
If you run this command, you will spawn a new instance of cmd.exe with the quoted string as its console window title, which is clearly not what was intended. Instead, you have to write this:
start "" "C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"

Environment Variable not expanding

Platform: Windows Vista Service Pack 2 (x86)
I was messing around with batch scripts and realized that they could act as the command prompt(yes I know batch scripts run threw the command prompt) I mean that a batch script could prompt the user for a command and then call the command.
SET command=
SET /P command=%cd%^>
ECHO(
%command%
ECHO(
The only problem is that when I type in for example cd %windir% I get an error message telling me that the system cannot find the path specified. So I typed echo %windir% and echo printed %windir% exactly it wasn't expanded at all. I am wondering if the problem is because I have the environment variable nested inside the %command% variable but from what I understand CMD.exe does support nested environment variables. I tried using Delayed Expansion but the variable still didn't expand.
Add a call or cmd /c to evaluate variables that way.
#echo off
setlocal
SET /P command=%cd%^>
call %command%
ECHO;

Resources