String being treated as Int

I have a function where a parameter variable declared as a [string]. The problem is I notice that if I feed it numbers with leading zeroes (e.g. 00426) it will trim those zeroes like it was an Int. I thought the point of making it a string is so that it won’t fiddle with input like that? Any way to avoid this? The only way I know to workaround is by wrapping input in quotes:

Bad:
My-Function -Parameter 0002440, 000953

Good:
My-Function -Parameter “0002440”, “000953”.

Parameter:

        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Device,  

Well, technically, a series of digits not in quotes is a number. The zeros don’t get “trimmed,” they’re just not significant, so they’re not stored - and that happens before the coercion into string. Put the digits in quotes if you want them treated as a string from the outset - as you noticed.

So there’s no way to force it to interpret them as significant such as with adding something to the console profile?

I just was hoping to avoid it since this script will be used by others and it will be one less “gotcha” they will have to deal with, plus it doesn’t appear it would translate as easily from other sources, such as pulling those values from CSVs. If that’s the nature of the beast however then I’ll just have to work around it but I feel it’ll end up being rather kludgy.

You can account for it in your function and pad the values passed to the function by using string format. In the example below we have an array of integers and an array of strings.

$array1 = 1234,64322,23523

$array2 = "1234","64322","23523"

foreach ($item in $array1) {
    "Array1 - ToString Method: {0}" -f $item.ToString("D8")
    "Array1 - Format Method: {0:D8}" -f $item
}

foreach ($item in $array2) {
    "Array2 - ToString Method: {0}" -f $item.ToString("D8")
    "Array2 - Format Method: {0:D8}" -f $item
}

When processing the “string”.ToString(“D8”) Powershell complained:

Cannot find an overload for "ToString" and the argument count: "1".
At line:1 char:1
+ $test.ToString("D8")
+ ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

So, I would use the string.Format method and pad the appropriate amount on $Device and then it would not matter if they passed strings or numbers, it would be 7 characters when being processed:

foreach ( $item in $Device ) {
    $item = "{0:D7}" -f $item
    "Doing something with device {0}" -f $item
}

Hi Rob,

Perhaps I’m not interpreting correctly. I tried the string.Format option for the string array but no changes occurred but it was able to pad the zeroes to the int array. MSDN documentation also says D format specifier is integral only, so I’d be surprised that it would work on a string. Any ideas?

This worked for me:

function Test-It {
    param(
        [Parameter(Mandatory=$true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName=$true,
        Position=0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Devices
    )
    begin{}
    process{
        foreach ($Device in $Devices) {
            $device = ([int]$Device).ToString("0000000")
            "Processing {0}" -f $device
        } 
    }
    end{}
}

Test-It -Devices 1234,64322,23523
Test-It -Devices "1234","64322","23523"

Output:

Processing 0001234
Processing 0064322
Processing 0023523
Processing 0001234
Processing 0064322
Processing 0023523

I also added ValueFromPipeline = $true which would allow you to pipe to the function:

"1234","64322","23523" | Test-It

Great, that works just fine! Only one minor thing I have to ask, and that’s how to get it to preserve the changes by placing the newly formatted values back into the original string$Device array. I noticed that it never actually places the results back into the array, and just displays them with the new format and then promptly discards the results.

It’s really a question of what you want to return. Typically, you want to return a PSObject.

function Test-It {
    param(
        [Parameter(Mandatory=$true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName=$true,
        Position=0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Devices
    )
    begin{}
    process{
        
        $results = foreach ($Device in $Devices) {
            $device = ([int]$Device).ToString("0000000")
            New-Object -TypeName PSObject -Property @{Device=$device;Status="Success"}
        } 
    }
    end{$results}
}

Test-It -Devices 1234,64322,23523 | Format-Table -AutoSize

The function would return this:

Status  Device 
------  ------ 
Success 0001234
Success 0064322
Success 0023523