PowerCLI update on VM network cards and types report also with MAC´s

Today i added some fields in my little reportscript for the VM and their NICs, the reason was because of a customer that had an issue with duplicate MAC´s on their network.

We had earlier this year moved some VMs from an old vCenter to a new, i have made a blog post about the migration and the script we ran there.

Now when they started to deploy new VMs on the old vCenter it gave out the same MAC addresses as the ones on the VM´s that we had moved.. not so good, there is a fix that can be implemented on the old vCenter so it will start using new MAC´s instead, if you have this issue you can read the following KB 1024025 and set a new ID on the old vCenter and restart the service 🙂

But to check the VMs on both vCenter servers i ran the following script to get the data, the customer wanted both the VM name and the hostname/fqdn from the vm, also for every nic if it was generated or assigned.

# Get the Virtual Network Adapter
# Niklas Akerlund / RTS

$VMs = Get-VM *
$Data = @()

foreach ($VM in $VMs){
 	$VMGuest = Get-View $VM.Id	
	$NICs = $VM.NetworkAdapters
	foreach ($NIC in $NICs) {
		$into = New-Object PSObject
		Add-Member -InputObject $into -MemberType NoteProperty -Name VMname $VM.Name
		Add-Member -InputObject $into -MemberType NoteProperty -Name VMfqdn $VM.Guest.HostName
		Add-Member -InputObject $into -MemberType NoteProperty -Name NICtype $NIC.Type
		Add-Member -InputObject $into -MemberType NoteProperty -Name MacAddress $NIC.MacAddress
		Add-Member -InputObject $into -MemberType NoteProperty -Name AddresType $NIC.ExtensionData.AddressType
		$Data += $into

$Data | Export-Csv -Path c:\powercli\VMNICinfo.csv -NoTypeInformation

Matt Boren that has the site vnugglets.com helped me with an more efficient way of getting the data, my script took about 5-10 minutes and Matt´s took 30 seconds, his key to lower time is using the Get-View for everything (i was only using it to get the vm.guest.hostname)

&{Get-View -ViewType VirtualMachine -Property Name, Guest.HostName, Config.Hardware.Device | %{
    $viewThisVM = $_
    $viewThisVM.Config.Hardware.Device | ?{$_ -is [VMware.Vim.VirtualEthernetCard]} | %{
        New-Object -Type PSObject -Property @{
            VMname = $viewThisVM.Name
            VMfqdn = $viewThisVM.Guest.HostName
            NICtype = $_.GetType().Name
            MacAddress = $_.MacAddress
            AddressType = $_.AddressType
        } ## end new-object
    } ## end foreach-object
} ## end foreach-object
} | Select VMname,VMfqdn,NICtype,MacAddress,AddressType | Export-Csv -Path C:\VMNICinfo2.csv -NoTypeInformation -UseCulture

And the result when imported into excel looks something like this:


Virtual Machine VMDK file report with PowerCLI

I have created a simple report-script that gives a list of what kind of format and how many vmdk each VM has. The report tells me if the disks are Thin or Thick and what size they are i GB.

after some magic in Excel it looks like this 🙂

And the powerCLI script looks like this, it is quite simple but still gives me information that i need for all my VMs on all datastores and quickly i can tell which machines that uses a lot of disk on my precious SAN 😉


# Get data about vmdk and format
# Niklas Åkerlund / RTS

$VMs = Get-VM *
$Data = @()

 foreach ($VM in $VMs){
	$VMDKs = $VM | get-HardDisk
	foreach ($VMDK in $VMDKs) {
		if ($VMDK -ne $null){
			$CapacityGB = $VMDK.CapacityKB/1024/1024
			$CapacityGB = [int]$CapacityGB
			$into = New-Object PSObject
			Add-Member -InputObject $into -MemberType NoteProperty -Name VMname $VM.Name
			Add-Member -InputObject $into -MemberType NoteProperty -Name Datastore $VMDK.FileName.Split(']')[0].TrimStart('[')
			Add-Member -InputObject $into -MemberType NoteProperty -Name VMDK $VMDK.FileName.Split(']')[1].TrimStart('[')
			Add-Member -InputObject $into -MemberType NoteProperty -Name StorageFormat $VMDK.StorageFormat
			Add-Member -InputObject $into -MemberType NoteProperty -Name CapacityGB $CapacityGB
			$Data += $into

$Data | Sort-Object VMname,Datastore,VMDK | Export-Csv -Path C:\temp\VM-VMDKs.csv -NoTypeInformation

Move VMs from an old SAN to an new using powerCLI part 2


I was informed that my script in the last post was not enough because @pfuhli has a bit more complex environment and then the Move-VM cmdlet is not sufficient because it moves the whole vm to the new datastore, no matter if the vmdk´s where located on different before.

As in some cases you have an virtual platform with different datastores for different performance levels and one VM has it´s vmdk configured to get the best throughput. So i  did this with help from a script that Luc Dekens did in a communities post, mine added some functionality as his only moved the config file.

please comment if you find something crazy, I have now started to get the hang of why I would use functions :-), yes i should add some error-checking, that will be in version 0.3

Probably it would take some time to get through 500 VM´s but instead of manual work it is worth it.

# Move VMs with sVMotion where vmdk is on different datastores and
# lastly move the config file to the same datastore as hard disk 1
# Niklas Åkerlund / RTS 20111127
# Part of code from Luc Dekens http://communities.vmware.com/message/1680735

# Here i extended Luc´s function for moving only config
function Move-VMs{
	Write-Host $vm
    $HDDs = Get-HardDisk -VM $vm    
	# a foreach loop to move vmdk
	$HDDs | %{
		# Get the datastore name of the old
		$oldDS = $_.Filename.Split(']')[0].TrimStart('[')
		# as @pfuhli said the new lun has a preceding letter that differs from the old.
		$newDS = "N" + $oldDS 
		# Here i check which is the first hdd to later move the config there
		if ($_.Name -eq "Hard disk 1"){
			$dsNameHDD1 = $newDS
		$newDS = Get-Datastore $newDS
		Set-HardDisk -HardDisk $_ -Datastore $newDS -Confirm:$false
	# This part is for moving the config file
	$HDDs = Get-HardDisk -VM $vm
	$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec 
	$spec.datastore = (Get-Datastore -Name $dsNameHDD1).Extensiondata.MoRef
    $HDDs | %{
        $disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
        $disk.diskId = $_.Extensiondata.Key
        $disk.datastore = $_.Extensiondata.Backing.Datastore
        $spec.disk += $disk
    $vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority")

Get-VM | %{ 
	Move-VMs $_ 


Before running it on all VM´s i would test it on a few and then when feeling comfortable, you can move all 😀

Move VMs from an old storage array to a new using powerCLI

I have after reading a tweet written the simplest script for a SAN exchange, my script just look for the VMs associated with one datastore and storage vmotion them to an new datastore with no downtime 🙂 of course this requires Enterprise or higher in your vSphere licensing.

I have done some assumptions that there is equally many datastores provisioned in the new as the old and that no VMs have RDMs and vmdk on several datastores.

The Get-Datastore cmdlet can filter using wildcards like *c2* if your naming convension is complex and you need to find your old/new datastores objects.

For each old datastore i wait 30 minutes before starting on the next, maybe this must be set a bit higher depending on how long the storage vmotion takes and how large the datastores/vmdk´s are. Maybe we should put a sleep after starting move of each VM?! I have not yet had the pleasure testing in a large environment yet..

# Move VMs to new datastore using SVMotion
# Niklas Akerlund /RTS

# I want all old and new datastores as objects in arrays
$OldDatastores = Get-Datastore vmfs-volumes-old0*
$NewDatastores = Get-Datastore vmfs-volumes-new0*
$i = 0

# Get all VMs in each old datastore and move them
Foreach ($OldDatastore in $OldDatastores){
	$VMs = Get-VM -Datastore $OldDatastore
	Foreach ($VM in $VMs)
		# Move the VM to a new datastore
		$VM | Move-VM -Datastore $NewDatastores[$i] -RunAsync
	# we want to give the SVMotions a little time before taking the next datastore 
	Start-Sleep 1800

I would recommend testing on a single datastore or a few VMs and when feeling comfortable running on all datastores..

HTML report checking your vSphere host configuration by powerCLI version 0.1

I have today started creating a script that is sort of a check that when installing new hosts, all of them are configured the same.

It is still very simple but yet kind of powerfull, we can easily see in the html report if some vmk nic is on the wrong IP subnet or not Jumboframes activated, the following screen dump shows the report, yes it is no fancy headlines and stuff yet 😉

I am going to work a lot more such as built in error checking and try to get some nice colors if a value differs with the other hosts, and also reporting on vSwitches and portgroups that they have the right uplinks etc, but that will have to be tomorrow or another day 🙂

# Check for Host Configuration and report
# Niklas Åkerlund / RTS

$vCenter = "vcenter.demo.local"
$AdvConf = @()
$Cluster = "Cluster1"

# We only want to get info from hosts that are online
Connect-VIServer $vCenter

$VMHosts = Get-Cluster -Name $Cluster | Get-VMHost | where {$_.ConnectionState -eq "Connected" }

# Get the cluster config 
$ClusterConf = Get-Cluster -Name $Cluster | Select-Object Name,HAEnabled,HAAdmissionControlEnabled,HAIsolationResponse,VMSwapfilePolicy,DrsEnabled,DrsMode,DrsAutomationLevel | ConvertTo-Html -Fragment

# Get Basic Conf 
$BaseConf = $VMHosts | Select-Object Name,Model,NumCPU,MemoryTotalMB,Version,Build,VMSwapfileDatastore | Sort-Object Name | ConvertTo-Html -Fragment

#adv config settings
foreach ($VMHost in $VMHosts){ 
		$into = New-Object PSObject
		Add-Member -InputObject $into -MemberType NoteProperty -Name VMHost $VMHost.Name
		$AdvScratch = Get-VMHostAdvancedConfiguration -VMHost $VMHost -Name ScratchConfig.ConfiguredScratchlocation
		$AdvScratch = [string]$AdvScratch.Values
		Add-Member -InputObject $into -MemberType NoteProperty -Name ScratchLocation $AdvScratch
		$AdvSwap = Get-VMHostAdvancedConfiguration -VMHost $VMHost -Name ScratchConfig.CurrentSwapState
		$AdvSwap = [string]$AdvSwap.Values
		Add-Member -InputObject $into -MemberType NoteProperty -Name Swapstate $AdvSwap
		$AdvSyslogRemote = Get-VMHostAdvancedConfiguration -VMHost $VMHost -Name Syslog.Remote.Hostname
		$AdvSyslogRemote = [string]$AdvSyslogRemote.Values
		Add-Member -InputObject $into -MemberType NoteProperty -Name SyslogRemote $AdvSyslogRemote
		$AdvSyslogLocal = Get-VMHostAdvancedConfiguration -VMHost $VMHost -Name Syslog.Local.DatastorePath
		$AdvSyslogLocal = [string]$AdvSyslogLocal.Values
		Add-Member -InputObject $into -MemberType NoteProperty -Name SyslogLocal $AdvSyslogLocal
		$AdvConf += $into


$AdvConf = $AdvConf | Sort-Object VMhost | ConvertTo-Html -Fragment

# Vmk ports and their MTU

$NetConf = $VMHosts | Get-VMHostNetworkAdapter | where {$_.Name -match "vmk"} | Select-Object VMHost,Name,IP,VMotionEnabled,FaultToleranceLoggingEnabled,ManagementTrafficEnabled,Mtu,PortGroupName | Sort-Object Name,VMHost | ConvertTo-Html -Fragment

# Create the html report from the different parts 
ConvertTo-Html -body "RTS Install documentation <p> $ClusterConf <p> $BaseConf <p> $AdvCOnf <p> $NetConf" -Title "RTS Installationscheck" | Out-File install.html


OS X Lion reset password and how to protect yourselves

Today i realized that i was kind of vulnerable with my Mac. Of course if anyone get the hands on your computer that is not good. Todays post will give you a little heads up and  some of you will secure your MacBooks from immediate access. There are always ways to get hold of your data but don´t do it to easy.

I had totally missed the firmware password, which is used as a security add-on that prevents any user to take your Mac and boot into rescue mode and then reset your password.

So how do you reset password on someones computer then,

Reboot the Macbook and press the “Option + R” , then you will get the recover boot

As you can see in the Utilities menu list there are some different tools, the one we want is the Terminal, and there you type “resetpassword”, without any cd or external osx media you get a root terminal to use..

You will get a fine graphical dialog asking what volume and what account you want to reset password on!

So how can we make it a bit more difficult to do this then? Still not impossible but at least more difficult and time consuming 🙂

The highlighted menu option in the first picture “Firmware Password Utility” is the one we want and set a password that is going to be asked for every time we want to do some alternative booting (Recover mode, usb hdd, DVD )

So now i have activated this and how does it work, if i boot ordinary i will not get any log in promt at boot asking me to enter firmware password, but if hold down the “option” key i will get a password prompt asking me for the firmware password, the following image shows how this looks like.

This is of course no security for your data that you store on your drive, if the evil forces want your data they can take out the hdd and connect it to another computer to get data. If you are running around with sensetive data you should also enable filevault and encrypt your profile and files. In System Preferences under Security and Privacy you can enable the FileVault. As it clearly says in the warning, if you loose your password and recovery key your data is gone! And it has to be the password that you set it up with, it will not work with a reset password.

Described in several google hits there are ways to reset the firmware password also, I have not tried those yet but i will..

I also use TrueCrypt to save files and stuff on encrypted volumes.

Recover Administrator password after some powershell on the Active Directory

Yes powershell can be used to administer your Active Directory, but you could do some serious damage also. I will show you one particular case where things can go very wrong and how to recover from it.

To use cmdlets for AD you simply start your powershell console and type

Import-Module ActiveDirectory

You get quite a few cmdlets to help you automate your user administration, if you write the following in your console it will list all of them.

Get-Command *-AD*

Well now to the problem, as a domain admin you do have some privileges and say that you want to disable some user accounts and you forget to add a searchbase or your filter does not do as you wish and in one line you have disabled all accounts in your domain, including admin. IF and i say IF you realize that misstake and quickly go in and enable the accounts again, you are safe, but if you log out of your session you wont be able to log in again with any account 🙂

Get-ADUser -Filter * | Set-ADUser -Enabled $False

try to log in as domain administrator and you will get this, on any DC (as long as your replication is working and if it is not you have other problems, trust me)

So how do we fix this then? luckily there is a way to do this and it is quite easy. You have to find a windows iso and as in this case a Win 2008 r2, start it in repair mode and start a CMD

when the command promt is started do this (i found it in another blog from Matheu the difference here is that i use net user administrator /active:yes to enable instead of change password)

  • Go to c:\windows\system32
  • Rename Utilman.exe to Utilman.exe.bak
  • Copy cmd.exe to Utilman.exe
  • Reboot on Windows
  • Do the keyboard shortcut Windows + U when on the logon screen
  • net user administrator /active:yes
  • log on with the domain admin account
  • Reboot on the DVD to put back the original Utilman.exe

Instead of panicking and try to restore your AD you can easily as i described log in again. This is of course a big security thing to consider in a virtual environment where users that have access to the virtual infrastructure but are not domain admins can manipulate virtual Domain controllers to get access to the administrator password “net user Administrator newpasswd123”. Here is a link to all net user commands.

So if i am going to do some account disabling i would include a searchbase in my Get-ADUser to not get the Administrator locked out by mistake and actually take the right OU to modify users on.

Get-ADUser -Filter * -SearchBase "OU=Employees, DC=Test, DC=local" | Set-ADUser -Enabled $False

In my test environment i used two DC´s and both the lock and unlocking replicated quite fast. There is maybe a way with the Active Directory Domain Services Recovery without having to do a restore, i will look into that and do a follow up post if i find any easy ways!

PowerCLI to the rescue, how to check all VMs for Network card type

I got a question what network card some VMs had in a datacenter, as a best practice you should use VMXNET 3 where it is possible because it gives the best performance.

So i wrote this very simple script in a few lines that do a csv export of all VMs and what kind of NIC they have, of course one could extend it with OS and stuff but that will have to be next time cause my schedule is kind of tight.

When you use the wizard to set up a Windows 2008 R2 the vSphere set an E1000 NIC by default and that is not what we want, so set up a correct template or remove this nic and add a new when installing single machines!

# Get the Virtual Network Adapter
# Niklas Åkerlund / RTS
$VMs = Get-VM *
$Data = @()
foreach ($VM in $VMs){
$NICs = $VM.NetworkAdapters
foreach ($NIC in $NICs) {
$into = New-Object PSObject
Add-Member -InputObject $into -MemberType NoteProperty -Name VMname $VM.Name
Add-Member -InputObject $into -MemberType NoteProperty -Name NICtype $NIC.Type
$Data += $into
$Data | Export-Csv -Path e:\temp\admna\NICs.csv -NoTypeInformation


Hyper-V R2 Core host networking problem in VMM 2008 R2

This Friday i helped a customer with a little problem, they have a Hyper-V cluster with 4 nodes, after a switch firmware upgrade they experienced some networking instability and in their search of failure they accidentally unchecked the Host access checkbox in the networking properties on the net, as their networking configuration did not allow a separate nic for the management we had to set it up with this enabled. Of course when they applied this change the host lost connection.

I instructed them to use the 59manager to configure the host locally and set the host access on this virtual switch, this did not help cause the server would still not respond. I went over to help them on site, the first thing we did was to remove the host from the cluster and then start to test and when we removed the virtual switch the nic started to respond to ping but as soon as we re-added it to the virtual switch it stopped working. We also tried to remove the nic config and set it to dhcp and then add it to the virtual switch with the host access enabled, which did not work either. After this when we tried to set the IP in SCONFIG we got an error that stated that there was an error and the address could not be set. I thought it might be some bug in the team networking sw or drivers so we updated those as well, but no more luck there either..

Then we found the following site that described the exact same problem, Microsoft Enterprise Networking Team , in this blog they referred to a script that clean out the whole hosts virtual networking config, “nvspcrub.js” , with the /p option. Well we had to try something so we ran the script and cleared the hosts all virtual switches.  Then we added a new virtual switch and checked the Host access and tried to set the IP in SCONFIG, Still same error with “Can not set IP address”, After this we where almost on our way to give up and reinstall the host, then we thought of one last chance to set the IP through netsh (this after reading about a bug with SCONFIG) so with the command

netsh int ip set add "Local area connection 3" static

It actually worked and the host started to respond to ping 🙂 , quite frustrating that we removed all the config and then find out it was a bug in sconfig that was the causing the error.

Now we had to re-add all virtual networking switches, this was of course a perfect job for powershell, so i wrote a script that took one of the other hosts config and created the same virtual switches on the failed host, also connecting to the NIC corresponding to the right net and vlan

# Create Virtual Networks on Host
# Niklas Akerlund /RTS

# Take ref nic from another host

Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
$VMMserver = Get-VMMServer sbgvmm01

$Networks = Get-VirtualNetwork | where {$_.VMHost -eq "HYP04.desso.se" -and $_.HostBoundVlanId -ne "3750"}

$NICs = Get-VMHostNetworkAdapter | where {$_.VMHost -eq "HYP01.desso.se"}

$VMHost = Get-VMhost -ComputerName "HYP01.desso.se"

foreach($Network in $Networks){
$split = $Network.Name -split ' '
if ($split[1] -eq "1"){
$Name = $split[0] + " " + $split[1]
$match = $split[2] -match "\d+"
$vlanid = $Matches[0]
$vlanid = [int]$vlanid
}elseif ($split[1] -like "VLAN*"){
$Name = $split[0]
$match = $split[1] -match "\d+"
$vlanid = $Matches[0]
$vlanid = [int]$vlanid
$Name = $split[0] + " " + $split[1]
$match = $split[2] -match "\d+"
$vlanid = $Matches[0]
$vlanid = [int]$vlanid

$HostNIC = Get-VMHostNetworkAdapter -VMHost $VMHost | where {$_.ConnectionName -eq $Name}

if ($HostNIC -ne $null){

New-VirtualNetwork -Name $Network.Name -VMHost $VMHost -VMHostNetworkAdapters $HostNIC -BoundToVMHost $FALSE
Set-VMHostNetworkAdapter -VMHostNetworkAdapter $HostNIC -VLANEnabled $TRUE -VLANMode "Trunk" -VLANTrunkID $vlanid
write-host $HostNIC.ConnectionName
Write-Host $vlanid

After i ran this and the host got all it´s virtual networks back i could add the host back to the cluster again. Instead of some typo errors with manually entering all the virtual switches, with some powershell we could be sure that we got the same config as the other host already in the cluster!

One thing that i first missed was the -BoundToVMHost $FALSE in the New-VirtualNetwork which resulted that all my virtual networks had the Host Access checkbox marked and i had one NIC for each of them on my host, this of course was not what i wanted, one could think that this would be false as default but for some reason MS and the VMM team thought different, well no worries i created a small script to just update my virtual networks with that option (the script above is corrected after my mistake), so i ran:

# Update networks with BoundtoHost $false
# Niklas Akerlund /RTS

$Networks = Get-VirtualNetwork | where {$_.VMHost -eq "HYP01.desso.se" -and $_.HostBoundVlanId -ne "3750"}

foreach ($Network in $Networks){
Set-VirtualNetwork -VirtualNetwork $Network -BoundToVMHost $false

Where the network with the VLAN 3750 was the one i wanted the host access to stay because it was the management nic of the host.

Hot-add CPU and Memory in a Win 2008 Datacenter with SQL in vSphere

I have today tested how it works to hot-add both memory and vCPU to a virtual machine running Windows 2008 R2 Datacenter Edition, this machine also has SQL 2008 R2 Enterprise edition installed.

First i had to enable hot-plug in the virtual machine, there is of course two ways to do this, either via the GUI or

the powerCLI way:

$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$mem = New-Object VMware.Vim.optionvalue
$vmConfigSpec.extraconfig += $mem
$cpu = New-Object VMware.Vim.optionvalue
$vmConfigSpec.extraconfig += $cpu

$vm = Get-VM TempNHot | Get-View

when this has been executed on the particular VM i can then when it is running use powerCLI again and add resources to it.

Get-VM TempNHot | Set-VM -MemoryMB 3072 -NumCpu 4 -Confirm:$false

According to Microsoft documentation it is only supported to do hot-add of memory and CPU in Datacenter edition of Windows, Also regarding SQL you have to use either Enterprise or Datacenter edition to also get it working into the application.

To check that the new resources where used i tested with the SQLstress application to get some load on the SQL server and check the taskmgr, but it did not show that the load where spreading to the new added vCPU, after some research i found out that the SQL server do not start to use new hardware right away, it need to be reconfigured to schedule load on additional CPU´s, so there is a little manual intervention but no downtime on the server!


So i started a query in SQL Management Studio and wrote


After :

In the taskmanager i could now see that all four vCPU where equally loaded by the SQL server.

Maybe it is not so common to have to do this but if you set up a large Tier-1 SQL server in a virtual world you surely want to be able to hot-add resources when it is loaded. Think of the advantages that this brings when you actually both can add memory and cpu resources without any downtime!

In a virtualization world we always recommend our customers to buy Windows Datacenter licenses on their hosts so using it on a VM will not add any extra cost. The SQL server is of course quite a price jump from standard to enterprise but if your big SQL server uses more than 64 GB ram you will still need to use Enterprise licenses 🙂