powershell command parameter with spaces - powershell

I am trying to call a powershell script using -command argument from a batch file. The powershell script accepts an argument which may contain spaces. The command fails to accept argument with spaces.
Here is there the batch file.
#echo off
set arg1=%*
call powershell.exe -ExecutionPolicy Bypass -command ".\build.ps1 %arg1%; exit $LASTEXITCODE"
exit /b %ERRORLEVEL%
This is how the batch file is called - .\build.bat '-testToolPath=as sdaf'
I am using -command instead of -file just to return the LASTEXITCODE

Have you tried to use escaped doublequotes?
call powershell -ExecutionPolicy Bypass -command ".\build.ps1 ^"%arg1%^"; exit $LASTEXITCODE"
Maybe you have to remove the other quotes before:
set "arg1=%arg1:'=%"

Related

Run Script within Batch File with Parameters

I'm writing a Batch File, and in this batch file i execute a script.
Batch File:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""C:\Public\File\SomeScript.ps1""' -Verb RunAs}"
Now this works fine.
Is it possible to execute the SomeScript.ps1 with parameters ?
Like
#echo off
echo %1
echo %2
echo %3
echo %4
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""C:\Public\File\SomeScript.ps1 Arg1 %1 Arg2 %2 Arg3 %3 Arg4 %4""' -Verb RunAs}"
The Batch File echos the values I'm giving. But after that nothing happens. So I'm not sure if I'm passing the Arguments correctly.
Any help appreciated :)
The arguments must be outside the quoted script path, ""C:\Public\File\SomeScript.ps1""
To be safe, you should double-quote the arguments too.
Use \" to escape embedded double quotes when calling the CLI of Windows PowerShell (powershell.exe) as in your case), and "" for PowerShell (Core) (pwsh.exe).
Note: Depending on the specific values of the pass-through arguments, use of \" with Windows PowerShell can break, due to cmd.exe's limitations; the - ugly - workaround is to use "^"" (sic).
Therefore (limited to passing %1 for brevity):
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process PowerShell '-NoProfile -ExecutionPolicy Bypass -File \"C:\Public\File\SomeScript.ps1\" Arg1 \"%1\"' -Verb RunAs"
As an aside: There's no reason to use & { ... } in order to invoke code passed to PowerShell's CLI via the -Command (-c) parameter - just use ... directly, as shown above. Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.

Calling a Powershell script from Batch script..But need the batch script to wait for the Powershell script to complete

I have a batch script being that has the following code in it:
Here is the batch script (Test.bat):
call powershell.exe -executionpolicy remotesigned -File TheScriptToBeExecuted.ps1
exit /b
The Powershell script (TheScriptToBeExecuted.ps1) has some wait built into it. But when this file is being called, the batch script is NOT waiting for the Powershell script to finish.
I ever tried:
START /wait powershell.exe -executionpolicy remotesigned -File TheScriptToBeExecuted.ps1
To no effect.
When I double click on the Test.bat file, it seems to be waiting. I have checked out a lot of answers, but couldnt find any that correspond to this issue.
Please help.
start /wait powershell.exe -executionpolicy remotesigned -File TheScriptToBeExecuted.ps1 | ECHO > nul
Try the above. Holds the command until scripts executed, without the Teminate Batch Prompt. Use start /min /wait if not needing to display or interact with the script, or Alternately:
start /wait powershell.exe -executionpolicy remotesigned -WindowStyle Hidden -File TheScriptToBeExecuted.ps1 | ECHO > nul
-WindowStyle Value
Sets the window style for the session. Valid values are Normal, Minimized, Maximized and Hidden.
* | * pipes the output of the command, however as your just starting powershell.exe and not using it in the context of utilizing a command like follows, It shouldn't be an issue.
powershell -command "((Get-date).AddDays(0)).ToString(':dd:MM:yyyy') | set-content 'captureVar.txt'" && set /p Yesterday=<captureVar.txt
It worked for the script I tested, but it's not thoroughly tested.
let me know how it goes.
I think the issue is more likely to be within "TheScriptToBeExecuted.ps1" than your bat. In fact several powershell command are working as Asyncronous.
I tested a Sleep-Start, which is not Asyncronous at all using the following code and the bat is waiting the end of it.
This is the code I used in my .bat
REM RUNTEST.BAT
time /T
echo started
powershell -executionpolicy remotesigned -File C:\Users\Alex\Desktop\DA_PROVARE\test.ps1
time /T
echo done
exit /b
The ps1 content is just one row, here below:
Start-Sleep -Seconds 25
The problem you are facing is probably because of the account under which the scheduler runs. Have faced similar problems where the .bat and/or .ps1 doesn't behave the same if launched by a scheduler or other tools
powershell -ExecutionPolicy ByPass -command ". 'C:\path\TheScriptToBeExecuted.ps1'"
This should do the it, if not then we will add < NUL to the end
powershell -ExecutionPolicy ByPass -command ". 'C:\path\TheScriptToBeExecuted.ps1'" < NUL
By using dot sourcing, we are opening powershell in the cmd window with the powershell reference in the above solution. Then the period allows the script to run in cmd window also. I did a double test and made a .ps1 with start-sleep -s 3 in it, and the above did wait for the powershell script to finish.
method 2
Using Start /wait
START /wait PowerShell.exe "& "'C:\path\TheScriptToBeExecuted.ps1'"
This method will not run inside the cmd window. It opens a powershell terminal and runs there then goes back to the bat.

Powershell / cmd - Redirecting embedded script's output streams to file

I have a situation in which a cmd script must launch a powershell script (install.ps1), elevating to admin if the cmd is not already. The line that launches the powershell looks like this:
powershell -WindowStyle Hidden "Start-Process powershell \"-NoP -Exec Bypass -File `\"%~dp0install.ps1`\" %args%\" -Verb runAs -Wait"
Or this also works:
powershell -WindowStyle Hidden "Start-Process powershell \"-NoP -Exec Bypass invoke-command { %~dp0install.ps1 %args% } \" -Verb runAs -Wait"
I would like to redirect the output from the install.ps1 script to a file for logging purposes, but having trouble doing this. Something like the following will generate the log.txt file, but output will still be shown in the console and the resulting log.txt file will be empty:
powershell -WindowStyle Hidden "Start-Process powershell \"-NoP -Exec Bypass invoke-command { %~dp0install.ps1 %args% } \" *> log.txt -Verb runAs -Wait"
Moving the *> log.txt portion to inside the Start-Process block (just after the invoke-command block), which I thought would be the key, seems to not even run the script at all (or it's flashing an error in the console too quick to see because it closes immediately).
Is it possible to achieve this logging behavior when the data I want is buried in a couple layers of powershell, executed by a cmd file?
We've technically gotten this to work by creating a powershell wrapper script that is called/elevated by the cmd, then within the wrapper calling the install.ps1 script and assigning logging in that call. Unfortunately the extra script layer causes a bunch of other tricky / more critical problems regarding getting arguments passed at the command line all the way through to the actual install script correctly, so we're really trying to avoid that route.
EDIT
Thanks to #mklement0 for the pointer that the redirect needed to be escaped, which was my problem. Follow-up question - The following command works great to log to file, but is there any way to get this same behavior using -File rather than -Command when invoking the PS script ("-Command %~dp0pg.ps1")?
powershell -Command "Start-Process -WindowStyle Hidden -Verb RunAs -Wait powershell \"-NoProfile -ExecutionPolicy Bypass -Command %~dp0pg.ps1 *^> %CD%\log.txt\""
Moving the *>log.txt redirection into the Invoke-Command block works in principle, but your problem is that in Windows PowerShell (as opposed to PowerShell Core) a process invoked with elevation (as admin), via -Verb RunAs, defaults to C:\Windows\System32 as the working directory, not the caller's working dir.
Aside from the fact that you probably didn't mean to create a log file in C:\Windows\System32, the command will fail, because writing to that location requires the caller to already be elevated.
The simplest solution is to make *> redirect to a file specified with a full path instead:
powershell -Command "Start-Process -WindowStyle Hidden -Verb RunAs -Wait powershell \"-NoProfile -ExecutionPolicy Bypass -Command %~dp0pg.ps1 *^> %CD%\log.txt\""
Note:
There is no need for Invoke-Command - just invoke the *.ps1 file directly; however, I've added -Command to make it more obvious that the remainder of the command line is to be interpreted as PowerShell code (not a script-file path with arguments only).
Because > is a cmd.exe metacharacter, it must be escaped as ^> in order to be passed through to PowerShell - perhaps surprisingly, cmd.exe considers the > to be unquoted, because it doesn't recognize the \" sequences as embedded double quotes - only PowerShell does.
As in your original command, the assumption is that neither %~dp0 - the batch file's folder dir. path - nor %CD% - the caller's working dir. path - contain spaces or other special chars. that would need additional quoting / escaping.

run script from command line and pass String array

So basically I need to run my ps1 script from command line and pass my custom arguments into my script. My script expects a String array, but when I run the command, I get an error that a positional parameter cannot be found that accepts argument 'X1'
This is my command line:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned -NoProfile -NonInteractive -File "C:\Program Files\MSBuild\MyScript.ps1" -builds "X1” “X2" "X3" "X4"
My understanding is it knows what to do with the first parameter 'X1' but not the second and so it crashes? Any ideas whay?
You need to use the -Command parameter instead of the -File parameter. Notice the change in behavior from the screenshot below, and the sample script.
[CmdletBinding()]
param (
[int[]] $MyInts
)
foreach ($MyInt in $MyInts) {
$MyInt + 1;
}
I can't quite explain why -file is not working but that parameter has other known issues. When you use it you don't get a proper exit code from PowerShell. Using -command does work:
Powershell.exe -ExecutionPolicy RemoteSigned -NoProfile -NonInteractive -Command "& {& 'C:\Program Files\MSBuild\myscript.ps1' -builds x1,x2,x3}"

Run PowerShell command from command prompt (no ps1 script)

I'm looking for a way to run just a couple PowerShell commands from the command prompt. I don't want to create a script for this since it's just a couple commands I need to run and since I don't really know how to script with PowerShell.
Here is the command I'm trying to use to start with:
Get-AppLockerFileInformation -Directory <folderpath> -Recurse -FileType <type>
I don't really want to create a script for this as it would be much easier if I can just run one or two commands from a batch file with the rest of the stuff.
EDIT:
Here is what I've tried so far.
1)
powershell -Command "Get-AppLockerFileInformation....."
Error: The term 'Get-AppLockerFileInformation is not recognized as the name of a cmdlet, function, script file, or operable program....
2)
powershell -Command {Get-AppLockerFileInformation.....}
No error with this way but I don't get anything back. If I use the Set-AppLockerPolicy... nothing happens.
3)
powershell -Command "{Get-AppLockerFileInformation.....}"
Error: The term 'Get-AppLockerFileInformation is not recognized as the name of a cmdlet, function, script file, or operable program....
4)
powershell -Command "& {Get-AppLockerFileInformation.....}"
Error: The term 'Get-AppLockerFileInformation is not recognized as the name of a cmdlet, function, script file, or operable program....
5)
powershell "& {Get-AppLockerFileInformation.....}"
Error: The term 'Get-AppLockerFileInformation is not recognized as the name of a cmdlet, function, script file, or operable program....
6)
powershell -ExecutionPolicy Bypass -NoLogo -NoProfile -Command {Get-AppLockerFileInformation....}
No error but nothing happens.
7)
powershell -ExecutionPolicy Bypass -NoLogo -NoProfile -Command "Get-AppLockerFileInformation...."
No error but nothing happens.
Here is the only answer that managed to work for my problem, got it figured out with the help of this webpage (nice reference).
powershell -command "& {&'some-command' someParam}"
Also, here is a neat way to do multiple commands:
powershell -command "& {&'some-command' someParam}"; "& {&'some-command' -SpecificArg someParam}"
For example, this is how I ran my 2 commands:
powershell -command "& {&'Import-Module' AppLocker}"; "& {&'Set-AppLockerPolicy' -XmlPolicy myXmlFilePath.xml}"
Run it on a single command line like so:
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile
-WindowStyle Hidden -Command "Get-AppLockerFileInformation -Directory <folderpath>
-Recurse -FileType <type>"
Maybe powershell -Command "Get-AppLockerFileInformation....."
Take a look at powershell /?
This works from my Windows 10's cmd.exe prompt
powershell -ExecutionPolicy Bypass -Command "Import-Module C:\Users\william\ps1\TravelBook; Get-TravelBook Hawaii"
This example shows
how to chain multiple commands
how to import module with module path
how to run a function defined in the module
No need for those fancy "&".