Needed to update a spreadsheet for a bunch of servers. I wanted PowerShell to just go look in DNS and try to resolve the name. I didn’t need to get the configured IP from the server directly and I know they are all registered in DNS. I also only wanted the v4 addresses, not v6.
Here is what I used to dump their name and IP in a text file. I then updated the spreadsheet by hand just so I could put human eyes on the list for sanity’s sake.
You’ll need to put the server names in a text file named “servernames.txt” in the same folder as the script.
ipconfig /flushdns
$servernames = Get-Content servernames.txt
foreach ($name in $servernames) {
$ips = [System.Net.Dns]::GetHostAddresses($name) | select-object AddressFamily, IPAddressToString $ip = $ips | ? {$_.AddressFamily -eq "InterNetwork"} $ip = $ip.IPAddressToString
$string = "$name $ip" out-file -filepath ips.txt -inputobject $string -append
$ips = $null $ip = $null
}
Some of this borrowed from - http://blogs.msdn.com/b/powershell/archive/2006/06/26/647318.aspx
Since Hyper-V Server has a reduced footprint, PowerShell is not enabled by default and so it would not make sense to have PowerShell listed by default on the Hyper-V Server Configuration menu. For those who live by PowerShell and love the simplicity of Hyper-V Server, it is “handy as a pocket on a shirt” (credit: Bill Dance) to add a link on the menu to launch a PowerShell console for local administration. I would assume that modifying the console is not supported and hereby make the recommendation that if you are going to be so bold, you do so at your own risk and of course should never impact the supportability of your production servers. That said, check this out!
Two things I’m not going to include because they are well documented elsewhere. Number one, you need to enable PowerShell on your server using ocsetup. You can use oclist to verify whether it is already enabled and/or get the component name. Number two, the console in Hyper-V server is launched by the Run key under HKLM. First the %SystemRoot%\System32\sconfig.cmd file is launched to setup the environment, and from there %SystemRoot%\System32\<language>\sconfig.vbs is called to provide the menu. By default, you will not have access to change either of these files even as a local administrator. This gives you two choices, you could use takeown and icacls to modify permissions and write your changes to the original file names after making backups, or you could save your changes to new file names and modify the registry key to point to the new .cmd file. Your choice.
I’m going to assume you have those taken care of and only show what needs to be changed in the .vbs file. I’m also only demonstrating this as it would occur in a default sconfig.vbs file. If you have made other changes, your Msg# and case # values may vary, so pay attention.
Look for the list of “const” in the beginning of the file and paste to the bottom: const L_Msg186_Text = ") Launch PowerShell"
Find: wscript.echo cstr(13+offset) & L_Msg018_Text ' Exit to cmd line Replace it with these two lines: wscript.echo cstr(13+offset) & L_Msg186_Text ' Launch PowerShell wscript.echo cstr(14+offset) & L_Msg018_Text ' Exit to cmd line
Find: Case "15" if HVS_SKU then 'Exit to command line wscript.quit end if Replace it with these two blocks: Case "15" if HVS_SKU then 'Exit to PowerShell oShell.Run "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe",1 end if Case "16" if HVS_SKU then 'Exit to command line wscript.quit end if
Just in case you didn’t catch it above – you modify any files or registry keys at your own risk! I am certain this would not be supported.
Was just building a UAG test server in our lab and came across an error, which was easily resolved and worth posting for others.
From the splash screen I clicked install only to receive a “system.exception” error. Even if I ran the .msi file directly, I would get a failure.
A search returned one brief mention of a fix. I had a Group Policy applying to the machine that was disabling the Windows Firewall. As soon as I moved the machine account to a test OU where the policy would not apply and rebooted to refresh, the issue went away. Setup now runs without issue.
update 4/17...
This is also mentioned in the troubleshooting section - http://technet.microsoft.com/en-us/library/ff607359.aspx
Further testing proved this may also occur if the Remote Settings for RDP are set to allow.
The most popular question I receive is how to best perform backup/restore of virtual machines running in Hyper-V without taking them offline. The best enterprise approach is Data Protection Manager and you may have already seen some of the extensions to this functionality in 2010. But what if you have just one server at a remote site and would like to run local backups from the host?
Linking up this support KB article for discoverability from the blog.http://support.microsoft.com/kb/958662
Great news from our friends on the other side of the globe.
http://www.itwire.com/it-industry-news/strategy/38018-massive-hyper-v-deployment-at-nsw-education
I just want to make sure I have all my bases covered and have invited everyone I can. If you work in Education and have interest in VDI, this will be worth attending. I’ll be scheduling a follow-up webcast specifically for Education, within the next few months.
Desktop Virtualization Hour
“What’s the easiest way to back up a Hyper-V VM on a stranded server at a remote site with low connectivity?” I get this question a fair amount. John’s blog post below shares an example script you could drop in place to schedule a VSS snap of Hyper-V VMs. This is just one of MANY possible ways to provide back-up in this scenario. I’ve heard of everything from sophisticated enterprise managed approaches to “once per night we shut everything down, robocopy to an external disk, and start back up”. Hey, whatever works for your needs and budget! There is no wrong answer as long as you can restore what you need to restore, within the amount of time you need to restore it.
John Kelbley's real life enterprise interop and administration : DiskShadow / Xcopy BACKUP of Hyper-V
Links to Links to Links are redundant, but in this case I wanted to serve as a bookmark for those in EDU to subscribe to my blog but not the main TechNet feed.
Remote Desktop Protocol 7, the version which shipped with Windows 7 and Windows Server 2008 R2, is available to install on Windows XP (x86) as well as Windows Vista (x86/x64). This will bring the RDP7 functionality to those platforms including new functional enhancements including multiple monitors, bidirectional audio, multimedia enhancements (specific codecs), etc. In my experience during real-world POCs, it is worth the upgrade.
The Start Menu subscription capability available in Windows 7 has not been backported. You will see the new system tray icon but when you click on it there will not be an option to invoke the control panel applet as you would see in Windows 7. One more reason to upgrade (as if you needed another reason).
http://support.microsoft.com/kb/969084/en-us
I came across a cool script today. The intent is to limit the output from ipconfig to only enabled, TCP-bound NICs. Of course this isn't really ipconfig, it is a wmi call for net info but the result is the same. I dig the frame output but decided to see how slim I could get it in pure PS form. Note, Grid-View only works if you have ISE enabled. If not, list or table might be preferred.
Great idea Mathieu, I will certainly find uses for this!
slim version:
gwmi -class "Win32_NetworkAdapterConfiguration" | ? {$_.IpEnabled -Match "True"} | select Description, MACAddress, IPAddress, IPSubnet, DefaultIPGateway, DNSServerSearchOrder | ogv
Something I discovered today in working on a project – it is possible to find out what the VM is named in Hyper-V from within the guest OS. This is only possible if the IC’s are installed. It is a registry key and can be queried in a script.
Example:
$Name = Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters" -Name VirtualMachineName
$Name.VirtualMachineName
This may be different than issuing “hostname” at the command line. That would tell you the OS name for the guest machine. The registry key above is specifically looking for the name of the VM in Hyper-V that represents the machine you are on.
I’m publishing some of the scripts I have written for VMM. These are each based on specific customer asks or conversations that lead me to go sleepless in trying to solve the problems myself. I am very interested in your feedback, especially if you would like to offer a change to improve efficiency or effectiveness.
Seperate VMs
There isn’t a really good way in the Failover Clustering console to prevent 2 VMs from migrating to the same host. For example, let’s say you have 2 VMs that share a SQL cluster, or a NLB web solution, and to provide fault tolerance you would like to ensure that the two VMs are always on separate hardware. If there ever happens to be a physical hardware outage on one of the hosts the service will still be available with no downtime. I set out to solve this problem. My first instinct was to leverage PRO or even just an auto-resolving alert in OpsMgr but I realized that at minimum I was going to need a script that ran on the client to check if 2 VMs were co-located. Well, if a script is going to run, it might as well solve the problem right then and there if we know that in 100% of cases we always want to resolve the issue.
Before we go any further, understand there is another way to solve this. If you view the Properties dialogue of the VM settings in the Failover Cluster Console, you can prevent the application resource from ever coming online on specific nodes. You could easily only allow 1 VM to come online on 2 specific nodes, and the other VM to only come online on 2 other specific nodes. If you have a large cluster, this option would be worth consideration as it would provide no chance of the VMs ever ending up co-located. In a small cluster, you may not have enough nodes to follow this method and still provide adequate hosts for failover. This is why I wrote the script. If I were an admin trying to implement a solution like this, I would consider all my options given what I know about the environment.
This is the dialogue:
So the alternate method I have been testing is allowing the VM to move to any node, but scheduling a script on the VMM server to check in and determine if the VMs are on the same node. If they are the script will LiveMigrate one of them to another host using Best Placement. The VMs are listed as items in an array at the top of the script. In the case below, you see I selected “v-win7-01” and “v-win7-02”. I have scheduled the script in Windows Task Scheduler to run every 60 seconds.
In other words, this would not provide a solution where there is no chance the VMs will ever end up on the same node, only that risk would be reduced to a possible few minutes. I say few minutes, because if the VM is moved outside of VM, it could take a minute for VMM to discover changes to the VM properties, and then the script would run on the next 60 second interval. If for some reason the VM cannot be moved, the VMs would stay together. In a smaller environment, this is actually a desirable outcome because if only 1 node was available in the cluster, both VMs would still be allowed to come online even if there is a risk involved.
Notes
Hint: when you setup the Scheduled Task, you actually want to run powershell.exe and pass the script (with full UNC path, if applicable) as an arguement.
In each of the scripts for this series, I have noted any manually assigned variables at the top of the script just under the header. For this script you will want to update your VMM server name.
In each of the scripts for this series, I have added a line to load the VMM snap-in. This way it can be run from any machine, including a workstation, where the VMM console is installed by right clicking on the file and choosing “run”. If you run the script from within VMM you will get a few lines of error text that the snap-in is already loaded. You can either ignore this, or comment out the line if it bothers you.
Screen Shots
Output of move-vm when running the script manually.
Script
disclaimer: this script is not supported in any way. I have posted the code rather than the .ps1 file so that you can review it, modify it to make it your own, and test it before trusting it in a production environment. now this is your code, I am not responsible for its use.
1: # ------------------------------------------------------------------------------
2: # Seperate VMs
3: # ------------------------------------------------------------------------------
4: # blogs.technet.com/offcampus
5: # version 1.0
6: #
7: # Description
8: # Useful as a scheduled task on the VMM server to seperate 2 VMs across hosts
9: #
10: # ------------------------------------------------------------------------------
11:
12: # All variables in the script with customizable values are mapped here for convenience
13: $VMMServerName = "v-vmm-01"
14: $HostGroupName = "All Hosts"
15: $VMGroup = "v-win7-01", "v-win7-02"
16:
17: # Load Snap-Ins
18: Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
19:
20: # Begin Script
21: Get-VMMServer $VMMServerName | out-null
22:
23: $VM = foreach ($Item in $VMGroup){get-vm | ? {$_.name -eq $Item}}
24: $List = $VM | group-object -property "VMHost" | ? {$_.count -gt 1}
25:
26: foreach ($Names in $List) {
27: $Cycle=1
28: while ($Cycle -lt $Names.count) {
29: $VMToMove = get-vm ($Names.group | select -first 1)
30: $VMHostRating = Get-VMHostRating -VM $VMToMove -VMHostGroup $HostGroupName -ismigration | ? {$_.Name -ne $VMToMove.VMHost} | sort -property rating -descending
31: Move-VM -vm $VMToMove -vmhost $VMHostRating[0].name -RunAsynchronously -BlockLMIfHostBusy -StartVMOnTarget
32: $Cycle++
33: }
34: }
Just a reminder, TechNet Webcast scheduled for today on Best Practices for Virtualizing Exchange. Delivered by PMs, level 300, so this is not just a broad overview. Worth checking out. If you are on central time, this runs over your lunch hour.
http://blogs.technet.com/virtualization/archive/2009/10/27/upcoming-webcasts-on-best-practices-for-virtualizing-ms-server-applications.aspx
As this has been a frequently requested link, I’m posting here.
Step by Step Guide to Building a Hyper-V Cluster
http://technet.microsoft.com/en-us/library/cc732181(WS.10).aspx
Information on upgrading a Hyper-V RTM cluster to R2.
http://blogs.msdn.com/clustering/archive/2009/10/08/9905089.aspx
New-VM
Not a lot to this one folks! In fact when I was looking through my scripts library, I was surprised I never published this one in the past. I use this script the most frequently of all.
The goal when I wrote this was to simplify deploying a new VM to as few steps as possible. I have used a lot of static variables in the script so it only asks for a server name. This means your template and profiles need to have already been created. If you want to fancy it up, I would start by prompting the user to input additional values at run time.
2: # New-VM
8: # Useful for quickly creating a VM from template in SCVMM
12:
13: # All variables in the script with customizable values are mapped here for convenience
14: $VMMServerName = "v-vmm-01"
15: $HostGroupName = "All Hosts"
16: $ProfileName = "Mid"
17: $TemplateVHDSize = 40
18: $NetworkName = "External1"
19: $TemplateName = "Windows Server 2008 R2 Ent Full - MID"
20: $TimeZone = 20
21:
23: # Load Snap-Ins
24: Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
26: # Begin Script
27: $Name = Read-Host "Please type a name for the new server"
28:
29: $VMMServer = get-vmmserver -computername $VMMServerName
30: $VMHostRating = Get-VMHostRating -VMHostGroup $HostGroupName -HardwareProfile $ProfileName -DiskSpaceGB $TemplateVHDSize -VMName $Name
31: $JobGroupId = [Guid]::NewGuid().ToString()
32: New-VirtualNetworkAdapter -JobGroup $JobGroupId -VirtualNetwork $NetworkName
33: New-VM -JobGroup $JobGroupId -Template $TemplateName -Name $Name -VMHost $VMHostRating[0].Name -ComputerName $Name -ProductKey "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" -Path $VMHostRating[0].vmhost.vmpaths[0] -TimeZone $TimeZone -RunAsynchronously -RunAsSystem -StartAction NeverAutoTurnOnVM -StopAction SaveVM
ShowDVDMediaCollisions
This script is designed to gather data on how each VM is physically connected to optical media and present it in such a way that an admin could quickly track down conflicts between two VMs. This resolves the case of a VM that is unable to start because the connection to DVD media is already in use. For each VM that is mapped to a physical DVD/CD drive, the script provides which host it is on and which drive it is connected to.
This presents the data as one line per VM mapped to a physical drive. That satisfies my need for this issue but if you would prefer to output an array of VMs with the host and drive information as properties. See the Get-NetworkMap script for an example.
2: # Show DVD Media Collisions
8: # Useful for displaying Optical Media mapped to more than 1 VM on the same host
12: write-host $args
13:
14: # All variables in the script with customizable values are mapped here for convenience
15: $VMMServerName = "v-vmm-01"
22: $VM = Get-VM
23:
24: $LocationVMMap = @{}
25: foreach ($entry in $VM)
26: {
27:
28: foreach($connection in $entry.VirtualDVDDrives){If ($connection.HostDrive -ne $null){write-host "$($entry.Name) on $($entry.VMHost) is connected to DVD drive $($connection.HostDrive)"}}
29: #$entry.Name | %{$LocationVMMap += @($entry.VMHost, )}
30: }
Special thank you to Rajesh Ravindranath who helped me out a lot with this script.
Refresh All
This post is a double-hitter. I am posting two versions of the same script.
VMM is a fairly passive management tool. On a regular cycle, or due to specific events, VMM collects data about the objects it is managing. This includes things like files in the library, virtual machines, hosts, clusters, and information about the VMM server itself. The problem is if you open the Hyper-V Console or Failover Cluster console directly and make changes, or manually copy files to the Library via Windows Explorer, you must wait for VMM to update before your changes would be reflected. In most cases, this is a non-issue because the cycles are short but when doing a lot of work and making quick changes outside VMM I decided I needed a script that would just tell VMM to go update NOW!
I ended up implementing this in two flavors, “Quick” and “Full”. The issue causing me to fork the road is synchronous vs. asynchronous handling of each refresh job. If you enumerate everything VMM knows about and tell them each to refresh asynchronously (everyone update right now, don’t wait for your neighbor to complete) then some jobs will be unable to complete because the objects are part of some of other object. An example would be refreshing VMs while the host where they reside is refreshing, or refreshing a host that is part of a cluster that is already updating. I have even encountered conflicts between two concurrently updating hosts that share some configuration details.
The workaround is one script that process every single object VMM knows about and synchronously refresh each of them one at a time. As you can imagine, this process is very thorough but it takes a lot of time. The second script updates just the library and cluster and runs asynchronously. Even in our environment, a 6 node cluster (soon to be 8) with 3 library servers, running Quick brings the console up to speed in short order.
Simple is good. As always, I ignore the snap-in error when running from console. The script returns each VM name and the location for the conflicting file.
2: # Refresh All
8: # Useful for quickly refreshing VMM all library and host information
14:
15: # Load Snap-Ins
16: Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
17:
18: # Begin Script
19: Get-VMMServer $VMMServerName | out-null
20: Get-LibraryShare | % {Refresh-LibraryShare $_}
21: Get-VMHostCluster | % {Refresh-VMHostCluster $_}
22: Get-VMHost | % {Refresh-VMHost $_}
23: Get-VirtualizationManager | % {Refresh-VirtualizationManager $_}
24: Get-VM | % {Refresh-VM $_}
2: # Quick Refresh
8: # Useful for quickly refreshing VMM library and cluster
20: Get-LibraryShare | % {Refresh-LibraryShare $_ -RunAsynchronously}
21: Get-VMHostCluster | % {Refresh-VMHostCluster $_ -RunAsynchronously}
Show VHD Collisions
This script looks for two VMs each mapped to the same VHD. This can cause issues when starting VMs and it is not simple to identify which VMs are in conflict.
Just to comment, there are very legitimate reasons for a VHD to be mapped to multiple VMs. If you had a very large set of data that needed to be accessed from two servers but those servers were not online at the same time, such as using a VHD as a container for transferring a large file copy rather than SMB. Now that R2 has hot-swap storage this is less of an issue than it was on RTM, so the examples of legitimate reasons are dwindling…
2: # Show Storage Collisions
8: # Useful for displaying any VHD or Pass-Through Disk mapped to more than 1 VM
20: $VM = Get-VM
22: $LocationVMMap = @{}
23: foreach ($entry in $VM)
24: {
25: $vhds = @(Get-VirtualHardDisk -vm $entry.Name)
26: If ($vhds) {$vhds | %{$LocationVMMap[$_.Location] += @($entry.Name)}}
27: }
29: if ($($LocationVMMap.Keys | ?{($LocationVMMap[$_]).Count –gt 1}) -lt 0) {write-host "No Collisions."}
30: Else {$LocationVMMap.Keys | ?{($LocationVMMap[$_]).Count –gt 1} | %{Write-Host “$($LocationVMMap[$_] –join ‘, ‘)" -nonewline -foregroundcolor yellow; Write-Host " collide on VHD file " -nonewline; Write-Host "$_.” -foregroundcolor yellow}}
Get-NetworkMap
This script is designed to gather data on how each VM is physically connected and present it in such a way that an admin could quickly track down the network path for troubleshooting purposes. For each VM, the script provides which host it is on, the virtual network name, vlan id, adapter type, the name of the physical device where the virtual network is assigned, and the physical network connection name for that device.
If the VM has more than one network adapter, each VM is displayed within the properties of that VM in the output. Commas separate the individual values so if you have several adapters you may need to consider modifying the script to output in a more friendly way. With 2-3 adapters, tracing the data across fields and keeping it straight is trivial.
I tried a lot of approaches at how this data should be presented and how the script should run. I settled on treating the script like a commandlet and passing command line arguments. So all you need to do is open PS somewhere that you have the console installed and run the script by passing it your VMM server name. The nice thing about this is the output can be stored to a new array to be worked in to other solutions.
example, “$netinfo = get-networkmap.ps1 v-vmm-01”
or dig a lot deeper, such as reporting the physical MAC address where the network for each VM is bound.
foreach ($record in $netinfo){write-host ""$record.name" - "$(foreach ($nic in $record.device){$nic.macaddress})""}
That’s all there is to it! See the very first listing, multiple values for each field because more than 1 adapter is assigned.
2: # Network Map
8: # Useful for displaying the physical network adapter information for each VM
10: # Command Arguements
11: # The script expects the VMM server name to be provided as an arguement
12: #
13: # ------------------------------------------------------------------------------
15: # All variables in the script with customizable values are mapped here for convenience
16: $VMMServerName = $args[0]
18: # Load Snap-Ins
19: Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
20:
21: # Begin Script
22: Get-VMMServer $VMMServerName | out-null
23: $VM = Get-VM
24:
25: $NetworkMap = @()
26: foreach ($entry in $VM)
27: {
28: $nic = (Get-VirtualNetworkAdapter -vm $entry.Name)
29: $hostadapters = foreach ($adapter in $nic) {get-virtualnetwork -vmhost $entry.VMHost -name $adapter.VirtualNetwork}
30: $connection = foreach ($network in $hostadapters) {$network.VMHostNetworkAdapters}
31: $hostnetworkadapters = $hostadapters.VMHostNetworkAdapters
32:
33: $netinfo = "" | Select-Object Name, HostName, VirtualNetwork, Type, VLAN, Device, Connection
34: $netinfo.Name=$entry.Name
35: $netinfo.HostName=$entry.VMHost
36: $netinfo.VirtualNetwork=foreach($virtualnetwork in $hostadapters){$virtualnetwork.Name}
37: $netinfo.Type=foreach($type in $nic){$type.VirtualNetworkAdapterType}
38: $netinfo.VLAN=foreach($vlan in $nic){$vlan.VLanId}
39: $netinfo.Device=foreach($device in $hostadapters){$device.VMHostNetworkAdapters}
40: $netinfo.Connection=foreach($nc in $connection){$nc.connectionname}
41: $NetworkMap += $netinfo
42: }
43:
44: $NetworkMap
As I am releasing several scripts for VMM over the next month, the details of of each weigh on my mind during spare cycles. One problem I thought I should solve is checking to see if the VMM snap-in has been loaded and then taking action based on the results.
Turns out Jeffrey Hicks, one of my favorite author/trainers, has already knocked this one out!
http://mcpmag.com/articles/2009/05/19/snapins-on-standby.aspx
I’m going to be publishing some of the scripts I have written for VMM. These are each based on specific customer asks or conversations that lead me to go sleepless in trying to solve the problems myself. I am very interested in your feedback, especially if you would like to offer a change to improve efficiency or effectiveness.
QuickChange
The idea behind this script is to accelerate changing the configuration of a VM so the amount of downtime required is minimized. The script focuses on Memory and Processor Count since those are the two values that require reboot. Performing this change “manually” meant multiple clicks and dialogue navigations. In automating the change via script I can typically reduce downtime to under 60 seconds.
After a lot of experimentation, I also implemented a choice menu in the script so before committing the change and starting the process. You will be prompted to either continue, continue with intelligent placement, or stop. The idea is if you are adjusting the amount of memory in a VM to a significantly higher amount, there may not be available memory on the same host to start it. Rather than waiting for the cluster to figure this out and move a VM, the script does a quick check for the best host across the cluster, moves it, and then starts it. Note – the “best host” may still not have enough memory available, so some common-sense qualification of the memory amount is recommended!
In each of the scripts for this series, I have noted any manually assigned variables at the top of the script just under the header. For this script you will want to update your VMM server name and the Host Group name.
Script starts by giving you a list of VMs. No error checking on this value, if you fat-finger the name the script would try to run but end in error that a VM by that name does not exist. See the snap-in error at the top? Since I launch from VMM, that is expected. I just ignore it, feel free to # it out.
The next screen gives you the current values for the VM and asks you what you would like to change them to. In this case I kept the values the same. The script doesn’t care, it assumes the person running the script is smart enough to know and still wants to make the “change”. The way I see it, the script should never argue with me.
Script prompting for confirmation. Just to be fancy, I did put in text for the help values, as demonstrated above.
The script finishes by returning the status of the VM as each of the jobs run. Nothing pretty. If you want pretty, switch over to the VMM console. You can see the shutdown, change, and start. If a move had occurred you would see that listed as well. In this case the VM was already on the best host. Not too bad, from shutdown to startup completing it took 46 seconds.
(Modified Script on 10/7 on line 22, avoiding move to same host)
2: # Quick Change
8: # Useful for quickly adjusting CPU count and Memory of a VM
15:
16: # Functions
17: function SetVmProperties ($CPUCount, $Memory, $MoveChoice)
18: {
19: Shutdown-VM $Name
20: Set-VM -vm $Name -CPUCount $CPUCount -MemoryMB $Memory
21: if ($Move -eq 1) {
22: $VMHostRating = Get-VMHostRating -VM $Name -VMHostGroup $HostGroupName -ismigration | ? {$_.Name -ne $Name.VMHost} | sort -property rating -descending
23: Move-VM -vm $Name -vmhost $VMHostRating[0].name -RunAsynchronously -StartVMOnTarget
24: }
25: Else {Start-VM $Name}
26: }
28: # Load Snap-Ins
29: Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
30:
31: # Begin Script
32: Get-VMMServer $VMMServerName | out-null
33: Get-VM | select Name | Format-Table
34: $Name = Read-Host "Which VM would you like to modify?"
35: cls
36:
37: Write-Host "That VM currently has the following properties:"
38: Get-VM $Name | select cpucount, memory | Format-List
39: $CPUCount = Read-Host "How many CPU's would you like?"
40: $MemoryMB = Read-Host "How much Memory would you like? (MB)"
41: cls
42:
43: $Caption = "Confirm Reboot"
44: $Message = "Please confirm you would like to reboot $Name to make the change?"
45: $Move = 0
46: $Yes = New-Object System.Management.Automation.Host.ChoiceDescription "&1. Yes", `
47: "Shutdown the VM, set the CPU Count and Memory values, and then attempt to start on the same host."
48: $Move = New-Object System.Management.Automation.Host.ChoiceDescription "&2. Yes, and move it to the best host", `
49: "Shutdown the VM, set the CPU Count and Memory values, query VMM for intelligent placement, move the VM to the best host, and then attempt to start the VM."
50: $No = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
51: "Do nothing. Exit Script."
52: $Choices = [System.Management.Automation.Host.ChoiceDescription[]] @($Yes,$Move,$No)
53: $choiceRTN = $host.ui.PromptForChoice($Caption,$Message,$Choices,2)
54: switch($choiceRTN)
55: {
56: 0 { SetVMProperties $CPUcount $MemoryMB }
57: 1 { $Move = 0
58: SetVMProperties $CPUcount $MemoryMB }
59: 2 { Write-Host "Exiting script. No changes were made."
60: Start-Sleep 5
61: Exit }
62: }
We have recently gone through the process of wiping out our lab and rebuilding from scratch on Windows Server 2008 R2 Enterprise. During this process, I recorded the steps I used to configure MPIO with the iSCSI initiator in R2. Just to make life more complex, our servers only have 2 NICs, so I am balancing the host traffic, virtual machine traffic, and MPIO across those two NIC devices. Is this supported? I seriously doubt it. :-) In the real world you would separate out iSCSI traffic on dedicated NICs, cables, and separate switch paths. The following step-by-step process should be relatively the same though.
Editorial Note: I do not work for the iSCSI team, I’m a field guy. If you see something you disagree with here don’t be angry, instead comment your point and I will update the article. Thanks.
The workflow I am following assumes that when starting out one NIC is configured for host traffic and the other for a VM network. On the WSS the secondary NIC was already configured not to register in DNS. Also, since I am using WSS and the built-in iSCSI Target I don’t have to configure a DSM for the storage device. If your configuration is different than that, you may have to ignore or add to a few parts of the below instructions. Sorry about that. I can only document what I have available for testing…
First I just want to show a screenshot of the iSCSI target on our Windows Storage Server, to indicate that it does have two IPs. Once again, I am cheating the system here. These are not dedicated TOE adapters for iSCSI on a separate network. This is a poor man’s environment with 1 VLAN and minimal network hardware. My highly available environment is anything but! To view this information on your own WSS, right-click on the words “Microsoft iSCSI Software Target” and click Properties.
Next I needed to enable MPIO on the servers making the iSCSI connections. MPIO is a Feature in Server 2008 R2 listed as Multipath I/O. Adding the Feature did not require a reboot on any of my servers.
Configuring MPIO to work with iSCSI was simple. Click Start and type “MPIO”, launch the control panel applet, and you should see the window below. Click on the Discover Multi-Paths tab, check the box for “Add support for iSCSI devices”, and click Add. You should immediately be prompted to reboot. This was consistent across 4 servers where I followed this process.
After rebooting, if you open the MPIO Control Panel applet again, you should see the iSCSI bus listed as a device. Note on my servers, the Discover Multi-Paths page becomes grayed out.
Now click Start and type “iSCSI”. Launch the iSCSI Initiator applet. Add your iSNS server or Target portal. There is plenty of documentation on how to do this on TechNet if you need assistance. I want to stay focused on the MPIO configuration.
Once you are connected to the target, click the button labeled “Devices…”. You should see each of the volumes you have connected listed in the top pane. Select a Disk and click the MPIO button. In the Device Details pane you should see information on the current path and session. If you click the Details button, you can verify the local and remote IPs the current connection is using. It should be the IPs that resolve from the hostnames of each server. See my remedial diagram below.
I recommend taking note of this IP, to make life easier later on!
So everything is setup for MPIO but you are only using a single path and that’s not really going to accomplish much now is it? Since I only have 2 NICs in my test server I need my host to share the second NIC with the VM network. This is not ideal but again I am using what I have and this is only a test box.
In R2 the host does not communicate by default on a NIC where a virtual network is assigned. To change this, open the Hyper-V console and click “Virtual Network Manager…”. Check the box “Allow management operating system to share this network adapter”.
This will create a third device in the network console (to get there click Start, type “ncpa.cpl”, and launch the applet). You should see the name of the new device matches your Virtual Network name. In my case Local Area Connection 4 has a device name “External1”. Right click on the connection and then click Properties. Select “Internet Protocal Version 4 (TCP/IPv4)” and click the Properties button. Configure your address and subnet but not the gateway as it should already be assigned on the first adapter. You also shouldn’t need to set the DNS addresses in the new adapter. You will however, want to click the “Advanced…” button followed by the DNS tab and uncheck the box next to “Register this connection’s address in DNS”. This really should be the job of your primary adapter, no need to have multiple addresses for the same hostname registering and causing confusion unless you have a unique demand for it.
Back in the iSCSI Initiator Applet, click the Connect button. I know you already have a connection. In this step we are adding an additional connection to the Target to provide a second path.
In the subsequent dialogue make sure you check the box next to “Enable multi-path” and then click the Advanced… button. In the Advanced Settings dialogue you will need to choose the IP for your second path. In the drop-down menu next to “Local adapter:” select Microsoft iSCSI Initiator”. In the drop-down next to “Initiator IP:” select the IP on your local server you would like the Initiator to use when making a connection for the secondary path. In the third drop-down, next to “Target portal IP:” select the IP of the iSCSI Target server you would like to connect to. This should be the opposite IP of the session we observed a few steps back when I mentioned you should take note of the IP.
Just one more step. Let’s verify that you now have 2 connections available for each disk, that they are using separate paths, and have the opportunity to choose the types of load balancing available. Once you have hit OK out of each of the open dialogues from the step above, click on the Devices… button again and check out the top pane. On each of my servers I see each disk listed twice, once per Target 0 and once per Target 1, as seen below. If you follow my remedial diagrams one more time and select a disk, then the MPIO button, you should now see two paths. Select the first path and click the Details button. It should be using the local and remote IPs we took note of earlier. Click OK. Now select the second path and then the Details… button. You should see it using the other adapter’s IP on BOTH the local and remote hosts.
A peer sent this link to me today. I felt it important to share as a few people have asked me if it would be possible. There is an update available.
http://support.microsoft.com/kb/968074
Working on another project and I needed a way to wake up an offline server from within my PS script. I found this genius blog post and converted it to a script.
Genius blog post - The PowerShell Guy : PowerShell Wake-on-lan script
I saved the below text as send-wol.ps1 for re-usability. This code came from The PowerShell Guy blog, I cannot claim credit!!!! I just made it a script. Mainly, I combined two snippets from his post and added the args reference.
$mac = [byte[]]($args[0].split('-') |% {[int]"0x$_"})
$UDPclient = new-Object System.Net.Sockets.UdpClient
$UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
$packet = [byte[]](,0xFF * 102)
6..101 |% { $packet[$_] = $mac[($_%6)]}
$UDPclient.Send($packet, $packet.Length)
So how would you run it? I would proactively open a command prompt and get the mac addresses from your arp table and save them to a file. You can get at the table by running “arp –a” and locating the IP address for the node you are concerned about. Later if you want to wake the host up, just open PowerShell, and run the script as follows:
Other ways to get the arp address for an offline machine? If your network devices have SNMP enabled you may be able to leverage vendor tools to retrieve arp data from there. If you have an inventory too such as System Center Configuration Manager, it would also store that data.
That’s the subtitle of a case study that recently went online (so I’m not plagiarizing). A colleague sent this over to me and I had the privilege of talking with these folks a couple of weeks ago. Interesting details of this deployment (scroll down now to see why). Reading the article I found some themes I hear across everyone in education -
(referring to managing labs)
“For years, meeting this challenge required two full-time IT administrators responsible for creating scripts for installing particular software combinations on PCs. Those hard disk drives then were cloned and the images distributed over the network to duplicate the software packages to other computers.”
How did they address this common challenge? Application Virtualization. From the article:
“Instead of installing entire applications through the network, Microsoft Application Virtualization 4.5 (part of the Microsoft Desktop Optimization Pack for Software Assurance) uses a streamlined delivery method. When a Sinclair student clicks to start an application, Application Virtualization receives a request from the student’s PC and then installs only the code necessary to start the application from a centralized virtual application server on the Sinclair campus. The software that is sent to the student’s computer is typically 20 to 40 percent of the total application. After a student ends a session, the application and its user preferences are saved in a local, file-based cache location on the PC. When the student wants to use the application again, it opens from the local PC cache, resulting in a faster start than the initial session. There is little impact on network bandwidth, and the user’s applications are preserved even in the case of unexpected computer shutdown.”
“Instead of installing entire applications through the network, Microsoft Application Virtualization 4.5 (part of the Microsoft Desktop Optimization Pack for Software Assurance) uses a streamlined delivery method. When a Sinclair student clicks to start an application, Application Virtualization receives a request from the student’s PC and then installs only the code necessary to start the application from a centralized virtual application server on the Sinclair campus. The software that is sent to the student’s computer is typically 20 to 40 percent of the total application.
After a student ends a session, the application and its user preferences are saved in a local, file-based cache location on the PC. When the student wants to use the application again, it opens from the local PC cache, resulting in a faster start than the initial session. There is little impact on network bandwidth, and the user’s applications are preserved even in the case of unexpected computer shutdown.”
Now, here is why I’m blogging about this. The implementation details are different than other App-V projects I have heard about in EDU. They are combing App-V, Terminal Services, and IAG, to do remote application access with end point inspection of student and faculty machines to ensure there is a consistent security baseline for anyone connecting in. Many other organizations have implemented this type of scanning on a per-semester basis when student machines are required to register for network access. In this case, every time a student accesses a virtualized application via IAG their machine is scanned to ensure they meet the security baseline throughout the duration of their enrollment. From the article:
“The school is using Microsoft Intelligent Application Gateway (IAG) 2007 as a remote access gateway that works in tandem with Application Virtualization to deliver software packages. The school worked with SCE Consultants for the deployment of IAG including customization to provide role-based access to the campus network. IAG uses a combination of a Secure Sockets Layer virtual private network (SSL VPN), a Web application firewall, and endpoint security so that students and faculty can easily access the software packages. The Sinclair IT department uses IAG to enforce compliance with rules that control access to and use of the applications, such as providing students with permissions to access software for particular classes after they are enrolled.”
“The school is using Microsoft Intelligent Application Gateway (IAG) 2007 as a remote access gateway that works in tandem with Application Virtualization to deliver software packages. The school worked with SCE Consultants for the deployment of IAG including customization to provide role-based access to the campus network.
IAG uses a combination of a Secure Sockets Layer virtual private network (SSL VPN), a Web application firewall, and endpoint security so that students and faculty can easily access the software packages. The Sinclair IT department uses IAG to enforce compliance with rules that control access to and use of the applications, such as providing students with permissions to access software for particular classes after they are enrolled.”
This is really good work. Congrats guys. Look forward to hearing more from Sinclair Community College in the future!
http://www.microsoft.com/casestudies/casestudy.aspx?casestudyid=4000003808
Just wanted to share this script I wrote. The idea is I want to do something (anything) to a host and feel it might cause a service interruption so I would prefer to move all VMs off the node. Rather than doing it manually in the cluster or in VMM, or forcing VMs off in a reboot, this script will get a list of all VMs on a node and use intelligent placement to fail over VMs to the best possible node in your cluster in one quick operation. This should work for VMs running on either Hyper-V or VMWare as long as you have SCVMM managing your environments.
2: # EVACUATE!
8: # Useful for quickly moving all VMs off a host using intelligent placement.
12: $vmhost=get-vmhost
13: write-host "Hosts:" -foregroundcolor "green"
14: foreach ($hostname in $vmhost){write-host $hostname.computername -foregroundcolor "green"}
15: write-host ""
17: $Name = Read-Host "Which host would you like to evacuate?"
18:
19: $VMMServer = get-vmmserver -computername "v-scvmm-01.usedu.int"
20: $VMArray = get-vm -vmhost $Name | where {$_.customproperties -notcontains "Local"}
21: @( ForEach ($VM in $VMArray) {
22: $VMHostRating = get-vmhostrating -vm $VM -vmhostgroup "All Hosts" -ismigration | sort -property rating -descending
23: move-vm -vm $VM -vmhost $VMHostRating[0].name -RunAsynchronously
24: })