Seeking clarity on Remote Background Job Data Retrieval

I am using an array of hash tables that hold server information.

get-adcomputer -Filter "Enabled -eq '$true'" -Property Name,OperatingSystem,Enabled,DistinguishedName,DNSHostname | 
Where-Object { ($_.OperatingSystem -like '*Server*') } |
    ForEach-Object -Process { 
        $ServerDetails = [PSCustomObject]@{
            FQDN = $_.DNSHostname
            Enabled = $_.Enabled
            DistinguishedName = $_.DistinguishedName
            Online = 'Empty'
            PrintServer = 'Empty'
            PrintSpooler = 'Empty'
            PrintSpoolerStartType = 'Empty'
            PrintSpoolerSatus = 'Empty'
            PrintSpoolerStartTypeNow = 'Empty'
            Resolveable = 'Empty'
            WinRMEnabled = 'Empty'
        }

        #Save to the global array
        $EnabledADServers+= $ServerDetails
    }

Later in my script I’m starting a bunch of persistent sessions with a subset of the array, running some commands remotely via those sessions as background jobs. I have hundreds of servers to query and get the data from. Doing them one at a time takes a long time vs running them remotely and retrieving the data.

Once that is done I have data sitting on the remote servers that I want to retrieve and put into the array of hash tables I have.

So far I am using the receive-job cmdlet to get the data results, but I’m saving it to a new variable. I would like to get the data and put it into the correct hash table within the array.

Is there a way to retrieve the remote data and populate the array? Can you point me to some online resources that could explain/expand this for me? I still get tripped up thinking like a programmer and often miss an easier way of doing things that PS provides.

You should really stop doing that:

From a technical point of view that’s a quite expensive operation because you actually destroy the complete array and create a new one including the added single element. :wink:

When you run Get-ADComputer it will return a subset of properties by default. You do not have to specify the properties belonging to this default set with the parameter -Properties explicitly. :wink:

I highly recommend to use PowerShell version 7 for this kind of tasks. There you have the option to use Foreach-Object -Parallel what saves a lot of time. So there shouldn’t be the need to use extra background jobs.

Here’s an example of how to use this:

$SearchBase = 'DC=contoso,DC=com'

$Result =
Get-ADComputer -Filter "Enabled -eq '$true'" -SearchBase $SearchBase -Properties OperatingSystem | 
Where-Object { ($_.OperatingSystem -like '*Server*') } |
ForEach-Object -Parallel {

    $ping = New-Object System.Net.NetworkInformation.Ping
    $pingTimeutMS = 200
    $test = $ping.Send($($_.Name), $pingTimeutMS)
 
    if ($test.Status -eq 'Success') {
        $CimSession = New-CimSession -ComputerName $($_.Name)
        $OS = Get-CimInstance -ClassName CIM_OperatingSystem -CimSession $CimSession 
        $Computer = Get-CimInstance -ClassName CIM_ComputerSystem -CimSession $CimSession
        [PSCustomObject]@{
            Name  = $($_.Name)
            FQDN  = $_.DNSHostname
            OS    = $OS.Caption
            Model = $Computer.Model
            RAM   = '{0,3} GB' -f [MATH]::Round($Computer.TotalPhysicalMemory / 1GB, 0)
        }
    }
    Else {
        [PSCustomObject]@{
            Name  = $($_.Name)
            FQDN  = 'n/a'
            OS    = 'n/a'
            Model = 'n/a'
            RAM   = 'n/a'
        }
    }
} -ThrottleLimit 40

$Result | 
Format-Table -AutoSize

I did set the -ThrottleLimit quite high to really push the task. In the environment I tested this code it takes about 4 seconds for about 80 server.