3

I am trying to get specific KBXXXXXX existence on a list of servers , but once my script one server it takes time and return result and come back and then move to next one . this script works perfectly fine for me . I want my script to kick off and get-hotfix as job and other process just to collect the results and display them.

$servers = gc .\list.txt 
foreach ($server in $servers) 
{ 
    $isPatched = (Get-HotFix -ComputerName $server | where HotFixID -eq 'KBxxxxxxx') -ne $null 
    If ($isPatched) 
    { 
    write-host $server + "Exist">> .\patchlist.txt} 
    Else  
    { 
    Write-host $server +"Missing"
$server  >> C:\output.txt
    } 

}

The objective it to make the list execute faster rather than running serially.

apomene
  • 14,282
  • 9
  • 46
  • 72
Fenomatik
  • 457
  • 2
  • 8
  • 22
  • Take a look at the similar question http://stackoverflow.com/questions/15580105/powershell-run-multiple-jobs-in-parralel-and-view-streaming-results-from-backgr – Roman Kuzmin Mar 28 '13 at 11:42

3 Answers3

4

With Powershell V2 you can use jobs as in @Andy answer or also in further detail in this link Can Powershell Run Commands in Parallel?

With PowerShell V2 you may also want to check out this script http://gallery.technet.microsoft.com/scriptcenter/Foreach-Parallel-Parallel-a8f3d22b using runspaces

With PowerShell V3 you have the foreach -parallel option.

for example (NB Measure-Command is just there for timing so you could make a comparison)

Workflow Test-My-WF {  
  param([string[]]$servers)

  foreach -parallel ($server in $servers) {

    $isPatched = (Get-HotFix -ComputerName $server | where {$_.HotFixID -eq 'KB9s82018'}) -ne $null     
    If ($isPatched) 
    { 
        $server | Out-File -FilePath "c:\temp\_patchlist.txt" -Append
    } 
    Else  
    { 
        $server | Out-File -FilePath "c:\temp\_output.txt" -Append 
    } 
  }
}

Measure-Command -Expression { Test-My-WF   $servers }
Community
  • 1
  • 1
Paul Rowland
  • 8,244
  • 12
  • 55
  • 76
0

For this use PowerShell jobs.

cmdlets:

  • Get-Job
  • Receive-Job
  • Remove-Job
  • Start-Job
  • Stop-Job
  • Wait-Job

Here's an untested example:

$check_hotfix = {
    param ($server)
    $is_patched = (Get-HotFix -ID 'KBxxxxxxx' -ComputerName $server) -ne $null 
    if ($is_patched) { 
        Write-Output ($server + " Exist") 
    } else { 
        Write-Output ($server + " Missing")
    }
}

foreach ($server in $servers) {
    Start-Job -ScriptBlock $check_hotfix -ArgumentList $server | Out-Null
}

Get-Job | Wait-Job | Receive-Job | Set-Content patchlist.txt
Andy Arismendi
  • 50,577
  • 16
  • 107
  • 124
0

Rather than use jobs, use the ability to query multiple computer that's built into the cmdlet. Many of Microsoft's cmdlets, especially those used for system management, take an array of strings as the input for a -Computername parameter. Pass in your list of servers, and the cmdlet will query all of them. Most of the cmdlets that have this ability will query the servers in series, but Invoke-Command will do it in parallel.

I haven't tested this as I don't have Windows booted at the moment, but this should get you started (in sequence).

$servers = gc .\list.txt 
$patchedServers = Get-HotFix -ComputerName $servers | where HotFixID -eq 'KBxxxxxxx'|select machinename

$unpatchedServers = compare-object -referenceobject $patchedServers -differenceobject $servers -PassThru

$unpatchedServers |out-file c:\missing.txt;
$patchedServers|out-file c:\patched.txt;

In parallel:

$servers = gc .\list.txt 
$patchedServers = invoke-command -computername $servers -scriptblock {Get-HotFix | where HotFixID -eq 'KBxxxxxxx'}|select -expandproperty pscomputername |sort -unique

As before, I don't have the right version of Windows available at the moment to test the above & check the output but it's a starting point.

alroc
  • 27,574
  • 6
  • 51
  • 97
  • @alroc thats interesting, could you link to some online articles on this type of parallel processing. Thanks – Paul Rowland Mar 28 '13 at 01:52
  • @PaulRowland, unfortunately I am having a hard time finding good documentation on "how" it works. Have a look at the help for [`Get-Hotfix`](http://technet.microsoft.com/en-us/library/hh849836.aspx) and [the first few hits here](https://www.google.com/search?q=powershell+computername+parameter+site:microsoft.com). Jobs are good when you need them, but they can introduce unnecessary complexity. Use what PowerShell provides you - MS has probably done the parallelism better than you would. – alroc Mar 28 '13 at 02:13
  • @alroc - thanks for that but I didn't see where it suggests its doing them in parallel. It would also be interesting to know if its the same under the covers as using the foreach -parallel option. I don't have test servers to hand right now but I may run a script to compare the two. – Paul Rowland Mar 28 '13 at 03:38
  • The above code didnt do any good to speed up the process by executing the series of same command to different servers in parallel . – Fenomatik Mar 28 '13 at 04:18
  • I've been corrected via Twitter; `invoke-command` runs parallel, but other cmdlets are sequential (see the "Retrieving WMI Information from Multiple Computers" section [here](http://www.petri.co.il/get-wmiobject-wmi-powershell-tricks.htm)). You can use the technique outlined there to use `Invoke-Command`to get the parallelism without resorting to jobs. – alroc Mar 28 '13 at 11:09