{"id":12541,"date":"2011-09-30T00:01:00","date_gmt":"2011-09-30T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/09\/30\/avoid-overload-by-scaling-and-queuing-powershell-background-jobs\/"},"modified":"2011-09-30T00:01:00","modified_gmt":"2011-09-30T00:01:00","slug":"avoid-overload-by-scaling-and-queuing-powershell-background-jobs","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/avoid-overload-by-scaling-and-queuing-powershell-background-jobs\/","title":{"rendered":"Avoid Overload by Scaling and Queuing PowerShell Background Jobs"},"content":{"rendered":"<p><strong>Summary<\/strong>: Use scaling and queuing Windows PowerShell background jobs to avoid system overload.<\/p>\n<p>&nbsp;<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. Today I am proud to announce the return of Boe Prox to the blog.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7331.HSG-09-30-11-1.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Photo of Boe Prox\" alt=\"Photo of Boe Prox\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7331.HSG-09-30-11-1.jpg\" width=\"300\" height=\"476\" \/><\/a><\/p>\n<p>Boe Prox is currently a senior systems administrator with BAE Systems. He has been in the IT industry since 2003 and has spent the past three years working with VBScript and <a href=\"http:\/\/technet.microsoft.com\/en-us\/scriptcenter\/powershell.aspx\">Windows PowerShell<\/a>. Boe looks to script whatever he can, whenever he can. He is also a moderator on the <a href=\"http:\/\/bit.ly\/scriptingforum\">Hey, Scripting Guy! Forum<\/a>. You can check out his blog at <a href=\"http:\/\/boeprox.wordpress.com\/\">http:\/\/boeprox.wordpress.com<\/a> and also see his current project, the <a href=\"http:\/\/poshwsus.codeplex.com\/\">WSUS Administrator module<\/a>, published on CodePlex.<\/p>\n<p>Take it away Boe!<\/p>\n<p>&nbsp;<\/p>\n<p>Ed asked us (the Hey, Scripting Guys! Forum moderators) what one of our favorite Windows PowerShell tricks is. After a little bit of time thinking, I decided that scaling and queuing background jobs to accomplish a task is one of my favorite tricks (and something that I have used quite a bit in the past few months).<\/p>\n<p>The Windows PowerShell team blogged (<a href=\"http:\/\/blogs.msdn.com\/b\/powershell\/archive\/2011\/04\/04\/scaling-and-queuing-powershell-background-jobs.aspx\">link to blog post<\/a>) about this topic earlier this year and explained what needs to be done in order to configure a script or function to process a number of items within a certain threshold.<\/p>\n<p>I have used this technique (modified for my own use) on several occasions and it has worked like a champ each time. In fact, this is one of the key components in my project, PoshPAIG. By using this, I was able to eliminate most of the UI freeze-up that occurs when you attempt to run a Windows PowerShell command under the same thread as the UI.<\/p>\n<p>Some uses for this that I have personally used are for performing a data migration where I only want to have so many copy jobs running at a time. As one job finishes up, another job begins to copy the next set of folders that I have queued. The example that I will show you uses this technique to perform a monitored reboot of a number of systems with a specific threshold of how many systems can be rebooted at a time. In this case, I will track five systems at a time and a warning will appear if a machine does not come up within five minutes of being rebooted. The script I am using is available on the <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Restart-ComputerJob-61e29ff1\">TechNet Script Gallery<\/a>, and I will go through it in chunks to show what is going on.<\/p>\n<p>I start by running my script, named Restart-ComputerJob:<b><\/b><\/p>\n<p style=\"padding-left: 30px\">.\\Restart-ComputerJob &ndash;MaxJobs&nbsp; 5 &ndash;InputObject (Get-Content hosts.txt)<\/p>\n<p style=\"padding-left: 30px\">#Define report<\/p>\n<p style=\"padding-left: 30px\">$Data = @()<\/p>\n<p style=\"padding-left: 30px\">$Start = Get-Date<\/p>\n<p style=\"padding-left: 30px\">#Queue the items up<\/p>\n<p style=\"padding-left: 30px\">$queue = [System.Collections.Queue]::Synchronized( (New-Object System.Collections.Queue) )<\/p>\n<p style=\"padding-left: 30px\">foreach($item in $InputObject) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;Adding $item to queue&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $queue.Enqueue($item)<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p>Here, I am defining an empty collection that will be used later to store the data from each job that has finished. I have my collection of computers defined from the <b>$InputObject<\/b> variable. Each item is added to the <b>$Queue<\/b>, which was created using the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.collections.queue.aspx\">System.Collections.Queue<\/a> class. Using the <b>Synchronized<\/b> method allows only one job to access the queue at a time:<\/p>\n<p style=\"padding-left: 30px\"># Start up to the max number of concurrent jobs<\/p>\n<p style=\"padding-left: 30px\"># Each job will take care of running the rest<\/p>\n<p style=\"padding-left: 30px\">For( $i = 0; $i -lt $MaxJobs; $i++ ) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Restart-ServerFromQueue<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>Now that we have the collection queued, we can now begin creating jobs to start rebooting the systems in the <b>Restart-ServerFromQueue<\/b> function. I use a <b>For<\/b> statement with the <b>$MaxJobs<\/b> variable that is defined by either the user, or sticks with the default value of five to limit the number of jobs that will be run at any given time.<\/p>\n<p style=\"padding-left: 30px\">Function&nbsp; Global:Restart-ServerFromQueue {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $server = $queue.Dequeue()<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $j = Start-Job -Name $server -ScriptBlock {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param($server,$location)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $i=0<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If (Test-Connection -Computer $server -count 1 -Quiet) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Try {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Restart-Computer -ComputerName $server -Force -ea stop<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Do {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Start-Sleep -Seconds 2<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;Waiting for $server to shutdown&#8230;&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; While ((Test-Connection -ComputerName $server -Count 1 -Quiet))&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Do {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Start-Sleep -Seconds 5<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $i++&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;$server down&#8230;$($i)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #5 minute threshold (5*60)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If($i -eq 60) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Warning &#8220;$server did not come back online from reboot!&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Output $False<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; While (-NOT(Test-Connection -ComputerName $server -Count 1 -Quiet))<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;$Server is back up&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Output $True<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } Catch {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Warning &#8220;$($Error[0])&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Output $False<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} Else {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Output $False<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; } -ArgumentList $server<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p>In the beginning part of the <b>Restart-ServerFromQueue<\/b> function, I first get the system name by using the <b>$Queue.dequeue()<\/b> method and saving it to the <b>$Server<\/b> variable that removes the system from the queue. From there, I create the new job and save the job object to a variable that will be used later. The job performs a reboot of the system and then goes into a monitoring phase until the system comes back online. If it doesn&rsquo;t come back online after five minutes, the system is deemed <b>Offline<\/b> and a Boolean value of <b>$False<\/b> is returned; otherwise, if the system is online, <b>$True<\/b> is returned.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Register-ObjectEvent -InputObject $j -EventName StateChanged -Action {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Set verbose to continue to see the output on the screen<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VerbosePreference = &#8216;continue&#8217;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $serverupdate = $eventsubscriber.sourceobject.name&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $results = Receive-Job -Job $eventsubscriber.sourceobject<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::Removing Job: $($eventsubscriber.sourceobject.Name)&#8221;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remove-Job -Job $eventsubscriber.sourceobject<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::Unregistering Event: $($eventsubscriber.SourceIdentifier)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Unregister-Event $eventsubscriber.SourceIdentifier<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::Removing Event Job: $($eventsubscriber.SourceIdentifier)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remove-Job -Name $eventsubscriber.SourceIdentifier<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If ($results) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::$serverupdate is online&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp = &#8220;&#8221; | Select Computer, IsOnline<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp.computer = $serverupdate<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp.IsOnline = $True<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } Else {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::$serverupdate is offline&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp = &#8220;&#8221; | Select Computer, IsOnline<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp.computer = $serverupdate<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $temp.IsOnline = $False<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Global:Data += $temp<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If ($queue.count -gt 0 -OR (Get-Job)) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose &#8220;[$(Get-Date)]::Running Restart-ServerFromQueue&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Restart-ServerFromQueue<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } ElseIf (@(Get-Job).count -eq 0) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $End = New-Timespan $Start (Get-Date)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &#8220;$(&#8216;Completed in: {0}&#8217; -f $end)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &#8220;Check the `$Data variable for report of online\/offline systems&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remove-Variable Queue -Scope Global<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remove-Variable Start -Scope Global<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; } | Out-Null<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;[$(Get-Date)]::Created Event for $($J.Name)&#8221;<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>The last piece of the function holds the event information that is used to track each job. I use the <b>$j<\/b> variable, which holds the job object for the most recently started job along with using the<a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/dd347672.aspx\"> Register-ObjectEvent<\/a> cmdlet and checking for the <b>StateChanged<\/b> status of the job. The job changing the status from <b>Running<\/b> to anything will prompt the registered event to perform the action defined in the <i>&ndash;Action<\/i> parameter. Because this parameter takes a script block, I can set up a series of commands to run to gather the results of the job and save it to a report. Also, I have added to this action block some commands to perform cleanup on both the job that finished and the associated event subscription. By default, I have <b>$VerbosePreference<\/b> set to <b>Continue<\/b>, which will display some extra messages after each job finishes up. You can set this to <b>SilentlyContinue<\/b>, if you do not wish to see these messages.<\/p>\n<p>The following figure shows this in action.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1526.HSG-09-30-11-2.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of script in action\" alt=\"Image of script in action\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1526.HSG-09-30-11-2.jpg\" \/><\/a><\/p>\n<p>As you can see, most of the systems are offline. DC1 is the one server that does get rebooted and the job continued to monitor the server until it came back online. By the way, did I mention I like to use <b>Write-Verbose<\/b>? (Another nice tip is to use <b>Write-Verbose<\/b> in your code to track your script in action). Here you see where each system is added into the queue and also where the first five are added into a job while the sixth system patiently waits until the first job has completed. You can also see where each job finishes and another begins, which includes removing of job, event job, and the event itself. After the last job is finished, a message is displayed showing how long it took to complete all of the jobs and to check the <b>$Data<\/b> variable for a report of systems that are either offline or came back up after the reboot.<\/p>\n<p>So there you have it. You can harness the power of background jobs and events to create a set of jobs that updates itself in the background without any user interaction. And it also frees up your console to perform other work while the jobs run in the background. I hope everyone enjoyed this article and can use this technique in their daily tasks or for some other project. Thanks again also to the Windows PowerShell team for their excellent article that helped pave the way in making this work!<\/p>\n<p>&nbsp;<\/p>\n<p>I want to thank Boe Prox for taking the time to share this really cool Windows PowerShell tip.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Use scaling and queuing Windows PowerShell background jobs to avoid system overload. &nbsp; Microsoft Scripting Guy Ed Wilson here. Today I am proud to announce the return of Boe Prox to the blog. &nbsp; Boe Prox is currently a senior systems administrator with BAE Systems. He has been in the IT industry since 2003 [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[162,56,2,3,4,45],"class_list":["post-12541","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-boe-prox","tag-guest-blogger","tag-running","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Use scaling and queuing Windows PowerShell background jobs to avoid system overload. &nbsp; Microsoft Scripting Guy Ed Wilson here. Today I am proud to announce the return of Boe Prox to the blog. &nbsp; Boe Prox is currently a senior systems administrator with BAE Systems. He has been in the IT industry since 2003 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=12541"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12541\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=12541"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=12541"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=12541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}