Reputation: 69
I'm trying to have a script update itself, and then relaunch itself.
The problem occurs when the script tries to pass parameters to itself, as apparently using param
clears $args
. I had an idea to make a custom $args
-handler that works like param
, but is there a better way? I do need the arguments to be named so some handling is necessary, I can't just use $args
.
param(
$a = "abc",
$b,
$c
)
Write-Host $a
Write-Host $b
Write-Host $c
Write-Host $args
This results in the following:
.\a.ps1 -a 1 -b 2 3
1
2
3
Writing the $args
to host returns nothing.
Upvotes: 1
Views: 1240
Reputation: 19684
Taking your problem statement:
I'm trying to have a script update itself, and then relaunch itself.
This is the purpose of the $PSBoundParameters
automatic variable:
.\myscript.ps1 @PSBoundParameters
And your other issue:
when the script tries to pass parameters to itself, as apparently using param clears $args
This is untrue. The issue in your example is positionally-bound parameter binding in action. What actually happens is the 3
gets bound to $c
. $args
will capture unbound parameters unless you have a parameter with the ValueFromRemainingArguments
attribute. You can stop this binding from occurring by using the CmdletBinding
attribute:
function Verb-Noun {
[CmdletBinding(PositionalBinding = $false)]
param(
As @mklement0
points out, you cannot use $args
in advanced functions, where you're using CmdletBinding
or Parameter
attributes, like my example above.
Docs:
about_Automatic_Variables#args
about_Functions_CmdletBindingAttribute
about_Functions_Advanced_Parameters
Upvotes: 5
Reputation: 23763
If you do not need to change the values of the parameters, you might just fetch the arguments from the raw command line:
Write-Host ($MyInvocation.Line -split '\.ps1[\s\''\"]\s*', 2)[-1])
(Or just re-invoke the whole command line in once, but you will need to prevent an infinitive loop somehow)
Upvotes: 0
Reputation: 13547
$args
are only available for the unbound parameters you pass into your script. Once you start binding params, each param you pass in to your script will be bound based on its value, type or position. Anything not matching your param binding will end up in $args
Let's say I have a script like this
#$args.ps1
write-host "args value 1 : $($args[0]) "
write-host "args value 2 : $($args[1]) "
When I call it, I can index into $args
and pull the values out.
& C:\temp\args.ps1 'SomeValue1' 'SomeValue2'
args value 1 : SomeValue1
args value 2 : SomeValue2
However, once I bind params, $args
will then only contains values which don't match your bindings. Notice that only the third param I pass in below ends up in $args
param($param1, $param2)
write-host "params value 1 : $($param1) "
write-host "params value 2 : $($param2) "
write-host "args value 1 : $($args[0]) "
write-host "args value 2 : $($args[1]) "
Now you'll some interesting behavior when I pass in additional params here.
& C:\temp\args.ps1 'SomeValue1' 'SomeValue2' 'SomeValue3'
params value 1 : SomeValue1
params value 2 : SomeValue2
args value 1 : SomeValue3
args value 2 :
Think about it like this: as we can see in the help under get-help about_automatic_variables
, $args is provided to map the undeclared parameters passed into a script. The second you begin declaring parameters, you are specifically describing which params your script will use, and $args
becomes a bit weird in usage.
$Args Contains an array of the undeclared parameters and/or parameter values that are passed to a function, script, or script block. When you create a function, you can declare the parameters by using the param keyword or by adding a comma-separated list of parameters in parentheses after the function name.
*thanks @LotPings for the correction on the behavior of $args
, I originally posted in error that $args
contians nothing if you bind params.
Upvotes: 1