Home > database >  Powershell - run script on multiple computers simultaneously
Powershell - run script on multiple computers simultaneously

Time:05-07

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 }
    }
```

CodePudding user response:

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
    }
}

CodePudding user response:

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.

  • Related