<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://powershell.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results for 'app:weblogs' matching tags 'Jobs', 'Georges Maheu', and 'writing'</title><link>http://powershell.com/cs/search/SearchResults.aspx?q=app:weblogs&amp;tag=Jobs,Georges+Maheu,writing&amp;orTags=0&amp;o=DateDescending</link><description>Search results for 'app:weblogs' matching tags 'Jobs', 'Georges Maheu', and 'writing'</description><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><item><title>Increase Performance by Slowing Down Your PowerShell Script</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2012/02/03/increase-performance-by-slowing-down-your-powershell-script.aspx</link><pubDate>Fri, 03 Feb 2012 06:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:14352</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;: Microsoft PFE, Georges Maheu, further optimizes the Windows PowerShell script he presented earlier this week.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is Georges Maheu. Georges presented a script three days ago to gather Windows services information in an Excel spreadsheet. Although the script did an adequate job for a small number of servers, it did not scale well for hundreds of servers. On day one, the script took 90 minutes to document 50 computers. On day two, it took less than three minutes. Day three went down to 43 seconds. Today, Georges wants to do even better! Here are quick links to his previous blogs:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Day&amp;nbsp;1: &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/01/31/beat-the-auditors-be-one-step-ahead-with-powershell.aspx" target="_blank"&gt;Beat the Auditors, Be One Step Ahead with PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Day&amp;nbsp;2: &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/01/speed-up-excel-automation-with-powershell.aspx" target="_blank"&gt;Speed Up Excel Automation with PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Day 3: &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/02/speed-up-excel-automation-with-powershell-jobs.aspx" target="_blank"&gt;Speed Up Excel Automation with PowerShell Jobs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note&lt;/b&gt;: All of the files from today, in addition to files for the entire week are in a zip file in the &lt;a href="http://gallery.technet.microsoft.com/scriptcenter/Get-on-thousands-of-ef3175c7" target="_blank"&gt;Script Repository&lt;/a&gt;. You can read more from Georges on the PFE Blog: &lt;a href="http://www.opsvault.com/" target="_blank"&gt;OpsVault&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Now, once again, here&amp;rsquo;s Georges...&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;There comes a time when there is no point to optimizing a script further. Moving from 90 minutes down to less than one minute was well worth the investment in time! But going from 43 seconds to 30 is not worth the effort for this script.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Today, we tackle typical issues that are encountered when collecting large volumes of information in a distributed environment. Excel can handle 1000 computers&amp;mdash;that&amp;rsquo;s cool, but not very practical beyond those numbers.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;There are a few options for dealing with large volumes of information: one could store all the information in a database and write nice reports by using queries. Personally, I could not create a decent database to save my life! Therefore, I will go to the next option, which is to use individual files for each computer.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Instead of writing the information in an Excel tab, the information will be exported to a file in .csv format by using the &lt;b&gt;Export-CSV&lt;/b&gt; cmdlet.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;First, the following lines are replaced:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$data = ($services `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Select-Object&amp;nbsp; $properties `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; | ConvertTo-Csv &lt;i&gt;-Delimiter&lt;/i&gt; &amp;quot;`t&amp;quot; &lt;i&gt;-NoTypeInformation&lt;/i&gt; ) -join &amp;quot;`r`n&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;[Windows.Clipboard]::setText($data) | Out-Null&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$computerSheet.range(&amp;quot;a$mainHeaderRow&amp;quot;).pasteSpecial(-4104) |&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Out-Null #Const xlPasteAll = -4104&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p&gt;With these lines:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$services |&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; Select-Object&amp;nbsp; $properties |&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; Export-CSV &amp;quot;$script:customerDataPath\$($currentJobName).csv&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-Encoding&lt;/i&gt; ASCII &lt;i&gt;-NoTypeInformation&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Then, all the code that is related to Excel is removed from the script.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Most of the optimization techniques that I have shown so far can be reused, but there are a few additional challenges. One of them is, &amp;ldquo;What should I do if a computer does not respond?&amp;rdquo; With 50 computers, one can afford to run a 43 second script repeatedly until all the data is gathered. Not so obvious when 5000 computers or more are involved.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;One could use the file system to keep track of computers already processed. If a CSV file exists, there is no need to collect the information again. If there is a need to update the information for a specific computer, simply delete that file and run the script again.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;if (Test-Path &amp;quot;$customerDataPath\$($jobName).csv&amp;quot;)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; write-host &amp;quot;$jobName data has already been collected&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;else&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Start-Job &lt;i&gt;-ScriptBlock&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; param($computerName);&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get-WmiObject `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-class&lt;/i&gt; win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ComputerName&lt;/i&gt; $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-Name&lt;/i&gt; $jobName `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ArgumentList&lt;/i&gt; $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Creating file for $computerName&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #if (Test-Path &amp;quot;$customerDataPath\$($jobName).csv&amp;quot;)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Yesterday, running out of resources was avoided with a rude implementation of a &lt;i&gt;producer&amp;ndash;consumer&lt;b&gt; &lt;/b&gt;&lt;/i&gt;design pattern. This same issue needs to be revisited because the script design was based on the time it took the &lt;i&gt;consumer&lt;/i&gt; to write the data in Excel. Writing to a file is much faster, and running out of resources could occur again.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This happens if there are too many jobs running at the same time. In fact, the more jobs that are running concurrently, the longer each ones takes to complete. This can be a vicious circle.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/4162.HSG_2D00_2_2D00_3_2D00_12_2D00_1.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/4162.HSG_2D00_2_2D00_3_2D00_12_2D00_1.png" alt="Image of performance data" title="Image of performance data" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Strangely enough, the performance of the script can be increased by slowing it down! I slow the script down a bit by using the &lt;b&gt;Start-Sleep&lt;/b&gt; cmdlet.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;if (@(get-job).count -gt 15)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Start-Sleep &lt;i&gt;-Milliseconds&lt;/i&gt; 250&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; write-host &amp;quot;Slow down!&amp;quot; &lt;i&gt;-ForegroundColor&lt;/i&gt; yellow&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;if (@(get-job).count -gt 5) {Get-CompletedJobs}&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Slowing down the rate at which new jobs are started allows existing jobs to finish and be processed. This will help maintain the job queue size within the limits of the computer&amp;rsquo;s resources. For example, the following 500 computer test run took 8 minutes and 3 seconds after encountering a resource struggle.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0550.HSG_2D00_2_2D00_3_2D00_12_2D00_2.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0550.HSG_2D00_2_2D00_3_2D00_12_2D00_2.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;After the lines were added to slow the script down, the same script completed in 3&amp;nbsp;minutes, 39&amp;nbsp;seconds.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The following screen capture shows these new lines in action after restarting a 5000 computer test run. The screen capture also shows the optimization mentioned earlier by using files as indicators that a computer has already been processed:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7220.HSG_2D00_2_2D00_3_2D00_12_2D00_3.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7220.HSG_2D00_2_2D00_3_2D00_12_2D00_3.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is not an exact science, you will need to experiment with these numbers based on your computer resources and the time it takes to get and process the information.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This latest version of the script gets these numbers:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;01 minute 19 seconds for 100 computers.&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;01 minutes 56 seconds for 250 computers.&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;03 minutes 39 seconds for 500 computers.&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;07 minutes 05 seconds for 1000 computers.&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;40 minutes 20 seconds for 5000 computers.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Not bad! However, there is one more thing to do to wrap up this project. All the services that run using nondefault service accounts need to be extracted.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Here is a second script that will process all those CSV files, extract that information, and store it in another CSV file.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;clear-host&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$startTime&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = Get-Date&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$scriptPath&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = Split-Path &lt;i&gt;-parent&lt;/i&gt; $myInvocation.myCommand.definition&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$customerDataPath = &amp;quot;$scriptPath\Services Data&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$reportPath&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = &amp;quot;$scriptPath\Services Report&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$CSVfiles = Get-Childitem $customerDataPath &lt;i&gt;-filter&lt;/i&gt; *.csv&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;if ($CSVfiles.count -ge 1)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Write-Host &amp;quot;There are: $($CSVfiles.count) data files&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;else&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Write-Host &amp;quot;There are no data files in $customerDataPath.&amp;quot; &lt;i&gt;-ForegroundColor&lt;/i&gt; red&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exit&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;new-item &lt;i&gt;-Path&lt;/i&gt; $scriptPath &lt;i&gt;-name&lt;/i&gt; &amp;quot;Services Report&amp;quot; &lt;i&gt;-force&lt;/i&gt; -type directory | Out-Null #Create report folder&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$exceptions = @()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$CSVfiles |&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ForEach-Object `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $services = Import-csv &lt;i&gt;-Path&lt;/i&gt; $_.fullname&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Processing $_&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; forEach ($service in $services)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $service.startName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ################################################&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # EXCEPTION SECTION&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # To be customized based on your criteria&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ################################################&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $service.startName -notmatch &amp;quot;LocalService&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -and $service.startName -notmatch &amp;quot;Local Service&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -and $service.startName -notmatch &amp;quot;NetworkService&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -and $service.startName -notmatch &amp;quot;Network Service&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -and $service.startName -notmatch &amp;quot;LocalSystem&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -and $service.startName -notmatch &amp;quot;Local System&amp;quot;)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Write-Host $service.startName &lt;i&gt;-ForegroundColor&lt;/i&gt; yellow&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $exceptions += $service&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #if ($service.startName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #foreach ($service in $services)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #ForEach-Object&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$exceptions |&amp;nbsp; Export-CSV &amp;quot;$reportPath\Non Standard Service Accounts Report.csv&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-Encoding&lt;/i&gt; ASCII &lt;i&gt;-NoTypeInformation&lt;/i&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$endTime&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = get-date&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;&amp;quot; #blank line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Write-Host &amp;quot;-------------------------------------------------&amp;quot; &lt;i&gt;-ForegroundColor&lt;/i&gt; Green&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Write-Host &amp;quot;Script started at:&amp;nbsp;&amp;nbsp; $startTime&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ForegroundColor&lt;/i&gt; Green&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Write-Host &amp;quot;Script completed at: $endTime&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ForegroundColor&lt;/i&gt; Green&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Write-Host &amp;quot;Script took $($endTime - $startTime)&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ForegroundColor&lt;/i&gt; Green&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Write-Host &amp;quot;-------------------------------------------------&amp;quot; &lt;i&gt;-ForegroundColor&lt;/i&gt; Green&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;&amp;quot; #blank line&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This script took just under 10 minutes to run. In summary, these two optimized scripts processed 5000 computers in about one hour. Not bad!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;These scripts can be adapted with minor modifications to collect just about any kind of data. Today&amp;rsquo;s script focuses on large environments while yesterday&amp;rsquo;s script is appropriate for a small to mid-size environment. The next time your manager tells you that the auditors are coming, you can sit back and smile. You will be ready.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;~ Georges&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Thank you, Georges. This has been a great series of blogs. The zip file that you will find in the &lt;a href="http://gallery.technet.microsoft.com/scriptcenter/Get-on-thousands-of-ef3175c7" target="_blank"&gt;Script Repository&lt;/a&gt; has all the files and scripts from Georges this week.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ed Wilson, Microsoft Scripting Guy&lt;/b&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3476120" width="1" height="1" alt="" /&gt;</description></item><item><title>Speed Up Excel Automation with PowerShell Jobs</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2012/02/02/speed-up-excel-automation-with-powershell-jobs.aspx</link><pubDate>Thu, 02 Feb 2012 06:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:14338</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;: Microsoft PFE, Georges Maheu, further optimizes the Windows PowerShell script that he presented in his previous two blogs.&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is Georges Maheu. Georges presented a script two days ago to gather Windows services information in an Excel spreadsheet:&amp;nbsp;&lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/01/31/beat-the-auditors-be-one-step-ahead-with-powershell.aspx"&gt;Beat the Auditors, Be One Step Ahead with PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although that script did an adequate job for a small number of servers, it did not scale well for hundreds of servers. Yesterday, he optimized the script to reduce the runtime from 90 minutes to less than three minutes:&amp;nbsp;&lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/01/speed-up-excel-automation-with-powershell.aspx"&gt;Speed Up Excel Automation with PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today, Georges wants to do even better.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note&lt;/b&gt;: All of the files from today, in addition to files for the entire week are in a zip file in the &lt;a href="http://gallery.technet.microsoft.com/scriptcenter/Get-on-thousands-of-ef3175c7"&gt;Script Repository&lt;/a&gt;.&amp;nbsp;You can read more from Georges on the PFE Blog:&amp;nbsp;&lt;a href="http://www.opsvault.com/" target="_blank"&gt;OpsVault&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take it away Georges...&lt;/p&gt;
&lt;p&gt;Today, we will see if yesterday&amp;rsquo;s script can be optimized further. As already seen, the script makes an inventory of all services running on your servers, and it identifies services that are using non-standard accounts. The inventory is presented in an Excel spreadsheet.&lt;/p&gt;
&lt;p&gt;The first version of the script was linear and simple but somewhat slow. Here is a screen capture of the WTM while the script is running. The script took 90 minutes to perform a 50 computer inventory. CPU on the test computer remained in the 20% utilization range during this test.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2845.hsg_2D00_2_2D00_2_2D00_12_2D00_1.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2845.hsg_2D00_2_2D00_2_2D00_12_2D00_1.png" alt="Image of performance data" title="Image of performance data" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Yesterday, the performance of this script was improved by focusing on a few bottlenecks. Runtime has been reduced dramatically&amp;mdash;down to two minutes and 31 seconds for the same 50 computer inventory. Not bad!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2248.hsg_2D00_2_2D00_2_2D00_12_2D00_2.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2248.hsg_2D00_2_2D00_2_2D00_12_2D00_2.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;CPU utilization varied, but it was mostly around 15%.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7317.hsg_2D00_2_2D00_2_2D00_12_2D00_3.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7317.hsg_2D00_2_2D00_2_2D00_12_2D00_3.png" alt="Image of performance data" title="Image of performance data" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now the question is, &amp;ldquo;How can we improve this further? Is it even possible?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Using the same technique as yesterday, let&amp;rsquo;s start with the &lt;b&gt;Measure-Command&lt;/b&gt; cmdlet:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Measure-Command {$services = Get-WmiObject win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ComputerName&lt;/i&gt; $computerName}&lt;/p&gt;
&lt;p&gt;This script provided the following information:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;WMI query: &amp;lt; 0.25 seconds for responding local computer&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;WMI query: &amp;lt; 1.00 seconds for responding remote computer&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;WMI query: &amp;lt; 20.00 seconds for non-responding computer&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Ping dead computer: &amp;lt; 2.5 seconds&lt;/p&gt;
&lt;p&gt;In the test scenario, I used my desktop computer (no, I do not have 50 computers in my lab). The projection is 47*0.25 + 3*20 = 72 seconds. Knowing the script actually takes 148 seconds, the overhead is about 50%. Knowing that it is impossible to improve the time to make the WMI query, the only option is to run the queries in parallel. The total amount of data will be the same, so the gain will have to come from the latency time it takes to perform a WMI query.&lt;/p&gt;
&lt;p&gt;Windows PowerShell 2.0 has functionality to support concurrency.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;First method: Get-WMIObject &amp;ndash;ComputerName&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;WMI can be used directly. The next screen capture shows the time it takes WMI to query 50 computers in a single statement:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0871.hsg_2D00_2_2D00_2_2D00_12_2D00_4.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0871.hsg_2D00_2_2D00_2_2D00_12_2D00_4.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The performance is great, but the data would need to be parsed based on the &lt;b&gt;systemName&lt;/b&gt; field, and the script structure would have to be modified considerably.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Second method: Invoke-Command&lt;/b&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;invoke-command &lt;i&gt;-ScriptBlock&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; param($computerName);&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get-WmiObject `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-class&lt;/i&gt; win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ComputerName&lt;/i&gt; $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-asJob&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-JobName&lt;/i&gt; &amp;quot;$i - $computerName&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ThrottleLimit&lt;/i&gt; 3 `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ArgumentList&lt;/i&gt; $computerName `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ComputerName&lt;/i&gt; LocalHost&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Invoke-Command&lt;/b&gt; looks promising. It has a &lt;i&gt;ThrottleLimit&lt;/i&gt; parameter, which limits the number of network connections, not the number of jobs running on a computer, as demonstrated in the following screen capture.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8802.hsg_2D00_2_2D00_2_2D00_12_2D00_5.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8802.hsg_2D00_2_2D00_2_2D00_12_2D00_5.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Invoke-Command&lt;/b&gt; would be nice if the queries were run on remote computers, but this is not the case. However, spreading the load across multiple computers would certainly be something to consider for the next round of optimization.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Invoke-Command&lt;/b&gt; needs the shell to be run as administrator. Permissions could be delegated to run &lt;b&gt;Invoke-Command&lt;/b&gt; as a regular user, but this would increase the complexity.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Third method: Start-Job&lt;/b&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Start-Job &lt;i&gt;-ScriptBlock&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; param($computerName);&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get-WmiObject `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-class&lt;/i&gt; win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;-ComputerName&lt;/i&gt; $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -Name &amp;quot;$i - $computerName&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -ArgumentList $computerName&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Start-Job&lt;/b&gt; creates a background process for each WMI query. The result is great. Our script can now do 50 computers in about 42 seconds.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2678.hsg_2D00_2_2D00_2_2D00_12_2D00_6.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2678.hsg_2D00_2_2D00_2_2D00_12_2D00_6.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, the script had to be modified&amp;mdash;the first part now starts all the jobs, and the second part processes the results. The main differences are the following lines:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;foreach ($computerName in $computers)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $workBook.workSheets.add() | Out-Null&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $workBook.workSheets.item(1).name = &amp;quot;$computerName&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Start-Job &lt;i&gt;-ScriptBlock&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; param($computerName);&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get-WmiObject `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -class win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -ComputerName $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -Name &amp;quot;$computerName&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -ArgumentList $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #forEach computer&lt;/p&gt;
&lt;p&gt;To generate all the jobs, use the following code to retrieve the information from the job queue.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;while (@(Get-Job &lt;i&gt;-State&lt;/i&gt; Completed).count -gt 0)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;============&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $currentJobName = (Get-Job &lt;i&gt;-State&lt;/i&gt; Completed |&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Select-Object &lt;i&gt;-First&lt;/i&gt; 1).name&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $services = Receive-Job &lt;i&gt;-name&lt;/i&gt; $currentJobName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Remove&lt;b&gt;-&lt;/b&gt;Job &lt;i&gt;-Name&lt;/i&gt; $currentJobName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;#same code to paste in Excel&amp;hellip;&lt;/p&gt;
&lt;p&gt;When the jobs are running, they can be in one of several states: Running, Completed, or Failed. There are other states, but these are the states of interest for this script. To process the jobs, the data needs to be retrieved when the job is completed. This is done with the &lt;b&gt;Receive-Job&lt;/b&gt; cmdlet. Note that the data returned is serialized&amp;mdash;this means that the script is not receiving the real objects as in the previous scripts, but rather a XML representation. In this scenario, this is irrelevant because this data will be converted to an Excel spreadsheet. When the data has been retrieved, the job is removed to free up resources.&lt;/p&gt;
&lt;p&gt;WOW, we went from 90 minutes, down to three minutes, down to 42 seconds to document 50 computers. The end result, the Excel report (for the auditors), is the same for all three versions. This is great performance but can it scale up? The test desktop computer can handle 50 computers. Can it do 100, 200, 500, or even 1000 computers?&lt;/p&gt;
&lt;p&gt;Well, let&amp;rsquo;s try!&lt;/p&gt;
&lt;p&gt;Here are the results for 100 computers:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/4336.hsg_2D00_2_2D00_2_2D00_12_2D00_7.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/4336.hsg_2D00_2_2D00_2_2D00_12_2D00_7.png" alt="Image of performance data" title="Image of performance data" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2538.hsg_2D00_2_2D00_2_2D00_12_2D00_8.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2538.hsg_2D00_2_2D00_2_2D00_12_2D00_8.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The computer list includes some nonexistent computers to test nonresponding computers.&lt;/p&gt;
&lt;p&gt;Here are the script results:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;97&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; seconds (01 minute&amp;nbsp; 37 seconds) for 100 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;380&amp;nbsp;&amp;nbsp; seconds (06 minutes 20 seconds) for 250 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;1228 seconds (20 minutes 28 seconds) for 500 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;3450 seconds (57 minutes 30 seconds) for 1000 computers.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2845.hsg_2D00_2_2D00_2_2D00_12_2D00_9.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2845.hsg_2D00_2_2D00_2_2D00_12_2D00_9.png" alt="Image of performance data" title="Image of performance data" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Scaling up requires additional care. For example, the computer may run out of resources and the script performance could seriously degrade. Worst, some data might be lost. Fortunately in this case, resolving this issue has an interesting side effect. It actually increases the performance!&lt;/p&gt;
&lt;p&gt;To avoid running out of resources, the script will be tweaked based on a rude implementation of a &lt;i&gt;producer&amp;ndash;consumer&lt;b&gt; &lt;/b&gt;&lt;/i&gt;design pattern. In other words, by limiting the number of concurrent jobs based on the speed the data is generated versus the speed it can be imported into Excel. This improved the script down to these numbers:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;94&amp;nbsp;&amp;nbsp; seconds (01 minute&amp;nbsp; 34 seconds) for 100 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;215 seconds (03 minutes 35 seconds) for 250 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;450 seconds (07 minutes 30 seconds) for 500 computers.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;904 seconds (15 minutes 04 seconds) for 1000 computers.&lt;/p&gt;
&lt;p&gt;The last modification to the script was to move the code that retrieves the data from the job, to paste it into Excel to a function (the consumer), and to call this function from the loop that generates the jobs (the producer).&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;foreach ($computerName in $computers)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $computerName = $computerName.trim()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $workBook.workSheets.add() | Out-Null&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $workBook.workSheets.item(1).name = &amp;quot;$computerName&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Creating sheet for $computerName&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Start-Job &lt;i&gt;-ScriptBlock&lt;/i&gt; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; param($computerName);&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get-WmiObject `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -class win32_service `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -ComputerName $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -Name &amp;quot;$computerName&amp;quot; `&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -ArgumentList $computerName&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (@(get-job).count -gt 5) {Get-CompletedJobs}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } #forEach computer&lt;/p&gt;
&lt;p&gt;The key line is:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; if (@(get-job).count -gt 5) {Get-CompletedJobs}&lt;/p&gt;
&lt;p&gt;This line stops the creation of new jobs while removing completed jobs from the job queue. You may want to experiment with the count greater than 5, depending on the time it takes to complete the WMI query versus the time it takes to paste it into Excel. Starting to process the data as it is being generated overlaps the overhead mentioned previously and produces the performance gain.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1638.hsg_2D00_2_2D00_2_2D00_12_2D00_10.png"&gt;&lt;img src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1638.hsg_2D00_2_2D00_2_2D00_12_2D00_10.png" alt="Image of command output" title="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Optimizing is always a question of balance. How much time do you want to invest to further optimize a script? There comes a point where the gain is not worth the pain.&lt;/p&gt;
&lt;p&gt;Having optimized the performance, the next challenge will be to scale this script from one thousand to several thousand computers. As we will see tomorrow, we will need to take a new approach to address this.&lt;/p&gt;
&lt;p&gt;BTW, I shaved one additional minute off the 1000 computer data by changing this line:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$excel.visible = $true&lt;/p&gt;
&lt;p&gt;To this:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$excel.visible = $false&lt;/p&gt;
&lt;p&gt;~ Georges&lt;/p&gt;
&lt;p&gt;Thank, Georges. The zip file that you will find in the &lt;a href="http://gallery.technet.microsoft.com/scriptcenter/Get-on-thousands-of-ef3175c7" target="_blank"&gt;Script Repository&lt;/a&gt; has all the files and scripts from Georges this week. Please join us tomorrow for the conclusion of the series.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ed Wilson, Microsoft Scripting Guy&lt;/b&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3476112" width="1" height="1" alt="" /&gt;</description></item></channel></rss>