{"id":8351,"date":"2012-08-10T00:01:00","date_gmt":"2012-08-10T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/08\/10\/use-background-jobs-to-run-a-powershell-server-uptime-report\/"},"modified":"2012-08-10T00:01:00","modified_gmt":"2012-08-10T00:01:00","slug":"use-background-jobs-to-run-a-powershell-server-uptime-report","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-background-jobs-to-run-a-powershell-server-uptime-report\/","title":{"rendered":"Use Background Jobs to Run a PowerShell Server Uptime Report"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft Scripting Guy, Ed Wilson, shows how to use background jobs to run a Windows PowerShell script that produces a server uptime report.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Question\" \/>&nbsp;Hey, Scripting Guy! I like your script to get uptime and to get free disk space, but I cannot be responsible for running it on a regular basis. In addition, keep in mind we have a very large network, and the script will take a long time to run. Is there a command to make this run in the background?<\/p>\n<p>&mdash;RE<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Answer\" \/>&nbsp;Hello RE,<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. <a href=\"http:\/\/powershellsaturday.com\/002\/\" target=\"_blank\">PowerShell Saturday in Charlotte, North Carolina<\/a> is a little more than a month away (September 15, 2012), and we have all the sponsors and all the speakers lined up, the agendas posted, and nearly half of the tickets are already sold. If you want to attend, you need to get your reservations placed before the tickets are all gone. There will be 200 people attending, and it will be a tremendous day of learning delivered by some &ldquo;rock star&rdquo; trainers!&nbsp; There are three different tracks (Beginner, Advanced, and Applied), so there will be something for anyone who uses or anticipates using Windows PowerShell.<\/p>\n<h2>Use Start-Job to run the report<\/h2>\n<p style=\"padding-left: 30px\"><b>Note<\/b> &nbsp;&nbsp;This is the fourth blog in a series about using the <b>Convertto-HTML<\/b> cmdlet and creating a HTML server uptime report. The first blog talked about <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/08\/07\/use-powershell-to-create-an-html-uptime-report.aspx\" target=\"_blank\">creating an HTML uptime report<\/a>, the second one <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/08\/08\/use-powershell-to-create-a-report-displaying-free-disk-space.aspx\" target=\"_blank\">used Windows PowerShell to create a report that displays disk space in addition to uptime<\/a>, the third discusses <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/08\/09\/use-powershell-to-create-a-color-server-uptime-report.aspx\" target=\"_blank\">adding color and stuff to the uptime report<\/a>. You should read the three previous blogs prior to reading today&rsquo;s.<\/p>\n<p>If you have a large network, it can take a very long time to reach out and touch every server on the network and to bring back the information to a central location. One thing that can help is to run the script as a background job. Using jobs, Windows PowerShell will run the script in the background. You then have the option of using the <b>Wait-Job<\/b> cmdlet to pause the Windows PowerShell console until the script completes, or you can allow the job to complete. At any rate, it is not really necessary to use the <b>Receive-Job<\/b> cmdlet to receive the job because the HTML page creates it as part of the script, and not as part of the job itself. The command shown here creates a job and runs the script.<\/p>\n<p style=\"padding-left: 30px\">Start-Job -FilePath C:\\fso\\HTML_Uptime_FreespaceReport.ps1<\/p>\n<p>To receive the job, use the following commands.<\/p>\n<p style=\"padding-left: 30px\">Get-Job | Receive-Job<\/p>\n<p>When you have done this, you may want to remove the job. This command accomplishes that task.<\/p>\n<p style=\"padding-left: 30px\">Get-Job | Remove-Job<\/p>\n<h2>Use Invoke-Command to multithread the job<\/h2>\n<p>Using <b>Start-Job<\/b> on the local computer does not really do much in the way of speeding up things&mdash;it simply hides how long the script takes by placing it in the background. If you have a large network, use the <b>Invoke-Command<\/b> to run the commands against remote machines. Windows PowerShell automatically determines the best number of concurrent connections (by default 32). To use the <b>Invoke-Command<\/b> cmdlet effectively requires a few changes to the HTML_UptimeReport.ps1 script. The changes involve removing the hard-coded list of servers in the <b>param<\/b><i> <\/i>portion of the script. This first change is shown here.<\/p>\n<p style=\"padding-left: 30px\">Param([string]$path = &#8220;c:\\fso\\uptime.html&#8221;)<\/p>\n<p>The next change involves removing the <b>servers<\/b><i> <\/i>parameter from the call to the <b>Get-UpTime<\/b> function as shown here.<\/p>\n<p style=\"padding-left: 30px\">Get-UpTime |<\/p>\n<p>The next change I make changes the <b>servers<\/b><i> <\/i>parameter on the <b>Get-UpTime<\/b> function. This change is shown here.<\/p>\n<p style=\"padding-left: 30px\">Function Get-UpTime<\/p>\n<p style=\"padding-left: 30px\">{ Param ([string]$servers = $env:COMPUTERNAME)<\/p>\n<p>The last change removes the <b>Invoke-Item<\/b> command that displayed the completed HTML report. This will not work remotely anyway, and it is therefore unnecessary.<\/p>\n<p>I leave the <b>foreach<\/b><i> <\/i>command because I do not want to make more changes to the function than required. The revised HTML_UptimeReport.ps1 is shown here as Invoke_HTML_UptimeReport.ps1.<\/p>\n<p style=\"padding-left: 30px\"><b>Invoke_HTML_UptimeReport.ps1<\/b><\/p>\n<p style=\"padding-left: 30px\">Param([string]$path = &#8220;c:\\fso\\uptime.html&#8221;)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Function Get-UpTime<\/p>\n<p style=\"padding-left: 30px\">{ Param ([string]$servers = $env:COMPUTERNAME)<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Foreach ($s in $servers)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; $os = Get-WmiObject -class win32_OperatingSystem -cn $s<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; New-Object psobject -Property @{computer=$s;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uptime = (get-date) &#8211; $os.converttodatetime($os.lastbootuptime)}}}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\"># Entry Point ***<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Get-UpTime |<\/p>\n<p style=\"padding-left: 30px\">ConvertTo-Html -As Table -body &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; &lt;h1&gt;Server Uptime Report&lt;\/h1&gt;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; The following report was run on $(get-date)&#8221; &gt;&gt; $path&nbsp;<\/p>\n<p>I now open my Windows PowerShell console, and I retrieve and store a credential object to be used when making the remote connections. Next, I provide an array of server names. Finally, I call the <b>Invoke-Command<\/b> cmdlet and specify the computer names and the credentials. I use the <b>FilePath<\/b><i> <\/i>parameter to point to a script that exists on my local computer. Next I use the <b>AsJob<\/b><i> <\/i>parameter to run the command as a job. Finally, I specify a friendly name for the job. This command permits up to 32 simultaneous remote connections to obtain the information. The commands I type are shown here.<\/p>\n<p style=\"padding-left: 30px\">$credential = Get-Credential -Credential iammred\\administrator<\/p>\n<p style=\"padding-left: 30px\">$servers = @(&#8220;dc1&#8243;,&#8221;dc3&#8243;,&#8221;ex1&#8243;,&#8221;sql1&#8221;)<\/p>\n<p style=\"padding-left: 30px\">Invoke-Command -ComputerName $servers -Credential $credential -FilePath C:\\fso\\Invoke_HTML_UptimeReport.ps1 -AsJob -JobName uptime<\/p>\n<p>There is one problem with this command. The c:\\fso\\uptime.html command refers to a folder (c:\\fso), which must exist on the remote server. Actually, several of my remote servers have a c:\\fso folder, but the ones that do not will generate an error when I receive the job. The commands and associated output are shown in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5050.HSG-8-10-12-01.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5050.HSG-8-10-12-01.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>To override the default value that is contained in the script, I supply a value for the <b>args<\/b><i> <\/i>parameter of the <b>Invoke-Command<\/b> cmdlet. The values for the <b>args<\/b><i> <\/i>parameter must appear in the same order that the script declares the parameters.<\/p>\n<p>If I run the command and do not make provisions for multiple file access, file locking issues arise. There are two easy ways to deal with this issue. The first is to dial down the <b>ThrottleLimit<\/b><i> <\/i>value to 1. Doing this, however, does no more than allow for a single connection at a time. This is the same thing the original script accomplished; and therefore, it is not a great solution. A better approach is to modify the output file name, to include the server name. Doing this permits simultaneous file access. Here is a modification to the code.<\/p>\n<p style=\"padding-left: 30px\">&gt;&gt; (&#8220;{0}{1}_Uptime.html&#8221; -f $path, $env:COMPUTERNAME)&nbsp;<\/p>\n<p>When I use <b>Invoke-Command<\/b> now, I do not include the file name, but only the <b>\\\\dc1\\share<\/b> path. This command is shown here.<\/p>\n<p style=\"padding-left: 30px\">Invoke-Command -ComputerName $servers -Credential $credential -FilePath C:\\fso\\Invoke_HTML_UptimeReport.ps1 -AsJob -JobName uptime -args &#8220;\\\\dc1\\share\\&#8221;<\/p>\n<p>RE, that is all there is to using jobs to run a Windows PowerShell script and produce an uptime report. Join me tomorrow for more Windows PowerShell cool stuff.<\/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\" target=\"_blank\">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>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use background jobs to run a Windows PowerShell script that produces a server uptime report. &nbsp;Hey, Scripting Guy! I like your script to get uptime and to get free disk space, but I cannot be responsible for running it on a regular basis. In addition, keep [&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":[193,3,4,45],"class_list":["post-8351","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-background-jobs","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use background jobs to run a Windows PowerShell script that produces a server uptime report. &nbsp;Hey, Scripting Guy! I like your script to get uptime and to get free disk space, but I cannot be responsible for running it on a regular basis. In addition, keep [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8351","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=8351"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8351\/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=8351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=8351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=8351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}