PowerShell to check Automatic Windows services after patch Tuesday

I did not get this idea all by my self, a customer I was at for a couple of weeks ago showed me a small script he had to check the services set to automatic after patching to see that they actually was running again.

I thought this could be somewhat more sophisticated done, so I created a script function that can handle single servers or an array of servers and in the script you can either start all services that are stopped or select just the ones you want, you can also in the function add services that you know are not important.

As you can see, I can get the servers from the Active Directory, In this example I have created a OU that contains the servers I want to check. I can also check for example in VMware with PowerCLI and getting an array of running VM´s. This can also be done on my Hyper-V environment with SCVMM. The different arrays I collect is just to get the server names and then I do an Get-wmiObject on the servers.

Here in this screen dump I check the computers in my AD, As you can see I select (N)o and that mean that I want all services that are not running and set to automatic to be started

In this next example I check the VM´s in my VMware vSphere environment

In this last example where i query a SCVMM server for the VM´s on the Hyper-V cluster I use the -AutoRestart parameter to start up all the services that the function finds.

And here is the powershell function, the tricky part here was to get the starting of services remote working and I had to use the -InputObject command as I did not get the pipeline of Get-Service -Computer xyz -Name Spooler | Start-Service to work.

function Check-Service{
<#
.SYNOPSIS
Check if Autostart Services has not started after patching

.DESCRIPTION
Use this function to check that all autostart services have started on the servers after patching

.PARAMETER  xyz 

.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-05-28
#>
    param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="A server",
    ValueFromPipeline=$True)]
    $Servers,
	[switch]$AutoRestart
    )
	
	$report = @()
	$IgnoreServices = "ShellHWDetection","clr_optimization_v4.0.30319_32","clr_optimization_v4.0.30319_64","sppsvc"
	
	if ($Servers.GetType().Name -eq "String"){
		$Services = Get-WmiObject -ComputerName $Servers -Class win32_service -ErrorAction SilentlyContinue | where {$_.Startmode -EQ "Auto" -and $_.State -NE "Running"}
		if ($Services -ne $null) {
			foreach ($Service in $Services){
				if(!($IgnoreServices -contains $Service.Name)){
					$data = New-Object PSObject -property @{
						Server = $Servers
						Name = $Service.Name
						StartMode = $Service.StartMode
						State = $Service.State
					}
				
				$report +=$data
				}
			}
		}
	}else{
		foreach ($Server in $Servers){	
			$Services = Get-WmiObject -ComputerName $Server.Name -Class win32_service -ErrorAction SilentlyContinue | where {$_.Startmode -EQ "Auto" -and $_.State -NE "Running"}
			if ($Services -ne $null) {
				foreach ($Service in $Services){
					if(!($IgnoreServices -contains $Service.Name)){
						$data = New-Object PSObject -property @{
							Server = $Server.Name
							Name = $Service.Name
							StartMode = $Service.StartMode
							State = $Service.State
						}
					
					$report +=$data
					}
				}	
			} else {
				Write-Host "Could not query server: $Server"
			}
		}
	}
	
	$report 
	if($AutoRestart){
			$report |%{ Start-Service -InputObject (Get-Service -ComputerName $_.Server -Name $_.Name)}
	}else{
		if($report -ne $null){
			Write-Host "Do you want to select which services to start? (Y) (N) (Q):"
			$select = Read-Host
			if ($select -eq "Y"){
				foreach ($item in $report){
					Write-Host "Start service " $item.Name " on server" $item.Server " (Y) (N)"
					$restart = Read-Host
					if ($restart -eq "Y"){
						Start-Service -InputObject (Get-Service -ComputerName $item.Server -Name $item.Name)
					}
				}
			}elseif($select -eq "N"){
				$report |%{ Start-Service -InputObject (Get-Service -ComputerName $_.Server -Name $_.Name)}
			}
		}
	}
}

Good luck in finding services that should be running in your environment 🙂
 

VMware vSwitch ports massage with PowerCLI

This week I have been teaching my first vSphere 5 ICM, I have been trying to show the students the wonderful world of PowerCLI and all good you can do with it.

When we got to the virtual networking I tested if I could add a switch with any number of ports

get-vmhost esxi01* | New-VirtualSwitch -Name TestNumPorts -NumPorts 12 -Nic vmnic0

When I try to add 12 ports with the -NumPorts parameter, powerCLI tells me that my switch has been created with 16 ports, but look here in my vSphere Client screen dump

hmm smells like a bug? or ?

Well now I wanted to test if I could add more than 4 VM´s and connect them and then start them, first I have to create a Portgroup that i can connect and then a nice for loop to create 10 VM´s

get-vmhost esxi01* | Get-VirtualSwitch -Name TestNumPorts | New-VirtualPortGroup -Name Test

for ($i=1;$i -le 10;$i++){New-VM -VMHost (Get-VMHost esxi01*) -Name ("VM01" + $i) -Datastore (Get-Datastore delad02) -NetworkName Test}

The last  oneliner creates a standard VM with 256 MB ram and a 4 GB vmdk disk, and then I want to start them to actually connect them to the network I created to see if anyone of them does not get connected.

So to get them connected I start them

And check the last command where we can see that my number of available ports has not decremented?

Here you can see in the vSphere client that all my new VM´s are connected to the Test portgroup

In this screenshot you can see why my vSwitch got 16 ports (as 8 are allocated by the vmkernel) and the options are 8/24/56/120/248/504/1016 and so on, but still it does not explan why the powercli does not show that i have used 10 of the ports, or?

To see maybe what causing this I changed the number of ports to one of the “allowed” and when I changed the number to 16 ports, directly my free ports changed to 4, but I have 10 machines + 8 reserved?

The following powerCLI command shows the VM´s and if they are connected if you do not believe the gui 😉

Get-VM VM01* | Get-NetworkAdapter | select parent, connectionstate

 

The conclusion is that I have no answer if this is as it should be or if it is a bug, maybe someone out there could clarify 🙂

Now time to prepare for tomorrow and the modules in the course 🙂

Shrink HyperV virtual hard disk Win8 / Win2012 with PowerShell

I read this post by Ben (Virtual PC Guy) Armstrong about shrinking a virtual hard disk and thought this should be done with powershell.

So first I have to shrink the partition inside the VM, for this I use the New-CIMSession (instead of powershell remoting and such) and then I shut down the VM and shrink the VHDx file, As someone correctly noted, this shrink of the virtual disk file is only possible when using the new VHDx format.

The VM is part of the same domain as the hyper-V server from which I am running the script, this made it easier to make a cim connection. The VM is also a Win 8 beta cause I need the latest win framework with powershell 3.

As you can see, the disk in my VM is 60 GB and I want to shrink it to the minimum size * 20% (so i get at least some space left 😉

Now I will run my little script and here is what that looks like

# vNiklas Masterblaster shrink
#
# Niklas Akerlund / 2012-05-13

$VM = "Shrink8"

$cim = New-CimSession $VM

$partitionC = Get-Partition -CimSession $cim -DriveLetter C

$newSize = ($partitionC | Get-PartitionSupportedSize).SizeMin*1.20

Resize-Partition -PartitionNumber $partitionC.PartitionNumber -DiskNumber $partitionC.DiskNumber -Size $newSize -CimSession $cim

Get-Volume C -CimSession $cim

$VM = Get-VM $VM

Stop-VM $VM

$hdd = $VM | Get-VMHardDiskDrive

Resize-VHD -Path $hdd.Path -ToMinimumSize

Start-VM $VM

And here you can see the result, a quite simple solution..

Good luck in your shrinking 🙂

Update:  I totally missed that Ben had done a post about doing it with powershell, just after his other post when i was making this post… At least my solution show how to connect to a VM with CIM 🙂

 

Bare metal deploy with SCVMM 2012 fail with error 800b0109 in WinPE

Today I was at a customer and upgraded their VMM 2012 from RC to RTM. We got an issue when trying to run a bare metal deploy after the upgrade, at first we did not understand what was causing the error, but my suspicion was on the winpe that was published by VMM in the WDS PXE.

Here is the error in the VMM Console also

And then i used PowerShell to update the VMM WinPE that resides in the WDS, this because their environment had new HP blades and i needed to add a nic driver. If you do not need to add anything to the winpe you can right click on the VMM console and the PXE  and you find a selection “Update WinPE Image” this will use an image from the WAIK installed on the VMM Server. Here is the link for the powershell cmdlet that updates the WinPE

The Powershell I ran was as below, I had to run the dism tools with elevated rights, this can be done by right click on the Powershell console and “Run As Administrator”

Import-Module "C:\Program Files\Microsoft System Center 2012\Virtual Machine Manager\bin\psModules\virtualmachinemanager\virtualmachinemanager.psd1"
Get-SCVMMServer localhost
$mountdir = "E:\mount"

$winpeimage = "E:\temp\custom_winpe.wim"

$winpeimagetemp = $winpeimage + ".tmp"

mkdir "E:\mount"

copy $winpeimage $winpeimagetemp

dism /mount-wim /wimfile:$winpeimagetemp /index:1 /mountdir:$mountdir

$path = "E:\temp\drivers\be2nd62.inf" # $driver.sharepath
dism /image:$mountdir /add-driver /driver:$path

Dism /Unmount-Wim /MountDir:$mountdir /Commit

publish-scwindowspe -path $winpeimagetemp

Here is a link to the technet forum where I found another guy having the same issue, whom I helped.

After updating the WinPE we tried to do a new bare metal deploy and this time we had no issues with the certificate.

 

PowerCLI report on datastores, overprovision and number of powered on VM´s

Today I had an reason for running PowerCLI again, the case was to get an quick report on the datastores at a customer, I have made a post about the one-liner that get the number of running VM´s on a datastore. As i described in that post, if your SAN does not support VAAI then you do not want to many VM´s on each datastore because of the SCSI-locking that can occur. This is just an extension of that because we also wanted to check how overprovisioned the datastores was (when using thin provisioning there is a risk that you will fill your datastores as the VM´s fill their vmdk disk´s)

The PowerCLI code looks like this

Get-Datastore | Select Name,@{N="TotalSpaceGB";E={[Math]::Round(($_.ExtensionData.Summary.Capacity)/1GB,0)}},@{N="UsedSpaceGB";E={[Math]::Round(($_.ExtensionData.Summary.Capacity - $_.ExtensionData.Summary.FreeSpace)/1GB,0)}}, @{N="ProvisionedSpaceGB";E={[Math]::Round(($_.ExtensionData.Summary.Capacity - $_.ExtensionData.Summary.FreeSpace + $_.ExtensionData.Summary.Uncommitted)/1GB,0)}},@{N="NumVM";E={@($_ | Get-VM | where {$_.PowerState -eq "PoweredOn"}).Count}} | Sort Name | Export-Csv -Path C:\temp\vmds-datastore.csv -NoTypeInformation -UseCulture

And this is when i have run it on my test system, the difference here is that i removed the Export-CSV to get the output in the console

And here is a simple excel report

 

VMware vCloud Director vApp and DRS cluster affinity with PowerCLI

To fully utilize the performance in a vApp in vCloud Director I got the task to create an affinity rule based on the VMs in the vApp. This can be the case for example when you have VMs in an vApp that exchange high loads of data. In our case we have virtual ESXi Servers that have a vsa for shared storage and need good performance when deploying VM´s and storage vMotion etc.

When deploying several vApps from the same template it is not just to run Get-CIVM and then use the VM name returned to run Get-VM for the correlation between the VM in VCD and in vCenter, as you can see in the screendumps these two have the same name but followed with an identifier from vCD in the vSphere Client. This is also described in the vSphere blog.

The fine part is that the MoRef is unique (in the relation one vcd <-> one vcenter) so I can check on that which VMs in the vCenter belongs to the same vCloud Director vApp.

I got the code for the MoRef in this community post.

And here is my script

<#
.Synopsis
   Add an affinity rule for a vCloud Director vAPP
.DESCRIPTION
   This function takes a vApp as parameter and creates an affinity rule for them to keep them together
.EXAMPLE
   Add-CIVAppAffinity -CIVApp Green01
.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-05-03
#>
function Add-CIVAppAffinity
{
    Param
    (
        # Parameter for the vAPP
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $CIVApp,

        # If the rule should apply on a different cluster
        $Cluster = "vCD-Cluster"
    )

	$pod = Get-CIVapp $CIVApp
	if ($pod){
		$PodVMs = Get-CIVM -VApp $pod
		$VMs = @()
		$Cluster = Get-Cluster $Cluster
		Foreach ($PodVM in $PodVMs) { 
			$VMname = $PodVM.Name + "*"
			$VM =  Get-VM $VMname | where {$_.ExtensionData.MoRef.Value -eq $PodVM.ExtensionData.VCloudExtension[0].Any[0].VmVimObjectRef.MoRef}
			$VMs +=$VM
		}

		if (!(Get-DrsRule -Cluster $Cluster -Name $pod.Name -ErrorAction SilentlyContinue)){ 
			New-DrsRule -Name $pod.Name -Cluster $Cluster -KeepTogether $true -VM $VMs
		}else{
			Remove-DrsRule -Rule (Get-DrsRule -Cluster $Cluster -Name $pod.Name) -Confirm:$false
			New-DrsRule -Name $pod.Name -Cluster $Cluster -KeepTogether $true -VM $VMs
		}
	}
}

And when checking the cluster i can see that my DRS affinity rule has been created and the VMs have been migrated to the same host

It is not so extensive but it helps us with the case to create DRS affinity on the VMs in a particular vApp 🙂 , The Rule is deleted when the vApp is removed, I have an extra check in the script and remove it if it still exist of some reason.