Split string in Windows batch file over multiple lines - windows

I want to invoke an elevated Powershell to execute a script and pass a bunch of parameters. I would like to have every parameter in the .bat file on its own line. Usually I can use the carat ^ to span commands over several lines in .bat files, just like using a grave accent ` in Powershell scripts. But both don't work in this situation:
As a one-liner it works:
Powershell.exe -Command "& {Start-Process Powershell.exe -Verb RunAs -ArgumentList '-ExecutionPolicy Bypass -File %~dp0HelloWorld.ps1 -parameter1 Long -parameter2 list -parameter3 of -parameter4 parameters' }"
Trying to split it up into multiple lines using a caret ^ doesn't work:
Powershell.exe -Command "& {Start-Process Powershell.exe -Verb RunAs -ArgumentList '-ExecutionPolicy Bypass -File %~dp0HelloWorld.ps1 ^
-parameter1 Long ^
-parameter2 list ^
-parameter3 of ^
-parameter4 parameters ^
'}"
Here is an example HelloWorld.ps1 to test with, (has to be in the same directory as the batch file):
param (
$parameter1="",
$parameter2="",
$parameter3="",
$parameter4=""
)
write-host "$parameter1 $parameter2 $parameter3 $parameter4"
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');

The simplest way to handle the issue in your example case above, is to use doublequotes, " instead of single, '. However to prevent cmd.exe from failing to parse the command, you'll need to escape those nested doublequotes, using backslashes, i.e. \".
Example:
#Powershell.exe -Command "& {Start-Process Powershell.exe -Verb RunAs -ArgumentList \" ^
-ExecutionPolicy RemoteSigned ^
-File `\"%~dp0HelloWorld.ps1`\" ^
-parameter1 Long ^
-parameter2 list ^
-parameter3 of ^
-parameter4 parameters ^
\"}"
I have specifically changed the ExecutionPolicy from Bypass, (which I wouldn't ever recommend using, even moreso when running elevated), to RemoteSigned, please do not change it back. Also for added safety, I have quoted your .ps1 file path, which could contain spaces. The backslashes escape the doublequotes for the cmd.exe parser, (as already mentioned), and then backticks escape the remaining nested doublequotes for the powershell.exe parser.

Related

Running SendKeys commands from a .lnk (shortcut) with powershell doesn't work

I'm playing around with SendKeys and powershell. I tried to close the active window with SendKeys (ALT + F4) after running a shortcut. I got this working with adding the following command to the Target field of a Windows shortcut(.lnk):
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "C:\Users\user\Documents\TEST\test.ps1"
Code in test.ps1:
(New-Object -ComObject Wscript.Shell).SendKeys("%{F4}")
When I run the shortcut the active windows closes. Now I wanted to make this work without .ps1 script. I tried to run the powershell command from the Target field of the shortcut and that didn't work.
The commands I added to the shortcut Target field that didn't work:
$ C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe $wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys("%{F4}")
$ C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys("%{F4}")"
$ C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe (New-Object -ComObject Wscript.Shell).SendKeys("%{F4}")
$ C:\Windows\System32\cmd.exe /c powershell.exe -noprofile -executionpolicy bypass $wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys("%{F4}")
$ C:\Windows\System32\cmd.exe /c powershell.exe -noprofile -executionpolicy bypass "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys("%{F4}")"
$ C:\Windows\System32\cmd.exe /c powershell.exe -noprofile -executionpolicy bypass (New-Object -ComObject Wscript.Shell).SendKeys("%{F4}")
What I'm doing wrong in the commands above? I need to use a different syntax when I run powershell commands from Shortcuts?
What I'm doing wrong in the commands above?
You're calling powershell.exe, the Windows PowerShell CLI, from outside PowerShell, such as in the no-shell context in which shortcut-file command lines are executed.
For troubleshooting such command lines, use -noexit as the first powershell.exe parameter in order to keep the resulting PowerShell session open, which allows you to see any error message.
The implied CLI parameter of powershell.exe is -Command (-c), which treats all subsequent arguments as tokens of a piece of PowerShell code to execute.
However, any unquoted " characters are stripped beforehand, during PowerShell's command-line processing.
In order to pass " characters through as part of a PowerShell command being passed to the PowerShell CLI via (possibly implied) -Command (-c), you need to escape them as \" (sic)
Additionally, for full robustness, it is best to pass the entire PowerShell command inside a single (unescaped) "..." string.
Therefore:
powershell.exe -noprofile -executionpolicy bypass "(New-Object -ComObject Wscript.Shell).SendKeys(\"%{F4}\")"
However, given that, in the context of your PowerShell command, a single-quoted string ('...') to represent the key combination %{F4} argument will do (and is arguably preferable, given that you only need "..." quoting in PowerShell for string interpolation), you can simplify to:
powershell.exe -noprofile -executionpolicy bypass "(New-Object -ComObject Wscript.Shell).SendKeys('%{F4}')"
The issue here is that the commands you are attempting to execute aren't being passed to the powershell exe correctly.
The below works for me in the terminal and also in the shortcut field:
powershell.exe -command "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('%{F4}')"
If the command you are attempting to execute does not need to interpolate any variables in its strings etc. (yours does not) then you can test your statements by executing them in a powershell session (Note that i have switched to single quotes ' for $wshell.SendKeys('%{F4}')"). Your examples would yield some errors and so you know it wont work in the shortcut.
and to give an example for the rest of your attempts (full path removed for brevity)
powershell.exe -command "(New-Object -ComObject Wscript.Shell).SendKeys('%{F4}')"
powershell.exe -noprofile -executionpolicy bypass -command "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('%{F4}')"

Execute powershell string via CMD

I try to execute the following command in console:
powershell.exe -NoLogo -Command `"Get-ChildItem "Cert:\CurrentUser\My" | WHERE{$_.Extensions['Certificate Template Name'] -match 'CA'}`"
But I get this error:
I need to execute this command in CMD, not ps1 script.
There was in issue with your double quotes.
I've changed it slightly:
powershell.exe -NoLogo -Command "Get-ChildItem Cert:\CurrentUser\My | where {$_.Extensions['Certificate Template Name'] -match 'CA'}"

Open a program as administrator with conditions (e.g. /h or something)

I want to run a program with PowerShell using Start-Process in a batch but with conditions.
I tested it and I ran cmd /c using the Start-Process command.
Command:
powershell -Command "Start-Process `cmd /c` -Verb runas"
It didn't work.
So I tested it on PowerShell. Tried the same command and it returned this error:
Start-Process : A positional parameter cannot be found that accepts argument
'runas'.
At line:1 char:14
+ Start-Process <<<< 'cmd /c' -Verb runas
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand
How can I make this work on batch using powershell command and on the main PowerShell?
The backtick is PowerShell's escape character. In a statement
Start-Process `cmd /c` -Verb runas
the backticks escape the c of cmd and the space following the /c. The former isn't problematic, because it just makes the c a literal c (which it is anyway). However, escaping the space between /c and -Verb effectively turns the whole sequence /c -Verb into a single string. Basically it's the same as if you'd run this statement:
Start-Process cmd "/c -Verb" runas
Since Start-Process accepts only 2 positional parameters (-FilePath and -ArgumentList) everything else must be passed via named parameters. Hence the error about no positional parameter accepting the argument runas.
Run the command like this:
Start-Process cmd /c, dir, "$env:windir\temp" -Verb runas
or
Start-Process -FilePath 'cmd.exe' -ArgumentList '/c', 'dir', "$env:windir\temp" -Verb runas
or like this (from CMD):
powershell.exe -Command "Start-Process cmd /c, dir, \"$env:windir\temp\" -Verb runas"
and it will work as you'd expect.
Edit
Since apparently it wasn't clear enough initially: the argument for the -ArgumentList parameter is a comma-separated list (an array).
Start-Process cmd /c, dir, "$env:windir\temp" -Verb runas
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
# this right here

How to start PowerShell script from BAT file with proper Working Directory?

I'm trying to create bat script that can start PowerShell script named the same as bat file in proper working directotry.
This is what I got:
#ECHO OFF
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -WorkingDirectory '%~dp0' -Verb RunAs}"
PAUSE
Passing working directory this way does not work.
How to make script that will pass proper working directroy and also command line arguments?
The -WorkingDirectory parameter doesn't work when using -Verb RunAs. Instead, you have to set the working directory by calling cd within a -Command string.
This is what I use: (cmd/batch-file command)
powershell -command " Start-Process PowerShell -Verb RunAs \""-Command `\""cd '%cd%'; & 'PathToPS1File';`\""\"" "
If you want to make a "Run script as admin" right-click command in Windows Explorer, create a new registry key at HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\Run with PowerShell (Admin)\Command, and set its value to the command above -- except replacing %cd% with %W, and PathToPS1File with %1 (if you want it to execute the right-clicked file).
Result: (Windows Explorer context-menu shell command)
powershell -command " Start-Process PowerShell -Verb RunAs \""-Command `\""cd '%W'; & '%1';`\""\"" "
EDIT: There's an alternative way to have the script be run as admin from Explorer, by using the "runas" sub-key: https://winaero.com/blog/run-as-administrator-context-menu-for-power-shell-ps1-files
If you want to run your script as admin from an existing powershell, remove the outer powershell call, replace %W with $pwd, replace %1 with the ps1 file-path, and replace each \"" with just ".
Note: The \""'s are just escaped quotes, for when calling from the Windows shell/command-line (it's quote-handling is terrible). In this particular case, just \" should also work, but I use the more robust \"" for easier extension.
See here for more info: https://stackoverflow.com/a/31413730/2441655
Result: (PowerShell command)
Start-Process PowerShell -Verb RunAs "-Command `"cd '$pwd'; & 'PathToPS1File';`""
Important note: The commands above are assuming that your computer has already been configured to allow script execution. If that's not the case, you may need to add -ExecutionPolicy Bypass to your powershell flags. (you may also want -NoProfile to avoid running profile scripts)
A workaround is to let the PowerShell script change the directory to it's own origin with:
Set-Location (Split-Path $MyInvocation.MyCommand.Path)
as the first command.
As per mklement0s hint: In PSv3+ use the simpler:
Set-Location -LiteralPath $PSScriptRoot
Or use this directory to open adjacent files.
$MyDir = Split-Path $MyInvocation.MyCommand.Path
$Content = Get-Content (Join-Path $MyDir OtherFile.txt)

Why does a second parameter cause this script to fail?

I have three bat files in Windows 7
1) main.bat:
test testEcho parm1 parm2
2) test.bat:
#echo With one parm
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -nologo -noprofile ^
-executionpolicy bypass -command "& {start-process -verb 'runas' -file %1.bat %2}"
#echo With two parms
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -nologo -noprofile ^
-executionpolicy bypass -command "& {start-process -verb 'runas' -file %1.bat %2 %3}"
pause
3) testEcho.bat:
#echo ==== 0:%0 1:%1 2:%2
pause
When I run main.bat, it passes the name of the target bat file (testEcho) and two parameters. Then I use PowerShell twice to run the passed in bat file name (%1 = testEcho). The first time is with one parameter (%2 = parm1) and the second time with two parameters (%2 = parm1, %3 = parm2).
The first time works as expected, running testEcho.bat with one parameter. It echos the result:
==== 0:C:\testEcho.bat 1:parm1 2:
The second run fails with error:
"Start-Process: A positional parameter cannot be found that accepts
argument 'parm2'.At line:1 char:4"
Why does the second attempt fail and how can I get it to work? The only difference between them is that the first attempt passes only one parameter and the second attempt passes more than one parameter.
You need to specify an ArgumentList in order to use multiple arguments. These arguments need to be delimited by commas. http://ss64.com/ps/start-process.html
#echo With one parm
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -nologo -noprofile ^
-executionpolicy bypass -command "& {start-process -verb 'runas' -file %1.bat %2}"
#echo With two parms
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -nologo -noprofile ^
-executionpolicy bypass -command "& {start-process -verb 'runas' -file %1.bat -ArgumentList %2, %3}"
pause

Resources