Configuring Nested Hyper-V on ESXi 5.5

In order to allow for installation of a nested Hyper-V on ESXi 5.5, there is a requirement to configure the virtual machine settings once the guest operating system has been deployed.

Firstly, we need to add two items to the existing virtual machine configuration file in a powered off state. Prior to making these changes we will make a backup of the current virtual machine configuration in the event we need to roll back.

cp /vmfs/volumes/<datastore>/<virtual machine>.vmx /vmfs/volumes/<datastore>/<virtual machine>.vmx.backup

In order to  enable nested Virtualization Technology to run 64-bit virtual machines the following is required to added to the configuration file using a text editor.

vhv.enabled = "TRUE"

Now in order to run a hypervisor inside a virtual machine, we will add the following item to override the default setting.  This prevents the error message “Hyper-V cannot be installed: A hypervisor is already running” if you attempt to install the Hyper-V server role in the guest operating system.

hypervisor.cpuid.v0 = "FALSE"

Finally, we need to expose hardware virtualization to the guest operating system so that the processors support the required virtualization capabilities. If you do not expose the hardware virtualization you will receive the error message “The processor does not have the required virtualization capabilities” on installing the Hyper-V server role.

This can be performed using the vSphere Web Client to edit the virtual machine CPU settings as below:

 

VMHyperVCPUSettings

 

Once , the above configuration changes have been applied to the virtual machine you should be able to install the Hyper-V server role.

 

 

Advertisements

Monitor WUInstall status in Nagios XI

I recently wrote about checking the last success time of Windows Update and reporting this to Nagios (http://wp.me/p15Mdc-mj). Now what happens if you do not use Windows Update as your patch management solution. In my case I have been managing the installation of updates using WUInstall (http://www.wuinstall.com).

When my updates are installed the registry is not updated to reflect the last success time, therefore how can I monitor the last time updates were run and the status? The command line tool WUInstall provides the functionality to write the console output to a log file, in the below example each log file is written to a shared folder.

As per the previous example, I want to report if any updates have been installed in a particular time-span and if the process was successful.

In the case of the time-span this would be dependent on the host being monitored and therefore this period would be specified as a mandatory parameter when invoking the powershell script which was to be used as the check plugin within Nagios.

Param ([parameter(Mandatory = $true)][string] $Days)

Now I want to return the most recent log file for the host being monitored from the shared folder, where the log file name is that of the host and is contained in a parent folder based on the date the process was invoked. By using the Get-ChildItem cmdlet with the recurse option I am able to retrieve the most recent log file by sorting by the LastWriteTime in descending order and selecting the first file. I will return the full name of the file to a variable to pass to the Get-Content cmdlet for reading.

$LogFile = (Get-ChildItem "\\Server\Share\Logs" -Recurse | Where-Object {$_.Name -like "$env:computername*"} | Sort LastWriteTime -Descending | Select -First 1).FullName

In order to read the content of the log file we will need to encode this in Unicode format, and then search for the string ‘Overall’. In order to retrieve the overall result code we will return the next line from the content and store this as a variable.

$Log = Get-Content $LogFile -Encoding Unicode | Select-String "Overall" -Context 0,1 | % {$_.Context.PostContext}

In order to get the last run time the datetime function will be used to parse the date in the string to return the first ten characters which contain the date and the modify the date string to be in the format ‘dd/MM/yyyy’.

$LastRun = [datetime]::ParseExact($Log.Substring(0,10) , "yyyy/MM/dd", $null)
$LastRun = $LastRun.ToString("dd/MM/yyyy")

Now that we have the last run time and the result code in the log variable we can use conditional logic to set the status of the service. Firstly we will check to see if the last run date is greater or equal to the timespan value specified in the mandatory days field by subtracting this from the current date and if the result code is like ‘Succeeded’ return the service status as ‘OK’

If ($LastRun -ge (get-date).AddDays(-$Days) -and $Log -like "*Succeeded*")
   { 
   $resultcode = "0"
   }

If the last run date is less than the time-span value but the result code is like ‘Succeeded’ we will return the service status as ‘OK’.

ElseIf ($LastRun -lt (get-date).AddDays(-$Days) -and $Log -like "*Succeeded*")
   { 
   $resultcode = "1"
   }

If the result code is not like ‘Succeeded’ we will return the service status as ‘Critical’.

ElseIf ($Log -notlike "*Succeeded*")
   { 
   $resultcode = "2"
   }

If we are unable to retrieve any information required in the conditional logic the service status will be returned as ‘Unknown’.

Else
   { 
   $resultcode = "3"
   }

Finally, we will set a status information meessage based on the result code where the substring function is invoked on the  log variable to remove the first twenty characters of the string which contains timestamp information and to include the last run time and terminate the powershell session to return the exit code for the service status.

$Log.Substring(20,$Log.Length-20) + " at " + $LastRun
exit $returncode

Once a check_nrpe command has been configured in Nagios (http://wp.me/p15Mdc-eC) and you begin to monitor your host(s), you should see a service check as below:

WindowsUpdateStatusNagios

You can also run the above in Windows Powershell, to return the status information as below:

PowershellStatusWindowsUpdate

The full powershell script can be downloaded from: https://app.box.com/s/cc2pkvx9a10g5ww6ha0i 

Enabling WinRM service using Group Policy

In order to remote manage your remote computers using Windows Powershell, there is a requirement to enable the WinRM service on each target.

This may be enabled by browsing to the below group policy setting path and enabling ‘Allow automatic configuration of listeners:

Computer Configuration/Policies/Administrative Templates/Windows Components/Windows Remote Management (WinRM)/WinRM Service

You may restrict the clients that may connect to the listener by filtering IPv4 and IPv6  addresses, use a wildcard (“*”) to allow all IP addresses or a null value would listen on no IP addresses.

If you have Windows Firewall enabled, you will also need to enable inbound connections for the WinRM Service by enabling TCP service port 5985.

Automating the simulation of random memory workloads using TestLimit utility with Powershell

I was recently looking at simulating memory usage across a number of VMs where the utilisation pattern, time duration of the memory load and idle time between workloads would be random.

I was looking at using the Sysinternals TestLimt utility to achieve this by invoking a leak and touch memory to simulate resource usage.

As I wanted to generate random values I will be using the Get-Random cmdlet to use a value specified in a minimum and maximum range.

One of the requirements of this script is to simulate memory resource usage in a continuous loop, this is achieved by providing the While statement for a condition that is always true.

While ($True)
   {

I will then generate a random values for the duration to run the TestLimit utility and the percentage of memory usage to touch where a minimum and maximum value is specified to the Get-Random cmdlet.

$Date = Get-Date
$Minutes = Get-Random -Minimum 20 -Maximum 120
$Duration = $Date.AddMinutes($Minutes)
$Utilisation = Get-Random -Minimum 20 -Maximum 60

As I specifying memory utilisation as a percentage, I will need to calculate this from the total physical memory configured on the host and truncate to round towards zero. The TestLimit utility requires that memory objects are specified in MB, so the value will be converted following the percentage calculation.

$ComputerSystem = Get-WmiObject Win32_ComputerSystem 
$Memory = [math]::truncate($ComputerSystem.TotalPhysicalMemory /100 * $Utilisasation

Now that I have the values I wish to pass as arguments to the TestLimit utility for the amount of memory to touch and leak, I will start the process, where TestLimit will leak and touch memory pages (-d) with a total amount of memory generated from the above calculation (-c), where the working directory of the utility is ‘C:\TestLimit’.

Start-Process testlimit64.exe -ArgumentList "-d -c $Memory" -workingdirectory "C:\TestLimit"

As I want to run the process only for a period of time specified until the current date is greater or equal to the random duration value generated, the powershell script will be paused using the Start-Sleep cmdlet to check the current date every 60 seconds and to compare that to the duration.

Do
   { 
   Start-Sleep -Seconds 60
   }
Until ((Get-Date) -ge $Duration

Once the current date is greater or equal to the duration string the process testlimit64 will be terminated and the script will then be paused for a random period of time generated from the minimum and maximum value. Once the script is resumed, the script block will be invoked again as we want this process to run in a continous loop.

Get-Process | Where-Object {$_.Name -eq "testlimit64"} | Stop-Process
$Sleep = Get-Random -Minimum 180 -Maximum 720
Start-Sleep -Seconds $Sleep 
}

In this instance the powershell script is invoked by a scheduled task at computer startup. The full script can be downloaded from:

https://app.box.com/s/lq0b6r9srjs5nmm55cta

The TestLimit utility can be downloaded from:

http://live.sysinternals.com/WindowsInternals/testlimit64.exe

Windows Server 2008 R2 Service Pack 1 fails with 800F0818

I was recently attempting to run Windows Server 2008 R2 Service Pack 1, which would fail with the error code 800F0818 due to Windows Update corruption.

In order to resolve the issue, run the System Update Readiness tool and then install the service pack.

The System Update Readiness tool is available from http://support.microsoft.com/kb/947821.

Patch Management for guest VMs with Windows Update Server and WuInstall on vSphere

I previously detailed steps to automate approved updates from a WSUS server with WUInstall (https://deangrant.wordpress.com/2013/09/24/patch-management-with-windows-update-server-and-wuinstall/) which focused on installing updates on Amazon Web Services EC2 instances.

I have recently modified the process to take into account VM guests in a vSphere environment ,using the same process of client side targeting and executing WuInstall on the remote machine, also with the following requirements:

  • Create a snapshot of the guest VM specified in the collection and add the name ‘Windows Update on ddMMyyyyHHmm’.
  • Once the snapshot is completed, invoke WuInstall to install the approved updates.

In order to target the guest VMs to which I wish to install the approved updates I am using custom attributes to determine the environment and if updates are enabled, as below:

Name Value
Environment DEV | TST | PRE | PRD
Windows Update Yes | No

As the script will target guest VMs in a number of environments, the script defines a mandatory parameter for an expected Environment value.

Param ([Parameter(Mandatory=$true)][string] $Environment)

In order to invoke the script there is a dependency on the Mware vSphere PowerCLI snap-in (https://www.vmware.com/support/developer/PowerCLI/) and for this to be imported into the current powershell session.

If (-not (Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue)) 
{
Add-PSSnapin VMware.VimAutomation.Core > $null
}

I will also generate a date string to be used in the snapshot name.

$Date = (get-date).toString('ddMMyyyyHHmm')

Now, we will establish a connection to the vCenter server.

Connect-VIServer <server name or ip address> > $null

We will now be required to filter the guest VMs where the custom attribute ‘Environment’ is equal to the mandatory parameter specified.

$VMs = Get-VM | Get-Annotation -CustomAttribute "Environment" | Where-Object {$_.Value -eq $Environment}

For each guest VM that is returned in the collection we will compare the ‘WindowsUpdate’ custom attribute and if this is equal to ‘Yes’ create a snapshot of the  guest VM with the name ‘Windows Update on ddMMyyyyHHmm’ and invoke the WuInstall to install the approved updates.

ForEach ($VM in $VMs)
{ 
$WindowsUpdate = Get-VM $VM.AnnotatedEntity.Name | Get-Annotation -CustomAttribute "WindowsUpdate" | Where-Object {$_.Value -eq "Yes"}
If ($WindowsUpdate.Value -eq "Yes")
{
New-Snapshot -VM $VM.AnnotatedEntity.Name -Name ("Windows Update on " + $Date)
$Hostname = $VM.AnnotatedEntity.Name
$Command =  "& 'C:\Program Files (x86)\SysinternalSuite\PsExec.exe' \\$Hostname -c -f -s \\<Server>\>Share>\Tools\WUInstall.exe /install /autoaccepteula /reboot_if_needed /logfile \\<Server>\<Share>\Logs\WUInstall_$Hostname.log"
Invoke-Expression $Command
}
}

Once completed the connection to the vCenter server will be terminated.

Disconnect-VIServer -Server <server name or ip address> -Confirm:$False

In order to invoke the script run the following:

./Invoke-WindowsUpdate.ps1 - Environment <Environment Attribute>

The script will require the user account invoking the script to have ‘Virtual Machine Power Users’ role, to which I cloned the built-in role and local administrator privelages on each guest VM to install the approved updates.

The full Windows Powershell script can be downloaded from the below link:

https://app.box.com/s/d7fp1qapfmp9un05f0x5