1

Suppose I have the following testArgsX.ps1 file:

$ARG_X_PARAMETER=1
If ($args[0] -ne "") {
    echo ARGS[X]="`"$args[0]`""
    $ARG_X_PARAMETER=$args[0]
}
echo ARG_X_PARAMETER=$ARG_X_PARAMETER

When I execute it either in a command prompt (C:\Test> powershell .\testArgsX.ps1) or in PowerShell prompt (PS C:\Test> .\testArgsX.ps1), it outputs the following:

ARGS[X]="[0]"
ARG_X_PARAMETER=

It seems that $args[0], in the if-condition, is not interpreted as a scalar value. Although I understand there are 2 ways to circumvent this problem (shown below). I want to know why it does not interpret it as a scalar value and if there is a way to fix it so that it does.

  1. Take out the entire if statement (If ( ... ) { ... }) and replace it with Param ( [Int]$RUN_JUST_ONCE = 1 )
  2. Change the if condition from If ($args[0] -ne "") { to If ($args.Length -gt 0) {
mak
  • 197
  • 9

1 Answers1

1

$args[0] is a scalar, but accessing a non-existent array element in PowerShell returns $null[1], and $null is indeed not equal to the empty string ("" or '').

  • Therefore, you should test for $null.

    • Note that testing for $null is best performed by placing $null on the LHS ($null -ne $args[0]), because on the RHS it would act as a filter instead of returning a Boolean in case the other operand happens to be an array.
  • Also, note that in order to use an expression such as $args[0] inside "...", an expandable (interpolating) string, you must use $(), the subexpression operator; without it, $args as a whole is expanded, and [0] is used verbatim - see this answer

  • echo is a built-in alias for the Write-Output cmdlet, whose explicit use is rarely needed; simply using a command or expression whose output is neither captured nor redirected is implicitly output.

To put it all together:

$ARG_X_PARAMETER=1
If ($null -ne $args[0]) {
    "ARGS[X]=`"$($args[0])`""
    $ARG_X_PARAMETER=$args[0]
}

"ARG_X_PARAMETER=$ARG_X_PARAMETER"

Alternatively, declare parameters for your script, which also makes it easy to assign default values:

param(
  # This implicitly becomes the 1st positional parameter.
  $ARG_X_PARAMETER = 1
)

"ARG_X_PARAMETER=$ARG_X_PARAMETER"

By default, parameters are positional, which means they can be used unnamed (e.g. testArgsX.ps1 42), though using the name explicitly is always an option (e.g.
testArgsX.ps1 -ARG_X_PARAMETER 42) - though a better name is the probably called for.

PowerShell optionally allows you to assign a data type to parameters and use a variety of attributes, notably ones for argument validation.

See about_Functions and about_Functions_Advanced_Parameters.


[1] With Set-StrictMode -Version 3 or higher in effect, accessing a non-existent element causes a statement-terminating error instead.

mklement0
  • 382,024
  • 64
  • 607
  • 775