Search code examples
functionpowershellobjectreturn

PowerShell adds int indexes of items when returning object


I've seen a lot of similar questions on here but none of the solutions are working for me.

I have a function that looks like this

function Get-ManagedDevices {

    # ...(params and stuff here)...

    $batchResponse = Invoke-RestMethod @restParams
    $responses = @{}
    foreach ($response in $batchResponse.responses) {
        $responses.Add($response.id, $response.body) > $null
    }
    return , $responses
}

that gets called like this

$data = Get-Devices -AccessToken $AccessToken -DeviceIds $DeviceIds

When I'm debugging inside of the function call I am getting what I expect when I look at the $response variable which is something like

PS> $responses

Name                           Value
----                           -----
d1290207-c693-4663-88bf-58512… @{@odata.context=https://graph.microsoft.com/v1.0/$metadat…
7ad71b70-b992-490f-8822-1561a… @{@odata.context=https://graph.microsoft.com/v1.0/$metadat…

PS> $responses.count

1

However, when I try to use the $data variable from after the function call I get this

PS> $data

0
1

Name                           Value
----                           -----
d1290207-c693-4663-88bf-58512… @{@odata.context=https://graph.microsoft.com/v1.0/$metadat…
7ad71b70-b992-490f-8822-1561a… @{@odata.context=https://graph.microsoft.com/v1.0/$metadat…

PS> $data.count

3

I'm so confused. I piped the addition of the variable to the hashtable to $null with >$null. I added the unary operator with return like return , $responses which is what's recommended in the 'about_return' PowerShell documentation . I tried omitting the return keyword, using an ArrayList instead, using an array instead, etc...

What on earth is going on and why can't I return a hashtable from this function?! I feel like I'm going crazy.


Solution

  • The about_Return Documentation makes no mention of returning a hash table directly from a function. The common problem your referring to is the ability to return an array in whole rather than iterated down the pipeline.

    Its common and straight forward to return a hash table. At a glance your code could be:

    function Get-ManagedDevices {
    
        # ...(params and stuff here)...
    
        $batchResponse = Invoke-RestMethod @restParams
        $responses = @{}
        foreach ($response in $batchResponse.responses) {
            $responses.Add($response.id, $response.body)
        }
        return $responses
    }
    

    It shouldn't be more complicated that that. Remove the comma it has no effect when returning a hash. >$null has no effect on the HashTable .Add(...) method.

    Given your results and the example, there may be some artifact from your earlier attempts using an ArrayList. The .Add(...) method on an ArrayList will emit the index # that it's adding to. When we forget to [void] or | Out-Null or $null = ...Add(...) this usually results in unwanted output polluting the pipeline. As you're getting the 2 index numbers then your data...