I'm trying to run a powershell script from the run dialog (will be used as a scheduled task), and I'm having troubles passing parameters.
The script will take in two parameters, named title and msg.
The script is located in: D:\Tasks Scripts\Powershell\script.ps1
This is what I'm trying to do:
powershell.exe -noexit 'D:\Tasks Scripts\Powershell\script.ps1' -title 'Hello world' -msg 'This is a test message'
But it fails upon reading the parameters.
Running .\script.ps1 -title 'Hello world' -msg 'This is a test message'
on powershell works fine.
Use -file
before the path to your script:
powershell.exe -noexit -file 'D:\Tasks Scripts\Powershell\script.ps1' etc...
I usually run powershell scripts from cmd.exe because this is portable
(works out-of-the-box on others' computers, like developer folks or clients):
no need to worry about Set-ExecutionPolicy or associating the .ps1 extension.
I create the file with .cmd extension (instead of .ps1), and copy&paste a short,
constant code to the first line(s) that invokes powershell.exe and passes the rest
of the file to it.
Passing arguments is tricky. I have multiple variants of the constant code
because the general case is painful.
when not passing arguments, the .cmd file looks like this:
@powershell -c ".(iex('{#'+(gc '%~f0' -raw)+'}'))" & goto :eof
# ...arbitrary PS code here...
write-host hello, world!
This uses the -Command argument of powershell.exe. Powershell reads the .cmd
file as text, puts it in a ScriptBlock with the first line commented out,
and evaluates it with the '.' command.
Further command line arguments
can be added to the Powershell invocation as required (e.g. -ExecutionPolicy Unrestricted,
-Sta etc.)
when passing arguments that do not contain spaces or are 'single-quoted'
(which is non-standard in cmd.exe), the one-liner is this:
@powershell -c ".(iex('{#'+(gc($argv0='%~f0') -raw)+'}'))" %* & goto :eof
write-host this is $argv0 arguments: "[$($args -join '] [')]"
param()
declarations could be used as well, $args
is not obligatory.
$argv0
is used to compensate for the missing $MyInvocation.PS*
info.
Examples:
G:\>lala.cmd
this is G:\lala.cmd arguments: []
G:\>lala.cmd "1 2" "3 4"
this is G:\lala.cmd arguments: [1] [2] [3] [4]
G:\>lala.cmd '1 2' '3 4'
this is G:\lala.cmd arguments: [1 2] [3 4]
when passing arguments that are "double-quoted" but do not contain
the & and ' characters, I use a two-liner to replace all " with '
@echo off& set A= %*& set B=@powershell -c "$argv0='%~f0';.(iex('{'
%B%+(gc $argv0|select -skip 2|out-string)+'}'))" %A:"='%&goto :eof
write-host this is $argv0 arguments: "[$($args -join '] [')]"
(Note that the space is important in the A= %*
assignment for the
argument-less case.)
Results:
G:\>lala.cmd
this is G:\lala.cmd arguments: []
G:\>lala.cmd "1 2" "3 4"
this is G:\lala.cmd arguments: [1 2] [3 4]
G:\>lala.cmd '1 2' '3 4'
this is G:\lala.cmd arguments: [1 2] [3 4]
the most general case passes the arguments via environment variables
thus Powershell's param()
declaration does not work. In this case the
arguments are expected to be "double-quoted" and may contain ' or &
(except for the path of the .cmd file itself):
;@echo off & setlocal & set A=1& set ARGV0=%~f0
;:loop
;set /A A+=1& set ARG%A%=%1& shift& if defined ARG%A% goto :loop
;powershell -c ".(iex('{',(gc '%ARGV0%'|?{$_ -notlike ';*'}),'}'|out-string))"
;endlocal & goto :eof
for ($i,$arg=1,@(); test-path -li "env:ARG$i"; $i+=1) { $arg += iex("(`${env:ARG$i}).Trim('`"')") }
write-host this is $env:argv0 arguments: "[$($arg -join '] [')]"
write-host arg[5] is ($arg[5]|%{if($_){$_}else{'$null'}})
(Note that in the first line A=1&
must not contain space.)
Result:
G:\>lala.cmd "a b" "c d" "e&f" 'g' "h^j"
this is G:\lala.cmd arguments: [a b] [c d] [e&f] ['g'] [h^j]
arg[5] is $null