'Powershell - run script on multiple computers simultaneously

Im working on a script that cleanup old user account and some data from computers. I would like to run the script on 5 computers at one time from the attached list of PCs. Is it possible?

    [CmdletBinding()]
Param(
    [Parameter(Mandatory=$true)]
    [string]$host_path = 'Host path'
)

$computer = Get-Content "$host_path"

foreach ($computer in $computer){

    Invoke-Command -ComputerName $computer -ScriptBlock { Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))}| Remove-WmiObject }
    Invoke-Command -ComputerName $computer -ScriptBlock { Remove-Item -Path C:\Windows\ccmcache\* -Confirm:$false -Force -Recurse -Debug }
    Invoke-Command -ComputerName $computer -ScriptBlock { Remove-Item -Path C:\ProgramData\1E\NomadBranch\* -Confirm:$false -Force -Recurse -Debug }
    }
```


Solution 1:[1]

You can pass multiple computer names to Invoke-Command at once to achieve this:

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true)]
    [string]$host_path = 'Host path'
)

$computerNames = Get-Content $host_path

Invoke-Command -ComputerName $computerNames -ScriptBlock { 
    Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))}| Remove-WmiObject
    Remove-Item -Path C:\Windows\ccmcache\* -Confirm:$false -Force -Recurse -Debug
    Remove-Item -Path C:\ProgramData\1E\NomadBranch\* -Confirm:$false -Force -Recurse -Debug
}

If you want to "chunk" the list of computer names into batches on N machines at a time, you can do it like this:

$computerNames = Get-Content $host_path
$batchSize = 5

while($computerNames.Count -gt 0){
    # Pull the first N names from the list
    $nextBatch = @($computerNames |Select -First $batchSize)
    # Then overwrite the list with any elements _after_ the first N names
    $computerNames = @($computerNames |Select -Skip $batchSize)

    Write-Host "Executing remote command against $($nextBatch.Count) computers: [$($nextBatch.ForEach({"'$_'"}) -join ', ')]"

    # Invoke remoting command against the batch of computer names
    Invoke-Command -ComputerName $nextBatch -ScriptBlock { 
        Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))}| Remove-WmiObject
        Remove-Item -Path C:\Windows\ccmcache\* -Confirm:$false -Force -Recurse -Debug
        Remove-Item -Path C:\ProgramData\1E\NomadBranch\* -Confirm:$false -Force -Recurse -Debug
    }
}

Solution 2:[2]

If you are using PowerShell 7.x, you can do the following.

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true)]
    [string]$host_path = 'Host path'
)
# The default value for ThrottleLimit is 5, but I put it here to show syntax.
# Throttle is the number of concurrent runspaces to use. (ex: do 5 objects at a time)
Get-Content $host_path | Foreach-Object -ThrottleLimit 5 -Parallel -ScriptBlock {
    Invoke-Command -ComputerName $_ -ScriptBlock { 
        Get-WMIObject -class Win32_UserProfile | Where-Object {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))}| Remove-WmiObject
        Remove-Item -Path C:\Windows\ccmcache\* -Confirm:$false -Force -Recurse -Debug
        Remove-Item -Path C:\ProgramData\1E\NomadBranch\* -Confirm:$false -Force -Recurse -Debug
    }
}

This will run X loops at a time, X being your -ThrottleLimit value, which defaults to 5.

Again, this is only available in PowerShell 7, and not backwards compatible with Windows PowerShell.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 TechDufus