{"id":4130,"date":"2013-02-21T00:01:00","date_gmt":"2013-02-21T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/02\/21\/use-powershell-to-perform-an-orderly-shutdown-of-a-server-running-hyper-v\/"},"modified":"2013-02-21T00:01:00","modified_gmt":"2013-02-21T00:01:00","slug":"use-powershell-to-perform-an-orderly-shutdown-of-a-server-running-hyper-v","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-perform-an-orderly-shutdown-of-a-server-running-hyper-v\/","title":{"rendered":"Use PowerShell to Perform an Orderly Shutdown of a Server Running Hyper-V"},"content":{"rendered":"<p><strong>Summary:<\/strong> Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to shut down all virtual machines on a server running Hyper-V prior to shutting down the server.<\/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! From time to time I need to shut down one of our servers that is running the Hyper-V role. The problem is that these servers have multiple virtual machines running, and I do not want to crash the virtual machines. So, right now, I use the Hyper-V Manager, target the server running Hyper-V, and right-click every running virtual machine and select <strong>Shut Down<\/strong>. I do not mind doing this, but some of the virtual machines are running things like Exchange and it takes them a long time to shut down. So, what should be a simple task of shutting down one of our Hyper-V servers ends up taking nearly an hour&mdash;an hour of very boring work, I might add.<\/p>\n<p>&mdash;BB<\/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 BB,<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Well, the snow is all gone. Yep, that is right, we had snow in Charlotte, NC. I am sitting here, sipping a nice cup of tea. I have been experimenting a bit. Today my teapot contains the following recipe: 2 teaspoons (tsp.) of English Breakfast, 1 tsp. of generic green tea, &frac12; tsp. of organic orange peel, &frac12; tsp. of licorice root, 1 tsp. of lemon grass, and a crushed cinnamon stick. Let it steep for 5 minutes, and I have a very nice pot of tea. It is sweet enough that I feel it needs no sweetener whatsoever.<\/p>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong> &nbsp;&nbsp;In this post, I am using the cmdlets from Windows Server&nbsp;2012 and the Hyper-V module. I obtained this module on my computer running Windows&nbsp;8 by downloading and installing the RSAT tools. <a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=28972\" target=\"_blank\">The Windows 8 RSAT tools<\/a> are available from the Microsoft Download Center.<\/p>\n<p>&nbsp;<\/p>\n<h2>Find all running virtual machines<\/h2>\n<p>BB, the first thing you need to do is to use the <strong>Get-VM<\/strong> cmdlet and find all virtual machines that are running on the remote host. To do this, use the <strong>Get-VM<\/strong> and pipe the results to the <strong>Where-Object<\/strong> cmdlet and filter out for a state that is equal to <strong>running<\/strong><em>. <\/em>It is not as difficult as it may sound. The command is shown here.<\/p>\n<p style=\"padding-left: 30px\">$runningVM = Get-VM -ComputerName $vmhost| where state -eq &#8216;running&#8217;<\/p>\n<p>Because you more than likely have more than a single virtual machine running on your remote Hyper-V server, I use the <strong>ForEach<\/strong> language statement to walk through the collection of virtual machines that I store in the <strong>$RunningVM<\/strong> variable. Inside the loop, I create a WMI Event that uses the <strong>Win32_ComputerShutdownEvent<\/strong> WMI class to let me know when each virtual machine shuts down. This portion of the code is shown here.<\/p>\n<p style=\"padding-left: 30px\">foreach ($cn in $runningVM)<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">Write-Debug &#8220;registering shutdown event for $($cn.name)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Register-WmiEvent -Class win32_ComputerShutdownEvent -ComputerName $cn.name `<\/p>\n<p style=\"padding-left: 30px\">&nbsp; -SourceIdentifier $cn.name.tostring()<\/p>\n<p>Once I have registered the event, then I call the <strong>Stop-Computer<\/strong> cmdlet to shut down the virtual machine. This code is shown here.<\/p>\n<p style=\"padding-left: 30px\">Write-debug &#8220;Shutting down $($cn.name)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Stop-Computer -ComputerName $cn.name -Force<\/p>\n<p>Because I registered a win32_ComputerShutdownEvent for the virtual machine, an event triggers after the virtual machine shuts down. To pick up this event, I use the <strong>Wait-Event<\/strong> cmdlet. Once the computer shuts down, the event triggers. This code is shown here.<\/p>\n<p style=\"padding-left: 30px\">Write-Debug &#8220;Waiting for shutdown to complete&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Wait-Event -SourceIdentifier $cn.Name.ToString()}<\/p>\n<p>After all of the virtual machines are shut down, it is time to shut down the Hyper-V host computer (the one that hosts all of the virtual machines). To do this, I use the <strong>Stop-Computer<\/strong> cmdlet. This is shown here.<\/p>\n<p style=\"padding-left: 30px\">Write-Debug &#8220;Shuting down $vmhost&#8221;<\/p>\n<p style=\"padding-left: 30px\">Stop-Computer -ComputerName $vmhost -Force<\/p>\n<h2>Monitor progress of the shutdown<\/h2>\n<p>Because I am watching the shutdown of the systems remotely, and I want to know what is happening, I decided to add a series of <strong>Write-Debug<\/strong> statements. This is extremely easy to use, and when the script runs without the <strong>&ndash;debug<\/strong> switch only the default output appears. But when the script runs with the <strong>&ndash;debug<\/strong> switch, it displays each statement and prompts for the action to take place. This is an interactive type of experience, and it may not be what you want. If you are just wanting more information about each statement without the prompt, then use the <strong>Write-Verbose<\/strong> cmdlet instead of <strong>Write-Debug<\/strong>. They both work the same&mdash;I get them for free as long as I add <strong>[cmdletbinding()]<\/strong><\/p>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong>&nbsp; &nbsp;During testing, I noticed that sometimes the script would appear to hang. This happens when the virtual machine stops more quickly than I am able to press &ldquo;y&rdquo; to confirm the next step, and therefore, the <strong>Wait-Event<\/strong> is waiting for an event that has already occurred.<\/p>\n<p>After testing, I decided I was tired of typing &ldquo;y&rdquo; all the time, and so I did a global find and replace of <strong>Write-Debug<\/strong> with <strong>Write-Verbose<\/strong>. I also decided I needed to remove lingering event objects. So I added the following code.<\/p>\n<p style=\"padding-left: 30px\">Get-Event -SourceIdentifier $cn.name.Tostring() | Remove-Event<\/p>\n<p>The revised script is shown here.<\/p>\n<p style=\"padding-left: 30px\">[cmdletbinding()]<\/p>\n<p style=\"padding-left: 30px\">Param($vmhost = &#8216;hyperv2&#8217;)<\/p>\n<p style=\"padding-left: 30px\">Write-Verbose &#8220;getting running VM&#8217;s on $vmhost&#8221;<\/p>\n<p style=\"padding-left: 30px\">$runningVM = Get-VM -ComputerName $vmhost| where state -eq &#8216;running&#8217;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;foreach ($cn in $runningVM)<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">Write-Verbose &#8220;registering shutdown event for $($cn.name)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Register-WmiEvent -Class win32_ComputerShutdownEvent -ComputerName $cn.name `<\/p>\n<p style=\"padding-left: 30px\">&nbsp; -SourceIdentifier $cn.name.tostring()<\/p>\n<p style=\"padding-left: 30px\">Write-Verbose &#8220;Shutting down $($cn.name)&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Stop-Computer -ComputerName $cn.name -Force<\/p>\n<p style=\"padding-left: 30px\">Write-Verbose &#8220;Waiting for shutdown to complete&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Wait-Event -SourceIdentifier $cn.Name.ToString()<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Get-Event -SourceIdentifier $cn.name.Tostring() | Remove-Event}<\/p>\n<p style=\"padding-left: 30px\">Write-Verbose &#8220;Shuting down $vmhost&#8221;<\/p>\n<p style=\"padding-left: 30px\">Stop-Computer -ComputerName $vmhost -Force<\/p>\n<p>When I run the script now, the following is shown.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7002.HSG-2-21-13-01.png\"><img decoding=\"async\" title=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7002.HSG-2-21-13-01.png\" alt=\"Image of command output\" \/><\/a><\/p>\n<p>BB, that is all there is to using Windows PowerShell to shut down your virtual machines and then to shut down your Hyper-V server.&nbsp; Join me tomorrow when I will talk about more 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><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to shut down all virtual machines on a server running Hyper-V prior to shutting down the server. &nbsp;Hey, Scripting Guy! From time to time I need to shut down one of our servers that is running the Hyper-V role. The problem is that these [&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":[42,271,3,4,130,45,6],"class_list":["post-4130","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-events-and-monitoring","tag-hyper-v","tag-scripting-guy","tag-scripting-techniques","tag-servers","tag-windows-powershell","tag-wmi"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to shut down all virtual machines on a server running Hyper-V prior to shutting down the server. &nbsp;Hey, Scripting Guy! From time to time I need to shut down one of our servers that is running the Hyper-V role. The problem is that these [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/4130","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=4130"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/4130\/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=4130"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=4130"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=4130"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}