Search code examples
powershellpowershell-remotingpowershell-5.1

How to execute a Powershell script in parallel


I have a powershell script which is run to connect to remote servers and execute a script. I am passing an argument as well. Is there a way to run this in parallel, passing the correct ids responding to each STORES. The powershell version is 5 in the system.

$storeids = Get-Content 'D:\StoreMap.json'  -Raw | ConvertFrom-Json
$storeids | Select-Object -Property STORE, ID | ForEach-Object {
    $computer = 'IN' + $_.STORE + 'test.org'
    $ID = $_.ID
    $script = 'D:\test.ps1'
    Write-Host "Started running the script on Store" + $computer

    try {
        Invoke-Command -ComputerName $computer -FilePath $script -ArgumentList $ID
    }
    catch {
        Write-Host $_.Exception.Message
    }
}

Solution

  • You could create a hash table to lookup the ID based on the remote computers name and then call them in parallel with Invoke-Command.

    Two things to note

    1. Update the hostname property if the assumption is incorrect (make it match each $env:computername)
    2. Update D:\test.ps1 to use the lookup table instead of the passed in argument

    also see inline comments for details.

    $storeids = Get-Content 'D:\StoreMap.json'  -Raw | ConvertFrom-Json
    
    # The assumption is IN + $_.Store is exactly the remote systems computer name, stored as Hostname property
    # The ComputerName property is the fqdn for the Invoke-Command call
    $selectprops = '*',
                    @{n='Hostname';e={"IN$($_.Store)"}},
                    @{n='ComputerName';e={"IN$($_.Store)test.org"}}
    
    # Create a lookup table. Each remote system will be able to extract their own ID from this table via it's computername
    $storetable = $storeids |
        Select-Object $selectprops |
            Group-Object -Property Hostname -AsHashTable
    
    # Instead of using a passed in argument, use $using:storetable to grab a local copy of the table and then
    # reference it with $localtable[$env:computername]
    # Silence errors to prevent interruption and capture any errors to $errors (appended due to +)
    $icmparams = @{
        ComputerName  = $storetable.Name
        FilePath      = 'D:\test.ps1'
        ErrorAction   = 'SilentlyContinue'
        ErrorVariable = '+errors'
        ThrottleLimit = 64 # 32 by default
    }
    
    $results = Invoke-Command @icmparams
    
    # output collected in $results
    $results 
    
    # check any errors
    $errors
    
    <# D:\test.ps1
    
    $localtable = $using:storetable
    $id = $localtable[$env:computername].ID
    "Computer: $env:Computername  ID: $id"
    
    #>