Prevent coercion

252 views Asked by At

Assuming:

Function Invoke-Foo {
  Param(
    [string[]]$Ids
  )
  Foreach ($Id in $Ids) {    
    Write-Host $Id
  }
}

If I do this:

PS> Invoke-Foo -ids '0000','0001'
0000
0001

If I do this:

PS> Invoke-Foo -ids 0000,0001
0
1

In the second case, is there a way to prevent the coercion, other than make them explicit strings (first case)?

2

There are 2 answers

2
Mathias R. Jessen On BEST ANSWER

No, unfortunately not.

From the about_Parsing help file:

When processing a command, the Windows PowerShell parser operates
in expression mode or in argument mode: 

    - In expression mode, character string values must be contained in
      quotation marks. Numbers not enclosed in quotation marks are treated
      as numerical values (rather than as a series of characters). 

    - In argument mode, each value is treated as an expandable string 
      unless it begins with one of the following special characters: dollar
      sign ($), at sign (@), single quotation mark ('), double quotation
      mark ("), or an opening parenthesis (().

So, the parser evaluates 0001 before anything is passed to the function. We can test the effect of treating 0001 as an "Expandable String" with the ExpandString() method:

PS C:\> $ExecutionContext.InvokeCommand.ExpandString(0001)
1
0
Varvara Kalinina On

At least, if you are sure that your ids are in the range [0, 9999], you can do the formatting like this:

Function Invoke-Foo {
    Param([int[]]$Ids)
    Foreach ($Id in $Ids) {    
        Write-Host ([System.String]::Format("{0:D4}", $Id))
    }
}

More about padding numbers with leading zeros can be found here.

What important to note here:

  1. Padding will work for numbers. I changed the parameter typing to int[] so that if you pass the strings they will be converted to numbers and the padding will work for them too.

  2. This method (as it is now) limits you to the range of ids I mentioned before and it always will give you four-zeros-padded output, even if you pass it '003'