Sometimes, when troubleshooting or for forensic reasons, you may have to determine if an application is running inside a virtual machine. John Kelbley, co-author of Windows Server 2008 Hyper-V : Insiders Guide to Microsoft's Hypervisor, shares how.
One (relatively) simple way to detect key virtualization information is via WMI / WBEM. You can use the root\CIM2 namespace and access the Baseboard class (full of interesting BIOS information) to get a description of the "physical" system. This class often includes information about the motherboard and chassis - manufacture, model, serial number, other. You can run the following VBS to get this info.
On Error Resume Next Const wbemFlagReturnImmediately = &h10 Const wbemFlagForwardOnly = &h20 arrComputers = Array(".") For Each strComputer In arrComputers WScript.Echo WScript.Echo "==========================================" WScript.Echo "Computer: " & strComputer WScript.Echo "==========================================" Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_BaseBoard", "WQL", _ wbemFlagReturnImmediately + wbemFlagForwardOnly) For Each objItem In colItems WScript.Echo "Caption: " & objItem.Caption strConfigOptions = Join(objItem.ConfigOptions, ",") WScript.Echo "ConfigOptions: " & strConfigOptions WScript.Echo " CreationClassName: " & objItem.CreationClassName WScript.Echo " Description: " & objItem.Description WScript.Echo " HostingBoard: " & objItem.HostingBoard WScript.Echo " InstallDate: " & WMIDateStringToDate(objItem.InstallDate) WScript.Echo " Manufacturer: " & objItem.Manufacturer WScript.Echo " Model: " & objItem.Model WScript.Echo " Name: " & objItem.Name WScript.Echo "OtherIdentifyingInfo: " & objItem.OtherIdentifyingInfo WScript.Echo " PartNumber: " & objItem.PartNumber WScript.Echo " Product: " & objItem.Product WScript.Echo " SerialNumber: " & objItem.SerialNumber WScript.Echo " SKU: " & objItem.SKU WScript.Echo " Status: " & objItem.Status WScript.Echo " Tag: " & objItem.Tag WScript.Echo " Version: " & objItem.Version WScript.Echo Next Next Function WMIDateStringToDate(dtmDate) WScript.Echo dtm: WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) & "/" & _ Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _ & " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2)) End Function
On Error Resume Next
Const wbemFlagReturnImmediately = &h10 Const wbemFlagForwardOnly = &h20
arrComputers = Array(".") For Each strComputer In arrComputers WScript.Echo WScript.Echo "==========================================" WScript.Echo "Computer: " & strComputer WScript.Echo "=========================================="
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_BaseBoard", "WQL", _ wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem In colItems WScript.Echo "Caption: " & objItem.Caption strConfigOptions = Join(objItem.ConfigOptions, ",") WScript.Echo "ConfigOptions: " & strConfigOptions WScript.Echo " CreationClassName: " & objItem.CreationClassName WScript.Echo " Description: " & objItem.Description WScript.Echo " HostingBoard: " & objItem.HostingBoard WScript.Echo " InstallDate: " & WMIDateStringToDate(objItem.InstallDate) WScript.Echo " Manufacturer: " & objItem.Manufacturer WScript.Echo " Model: " & objItem.Model WScript.Echo " Name: " & objItem.Name WScript.Echo "OtherIdentifyingInfo: " & objItem.OtherIdentifyingInfo WScript.Echo " PartNumber: " & objItem.PartNumber WScript.Echo " Product: " & objItem.Product WScript.Echo " SerialNumber: " & objItem.SerialNumber WScript.Echo " SKU: " & objItem.SKU WScript.Echo " Status: " & objItem.Status WScript.Echo " Tag: " & objItem.Tag WScript.Echo " Version: " & objItem.Version WScript.Echo Next Next
Function WMIDateStringToDate(dtmDate) WScript.Echo dtm: WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) & "/" & _ Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _ & " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2)) End Function
Here is a screen capture of the script results for a physical system running Windows Server 2008.
NOTE the motherboard was manufactured by Intel (model DG45ID).
Running the same script in a virtual machine returns similar information:
NOTE On the virtual machine, the "motherboard" appears to be made by Microsoft (we don't make motherboards!) and is of a virtual type.
The version number shown reflects the version of Hyper-V (Server 2008 RTM), and the Serial Number matches that found in the VM configuration file (XML file on the physical host).
The Perl script version for this is:
use strict; use Win32::OLE('in'); use constant wbemFlagReturnImmediately => 0x10; use constant wbemFlagForwardOnly => 0x20; my @computers = ("."); foreach my $computer (@computers) { print "\n"; print "==========================================\n"; print "Computer: $computer\n"; print "==========================================\n"; my $objWMIService = Win32::OLE->GetObject("winmgmts:\\\\$computer\\root\\CIMV2") or die "WMI connection failed.\n"; my $colItems = $objWMIService->ExecQuery("SELECT * FROM Win32_BaseBoard", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly); foreach my $objItem (in $colItems) { print " Caption: $objItem->{Caption}\n"; print " ConfigOptions: " . join(",", (in $objItem->{ConfigOptions})) . "\n"; print " CreationClassName: $objItem->{CreationClassName}\n"; print " Description: $objItem->{Description}\n"; print " HostingBoard: $objItem->{HostingBoard}\n"; print " InstallDate: $objItem->{InstallDate}\n"; print " Manufacturer: $objItem->{Manufacturer}\n"; print " Model: $objItem->{Model}\n"; print " Name: $objItem->{Name}\n"; print "OtherIdentifyingInfo: $objItem->{OtherIdentifyingInfo}\n"; print " Product: $objItem->{Product}\n"; print " SerialNumber: $objItem->{SerialNumber}\n"; print " SKU: $objItem->{SKU}\n"; print " Status: $objItem->{Status}\n"; print " Tag: $objItem->{Tag}\n"; print " Version: $objItem->{Version}\n"; print "\n"; } }sub WMIDateStringToDate(strDate) { return "blah"; }
use strict; use Win32::OLE('in');
use constant wbemFlagReturnImmediately => 0x10; use constant wbemFlagForwardOnly => 0x20;
my @computers = ("."); foreach my $computer (@computers) { print "\n"; print "==========================================\n"; print "Computer: $computer\n"; print "==========================================\n";
my $objWMIService = Win32::OLE->GetObject("winmgmts:\\\\$computer\\root\\CIMV2") or die "WMI connection failed.\n"; my $colItems = $objWMIService->ExecQuery("SELECT * FROM Win32_BaseBoard", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly);
foreach my $objItem (in $colItems) { print " Caption: $objItem->{Caption}\n"; print " ConfigOptions: " . join(",", (in $objItem->{ConfigOptions})) . "\n"; print " CreationClassName: $objItem->{CreationClassName}\n"; print " Description: $objItem->{Description}\n"; print " HostingBoard: $objItem->{HostingBoard}\n"; print " InstallDate: $objItem->{InstallDate}\n"; print " Manufacturer: $objItem->{Manufacturer}\n"; print " Model: $objItem->{Model}\n"; print " Name: $objItem->{Name}\n"; print "OtherIdentifyingInfo: $objItem->{OtherIdentifyingInfo}\n"; print " Product: $objItem->{Product}\n"; print " SerialNumber: $objItem->{SerialNumber}\n"; print " SKU: $objItem->{SKU}\n"; print " Status: $objItem->{Status}\n"; print " Tag: $objItem->{Tag}\n"; print " Version: $objItem->{Version}\n"; print "\n"; } }sub WMIDateStringToDate(strDate) { return "blah"; }
For additional reference, within Windows I could also access the same information in a single command line (in Windows XP or newer) by typing the following:
wmic baseboard get manufacturer, product, Serialnumber, version
For info on how to use Hper-V PS cmdlets see: http://www.microsoft.com/technet/scriptcenter/topics/msh/cmdlets/index.mspx
See also James O’Neil’s New and improved PowerShell Library for Hyper-V. Now with more functions and... documentation!
For 35 sample Hyper-V PS1 scripts in a zipfile, go to: Hyper-V%20PowerShell%20Example%20Scripts.zip-download
And buy John(et al)’s book!
Update: John's blogging now and has an updated method to detect the hypervisor: http://blogs.technet.com/enterprise_admin/archive/2009/10/20/detecting-the-virtualization-layer-from-within-a-guest-child-instance.aspx
Want to move a VM from server A to server B along with its associated storage and snapshots in R2? Snapshots are associated with the VMs and not the VHD files. You should explore import/export. Soumya’s written a series of blogposts to get you started:
http://blogs.technet.com/virtualization/archive/2009/05/20/hyper-v-r2-import-export-part-1-the-case-for-new-import-export-functionality.aspx
http://blogs.technet.com/virtualization/archive/2009/05/21/hyper-v-r2-import-export-part-2-the-new-import-export-apis.aspx
http://blogs.technet.com/virtualization/archive/2009/05/22/hyper-v-r2-import-export-part-3-the-ui.aspx
http://blogs.technet.com/virtualization/archive/2009/05/27/hyper-v-r2-import-export-part-4-export-code-sample.aspx
http://blogs.technet.com/virtualization/archive/2009/05/28/hyper-v-r2-import-export-part-5-import-code-sample.aspx
http://blogs.technet.com/virtualization/archive/2009/05/29/hyper-v-r2-import-export-part-6-so-what-happened-to-configuration-only-export.aspx
Ben blogged about V1 (also called R1 now by some folks…) import/export: http://blogs.msdn.com/virtual_pc_guy/archive/2008/08/26/hyper-v-export-import-part-1.aspx http://blogs.msdn.com/virtual_pc_guy/archive/2008/08/27/hyper-v-export-import-part-2.aspx
Need to remotely set the VLAN IDs on your server core installation? Some friends on the Hyper-V team put together a powershell 2.0 script for setting vlan id which you could run on the server core directly (rename the extension of the script to .ps1). The script accepts a vm name, and vlan id, finds the first connected network adapter of that vm and sets it to that vlan id.
################################################################################ # # Copyright ©2009 Microsoft Corporation. All rights reserved. # # File: modify-vlan.ps1 # # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF # ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A # PARTICULAR PURPOSE. # # Copyright ©2009 Microsoft Corporation. All rights reserved. # ################################################################################ param( $vmName = $(throw "Must supply a virtual machine name"), $vlanId = $(throw "Must supply vlan id"), $computer = "." ) $ns = "root\virtualization" # get the computer system $vm = gwmi -namespace $ns -computerName $computer Msvm_ComputerSystem -filter "ElementName = '$vmName'" if ($vm -eq $null) { "No virtual machine with name '$vmName'" return } # get its related vssd $vssd = gwmi -namespace $ns -computerName $computer -query "associators of {$vm} where AssocClass=Msvm_SettingsDefineState" # get its synthetic and enumlated NICs $nics = gwmi -namespace $ns -computerName $computer -query "associators of {$vssd} where AssocClass=Msvm_VirtualSystemSettingDataComponent" | where {$_.ResourceType -eq 10 -and ($_.ResourceSubType -eq 'Microsoft Synthetic Ethernet Port' -or $_.ResourceSubType -eq 'Microsoft Emulated Ethernet Port')} if ($nics -eq $null) { # vm does not have any NICs. "Virtual machine '$vmName' does not have any NICs" return } # Find the first nic which has a connection $nic = $nics | where {$_.Connection -ne $null} | select-object -first 1 if ($nic -eq $null) { "None of the NICs on virtual machine '$vmName' are connected" return } # get the connected switch port. $connectedPort = [wmi]$nic.Connection[0] # need to set the external trunk list of the external port on this same switch # to include this vlan id, else traffic won't get through. # first get its switch. $switch = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_HostedAccessPoint" # enumerate all of its ports. Find the port which is externally connected. $ports = gwmi -namespace $ns -computerName $computer -query "associators of {$switch} where ResultClass=Msvm_SwitchPort" $externalPort = $null foreach ($p in $ports) { $switchLanEndpoint = gwmi -namespace $ns -computerName $computer -query "associators of {$p} where ResultClass=Msvm_SwitchLanEndpoint" if ($switchLanEndpoint -ne $null) { $externalEthernetPort = gwmi -namespace $ns -computerName $computer -query "associators of {$switchLanEndpoint} where resultclass=Msvm_ExternalEthernetPort" if ($externalEthernetPort -ne $null) { # we got it, we found the switch port connected to the external # port, save it and break out of the loop. $externalPort = $p break } } } if ($externalPort -ne $null) { # get the port's VlanEndpoint $vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$externalPort} where AssocClass=Msvm_BindsTo" # get the vlan's setting object $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" # get the current trunk list and add the new vlan id into it. # one thing additionally we could do here, which the Hyper-V UI does is clean up # the old AccessVlan id of the port from the trunk list. But, we can't just remove the # old AccessVlan from the trunklist, because another port might be using the same vlan id. # We would have to enumerate all of the ports on the switch and build a new trunk list. # For the purposes of this script, don't worry about cleaning up old vlan id' from the trunk list. $trunkList = $vlanSetting.TrunkedVLANList if ($trunkList -notcontains $vlanid) { $trunkList = $trunkList + $vlanId $vlanSetting.TrunkedVLANList = $trunkList $result = $vlanSetting.Put() } # set the vlan mode into trunking mode. if ($vlan.DesiredEndpointMode -ne 5) { $vlan.DesiredEndpointMode = 5 $result = $vlan.Put() } } # Now that we have finished with the trunklist, set the vlan id of the original connected port. $vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_BindsTo" $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" $vlanSetting.AccessVlan = $vlanId $result = $vlanSetting.Put() ################################################################################ # # .SYNOPSIS # # Sets the vlan id of the first connected NIC on a virtual machine. # # # .DESCRIPTION # # Finds the first connected NIC of a virtual machine and sets up its VLAN # settings in the same manner as the Hyper-V UI. First it checks to see if # the NIC is connected to an external network, and if so it adds the VLAN id # to the trunking list, and sets the endpoint mode to trunking. This makes sure # that traffic with that VLAN id from the external network goes through the switch. # Next it sets up the Access VLAN of the virtual machine's NIC. # # .PARAMETER VmName # # The name of the virtual machine to modify. We will modify the first connected # NIC we find on this virtual machine. # # .PARAMETER VlanId # # The vlan id to set. # # .PARAMETER Computer # # The host computer where $vmname resides. # # .EXAMPLE # # C:\PS> mount-vlan.ps1 foo 512 # # ################################################################################
################################################################################ # # Copyright ©2009 Microsoft Corporation. All rights reserved. # # File: modify-vlan.ps1 # # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF # ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A # PARTICULAR PURPOSE. # # Copyright ©2009 Microsoft Corporation. All rights reserved. # ################################################################################
param( $vmName = $(throw "Must supply a virtual machine name"), $vlanId = $(throw "Must supply vlan id"), $computer = "." )
$ns = "root\virtualization"
# get the computer system $vm = gwmi -namespace $ns -computerName $computer Msvm_ComputerSystem -filter "ElementName = '$vmName'"
if ($vm -eq $null) { "No virtual machine with name '$vmName'" return }
# get its related vssd $vssd = gwmi -namespace $ns -computerName $computer -query "associators of {$vm} where AssocClass=Msvm_SettingsDefineState"
# get its synthetic and enumlated NICs $nics = gwmi -namespace $ns -computerName $computer -query "associators of {$vssd} where AssocClass=Msvm_VirtualSystemSettingDataComponent" | where {$_.ResourceType -eq 10 -and ($_.ResourceSubType -eq 'Microsoft Synthetic Ethernet Port' -or $_.ResourceSubType -eq 'Microsoft Emulated Ethernet Port')}
if ($nics -eq $null) { # vm does not have any NICs. "Virtual machine '$vmName' does not have any NICs" return }
# Find the first nic which has a connection $nic = $nics | where {$_.Connection -ne $null} | select-object -first 1
if ($nic -eq $null) { "None of the NICs on virtual machine '$vmName' are connected" return }
# get the connected switch port. $connectedPort = [wmi]$nic.Connection[0]
# need to set the external trunk list of the external port on this same switch # to include this vlan id, else traffic won't get through.
# first get its switch. $switch = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_HostedAccessPoint"
# enumerate all of its ports. Find the port which is externally connected. $ports = gwmi -namespace $ns -computerName $computer -query "associators of {$switch} where ResultClass=Msvm_SwitchPort" $externalPort = $null
foreach ($p in $ports) { $switchLanEndpoint = gwmi -namespace $ns -computerName $computer -query "associators of {$p} where ResultClass=Msvm_SwitchLanEndpoint" if ($switchLanEndpoint -ne $null) { $externalEthernetPort = gwmi -namespace $ns -computerName $computer -query "associators of {$switchLanEndpoint} where resultclass=Msvm_ExternalEthernetPort" if ($externalEthernetPort -ne $null) { # we got it, we found the switch port connected to the external # port, save it and break out of the loop. $externalPort = $p break } } }
if ($externalPort -ne $null) { # get the port's VlanEndpoint $vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$externalPort} where AssocClass=Msvm_BindsTo" # get the vlan's setting object $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData"
# get the current trunk list and add the new vlan id into it. # one thing additionally we could do here, which the Hyper-V UI does is clean up # the old AccessVlan id of the port from the trunk list. But, we can't just remove the # old AccessVlan from the trunklist, because another port might be using the same vlan id. # We would have to enumerate all of the ports on the switch and build a new trunk list. # For the purposes of this script, don't worry about cleaning up old vlan id' from the trunk list. $trunkList = $vlanSetting.TrunkedVLANList if ($trunkList -notcontains $vlanid) { $trunkList = $trunkList + $vlanId $vlanSetting.TrunkedVLANList = $trunkList $result = $vlanSetting.Put() } # set the vlan mode into trunking mode. if ($vlan.DesiredEndpointMode -ne 5) { $vlan.DesiredEndpointMode = 5 $result = $vlan.Put() } }
# Now that we have finished with the trunklist, set the vlan id of the original connected port.
$vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_BindsTo" $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" $vlanSetting.AccessVlan = $vlanId $result = $vlanSetting.Put()
################################################################################ # # .SYNOPSIS # # Sets the vlan id of the first connected NIC on a virtual machine. # # # .DESCRIPTION # # Finds the first connected NIC of a virtual machine and sets up its VLAN # settings in the same manner as the Hyper-V UI. First it checks to see if # the NIC is connected to an external network, and if so it adds the VLAN id # to the trunking list, and sets the endpoint mode to trunking. This makes sure # that traffic with that VLAN id from the external network goes through the switch. # Next it sets up the Access VLAN of the virtual machine's NIC. # # .PARAMETER VmName # # The name of the virtual machine to modify. We will modify the first connected # NIC we find on this virtual machine. # # .PARAMETER VlanId # # The vlan id to set. # # .PARAMETER Computer # # The host computer where $vmname resides. # # .EXAMPLE # # C:\PS> mount-vlan.ps1 foo 512 # # ################################################################################
For more info on how to use PS cmdlets see: http://www.microsoft.com/technet/scriptcenter/topics/msh/cmdlets/index.mspx
For all 35 sample Hyper-V PS1 scripts in a zipfile, go to: Hyper-V PowerShell Example Scripts.zip-download
I recently had the opportunity to chat with Rodney Fournier, Senior PFE at Microsoft, about building and running a testing infrastructure with our virtualization and management products, including Hyper-V R2, SCVMM, Operations Manager, Configurations Manager, PowerShell, well…Rod works with the whole stack basically. You kind of have to work with the whole stack to get a good pre-production test, don’t you?
Click on the image to hear the 10 minute audio podcast.
Some useful links if you are in the same situation:
Jamesone’s excellent PowerShell Management Library for Hyper-V includes a Hyper-V cmdlet documentation PDF file that helps you chunk all the things you can do with Hyper-V using PS, for example, the following list of cmdlets parsed by function:
Admin functions not specific to Hyper-V
Conversion functions
Functions for Hyper-V Servers
Functions for checking WMI jobs created through Hyper-v
Virtual Machine
VM Memory
VM Processors
VM Disk Controllers
Hard disk and DVD drive objects
Hardisk and DVD disk Image object
Virtual Hard disk image files
VM Floppy Disk
Resource Allocation Settings data objects
Serial Port Objects
Ethernet Cards
Ethernet Switches
Key value Pairs
Snapshots
Did I mention the Management Library is free-as-in-beer?
Want to know more about James? See http://blogs.technet.com/tonyso/archive/2009/06/24/a-day-in-the-life-of-an-it-pro-evangelist-james-o-neill.aspx
For more Hyper-V scripts, see the Official Scripting Guys Forum.
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for creating a VM:
# Create a VM param( [string]$vmName = $(throw "Must supply a virtual machine name") ) # Get a new instance of Msvm_VirtualSystemGlobalSettingData $vsgsdClass = [wmiclass]"root\virtualization:Msvm_VirtualSystemGlobalSettingData" $vsgsd = $vsgsdClass.CreateInstance() $vsgsd.ElementName = $vmName # Get the managment service and define the system from the embedded instance $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $result = $vmms.DefineVirtualSystem($vsgsd.GetText(1)) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Create a VM
param( [string]$vmName = $(throw "Must supply a virtual machine name") )
# Get a new instance of Msvm_VirtualSystemGlobalSettingData $vsgsdClass = [wmiclass]"root\virtualization:Msvm_VirtualSystemGlobalSettingData" $vsgsd = $vsgsdClass.CreateInstance() $vsgsd.ElementName = $vmName
# Get the managment service and define the system from the embedded instance $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
$result = $vmms.DefineVirtualSystem($vsgsd.GetText(1))
if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for modifying hte VLAN settings on your VMs:
# Modify VLAN setting for VM param( $vmName = $(throw "Must supply a virtual machine name"), $vlanId = $(throw "Must supply vlan id"), $computer = "." ) $ns = "root\virtualization" # get the computer system $vm = gwmi -namespace $ns -computerName $computer Msvm_ComputerSystem -filter "ElementName = '$vmName'" if ($vm -eq $null) { "No virtual machine with name '$vmName'" return } # get its related vssd $vssd = gwmi -namespace $ns -computerName $computer -query "associators of {$vm} where AssocClass=Msvm_SettingsDefineState" # get its synthetic and enumlated NICs $nics = gwmi -namespace $ns -computerName $computer -query "associators of {$vssd} where AssocClass=Msvm_VirtualSystemSettingDataComponent" | where {$_.ResourceType -eq 10 -and ($_.ResourceSubType -eq 'Microsoft Synthetic Ethernet Port' -or $_.ResourceSubType -eq 'Microsoft Emulated Ethernet Port')} if ($nics -eq $null) { # vm does not have any NICs. "Virtual machine '$vmName' does not have any NICs" return } # Find the first nic which has a connection $nic = $nics | where {$_.Connection -ne $null} | select-object -first 1 if ($nic -eq $null) { "None of the NICs on virtual machine '$vmName' are connected" return } # get the connected switch port. $connectedPort = [wmi]$nic.Connection[0] # need to set the external trunk list of the external port on this same switch # to include this vlan id, else traffic won't get through. # first get its switch. $switch = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_HostedAccessPoint" # enumerate all of its ports. First the port which is externally connected. $ports = gwmi -namespace $ns -computerName $computer -query "associators of {$switch} where ResultClass=Msvm_SwitchPort" $externalPort = $null foreach ($p in $ports) { $switchLanEndpoint = gwmi -namespace $ns -computerName $computer -query "associators of {$p} where ResultClass=Msvm_SwitchLanEndpoint" if ($switchLanEndpoint -ne $null) { $externalEthernetPort = gwmi -namespace $ns -computerName $computer -query "associators of {$switchLanEndpoint} where resultclass=Msvm_ExternalEthernetPort" if ($externalEthernetPort -ne $null) { # we got it, we found the switch port connected to the external # port, save it and break out of the loop. $externalPort = $p break } } } if ($externalPort -ne $null) { # get the port's VlanEndpoint $vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$externalPort} where AssocClass=Msvm_BindsTo" # get the vlan's setting object $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" # get the current trunk list and add the new vlan id into it. # one thing additionally we could do here, which the Hyper-V UI does is clean up # the old AccessVlan id of the port from the trunk list. But, we can't just remove the # old AccessVlan from the trunklist, because another port might be using the same vlan id. # We would have to enumerate all of the ports on the switch and build a new trunk list. # For the purposes of this script, don't worry about cleaning up old vlan id' from the trunk list. $trunkList = $vlanSetting.TrunkedVLANList if ($trunkList -notcontains $vlanid) { $trunkList = $trunkList + $vlanId $vlanSetting.TrunkedVLANList = $trunkList $result = $vlanSetting.Put() } # set the vlan mode into trunking mode. if ($vlan.DesiredEndpointMode -ne 5) { $vlan.DesiredEndpointMode = 5 $result = $vlan.Put() } } # Now that we have finished with the trunklist, set the vlan id of the original connected port. $vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_BindsTo" $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" $vlanSetting.AccessVlan = $vlanId $vlanSetting.Put()
# Modify VLAN setting for VM
# enumerate all of its ports. First the port which is externally connected. $ports = gwmi -namespace $ns -computerName $computer -query "associators of {$switch} where ResultClass=Msvm_SwitchPort" $externalPort = $null
$vlan = gwmi -namespace $ns -computerName $computer -query "associators of {$connectedPort} where AssocClass=Msvm_BindsTo" $vlanSetting = gwmi -namespace $ns -computerName $computer -query "associators of {$vlan} where AssocClass=Msvm_NetworkElementSettingData" $vlanSetting.AccessVlan = $vlanId $vlanSetting.Put()
In this 5 minute video Windows Server Technical Writer Felipe Ayora demonstrates how to change the BIOS settings on your computer to make the hypervisor run. NOTE: remember to completely power off your computer after making the changes to the BIOS. Some computers will not take the changes unless they are powered off and back on.
This error (BIOS misconfig) stalls many users.
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for shutting down your VMs:
# Shutdown a Virtual Machine (requires Integration Components) param( [string]$vmName = $(throw "Must specify virtual machine name") ) # Get the VM by name and request state to change to Enabled $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'" # Get the associated Shutdown Component $shutdown = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_ShutdownComponent" # Initiate a forced shutdown with simple reason string, return resulting error code return $shutdown.InitiateShutdown($true,"System Maintenance")
# Shutdown a Virtual Machine (requires Integration Components)
param( [string]$vmName = $(throw "Must specify virtual machine name") )
# Get the VM by name and request state to change to Enabled $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'"
# Get the associated Shutdown Component $shutdown = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_ShutdownComponent"
# Initiate a forced shutdown with simple reason string, return resulting error code return $shutdown.InitiateShutdown($true,"System Maintenance")
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for deleting a VM snapshot:
However BEFORE you go deleting snapshots, please read the Hyper-V Snapshot FAQ, and have a look at the Ben Armstrong Snapshot FAQ Video.
# Delete Virtual System Snapshot param( [string]$vmName = $(throw "Must specify virtual machine name"), [string]$vmSnapName = $(throw "Must specify snapshot name") ) # Get the virtual machine by name $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'" # Get the setting data for the snapshot by name $snapshot = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemSettingData ` -filter "SystemName='$($vm.Name)' and SettingType = 5 and ElementName = '$vmSnapName'” if($snapshot -eq $null -or $snapshot -is [array]){ throw "Unable to find single snapshot with name `"$vmSnapName`"" } # Get the management service and apply the snapshot $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $result = $vmms.RemoveVirtualSystemSnapshot($snapshot) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Delete Virtual System Snapshot
param( [string]$vmName = $(throw "Must specify virtual machine name"), [string]$vmSnapName = $(throw "Must specify snapshot name") )
# Get the virtual machine by name $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'"
# Get the setting data for the snapshot by name $snapshot = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemSettingData ` -filter "SystemName='$($vm.Name)' and SettingType = 5 and ElementName = '$vmSnapName'” if($snapshot -eq $null -or $snapshot -is [array]){ throw "Unable to find single snapshot with name `"$vmSnapName`"" } # Get the management service and apply the snapshot $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
$result = $vmms.RemoveVirtualSystemSnapshot($snapshot)
For all 35 sample Hyper-V PS1 scripts in a zipfile, go to: Hyper-V%20PowerShell%20Example%20Scripts.zip-download
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for compacting your VHDs:
# Compact a VHD param( [string]$vhdPath = $(throw "Must specify complete VHD path, including extension") ) #obtain the Msvm_ImageManagementService class $ImageMgtService = get-wmiobject Msvm_ImageManagementService -namespace root\virtualization # Compact a Dynamic VHD $result = $ImageMgtService.CompactVirtualHardDisk($VHD_Path.ToString()) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Compact a VHD
param( [string]$vhdPath = $(throw "Must specify complete VHD path, including extension") )
#obtain the Msvm_ImageManagementService class $ImageMgtService = get-wmiobject Msvm_ImageManagementService -namespace root\virtualization
# Compact a Dynamic VHD $result = $ImageMgtService.CompactVirtualHardDisk($VHD_Path.ToString())
# Expand a VHD param( [string]$vhdPath = $(throw "Must specify full path for VHD"), [string]$vhdSize = $(throw "Must specify expansion to add to VHD (in MB)") ) # Size in bytes $MB = [System.UInt64] $vhdSize*1024*1024 #obtain the Msvm_ImageManagementService class $ImageMgtService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization" # Create the Dynamic VHD $result = $ImageMgtService.ExpandVirtualHardDisk($vhdPath,$MB) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Expand a VHD
param( [string]$vhdPath = $(throw "Must specify full path for VHD"), [string]$vhdSize = $(throw "Must specify expansion to add to VHD (in MB)") )
# Size in bytes $MB = [System.UInt64] $vhdSize*1024*1024
#obtain the Msvm_ImageManagementService class $ImageMgtService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization"
# Create the Dynamic VHD $result = $ImageMgtService.ExpandVirtualHardDisk($vhdPath,$MB)
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for copying a VM:
################################################################################ # # Copyright ©2008 Microsoft Corporation. All rights reserved. # # File: Copy-Vm.ps1 # # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF # ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A # PARTICULAR PURPOSE. # # Copyright ©2008 Microsoft Corporation. All rights reserved. # ################################################################################ param ( [string]$VmName = $(throw "VmName required"), [string]$Path = $(throw "Path required"), [string]$NewName = "" ) # # Constants # $SilentlyContinue = [System.Management.Automation.ActionPreference]0 # # Utility functions # # Processes the (possibly asynchronous) result of a method call on one # of Hyper-V's service objects, and return the resulting object, if any. function ProcessResult { param ( [System.Management.ManagementBaseObject]$Result, [ScriptBlock]$ExtractScript = $null, [string]$ResultClass = "" ) $RetObj = $null if ($Result.ReturnValue -eq 0) { if ($ExtractScript -ne $null) { $RetObj = [WMI] ($Result | Select-Object -inputObject $ExtractScript) } } else { if ($Result.ReturnValue -ne 4096) { throw $Result.ReturnValue } $Job = [WMI]$Result.Job while ($Job.JobState -eq 4) { Write-Progress $Job.Caption "% Complete" -PercentComplete $Job.PercentComplete Start-Sleep 1 $Job.PSBase.Get() } if ($Job.JobState -ne 7) { throw $Job.ErrorDescription } Write-Progress $Job.Caption "Completed" -Completed $true if ($ResultClass -ne "") { $Query = "Associators of {$Job} Where ResultClass=$ResultClass AssocClass=Msvm_AffectedJobElement" $RetObj = Get-WmiObject -Namespace root\virtualization -Query $Query } } if ($RetObj -ne $null) { $RetObj } } # # Main script body # #Stop script exection on errors Set-Variable $ErrorActionPreference Stop # If no target name was specified, generate a generic one if ($NewName -eq "") { $NewName = "Copy of " + $VmName } # If we are going to display progress bars, clear the console window so that # we can see the progress bars more clearly, if ($ProgressPreference -ne $SilentlyContinue) { Clear-Host Write-Host "Copying `"$VmName`" to `"$NewName`"..." } # Get the service object $VmSvc = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService # Find the virtual machine to copy. $Query = @" Select * From Msvm_ComputerSystem Where ElementName='$VmName' Or Name='$VmName' "@ $SourceVm = Get-WmiObject -Namespace root\virtualization -Query $Query # Since the virtual machine name is not unique, we need to check for # multiples. If there is more than one, we'll return an error. $SourceCount = [int]0 if ($SourceVm -ne $null) { $SourceCount = [int]($SourceVm | Measure-Object).Count } if ($SourceCount -eq 0) { throw "Virtual machine `"$VmName`" not found." return } elseif ($SourceCount -ne 1) { if ($ProgressPreference -ne $SilentlyContinue) { Write-Host "The name `"$VmName`" has been given to multiple virtual machines. Specify the source virtual machine by ID instead. The IDs for virtual machines with this name are listed below." $SourceVm | ` Select-Object @{Name="ID";Expression={$_.Name}},@{Name="Name";Expression={$_.ElementName}} | ` Format-Table -AutoSize } throw "The name `"$VmName`" has been given to multiple virtual machines." } # Export the virtual machine $Result = $VmSvc.ExportVirtualSystem($SourceVm, $true, $Path) $Temp = ProcessResult $Result # Rename the export directory $CopyPath = (Join-Path $Path $VmName | Rename-Item -NewName $("Copy of " + $VmName) -PassThru) # Import the virtual machine $Result = $VmSvc.ImportVirtualSystem($CopyPath, $true) $CopyVm = ProcessResult $Result {throw "Unexpected error."} Msvm_ComputerSystem # Rename the copy virtual machine to "Copy of $VmName" $Query = @" Associators of {$CopyVm} Where ResultClass=Msvm_VirtualSystemSettingData AssocClass=Msvm_SettingsDefineState "@ $CopyVssd = Get-WmiObject -Namespace root\virtualization -Query $Query $CopyVssd.ElementName = "Copy of " + $CopyVssd.ElementName $Result = $VmSvc.ModifyVirtualSystem($CopyVm, $CopyVssd.PSBase.GetText(1)) $Temp = ProcessResult $Result {$_.ModifiedSettingData} Msvm_VirtualSystemSettingData # Update and return the copied virtual machine object $CopyVm.PSBase.Get() $CopyVm
################################################################################ # # Copyright ©2008 Microsoft Corporation. All rights reserved. # # File: Copy-Vm.ps1 # # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF # ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A # PARTICULAR PURPOSE. # # Copyright ©2008 Microsoft Corporation. All rights reserved. # ################################################################################
param ( [string]$VmName = $(throw "VmName required"), [string]$Path = $(throw "Path required"), [string]$NewName = "" )
# # Constants # $SilentlyContinue = [System.Management.Automation.ActionPreference]0
# # Utility functions #
# Processes the (possibly asynchronous) result of a method call on one # of Hyper-V's service objects, and return the resulting object, if any. function ProcessResult { param ( [System.Management.ManagementBaseObject]$Result, [ScriptBlock]$ExtractScript = $null, [string]$ResultClass = "" )
$RetObj = $null
if ($Result.ReturnValue -eq 0) { if ($ExtractScript -ne $null) { $RetObj = [WMI] ($Result | Select-Object -inputObject $ExtractScript) } } else { if ($Result.ReturnValue -ne 4096) { throw $Result.ReturnValue } $Job = [WMI]$Result.Job while ($Job.JobState -eq 4) { Write-Progress $Job.Caption "% Complete" -PercentComplete $Job.PercentComplete Start-Sleep 1 $Job.PSBase.Get() }
if ($Job.JobState -ne 7) { throw $Job.ErrorDescription }
Write-Progress $Job.Caption "Completed" -Completed $true
if ($ResultClass -ne "") { $Query = "Associators of {$Job} Where ResultClass=$ResultClass AssocClass=Msvm_AffectedJobElement" $RetObj = Get-WmiObject -Namespace root\virtualization -Query $Query } }
if ($RetObj -ne $null) { $RetObj } }
# # Main script body #
#Stop script exection on errors Set-Variable $ErrorActionPreference Stop
# If no target name was specified, generate a generic one if ($NewName -eq "") { $NewName = "Copy of " + $VmName }
# If we are going to display progress bars, clear the console window so that # we can see the progress bars more clearly, if ($ProgressPreference -ne $SilentlyContinue) { Clear-Host Write-Host "Copying `"$VmName`" to `"$NewName`"..." }
# Get the service object $VmSvc = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService
# Find the virtual machine to copy. $Query = @" Select * From Msvm_ComputerSystem Where ElementName='$VmName' Or Name='$VmName' "@
$SourceVm = Get-WmiObject -Namespace root\virtualization -Query $Query
# Since the virtual machine name is not unique, we need to check for # multiples. If there is more than one, we'll return an error. $SourceCount = [int]0 if ($SourceVm -ne $null) { $SourceCount = [int]($SourceVm | Measure-Object).Count }
if ($SourceCount -eq 0) { throw "Virtual machine `"$VmName`" not found." return } elseif ($SourceCount -ne 1) { if ($ProgressPreference -ne $SilentlyContinue) { Write-Host "The name `"$VmName`" has been given to multiple virtual machines. Specify the source virtual machine by ID instead. The IDs for virtual machines with this name are listed below." $SourceVm | ` Select-Object @{Name="ID";Expression={$_.Name}},@{Name="Name";Expression={$_.ElementName}} | ` Format-Table -AutoSize } throw "The name `"$VmName`" has been given to multiple virtual machines." }
# Export the virtual machine $Result = $VmSvc.ExportVirtualSystem($SourceVm, $true, $Path) $Temp = ProcessResult $Result
# Rename the export directory $CopyPath = (Join-Path $Path $VmName | Rename-Item -NewName $("Copy of " + $VmName) -PassThru)
# Import the virtual machine $Result = $VmSvc.ImportVirtualSystem($CopyPath, $true) $CopyVm = ProcessResult $Result {throw "Unexpected error."} Msvm_ComputerSystem
# Rename the copy virtual machine to "Copy of $VmName" $Query = @" Associators of {$CopyVm} Where ResultClass=Msvm_VirtualSystemSettingData AssocClass=Msvm_SettingsDefineState "@
$CopyVssd = Get-WmiObject -Namespace root\virtualization -Query $Query $CopyVssd.ElementName = "Copy of " + $CopyVssd.ElementName
$Result = $VmSvc.ModifyVirtualSystem($CopyVm, $CopyVssd.PSBase.GetText(1)) $Temp = ProcessResult $Result {$_.ModifiedSettingData} Msvm_VirtualSystemSettingData
# Update and return the copied virtual machine object $CopyVm.PSBase.Get() $CopyVm
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for adding a virtual NIC to a VM:
# Add a NIC (synthetic ethernet port) to a virtual machine param( [string]$vmName = $(throw "Must specify virtual machine name"), [string]$ethPortName = "New Network Adapter" ) $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'" # Allocate the new ethernet port $allocationCapabilities = gwmi -namespace root\virtualization Msvm_AllocationCapabilities ` -filter "ResourceType = 10 AND ResourceSubtype = 'Microsoft Synthetic Ethernet Port'" $allocationPath = $allocationCapabilities.__PATH.replace("\","\\") $default = gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities ` -filter "ValueRange = 0 AND GroupComponent = '$allocationPath'" $synthEth = [wmi]$default.PartComponent $synthEth.ElementName = $ethPortName $newGuid = [System.Guid]::NewGuid().Guid $synthEth.VirtualSystemIdentifiers = @("{$newGuid}") # Attach the new NIC (ethernet port) to the virtual machine $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $result = $vmms.AddVirtualSystemResources($vm,@($synthEth.GetText(1))) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Add a NIC (synthetic ethernet port) to a virtual machine
param( [string]$vmName = $(throw "Must specify virtual machine name"), [string]$ethPortName = "New Network Adapter" )
$vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'"
# Allocate the new ethernet port $allocationCapabilities = gwmi -namespace root\virtualization Msvm_AllocationCapabilities ` -filter "ResourceType = 10 AND ResourceSubtype = 'Microsoft Synthetic Ethernet Port'" $allocationPath = $allocationCapabilities.__PATH.replace("\","\\") $default = gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities ` -filter "ValueRange = 0 AND GroupComponent = '$allocationPath'"
$synthEth = [wmi]$default.PartComponent $synthEth.ElementName = $ethPortName $newGuid = [System.Guid]::NewGuid().Guid $synthEth.VirtualSystemIdentifiers = @("{$newGuid}")
# Attach the new NIC (ethernet port) to the virtual machine $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
$result = $vmms.AddVirtualSystemResources($vm,@($synthEth.GetText(1)))
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for creating a virtual switch:
# Create a Virtual Switch param( [string]$vsName = $(throw "Must specify virtual switch name") ) # Get the Virtual Switch Management Service $vsms = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService # Use CreateSwitch method to specify the name, friendly name, learnable addresses, # and authorization scope of the created switch (use "" for the root scope) $result = $vsms.CreateSwitch($vsName,$vsName,2048,"") if($result.ReturnValue -ne 0){ throw "Error: $($result.ReturnValue)" } return ([wmi]$result.CreatedVirtualSwitch)
# Create a Virtual Switch
param( [string]$vsName = $(throw "Must specify virtual switch name") )
# Get the Virtual Switch Management Service $vsms = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService
# Use CreateSwitch method to specify the name, friendly name, learnable addresses, # and authorization scope of the created switch (use "" for the root scope) $result = $vsms.CreateSwitch($vsName,$vsName,2048,"") if($result.ReturnValue -ne 0){ throw "Error: $($result.ReturnValue)" } return ([wmi]$result.CreatedVirtualSwitch)
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for checking in the hypervisor is running on a Hyper-V server (host/parent partition):
# Check if Hypervisor is running $hypervisor = gwmi –ErrorAction SilentlyContinue Win32_PerfRawData_HvStats_HyperVHypervisor return $hypervisor.Partitions -ge 1
# Check if Hypervisor is running
$hypervisor = gwmi –ErrorAction SilentlyContinue Win32_PerfRawData_HvStats_HyperVHypervisor return $hypervisor.Partitions -ge 1
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for adding a pass-through disk to a VM:
# Add a pass-through disk to a VM
param( [string]$vmName = $(throw "Must specify virtual machine name"), [int]$ideNum = $(throw "Must specify IDE location to attach the pass-through disk"), [int]$lunNum = $(throw "Must specify LUN location to attach the pass-through disk") ) $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'" # Disks available for pass-through are associated to the physical disk resource pool # (for this example, it is assumed there is only one disk available) $diskPool = gwmi -namespace root\virtualization Msvm_ResourcePool ` -filter "ResourceType = 22 AND ResourceSubtype = 'Microsoft Physical Disk Drive'" $disk = gwmi -namespace root\virtualization ` -query "Associators of {$diskPool} where ResultClass=Msvm_DiskDrive" # Get the virtual machine's setting data $vssd = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_VirtualSystemSettingData" |` where{$_.SettingType -eq 3} # Get IDE Controller $ide = gwmi -namespace root\virtualization ` -query "Associators of {$vssd} where ResultClass=Msvm_ResourceAllocationSettingData" |` where{$_.ResourceType -eq 5 -and $_.Address -eq $ideNum} # Create a new Hard Disk Resource Allocation object for a disk at specified lun, # and connect it to the server disk $allocationCapabilities = gwmi -namespace root\virtualization Msvm_AllocationCapabilities ` -filter "ResourceType = 22 AND ResourceSubtype = 'Microsoft Physical Disk Drive'" $allocationPath = $allocationCapabilities.__PATH.replace("\","\\") $default = gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities ` -filter "ValueRange = 0 AND GroupComponent = '$allocationPath'" $hardDisk = [wmi]$default.PartComponent $hardDisk.Address = $lunNum $hardDisk.HostResource = @($disk.__PATH) $hardDisk.Parent = $ide.__PATH # Attach the new Hard Disk to the virtual machine $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $result = $vmms.AddVirtualSystemResources($vm,@($hardDisk.GetText(1))) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
param( [string]$vmName = $(throw "Must specify virtual machine name"), [int]$ideNum = $(throw "Must specify IDE location to attach the pass-through disk"), [int]$lunNum = $(throw "Must specify LUN location to attach the pass-through disk") )
# Disks available for pass-through are associated to the physical disk resource pool # (for this example, it is assumed there is only one disk available) $diskPool = gwmi -namespace root\virtualization Msvm_ResourcePool ` -filter "ResourceType = 22 AND ResourceSubtype = 'Microsoft Physical Disk Drive'" $disk = gwmi -namespace root\virtualization ` -query "Associators of {$diskPool} where ResultClass=Msvm_DiskDrive"
# Get the virtual machine's setting data $vssd = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_VirtualSystemSettingData" |` where{$_.SettingType -eq 3}
# Get IDE Controller $ide = gwmi -namespace root\virtualization ` -query "Associators of {$vssd} where ResultClass=Msvm_ResourceAllocationSettingData" |` where{$_.ResourceType -eq 5 -and $_.Address -eq $ideNum}
# Create a new Hard Disk Resource Allocation object for a disk at specified lun, # and connect it to the server disk $allocationCapabilities = gwmi -namespace root\virtualization Msvm_AllocationCapabilities ` -filter "ResourceType = 22 AND ResourceSubtype = 'Microsoft Physical Disk Drive'" $allocationPath = $allocationCapabilities.__PATH.replace("\","\\") $default = gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities ` -filter "ValueRange = 0 AND GroupComponent = '$allocationPath'"
$hardDisk = [wmi]$default.PartComponent $hardDisk.Address = $lunNum $hardDisk.HostResource = @($disk.__PATH) $hardDisk.Parent = $ide.__PATH
# Attach the new Hard Disk to the virtual machine $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
$result = $vmms.AddVirtualSystemResources($vm,@($hardDisk.GetText(1)))
Useful? Want to see more sample scripts? Leave feedback.
Hyper-V R2 users have been waiting for the remote tools, released today as RSAT Tools for Windows 7 at: http://www.microsoft.com/downloads/details.aspx?FamilyID=7d2f6ad7-656b-4313-a005-4e344e43997d&displaylang=en
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for converting your VHDs:
# Convert a VHD param( [string]$vhdPath = $(throw "Must specify full VHD path, including extension"), [string]$destPath = $(throw "Must specify full path of destination VHD, including extension"), [switch]$Fixed, [switch]$Dynamic ) #obtain the Msvm_ImageManagementService class $ImageMgtService = get-wmiobject Msvm_ImageManagementService -namespace root\virtualization # Convert the VHD if($Dynamic){ $result = $ImageMgtService.ConvertVirtualHardDisk($vhdPath,$destPath,3) }else if($Fixed){ $result = $ImageMgtService.ConvertVirtualHardDisk($vhdPath,$destPath,2) }else{ throw "Must specify type of vhd to covert to with either the -Fixed or -Dynamic flag" } if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Convert a VHD
param( [string]$vhdPath = $(throw "Must specify full VHD path, including extension"), [string]$destPath = $(throw "Must specify full path of destination VHD, including extension"), [switch]$Fixed, [switch]$Dynamic )
# Convert the VHD if($Dynamic){ $result = $ImageMgtService.ConvertVirtualHardDisk($vhdPath,$destPath,3) }else if($Fixed){ $result = $ImageMgtService.ConvertVirtualHardDisk($vhdPath,$destPath,2) }else{ throw "Must specify type of vhd to covert to with either the -Fixed or -Dynamic flag" }
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for checking the integration services/integration components to see if they are current in your VMs:
# Test if the IC version is up to date param( [string]$vmName = $(throw "Must specify virtual machine name") ) $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName='$vmName'" # Get the associated KVP Exchange component $kvp = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_KvpExchangeComponent" # Pull the Guest Intrinsic Exchange Items from XML into a hash $kvpHash = @{} if($kvp.GuestIntrinsicExchangeItems){ ([xml]("<xml>"+$kvp.GuestInstrinsicExchangeItems+"</xml>")).xml.instance | ` foreach{$kvphash.add($_.property[4].value,$_.property[1].value)} } # Save the guest's version $icVersionGuest = $kvpHash.IntegrationServicesVersion # Save the host's version $icVersionHost = (ls 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestInstaller').` GetValue("Microsoft-Hyper-V-Guest-Installer-Win60-Package") return -not $icVersionGuest -lt $icVersionHost
# Test if the IC version is up to date
# Get the associated KVP Exchange component $kvp = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass=Msvm_KvpExchangeComponent"
# Pull the Guest Intrinsic Exchange Items from XML into a hash $kvpHash = @{} if($kvp.GuestIntrinsicExchangeItems){ ([xml]("<xml>"+$kvp.GuestInstrinsicExchangeItems+"</xml>")).xml.instance | ` foreach{$kvphash.add($_.property[4].value,$_.property[1].value)} }
# Save the guest's version $icVersionGuest = $kvpHash.IntegrationServicesVersion
# Save the host's version $icVersionHost = (ls 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestInstaller').` GetValue("Microsoft-Hyper-V-Guest-Installer-Win60-Package")
return -not $icVersionGuest -lt $icVersionHost
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for deleting a VM:
# Delete a VM param( [string]$VMName = $(throw "Must specify name of virtual machine to delete") ) #Obtain the VM object that we are going to destroy $query = "SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" + $VMName + "'" $VM = gwmi -query $query -namespace "root\virtualization" #obtain the VirtualSystemManagementService class $VSMgtService = get-wmiobject -class "Msvm_VirtualSystemManagementService" -namespace "root\virtualization" #Destroy the virtual computer system. $result = $VSMgtService.DestroyVirtualSystem($VM) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Delete a VM
param( [string]$VMName = $(throw "Must specify name of virtual machine to delete") ) #Obtain the VM object that we are going to destroy $query = "SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" + $VMName + "'" $VM = gwmi -query $query -namespace "root\virtualization" #obtain the VirtualSystemManagementService class $VSMgtService = get-wmiobject -class "Msvm_VirtualSystemManagementService" -namespace "root\virtualization" #Destroy the virtual computer system. $result = $VSMgtService.DestroyVirtualSystem($VM)
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for getting a mapping your virtual network settings:
# Navigate Network Topology to determine Virtual Switch type # ie: Internal, External, External-Shared, or Private # Prompt for the Hyper-V Server to use $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)" write-host # Get the list of all available network switches $query = "Select * From Msvm_VirtualSwitch" $VirtualSwitches = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # Iterate over each virtual switch foreach ($VirtualSwitch in $VirtualSwitches) { # Initialize variables for counting number of internal and external ports per switch $InternalPortCount = 0 $ExternalPortCount = 0 # Get the Switch ports on the virtual switch $query = "Associators of {$VirtualSwitch} where ResultClass=CIM_SwitchPort" $switchPorts = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # A VM only switch with no VMs connected will return null if ($switchPorts -ne $null) { # Iterate over each switch port foreach ($switchPort in @($switchPorts)) { # Get the Msvm_SwitchLANEndpoint associated with the switch port $query = "Associators of {$switchPort} where ResultClass=Msvm_SwitchLANEndpoint" $SwitchLANEndpoint = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # If there is no active connection on the switch port the results will be null if ($SwitchLANEndpoint -ne $null) { # Get the CIM_EthernetPort for the Msvm_SwitchLANEndpoint $query = "Associators of {$SwitchLANEndpoint} where ResultClass=CIM_EthernetPort" $EthernetPort = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # Check to see if the associated Ethernet port is an internal port if ($EthernetPort.__CLASS -eq "Msvm_InternalEthernetPort") { $InternalPortCount = $InternalPortCount + 1 } # Check to see if the associated Ethernet port is an external port if ($EthernetPort.__CLASS -eq "Msvm_ExternalEthernetPort") { $ExternalPortCount = $ExternalPortCount + 1 } } } } switch ($InternalPortCount) { 0 { switch ($ExternalPortCount) { 0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is a virtual machine only virtual network."} 1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external-only virtual network."} default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } } 1 { switch ($ExternalPortCount) { 0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an internal virtual network."} 1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external virtual network."} default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } } default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } write-host $output }
# Navigate Network Topology to determine Virtual Switch type # ie: Internal, External, External-Shared, or Private
# Prompt for the Hyper-V Server to use $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)" write-host # Get the list of all available network switches $query = "Select * From Msvm_VirtualSwitch" $VirtualSwitches = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # Iterate over each virtual switch foreach ($VirtualSwitch in $VirtualSwitches) { # Initialize variables for counting number of internal and external ports per switch $InternalPortCount = 0 $ExternalPortCount = 0 # Get the Switch ports on the virtual switch $query = "Associators of {$VirtualSwitch} where ResultClass=CIM_SwitchPort" $switchPorts = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # A VM only switch with no VMs connected will return null if ($switchPorts -ne $null) { # Iterate over each switch port foreach ($switchPort in @($switchPorts)) { # Get the Msvm_SwitchLANEndpoint associated with the switch port $query = "Associators of {$switchPort} where ResultClass=Msvm_SwitchLANEndpoint" $SwitchLANEndpoint = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # If there is no active connection on the switch port the results will be null if ($SwitchLANEndpoint -ne $null) { # Get the CIM_EthernetPort for the Msvm_SwitchLANEndpoint $query = "Associators of {$SwitchLANEndpoint} where ResultClass=CIM_EthernetPort" $EthernetPort = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer # Check to see if the associated Ethernet port is an internal port if ($EthernetPort.__CLASS -eq "Msvm_InternalEthernetPort") { $InternalPortCount = $InternalPortCount + 1 } # Check to see if the associated Ethernet port is an external port if ($EthernetPort.__CLASS -eq "Msvm_ExternalEthernetPort") { $ExternalPortCount = $ExternalPortCount + 1 } } } } switch ($InternalPortCount) { 0 { switch ($ExternalPortCount) { 0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is a virtual machine only virtual network."} 1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external-only virtual network."} default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } } 1 { switch ($ExternalPortCount) { 0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an internal virtual network."} 1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external virtual network."} default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } } default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."} } write-host $output }
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for connecting a virtual switch to a VM:
# Connect Virtual Switch to VM param( [string]$vsName = $(throw "Must specify virtual switch name"), [string]$vmName = $(throw "Must specify virtual machine name"), [string]$switchPortName = [guid]::NewGuid().guid ) $vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName = '$vmName'" # Find the NIC from the virtual system setting data (assuming there is only one) $vssd = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass = Msvm_VirtualSystemSettingData" |` where{$_.SettingType -eq 3} $synthEth = gwmi -namespace root\virtualization ` -query "Associators of {$vssd} where ResultClass = Msvm_SyntheticEthernetPortSettingData" # Get the virtual switch (assuming only one in the system) $vSwitch = gwmi -namespace root\virtualization Msvm_VirtualSwitch -filter "ElementName = '$vsName'" # Get the virtual switch and virtual system services $vsms = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService # Use the switch service to create a new switch port $result = $vsms.CreateSwitchPort($vSwitch, $switchPortName, "VM Switch Port", "") if($result.ReturnValue -ne 0){ return $result.ReturnValue } $switchPort = [wmi]$result.CreatedSwitchPort # Set the NIC (synthetic ethernet port) connection to the switch port, and # then modify the virtual system $synthEth.Connection = @($switchPort.__PATH) $result = $vmms.ModifyVirtualSystemResources($vm,@($synthEth.GetText(1))) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
# Connect Virtual Switch to VM
param( [string]$vsName = $(throw "Must specify virtual switch name"), [string]$vmName = $(throw "Must specify virtual machine name"), [string]$switchPortName = [guid]::NewGuid().guid )
$vm = gwmi -namespace root\virtualization Msvm_ComputerSystem -filter "ElementName = '$vmName'"
# Find the NIC from the virtual system setting data (assuming there is only one) $vssd = gwmi -namespace root\virtualization ` -query "Associators of {$vm} where ResultClass = Msvm_VirtualSystemSettingData" |` where{$_.SettingType -eq 3} $synthEth = gwmi -namespace root\virtualization ` -query "Associators of {$vssd} where ResultClass = Msvm_SyntheticEthernetPortSettingData"
# Get the virtual switch (assuming only one in the system) $vSwitch = gwmi -namespace root\virtualization Msvm_VirtualSwitch -filter "ElementName = '$vsName'"
# Get the virtual switch and virtual system services $vsms = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $vmms = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
# Use the switch service to create a new switch port $result = $vsms.CreateSwitchPort($vSwitch, $switchPortName, "VM Switch Port", "") if($result.ReturnValue -ne 0){ return $result.ReturnValue } $switchPort = [wmi]$result.CreatedSwitchPort
# Set the NIC (synthetic ethernet port) connection to the switch port, and # then modify the virtual system $synthEth.Connection = @($switchPort.__PATH) $result = $vmms.ModifyVirtualSystemResources($vm,@($synthEth.GetText(1))) if($result.ReturnValue -eq 4096){ # A Job was started, and can be tracked using its Msvm_Job instance $job = [wmi]$result.Job # Wait for job to finish while($job.jobstate -lt 7){$job.get()} # Return the Job's error code return $job.ErrorCode } # Otherwise, the method completed return $result.ReturnValue
Courtesy of a colleague, here are some handy resources for reading up on how to set up a multi-site cluster:
My teenage daughter never tires of reminding me how often I show my age. The punning title of this blog is no exception.
However, that should not take away from the awesomeness of the Clustering Team Blog post that lists 300+ useful documents, guides, information and utilities.
My favorites of course are on Hyper-V:
I prefer mine with PowerShell:
and a side of tools:
Utility: ClusPrep: Cluster Configuration Validation Wizard (2003)
Utility: Failover Cluster Management Pack for Operations Manager 2007
Utility: File Server Migration Toolkit (FSMT) (2008)
Utility: Microsoft iSCSI Target Software available to the public!
Utility: NLB Management Pack for SCOM 2007 Released
Utility: RSAT - Remote Server Administration Tools (2008)
Utility: RSAT – Remote Server Administration Tools (2008 R2)