I have the following commands that I need to run in a Command Prompt from PowerShell, in order.
/k "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
copype amd64 C:\WinPE_amd64_PS
I can execute the first command by the following PowerShell command:
Start-Process -FilePath 'C:\Windows\system32\cmd.exe' -ArgumentList '/k "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"'
That works fine, but I can't pass the second command into the Start-Process. How do I go about doing that? The DandISetEnv.bat file needs to be loaded and the Command Prompt remain open using the /k switch.
Is there a switch or command I can put between the first and second command, or redirect the next command into the Command Prompt process that was started up?
Since your intent is to pass multiple commands to cmd, you need to separate these commands with its statement-chaining operator, &:
# Define the array of commands to pass to cmd.exe
$cmdCommands =
'"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"',
'copype amd64 C:\WinPE_amd64_PS'
Start-Process -FilePath cmd -ArgumentList ('/k ' + ($cmdCommands -join ' & '))
Note that if you wanted to only execute the latter command if the former succeeds, you should use && instead of &.
Related
Thank you for your help.
I use Powershell in the Windows 10 command prompt and try to execute commands with administrative rights.
When I try the following three, a, b and c, I cannot start with "RunAs" as I think.
Does anyone know how to solve this problem?
(a) It can be executed successfully. The arguments are also passed correctly.
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '\"a\" \"B C\" \"d\"' -Verb Open
(b) Does not start after UAC confirmation.
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '\"a\" \"B C\" \"d\"' -Verb RunAs
(c) It is possible to invoke it, but the "B C" argument is not reflected in the "double quotes" argument, and "B C" is recognized separately.
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '"a" "B C" "d"' -Verb RunAs
Translated with www.DeepL.com/Translator (free version)
tl;dr
REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k {0} \"a\" \"B C\" \"d\"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))
Replace /k with /c to make the new window close automatically when the batch file exits.
The working directory for the batch file is C:\Windows\System32.
If you also want to ensure that the batch file executes in the caller's current directory:
REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k cd \"{0}\" ^&^& {1} \"a\" \"B C\" \"d\"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))
Read on for an explanation.
The main problem is:
When you pass a batch-file path directly - as the executable - to Start-Process -Verb RunAs, there seems to be a problem with passing an argument list that contains double quotes (") - I don't know the reason, but the problem occurs in a layer below PowerShell, either in the underlying System.Diagnostics.ProcessStartInfo .NET API or possibly even in the underlying ShellExecuteExe WinAPI function.
(If you either need no arguments or none of them require ", you can pass the batch-file path directly as the executable; by default, because the underlying executable is cmd.exe, which is located in C:\Windows\System32, C:\Windows\System32 becomes the working directory, which you can override with -WorkingDirectory, but note that you must then refer to the batch file with a (possibly relative) path, if it is located elsewhere.)
Workaround:
Instead of using the batch-file path directly as the executable to launch, use cmd.exe as the executable, and pass the batch-file path and all its arguments as arguments to the /c option (or /k, if you want to keep the new window open).
Unfortunately, with -Verb Runas, cmd.exe invariably uses C:\Windows\System32 as the new process' working directory - passing a startup directory with the -WorkingDirectory parameter is then ignored.
The same applies to powershell.exe, but, curiously, not to pwsh.exe (PowerShell [Core] v6+) and .NET-based executables, which (a) preserve the caller's working directory by default and (b) do honor a -WorkingDirectory argument.
Therefore, if your TestEnv.cmd batch file is located in the current directory - as opposed to a directory listed in the PATH environment variable ($env:PATH) - you must pass the batch file's full path to cmd.exe, which you can determine with Convert-Path.
Note: If you batch file is in the PATH, so to speak, this step isn't necessary.
Unfortunately, another workaround is then needed, in case the batch file's full path contains spaces: Because "..."-enclosing the batch-file path inexplicably fails, the individual spaces must be ^-escaped instead.
From inside PowerShell this means your command must look like this (note that I'm using /k to keep the new window open, for diagnostic purposes; use /c to auto-close the window when the batch file exits):
# From inside PowerShell:
Start-Process cmd.exe -Verb RunAs (
'/k {0} "a" "B C" "d"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^ ')
)
Caveat: Since cmd.exe is being invoked, C:\Windows\System32 is the working directory.
If you also want to ensure that the batch file executes in the caller's current directory, you must prepend a cd command:
# From inside PowerShell:
Start-Process cmd.exe -Verb RunAs (
'/k cd "{0}" && {1} "a" "B C" "d"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^ ')
)
Calling this from cmd.exe (Command Prompt) / a batch file, via Windows PowerShell's CLI, powershell.exe (note that in PowerShell [Core] v6+ it is now pwsh), adds additional complexity:
The " chars. must be escaped as \" so that PowerShell recognizes as them as part of the command to execute rather than as syntactic quoting around the CLI arguments.
^ must be escaped as ^^ and, in the second command below, & as ^& to prevent cmd.exe from interpreting these characters (up front).
REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k {0} \"a\" \"B C\" \"d\"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))
If you also want to ensure that the batch file executes in the caller's current directory:
REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k cd \"{0}\" ^&^& {1} \"a\" \"B C\" \"d\"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))
I am new to Powershell.I am trying to generate a war file in the location of jar.exe , any inputs highly appreciated.
I have tried to generate the war file using Start Process, But it is not generating the war file
$wargen=Start-Process -FilePath "cmd.exe" -ArgumentList "/K cd /d D:\Temp\ws\9.0\base\java\8.0\bin\jar.exe -cvf foo.war" -Verb "runas" -Verbose
You don't need to try so hard. It's not necessary to invoke Start-Process or cmd.exe to run a command. PowerShell is a shell; it can run commands. Just type the command at the PowerShell prompt and press Enter.
PS C:\> D:\Temp\ws\9.0\base\java\8.0\bin\jar.exe -cvf foo.war
I am wondering about why your example uses the runas shell verb to run the command as an elevated process; my guess is that this is unnecessary.
I'm using Start-Process to start another instance of Powershell as an administrator but when I try to pass the argument list, whether as a variable or as a plain string, Powershell removes the quotes. Below is the command I'm using:
$argu = '-noexit "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"';
powershell Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu
This is the error I get:
x86 : The term 'x86' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At line:1 char:88
+ ... Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\v ...
+ ~~~
+ CategoryInfo : ObjectNotFound: (x86:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Thank you in advance for any help.
Update:
$argu = '''-noexit ""C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat""''';
powershell Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu
This almost fixes it but now I'm getting the error above in the second window instead of the first.
(A) From inside PowerShell:
$argu = '-noexit -command & \"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat\"'
Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu
Note: I'm not calling Start-Process via powershell.exe, as there is generally no need for that.
The embedded " are \-escaped, which is what PowerShell requires when you call its CLI (perhaps surprisingly, given that PowerShell-internally it is ` that acts as the escape character).
That said given that the " are embedded inside '...' here, they shouldn't require extra escaping - see below.
The file path to execute is prefixed with call operator &, because you need it in order to execute files that are specified in quoted form.
Note that I've added -Command, which is not strictly necessary in Windows PowerShell, but would be if you ran your command from PowerShell Core (which now defaults to -File).
Alternatively, you could also specify your arguments individually, as part of an array, which is arguably the cleaner solution:
$argu = '-noexit', '-command', '&', 'de',
'\"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat\"'
Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu
Sadly, even in this case you need the extra, embedded quoting for arguments that contain spaces, which is a known Start-Process problem being tracked on GitHub.
PowerShell's handling of quoting when calling external programs is generally problematic; the current issues are summarized in this GitHub issue.
(B) From outside PowerShell (cmd.exe, a custom File Explorer context menu):
powershell -command Start-Process -Verb RunAs -FilePath powershell -ArgumentList '-noexit -command . ''C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat'''
single-quoting is now employed (with nested single quotes escaped as ''), because double-quoting would substantially complicate the escaping.
. is used instead of & to execute the .bat file, which avoids a problem with how the & is parsed; while . generally serves a different purpose than &, the two operators behave the same when calling external programs.
If you also want to set the working directory for the PowerShell session that ultimately opens elevated, you need to incorporate an explicit Set-Location (cd) call into the command string, because Start-Process -Verb RunAs always defaults to the SYSTEM32 folder (even the -WorkingDirectory parameter doesn't help in that case).
For that to work safely, however, you must quote the directory path using double-quoting, given that file names may contain single quotes; with %V as the directory path (which File Explorer supplies to commands invoked via custom context menus), the properly escaped Set-Location call looks like this (I wish I were kidding):
Set-Location \"\"\"%V%\"\"\"
Integrated into the full command (using Set-Location's built-in alias cd for brevity):
powershell -command Start-Process -Verb RunAs -FilePath powershell -ArgumentList '-noexit -command cd \"\"\"%V%\"\"\"; . ''C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat'''
As an aside: PowerShell Core now has a -WorkingDirectory (-wd) CLI parameter that allows you to control the startup directory more robustly (pwsh -wd "c:\path\to\dir" ...); in fact, it was precisely the File Explorer custom context-menu use case that prompted the introduction of this parameter.
I want to register a dll using gacutil.exe.
Start-Process -Wait -FilePath "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\gacutil.exe" -ArgumentList '/u', "USB\CRM\Common"
It throw the error:
You don't need Start-Process if you just want to run a command at the PowerShell command line. PowerShell can run commands typed at its prompt. (It's a shell; one of the purposes of a shell is to run commands you enter.) Since the command contains spaces, enclose it in " and execute it with the & (call or invocation) operator.
& "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\gacutil.exe" /u USB\CRM\Common
Is there any possibility to run a cmd command from a different folder then the script home location (e.g. C:\ScriptHome)?
I mean e.g.
Cmd /C "C:\Test\test.exe"
but this exe should be called from e.g. "C:\RunTestExeHere"
Basically, it can be done in pure cmd, like cd "C:\RunTestExeHere" and after
C:\RunTestExeHere>C:\Test\test.exe
but can it be done in powershell?
Thank you!
Your best bet is to sandwich your external command between Push-Location and Pop-Location commands.
A simple example:
Push-Location -EA Stop C:\ # You'd use C:\RunTestExeHere instead
cmd /c dir # You'd use & "C:\Test\test.exe" instead
Pop-Location
Another option (the invocation syntax is less convenient):
Start-Process -Wait -NoNewWindow cmd -ArgumentList /c, dir -WorkingDirectory C:\