"Parallel" queries in functions

Hi folks! I’m trying to master functions in powershell and I have a problem with my functions running queries “one-by-one”.
So I have this sample function which I want to collect data from several computers in Domain (see below).
I have noticed that this command

`'pc01', 'pc02', 'pc03' | get-diskspace `

queries pc01, gets result and only after that sends next query to pc02. As far as I know powershell is able to split this query into 3 and send it to all 3 computers concurrently.

So my questin is: what have I done wrong? Why it isn’t working as planned?

`function Get-DiskSpace
{
    [CmdletBinding()]
    Param
    (
        # NetBios name of computer
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
        [string]$ComputerName = 'localhost'

    )

    Begin
    {
    $report = @()
    }
    Process
    {
    $disk = Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $ComputerName | 
    Select DeviceID, 
        @{n='Size'; e={$_.size / 1gb -as [int]}},
        @{n='Free'; e={$_.freespace / 1gb -as [int]}}



    foreach ($item in $disk.deviceid) {
        $i=[array]::IndexOf($disk.deviceid, $item)
        $letter = "Disk $item"
        $value = $disk.size[$i]
        $disk2 = New-Object PSObject
        $disk2 | Add-Member -type NoteProperty -Name 'Name' -Value $item
        $disk2 | Add-Member -type NoteProperty -Name 'Capacity' -Value $disk.size[$i]
        $disk2 | Add-Member -type NoteProperty -Name 'Freespace' -Value $disk.Free[$i]
        $report += $disk2
        }

    }
    End
    {
    $report
    }
}`

P.S. Sorry for my bad English

Hi StrangeWalker,

It won’t work concurrently. You need to specify some form of asynchrounous operation. For remote operations, i’d recommend instead performing the actions as jobs instead of using pipeline operations.

I’d typically do this within an Invoke-Command -Computername @(‘comp1’,‘comp2’) -Scriptblock {} -AsJob operation. At the end of your code perform a Get-Job | Wait-Job to pause until all remote jobs have completed. You can then use Receive-Job to gather the output.

There are, however, other ways to do this.

In this particular case, it’s easier to just make one call to Get-WmiObject in your function’s End block, passing in all of the computer names. This is because Get-WmiObject already works concurrently when you give it multiple computer names, and you don’t have to do any of the work of managing that concurrency yourself.

When you do need to do things yourself, the code can get quite complicated, but lots of people have been working on making this easier, and one such project is PoshRSJob from Boe Prox (see Introducing PoshRSJob as an Alternative to PowerShell Jobs | Learn Powershell | Achieve More ).

Anyhow, here’s how I’d tweak your code to make it faster with just Get-WmiObject:

function Get-DiskSpace
{
    [CmdletBinding()]
    Param
    (
        # NetBios name of computer
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
        [string]$ComputerName = 'localhost'

    )

    Begin
    {
        $computers = New-Object System.Collections.ArrayList
    }
    Process
    {
        $null = $computers.Add($ComputerName)
    }
    End
    {
        $selectProperties = @(
            'PSComputerName'
            @{ Name = 'Name'; Expression = { "Disk $($_.DeviceID)" } }
            @{ Name = 'Size'; Expression = { $_.size / 1gb -as [int] } }
            @{ Name = 'Free'; Expression = { $_.freespace / 1gb -as [int] } }
        )

        Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $computers | 
        Select-Object -Property $selectProperties
    }
}

Thanks for your answers!

I dont trust Invoke-Command because of two reasons:

First, it uses local instance of powershell and its version can vary anywhere between v2 and v5
Second, it makes impossible to use my favorite custom-build functions. And keeping track of cmdlets used in code may become a challenge

So, I guess I will have to dig into PSJobs. At least now I know that my goal cannot be achieved the way I have tried. Thanks again!