Reputation: 163
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
}
}
Upvotes: 1
Views: 1270
Reputation: 131
function BatchParallel($items, $scriptBlock) {
$pool = [runspacefactory]::CreateRunspacePool(1, 5)
$pool.Open()
$results = @()
[System.Collections.ArrayList]$tasks = @()
$totalTasks = $items.Count
$completedTasks = 0
$items | ForEach-Object {
$item = $_
$ps = [powershell]::Create().AddScript($scriptBlock).AddArgument($item)
$ps.RunspacePool = $pool
$task = $ps.BeginInvoke()
$tasks += [PSCustomObject]@{
PowerShell = $ps
Task = $task
}
}
$tasks | ForEach-Object {
# Wait for task completion
$_.PowerShell.EndInvoke($_.Task)
$_.PowerShell.Dispose()
$completedTasks++
}
$pool.Close()
$pool.Dispose()
return $results
}
Upvotes: 1
Reputation: 8868
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
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"
#>
Upvotes: 1
Reputation: 538
I would propose this
Get-Content 'D:\StoreMap.json' -Raw |
ConvertFrom-Json |
Select-Object -Property STORE, ID |
ForEach-Object {
$computer = 'IN'+$_.STORE+'test.org'
$ID= $_.ID
Write-Host "Started running the script on Store " + $computer
$ScriptBlock = {
Param([string] $ID)
#Your remote code here, most likely content of D:\test.ps1
}
Start-Job -Name "Script on $($computer)" -ScriptBlock $ScriptBlock -Args $ID
}
Get-Job | Wait-Job
$return += Get-Job | Receive-Job
Upvotes: 0