Change SCSI controller with PowerCLI on win 2008 R2 VM from Paravirtual

I found this KB 2004578 and thought that of course should this be done with PowerCLI

I made a function to be able to do it just by sending the VM parameter, it can be done if the VM is already shutdown with a simple one-liner

Get-VM v2vtest2 | Get-ScsiController | where {$_.Type -eq "Paravirtual"} | Set-ScsiController -Type VirtualLsiLogicSAS

But I wanted a more sophistical approach where my function shutdown the VM properly and then change the controller and starts the VM, the tricky part here was to check that the VM actually had shutdown before I change controller 🙂

function Change-ScsiController{
<#
.SYNOPSIS
Stop a VM and replace the SCSI controller and start it again

.DESCRIPTION
Use this function to change scsi cntroller

.PARAMETER  xyz 

.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-03-21
#>
    param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="A virtual machine",
    ValueFromPipeline=$True)]
    $VM
    )
	$VM = Get-VM $VM	
	
	Shutdown-VMGuest -VM $VM -Confirm:$false
	while ($VM.PowerState -eq "PoweredOn")
	{
	$VM = Get-VM $VM
	Start-Sleep -s 1	
	}
	Get-ScsiController -VM $VM | where {$_.Type -eq "Paravirtual"} | Set-ScsiController -Type VirtualLsiLogicSAS 
	Start-VM -VM $VM
	
}

A bug in the vSphere Client?!

During the ICM course that I was co-teaching last week i found a bug (I think) in the vSphere Client.

When I have installed a windows 2003 virtual machine and also deployed the VM tools i can configure the behavior of the power controls when editing the properties.

The interesting part here is that when i open the virtual machine console, although as you can see that i have set it to “Shut Down guest”, when i press that button in the virtual machine console i get a question about if i am sure that i want to turn it off, this as you can see on my next screenshot. And some of you will say, oh your tools are not running, that is why you get this, but…

If i use the power controls in the vSphere Client i get the following confirmation, that is the correct one ( I have not restarted or done anything other than change to the Client instead of the virtual machine console)

The strange thing is that it is not consistent this error and some times in the virtual machine console the stop button works as expected.

Anyone else seen this?

Updated VMware vSphere FT (Fault Tolerance) function for PowerCLI

After this week when i have been co-teaching a VMware vSphere ICM course i was going to show the students FT and I was seeking in the powerCLI reference for some cmdlets but could not find any.

I created my own function for enabling this, i got inspiration from Cody Bunch post but extended it with a function and also with my function you can disable/enable/remove and test restart/failover the secondary vm. I also check if the FT is enabled or not before making any changes.

Here is the PowerCLI function, i am using some Get-View to be able to use the FT functions.

Updated: Today (Monday 27/2) i added functionality with a possibility to also send VMHost as argument, but then i realized some errors occuring, my assumtions that the primary VM always was the first object when doing a Get-VM was false, i have corrected the function that it actually checks for the correct VM, Primary or Secondary. If you do not send VMHost parameter the FT process will choose a Host for you, this cannot be the same as the Primary VM resides on.

function Set-VMFaultTolerance{
<#
.SYNOPSIS
Enable FT for the VM sent as parameter

.DESCRIPTION
Use this function to enable or disable Fault Tolerance

.PARAMETER  xyz 

.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-02-27
#>
    param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="A virtual machine",
    ValueFromPipeline=$True)]
    $VM,
	$VMHost = $null,
	[switch]$enableFT,
	[switch]$disableSecondaryFT,
	[switch]$removeFT,
	[switch]$failOverFT,
	[switch]$restartSecondaryFT
    )
	if ($VM.ExtensionData.Config.FtInfo -ne $null){
		$VM = Get-VM $VM | where {$_.Extensiondata.Config.FtInfo.Role -eq 1}
	} else {
		$VM = Get-VM $VM
	}
	if ($VMHost -ne $null){
		$VMHost = Get-VMHost $VMHost | Get-View
		if ($VMHost -ne $null) {
			$VMHostobj = New-Object VMware.Vim.ManagedObjectReference
			$VMHostobj.type = "HostSystem"
			$VMHostobj.value = $VMHost.MoRef.Value
			$VMHost = $VMHostobj
		}
	}

	if ($enableFT) {
		if ($VM.ExtensionData.Config.FtInfo -eq $null){
			$VMview = $VM | Get-View
			$VMview.CreateSecondaryVM($VMHost)
		} else{
			$VMsec = Get-VM $VM.Name | where {$_.Extensiondata.Config.FtInfo.Role -eq 2}| Get-View
			$VMobj = New-Object VMware.Vim.ManagedObjectReference
			$VMobj.type = "VirtualMachine"
			$VMobj.value = $VMsec.MoRef.Value
			$VMview = $VM | Get-View
			$VMview.EnableSecondaryVM($VMobj, $null)
		}
	}elseif ($disableSecondaryFT) {
		if ($VM.ExtensionData.Config.FtInfo -ne $null){
			$VMsec = Get-VM $VM.Name | where {$_.Extensiondata.Config.FtInfo.Role -eq 2 -and $_.PowerState -eq "PoweredOn"}| Get-View
			if ($VMsec -ne $null){			
				$VMobj = New-Object VMware.Vim.ManagedObjectReference
				$VMobj.type = "VirtualMachine"
				$VMobj.value = $VMsec.MoRef.Value
				$VMview = $VM | Get-View
				$VMview.DisableSecondaryVM($VMobj)
			}else {
				Write-Host "The Secondary is already disabled"
			}
		}else {
			Write-Host "This VM is not FT enabled"
		}
	}elseif ($failOverFT) {
		if ($VM.ExtensionData.Config.FtInfo -ne $null){
			$VMsec = Get-VM $VM.Name | where {$_.Extensiondata.Config.FtInfo.Role -eq 2 -and $_.PowerState -eq "PoweredOn"}| Get-View
			if ($VMsec -ne $null){
				$VMobj = New-Object VMware.Vim.ManagedObjectReference
				$VMobj.type = "VirtualMachine"
				$VMobj.value = $VMsec.MoRef.Value
				$VMview = $VM | Get-View
				$VMview.MakePrimaryVM($VMobj)
			}else {
				Write-Host "The Secondary is disabled"
			}
		}else {
			Write-Host "This VM is not FT enabled"
		}
	}elseif ($restartSecondaryFT) {
		if ($VM.ExtensionData.Config.FtInfo -ne $null){
			$VMsec = Get-VM $VM.Name | where {$_.Extensiondata.Config.FtInfo.Role -eq 2 -and $_.PowerState -eq "PoweredOn"}| Get-View
			if ($VMsec -ne $null){
				$VMobj = New-Object VMware.Vim.ManagedObjectReference
				$VMobj.type = "VirtualMachine"
				$VMobj.value = $VMsec.MoRef.Value
				$VMview = $VM | Get-View
				$VMview.TerminateFaultTolerantVM($VMobj)
			}else {
				Write-Host "The Secondary is disabled"
			}
		}else {
			Write-Host "This VM is not FT enabled"
		}
	}elseif ($removeFT){
		if ($VM.ExtensionData.Config.FtInfo -ne $null){
			$VMview = Get-VM $VM | where {$_.Extensiondata.Config.FtInfo.Role -eq 1}| Get-View
			$VMview.TurnOffFaultToleranceForVM()
		} else {
			Write-Host "This VM is not FT enabled"
		}
	} 

}

 

Updated powerCLI function for setting HA Admission control policy in percent with number of hosts

I got the question from a colleague if i could add a parameter in my function, no problem, just some dividing..

So you can either set percent CPU/Memory or number of hosts and from that get a percent on the policy. I have not taken care of the case if you have more than 100 hosts in your cluster (as this is not possible, at least not yet 😉 )

function Set-HAAdmissionControlPolicy{
<#
.SYNOPSIS
Set the Percentage HA Admission Control Policy
 
.DESCRIPTION
Percentage of cluster resources reserved as failover spare capacity
 
.PARAMETER  Cluster
The Cluster object that is going to be configurered 

.PARAMETER numberHosts
When this parameter is set the percentage is set based on number of hosts in cluster
 
.PARAMETER percentCPU
The percent reservation of CPU Cluster resources
 
.PARAMETER percentMem
The percent reservation of Memory Cluster resources
 
.EXAMPLE
PS C:\> Set-HAAdmissionControlPolicy -Cluster $CL -percentCPU 50 -percentMem 50
 
.EXAMPLE
PS C:\> Get-Cluster | Set-HAAdmissionControlPolicy -percentCPU 50 -percentMem 50

.EXAMPLE
PS C:\> Set-HAAdmissionControlPolicy -Cluster $CL -numberHosts 5
 
.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-01-25
#>
   param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="This need to be a clusterobject",
    ValueFromPipeline=$True)]
    $Cluster,
	[int]$numberHosts = 0,
    [int]$percentCPU = 25,
    [int]$percentMem = 25
    )
 
    if(Get-Cluster $Cluster){
 
        $spec = New-Object VMware.Vim.ClusterConfigSpecEx
        $spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
        $spec.dasConfig.admissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
		if($numberHosts -eq 0){
        	$spec.dasConfig.admissionControlPolicy.cpuFailoverResourcesPercent = $percentCPU
        	$spec.dasConfig.admissionControlPolicy.memoryFailoverResourcesPercent = $percentMem
 		}else{
			$spec.dasConfig.admissionControlPolicy.cpuFailoverResourcesPercent = 100/$numberHosts
        	$spec.dasConfig.admissionControlPolicy.memoryFailoverResourcesPercent = 100/$numberHosts
		}
        $Cluster = Get-View $Cluster
        $Cluster.ReconfigureComputeResource_Task($spec, $true)
    }
}

powerCLI function to set HA Admission Control Policy in percent

I am attending a VMware vSphere ICM 5 course this week, this because I am planning to become a VCI.

As I am a bit of PowerCLI fan i am trying to do all the labs in the course from the powerCLI console 🙂

In the HA laboration i found that the default implementation of the powerCLI does not allow you to set the HA Admission Control Policy Percentage, only the Host failure the cluster tolerates, here is a link to the powerCLI reference page for Set-Cluster. In the slides VMware recommends that you set percentage in a HA setup.

This led me to develop a powerCLI function that can configure this. The function has a default value for CPU and Memory that is 25 %, so if you only give the Cluster parameter the Capacity setting will be 25 %.

function Set-HAAdmissionControlPolicy{
<#
.SYNOPSIS
Set the Percentage HA Admission Control Policy

.DESCRIPTION
Percentage of cluster resources reserved as failover spare capacity

.PARAMETER  Cluster
The Cluster object that is going to be configurered 

.PARAMETER percentCPU
The percent reservation of CPU Cluster resources

.PARAMETER percentMem
The percent reservation of Memory Cluster resources

.EXAMPLE
PS C:\> Set-HAAdmissionControlPolicy -Cluster $CL -percentCPU 50 -percentMem 50

.EXAMPLE
PS C:\> Get-Cluster | Set-HAAdmissionControlPolicy -percentCPU 50 -percentMem 50

.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-01-19
#>
   param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="This need to be a clusterobject",
    ValueFromPipeline=$True)]
    $Cluster,
    [int]$percentCPU = 25,
    [int]$percentMem = 25
    )
    
    if(Get-Cluster $Cluster){
    
        $spec = New-Object VMware.Vim.ClusterConfigSpecEx
        $spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
        $spec.dasConfig.admissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
        $spec.dasConfig.admissionControlPolicy.cpuFailoverResourcesPercent = $percentCPU
        $spec.dasConfig.admissionControlPolicy.memoryFailoverResourcesPercent = $percentMem
    
        $Cluster = Get-View $Cluster
        $Cluster.ReconfigureComputeResource_Task($spec, $true)
    }
}

Here is a screenshot when running the function

Check number of running VMs on datastores

If you are running too many VM´s on your datastores in your vSphere environment you can have some problems, this if your SAN is not VAAI compliant and can handle SCSI locking etc.

Alan Renouf has made a blog post about how to get a report about how many VM´s you have on every datastore, I have extended to only report on running VM´s as these are the interesting number..

Get-Datastore | Select Name, @{N="NumVM";E={@($_ | Get-VM | where {$_.PowerState -eq "PoweredOn"}).Count}} | Sort Name | Export-Csv -Path C:\temp\vms-datastore.csv -NoTypeInformation -UseCulture

And the report loooks like this when imported into excel

Use of PowerCLI and invoke-script to get HAL running of Windows VM´s

I was thinking of how to get an report after reading about the converter best practice from Vladan and he also has this blog post about how to change the HAL, but first i want to know what running guests are there that has the wrong HAL running. I have selected to get an report out of the running windows 2003 ( windows 2008 and later has an uniform HAL that is the same for one or more cpu´s).

I have made an little script somewhat alike to Alan Renouf´s to get the HAL of the VM guest running in your environment, the difference in my approach is that i use invoke-script and get the info from inside the VM, as i have a case where the VMs are isolated and i can not get the wmi info from the network, Arnim Van Lieshout has made one blog post about  running wmi queries this way.

 

# Check the HAL in the VM with invoke-VMScript
#
# Niklas Akerlund / RTS

$VMs = Get-VM | Where {$_.Guest.OSFullName -eq "Microsoft Windows Server 2003 Standard (32-bit)" -and $_.PowerState -eq "PoweredOn"}
$guestcred = get-Credential
$report = @()

foreach ($VM in $VMs){
    $HAL = Invoke-VMScript "wmic path Win32_PnPEntity WHERE ""DeviceID='ROOT\\ACPI_HAL\\0000'"" GET NAME /VALUE" -VM $VM -GuestCredential $guestcred -scripttype "bat"
	$HAL = $HAL.Split('=')[1]
    $data = New-Object PSObject -property @{
        VMName=$VM.Name
        vCPUs=$VM.NumCPU
        HAL=$HAL.Trim('')
    }
    $report +=$data
}

$report | Export-Csv -path c:\temp\hal4.csv -NoTypeInformation -UseCulture

And the simple report looks like this:

 

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

Hi

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{
    param($vm)
	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 😀