Why Doesn't the Command Line Argument Work When Put Directly Into a Command in a Script?

Viewed 50

I am struggling to understand why using $args[$i] directly in this command doesn't work. It gives a completely wrong answer.

$memory=$(Get-Process | Where-Object {$_.id -eq "$($args[$i])"}  | select -expand VirtualMemorySize64)

However, putting the command line argument into another variable and using that one works.

$id=($args[$i])
$memory=$(Get-Process | Where-Object {$_.id -eq "$id"}  | select -expand VirtualMemorySize64)

An explanation on why this is would be great.

1 Answers

Every script block ({ ... }) in PowerShell has its own copy of the automatic $args array in which positionally passed arguments are automatically collected.

Therefore, $args inside {$_.id -eq "$($args[$i])"} is not the same as $args at the script level, so you indeed need to save the script-level value in an auxiliary variable first, as in your 2nd snippet, which can be streamlined as follows:

# Must use aux. variable to access the script-level $args inside
# the Where-Object script block.
$id = $args[$i] 

$memory = Get-Process | Where-Object { $_.id -eq $id } | 
            Select-Object -ExpandProperty VirtualMemorySize64

Note the absence of superfluous (...) and $(...), and the removal of quoting around "$id", given that the .Id property of process object is a number (type [int]).

Taking a step back, I suggest declaring parameters in your script, which is preferable to using $args - the variables holding the values of such parameters can be used without a problem in Where-Object script blocks.


Generally:

  • It is only meaningful to access $args inside a script block that you've invoked with arguments, which is not the case in a script block passed to Where-Object, where the input to the script block comes (only) from the pipeline, via the automatic $_ variable

  • By contrast, you can pass arguments to a script block, if you invoke it with &, the call operator, for instance: & { "[$args]" } 'foo' yields [foo].

Related