{"id":11811,"date":"2011-12-12T00:01:00","date_gmt":"2011-12-12T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/12\/12\/use-a-powershell-script-to-start-non-running-automatic-services\/"},"modified":"2011-12-12T00:01:00","modified_gmt":"2011-12-12T00:01:00","slug":"use-a-powershell-script-to-start-non-running-automatic-services","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-a-powershell-script-to-start-non-running-automatic-services\/","title":{"rendered":"Use a PowerShell Script to Start Non-Running Automatic Services"},"content":{"rendered":"<p><b>Summary<\/b>: Guest blogger, Karl Mitschke, discusses a Windows PowerShell script to start non-running services that are set to start automatically.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is Karl Mitschke, one of the authors of the <a href=\"http:\/\/www.amazon.com\/Windows-PowerShell-2-0-Bible-Thomas\/dp\/1118021983\" target=\"_blank\">Windows PowerShell 2.0 Bible<\/a>. Here is a little bit about Karl.<\/p>\n<p>Karl Mitschke is an IT veteran with over 20 years of experience. He has specialized in messaging since the early 1990s. Karl has been automating tasks with script since moving to Microsoft Exchange 5.0, starting with WinBatch. He started using Windows PowerShell in 2007 when he moved to Exchange Server&nbsp;2007. When he&rsquo;s not writing Windows PowerShell scripts, or writing about &nbsp;Windows PowerShell scripts, Karl enjoys spending time with his bride, Sherry, and their two dogs.<br \/> Blog: <a href=\"http:\/\/unlockpowershell.wordpress.com\/\" target=\"_blank\">Unlock-PowerShell<\/a><br \/> <a href=\"http:\/\/www.wiley.com\/WileyCDA\/WileyTitle\/productCd-1118021983.html\" target=\"_blank\">Windows PowerShell 2.0 Bible<\/a><\/p>\n<h2>Starting services on remote servers<\/h2>\n<p>In the &ldquo;Performing Advanced Server Management&rdquo; chapter in the <a href=\"http:\/\/www.amazon.com\/Windows-PowerShell-2-0-Bible-Thomas\/dp\/1118021983\" target=\"_blank\">Windows PowerShell 2.0 Bible<\/a>, I presented a script that would start services on remote servers that are set to start automatically and were not started. Due to the constraints of the book, the script was severely limited. That script is shown here.<\/p>\n<p style=\"padding-left: 30px\">$Computers = &ldquo;FileServer01&rdquo;,&rdquo;FileServer02&rdquo;<br \/> $WmiObject = @{<br \/> Class = &ldquo;Win32_Service&rdquo;<br \/> Filter = &ldquo;StartMode=&rsquo;Auto&rsquo; and State!=&rsquo;Running&rsquo;&rdquo;<br \/> }<br \/> foreach ($Computer in $Computers)<br \/> {<br \/> foreach ($Svc in Get-WmiObject @WmiObject -ComputerName $Computer)<br \/> {<br \/> Write-Host &ldquo;Starting the&rdquo; $Svc.DisplayName &ldquo;service on $Computer&rdquo;<br \/> $Svc.StartService() | Out-Null<br \/> }<br \/> }<\/p>\n<p>This was fine, but the script could really use some improvement. For one thing, you needed to hard code the server names. In addition, it did not accept credentials, you could not simulate the action, and there was no Help.<\/p>\n<p>The concept was sound, however, so I decided to extend the script to put it into production at work, where I use it to verify that services are running after performing updates on our Exchange Server infrastructure. Unfortunately, extending the script makes it too long for the book and too long for this blog. The complete script is available in the <a href=\"http:\/\/gallery.technet.microsoft.com\/Starts-automatic-on-remote-26ddd199\" target=\"_blank\">Scripting Guys Script Repository<\/a>, but I will discuss highlights of the script in this blog post.<\/p>\n<h2>Extending the script with Help<\/h2>\n<p>The first several objections are easy to overcome with advanced parameters. The final objection is overcome with comment-based Help. Windows PowerShell even includes a method to add Help. I am referring to the built in <b>Get-Help<\/b> cmdlet. In fact, you can potentially get more Help than you will ever need by typing the following script into your Windows PowerShell console:<\/p>\n<p style=\"padding-left: 30px\">Get-Help -Name functions_advanced_parameters<\/p>\n<p style=\"padding-left: 30px\">Get-Help -Name about_comment_based_help<\/p>\n<p>The Help about advanced parameters is too verbose to summarize, so I would suggest that you read it and familiarize yourself with the content.<\/p>\n<p>The Help for comment-based Help shows that for script-based Help, comment-based Help can appear in two locations:<\/p>\n<ul>\n<li><b>At the beginning of the script file<\/b>. Script Help can be preceded in the script only by comments and blank lines. If the first item in the script body (after the Help) is a function declaration, there must be at least two blank lines between the end of the script Help and the function declaration. Otherwise, the Help is interpreted as being Help for the function, not Help for the script.<\/li>\n<li><b>At the end of the script file<\/b>. If the script is signed, place comment-based Help at the beginning of the script file. The end of the script file is occupied by the signature block.<\/li>\n<\/ul>\n<p>As I sign the scripts that I use at work, I include comment-based Help at the beginning of the file.<\/p>\n<p>I also choose to use the comment-block syntax as opposed to using the comment character (#) in front of each line, because I find it to be more readable. An example of the comment-block syntax is shown here.<\/p>\n<p style=\"padding-left: 30px\">&lt;#<\/p>\n<p style=\"padding-left: 30px\">.SYNOPSIS<\/p>\n<p style=\"padding-left: 30px\">Invoke-StartService &#8211; Start all essential services that are not running.<\/p>\n<p style=\"padding-left: 30px\">.DESCRIPTION<\/p>\n<p style=\"padding-left: 30px\">This script finds services that are set to start automatically, and starts them.<\/p>\n<p style=\"padding-left: 30px\">#&gt;<\/p>\n<p>Therefore, Help is out of the way with the comment-based Help. Next, I tackle the parameters.<\/p>\n<h2>Adding arguments<\/h2>\n<p>I wanted to allow the script to accept server names from the command line or from a pipeline, so I used the <b>ValueFromPipeline<\/b> argument when I declare the <i>ComputerName<\/i> parameter for the script. I also want to allow the script to target multiple computers, so I declared the <i>ComputerName<\/i> parameter as an array of strings as shown here.<\/p>\n<p style=\"padding-left: 30px\">[Parameter(<\/p>\n<p style=\"padding-left: 30px\">Position = 0,<\/p>\n<p style=\"padding-left: 30px\">ValueFromPipeline=$true,<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $false,<\/p>\n<p style=\"padding-left: 30px\">HelpMessage = &#8220;The computer to start services on&#8221;<\/p>\n<p style=\"padding-left: 30px\">)]<\/p>\n<p style=\"padding-left: 30px\">[string[]]$ComputerName = $env:ComputerName<\/p>\n<p>As you can see, I set the <i>ComputerName <\/i>parameter to not be required by using the local computer name if it is not specified. I also set the parameter to be positional&mdash;that means that you do not need to use the name of the parameter as long as the computer name(s) are specified as the first-passed parameter to the script.<\/p>\n<p>I wanted the script to accept credentials so that I could start my Windows PowerShell session with a non-administrator account. I added the optional parameter <i>Credential<\/i> to handle these credentials.<\/p>\n<p>Finally, I wanted to emulate the WhatIf functionality in so many of my favorite cmdlets, so I added the optional switch parameter <i>WhatIf<\/i>.&nbsp;The entire parameter declaration is shown here.<\/p>\n<p style=\"padding-left: 30px\">param (<\/p>\n<p style=\"padding-left: 30px\">[Parameter(<\/p>\n<p style=\"padding-left: 30px\">Position = 0,<\/p>\n<p style=\"padding-left: 30px\">ValueFromPipeline=$true,<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $false<\/p>\n<p style=\"padding-left: 30px\">)]<\/p>\n<p style=\"padding-left: 30px\">[string[]]$ComputerName = $env:ComputerName,<\/p>\n<p style=\"padding-left: 30px\">[Parameter(<\/p>\n<p style=\"padding-left: 30px\">Position = 1,<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $false<\/p>\n<p style=\"padding-left: 30px\">)]<\/p>\n<p style=\"padding-left: 30px\">$Credential,<\/p>\n<p style=\"padding-left: 30px\">[Parameter(<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $false<\/p>\n<p style=\"padding-left: 30px\">)]<\/p>\n<p style=\"padding-left: 30px\">[switch]$WhatIf<\/p>\n<p style=\"padding-left: 30px\">)<\/p>\n<h2>Using $PSBoundParameters<\/h2>\n<p>I wanted to avoid If statements as much as possible, so I take advantage of the automatic variable <b>$PSBoundParameters<\/b>, which is a hash table of the parameter names and values that are passed to the script.<\/p>\n<p>You can pass the <b>$PSBoundParameters<\/b> to the <b>Get-WmiObject<\/b> cmdlet as a splatted hash table as shown here:<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject -Class Win32_Service @PSBoundParameters<\/p>\n<p>The parameters <i>ComputerName<\/i> and <i>Credential<\/i> can be passed directly to the <b>Get-WmiObject<\/b> cmdlet. However, that cmdlet does not accept the <i>WhatIf<\/i> parameter, if present, which would cause the error message shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5314.hsg-12-12-11-1.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5314.hsg-12-12-11-1.jpg\" alt=\"Image of error message\" title=\"Image of error message\" \/><\/a><\/p>\n<p>This can be resolved by using the <b>Remove()<\/b> method of the hash table. You can check for the existence of the parameters with an If statement, or you can pass the command to the <b>Out-Null<\/b> cmdlet to avoid the If statement as shown here.<\/p>\n<p style=\"padding-left: 30px\">$PSBoundParameters.Remove(&#8220;WhatIf&#8221;) | Out-Null<\/p>\n<p>I also have to handle the two methods of passing credentials to the script. The parameter <i>Credential<\/i> is not typed, so it accepts a string or a credential object as shown here.<\/p>\n<p style=\"padding-left: 30px\">$cred = Get-Credential -Credential &#8220;mitschke\\karlm&#8221;<\/p>\n<p style=\"padding-left: 30px\">.\\Invoke-StartService.ps1 -Credential $cred<\/p>\n<p>When it is supplied like that, the <b>$PSBoundParameters<\/b> hash table passes a credential object to the <b>Get-WmiObject<\/b> cmdlet. However, if you supply the <i>Credential<\/i> parameter with a string, allowing the script to prompt for a password, the <b>$PSBoundParameters<\/b> hash table passes the string to the <b>Get-WmiObject<\/b> cmdlet and prompts for a password on every service that needs starting.<\/p>\n<p>This is resolved by once again using the <b>Remove()<\/b> method of the hash table, and then using the <b>Add()<\/b> method to add the valid credential object to the <b>$PSBoundParameters<\/b> hash table as shown here.<\/p>\n<p style=\"padding-left: 30px\">if ($Credential -ne $null -and $Credential.GetType().Name -eq &#8220;String&#8221;)<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">$PSBoundParameters.Remove(&#8220;Credential&#8221;) | Out-Null<\/p>\n<p style=\"padding-left: 30px\">$PSBoundParameters.Add(&#8220;Credential&#8221;, (Get-Credential -Credential $Credential))<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>I modified the <i>Filter<\/i> parameter for the <b>Get-WmiObject<\/b> cmdlet to find only the services that I was interested in. Specifically, I am not interested in starting the Microsoft .NET Framework Runtime Optimization Services, which may be set to start automatically. The service would start and then stop because it finds that no action is needed. It is not really a problem starting these services, I just wanted to avoid the time it takes to start them, and avoid event log entries that show they had started and stopped.<\/p>\n<p>These services have a service name starting with clr_optimization_. The filter I use is shown here.<\/p>\n<p style=\"padding-left: 30px\">Filter &#8220;startmode=&#8217;auto&#8217; and state=&#8217;stopped&#8217; and (name &gt; &#8216;clra&#8217; or name &lt; &#8216;clr&#8217;)&#8221;<\/p>\n<p>The filter isn&rsquo;t perfect&mdash;I suppose there could be a service with a name that starts with clra, but I have not seen one, so the filter serves my purposes. A better filter could use the grave accent character (`). The grave accent character is also the escape character for Windows PowerShell, so you would need to use two grave accents as &ldquo;name &gt; &#8216;clr&#8220;&rsquo;&rdquo;. You could also use a client-side filter by using the <b>Where-Object<\/b> cmdlet as shown here:<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject -Class Win32_Service | Where-Object -FilterScript {$_.Name -notmatch &#8220;clr_*&#8221; -and $_.StartMode -eq &#8220;Auto&#8221; -And $_.State -ne &#8220;Running&#8221;}<\/p>\n<p>That is perfectly valid; however, using the <i>Filter<\/i> parameter of the <b>Get-WmiObject<\/b> cmdlet performs server-side filtering, which should be quicker because only the objects we are interested in are passed back to the client. The complete server-side filtering example is shown here:<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject -Class Win32_Service &ndash;Filter &#8220;startmode=&#8217;auto&#8217; and state=&#8217;stopped&#8217; and (name &gt; &#8216;clra&#8217; or name &lt; &#8216;clr&#8217;)&#8221;<\/p>\n<p>So now we have a working filter, working parameters, and working Help. It is now time to test the parameters with the <i>WhatIf <\/i>switch. The command line and its associated output are shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3173.hsg-12-12-11-2.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3173.hsg-12-12-11-2.jpg\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>When I see what the script will do, I run the script without the <i>WhatIf <\/i>parameter. The output from the command appears in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4477.hsg-12-12-11-3.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4477.hsg-12-12-11-3.jpg\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>As mentioned, the entire script is available in the <a href=\"http:\/\/gallery.technet.microsoft.com\/Starts-automatic-on-remote-26ddd199\" target=\"_blank\">Scripting Guys Script Repository<\/a>. The output of the script follows the script. I believe the script is pretty well written; but as always, I am open to suggestions. You can reach me at:<\/p>\n<p style=\"padding-left: 30px\">-join (&#8220;6B61726C6D69747363686B65406D742E6E6574&#8243;-split&#8221;(?&lt;=\\G.{2})&#8221;,19|%{[char][int]&#8221;0x$_&#8221;})<\/p>\n<p>Thank you Karl, for a very useful and interesting blog post. Join me tomorrow for more Windows PowerShell goodness.<\/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: Guest blogger, Karl Mitschke, discusses a Windows PowerShell script to start non-running services that are set to start automatically. Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is Karl Mitschke, one of the authors of the Windows PowerShell 2.0 Bible. Here is a little bit about Karl. Karl Mitschke is an [&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":[56,304,31,3,39,45],"class_list":["post-11811","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-karl-mitschke","tag-operating-system","tag-scripting-guy","tag-services","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Karl Mitschke, discusses a Windows PowerShell script to start non-running services that are set to start automatically. Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is Karl Mitschke, one of the authors of the Windows PowerShell 2.0 Bible. Here is a little bit about Karl. Karl Mitschke is an [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11811","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=11811"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11811\/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=11811"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=11811"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=11811"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}