Category Archives: Hyper-V

Monitoring with PowerShell Chapter 3: Hyper-v state

We managed a whole lot of hyper-v servers for our clients, including large clusters but also smaller single server solutions. This makes it difficult to make sure that everyone creates VM’s as they should, and sometimes mistakes are made by engineers or backup software that cause a checkpoint to be left on a production server.

To make sure we don’t get problems along the way we use the following monitoring sets.

Monitoring checkpoints, Snapshots, AVHD’s

We monitor each VM for running checkpoints and snapshots by running the following script. This checks if a snapshot is older than 24 hours and creates an alert based on this. If no snapshots are found it reports that the snapshot state is healthy

$snapshots = Get-VM | Get-VMSnapshot | Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-1) }
foreach($Snapshot in $snapshots){
$SnapshotState += "A snapshot has been found for VM $($snapshot.vmname). The snapshot has been created at  $($snapshot.CreationTime)  `n"
}
if(!$SnapshotState) { $snapshotstate = "Healthy"}

we used this monitoring set for a while, but then found that we had some servers that got restored from a backup that did not have a snapshot available, but did run on an AVHX. That can cause issues as the AVHDX can grow without you noticing as it doesn’t have a complete snapshot available. To also monitor AVHDX’s we’re using the following set

$VHDs = Get-VM | Get-VMHardDiskDrive
foreach($VHD in $VHDs){
if($vhd.path -match "avhd"){ $AVHD += "$($VHD.VMName) is running on AVHD: $($VHD.path) `n"}
}
if(!$AVHD){ $AVHD = "Healthy" }

Version of Integration services

Monitoring Integration services on older version of hyper-v, or migrated versions is quite important as the hyper-v integration services also provider driver interfaces to the client VM’s. To solve this we use the following monitoring script:

$VMMS = gwmi -namespace root\virtualization\v2 Msvm_VirtualSystemManagementService
 
# 1 == VM friendly name. 123 == Integration State
$RequestedSummaryInformationArray = 1,123
$vmSummaryInformationArray = $VMMS.GetSummaryInformation($null, $RequestedSummaryInformationArray).SummaryInformation
 

$outputArray = @()
 

foreach ($vmSummaryInformation in [array] $vmSummaryInformationArray)
   {  
 
   switch ($vmSummaryInformation.IntegrationServicesVersionState)
      {
       1       {$vmIntegrationServicesVersionState = "Up-to-date"}
       2       {$vmIntegrationServicesVersionState = "Version Mismatch"}
       default {$vmIntegrationServicesVersionState = "Unknown"}
      }

   $vmIntegrationServicesVersion = (get-vm $vmSummaryInformation.ElementName).IntegrationServicesVersion
   if ($vmIntegrationServicesVersion -eq $null) {$vmIntegrationServicesVersion = "Unknown"}
 
   $output = new-object psobject
   $output | add-member noteproperty "VM Name" $vmSummaryInformation.ElementName
   $output | add-member noteproperty "Integration Services Version" $vmIntegrationServicesVersion
   $output | add-member noteproperty "Integration Services State" $vmIntegrationServicesVersionState
 
   # Add the PSObject to the output Array
   $outputArray += $output
 
   }

foreach ($VM in $outputArray){
if ($VM.'Integration Services State' -contains "Version Mismatch"){
$ISState += "$($VM.'VM Name') Integration Services state is $($VM.'Integration Services State')`n"
}}
if(!$IIState){ $IIState = "Healthy" }

NUMA spanning

The next script is made to monitor the NUMA span of virtual machine. You might notice a decrease in performance when your NUMA spanning incorrect, not just in assigned memory but a general performance degradation of up to 80%. For more information, you can check this link and this link.

$VMs = Get-VM
foreach ($VM in $VMs){
$GetvCPUCount = Get-VM -Name $VM.Name | select Name,NumaAligned,ProcessorCount,NumaNodesCount,NumaSocketCount
$CPU = Get-WmiObject Win32_Processor
$totalCPU = $CPU.numberoflogicalprocessors[0]*$CPU.count
if ($GetvCPUCount.NumaAligned -eq $False){
$vCPUoutput += "NUMA not aligned for; $($VM.Name). vCPU assigned: $($GetvCPUCount.ProcessorCount) of $totalCPU available`n"
}}
if(!$vCPUOutput){ $vCPUOutput = "Healthy" }

Monitoring with PowerShell Chapter 3: Monitoring creation of scheduled tasks

Hi All,

After a blog post from Malwarebytes (here) about specific adware and cryptolockers using scheduled tasks to make sure they can remain undetected, or even regain control of the system by running a specific task every once in a while, We’ve decided with to start monitoring the creation of scheduled tasks. Users generally don’t really setup these tasks in normal situations.

We’ve decided to start alerting on any task created in the last 24 hours. Our N-Central monitoring system creates a ticket for this so we can investigate it. The great trick about this is that the set automatically resets itself after 24 hours, unless we create another task.

The monitoring set

Ok, so lets get started! the ingredients we will need today are:

  • Windows 8.1 or higher
  • PowerShell
  • A monitoring system, or way to run the scripts.

First, We’ll start by trying to get all tasks on our system. We’ll use the get-scheduledtask cmdlet.

Get-ScheduledTask

Now we have a cool list of tasks, but hey, there is no date information that is returned by this cmdlet?! That’s no fun. It seems like Microsoft had a little oversight in this case. Still, its not really a problem for us; Microsoft always stores the XML files for the scheduled tasks on the same location, namely %WINDIR%\System32\Tasks.

Instead of messing with extra modules, or even trying to get date information out of the default cmdlets we’ll move on to using get-childitem, with a filter of 24 hours. Lets start by grabbing our Task Path and setting it to a variable for ease of use, and then get the list of tasks created today.

$Taskpath = "$ENV:windir\system32\Tasks"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Ok, Great! now we already have a list of all files created today. We could stop right now, set this up in our monitoring system and be done with it. The only issue I have with this is that I’d like to know the actual tasks settings. So lets try getting those too.

We start looping through all the files, loading them as XML objects, and getting the information we care about. in our case we only want to know the name, author, and what command it would execute. We put that information in $TaskState. If $Taskstate remains blank during the entire script. We simply output “Healthy”.

$Taskpath = "$ENV:windir\system32\Tasks"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Foreach($task in $TasksToday){
[xml]$TaskXML = get-content $Task.FullName
$TaskName = $($TaskXML.task.RegistrationInfo.uri)
$TaskAuthor = $TaskXML.task.Principals.Principal.userid
$TaskExec = $TaskXML.task.actions.exec.command + $TaskXML.task.actions.exec.Arguments
$TaskState += "$TaskName has been created by SID: $TaskAuthor and executes $TaskExec`n"
}

if(!$TaskState){ $TaskState = "Healthy"}

Based on this information, we load this into our monitoring system and alert if the TaskState is anything but “Healthy”. And that’s it, we’re now monitoring the scheduled tasks with PowerShell. Happy PowerShelling!

Update: it was reported by a reader that he has some jobs that he did not have permissions on, and thus the task failed. My RMM system runs every PowerShell command as SYSTEM, so this wasn’t noticed during testing. Anyway, to solve this issue you can run the script below instead. This script forces ownership to be taken over for the current account.

$Taskpath = "$ENV:windir\system32\Tasks"
takeown /a /r /d Y /f "$TaskPath"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Foreach($task in $TasksToday){
[xml]$TaskXML = get-content $Task.FullName
$TaskName = $($TaskXML.task.RegistrationInfo.uri)
$TaskAuthor = $TaskXML.task.Principals.Principal.userid
$TaskExec = $TaskXML.task.actions.exec.command + $TaskXML.task.actions.exec.Arguments
$TaskState += "$TaskName has been created by SID: $TaskAuthor and executes $TaskExec`n"
}

if(!$TaskState){ $TaskState = "Healthy"}

Blog Series: Monitoring using PowerShell: Part Eight – Monitoring health with PowerShell

Hi All,

My next couple of blogs will be a series of blogs where I will be explaining on how to use PowerShell for the monitoring of critical infrastructure. I will be releasing a blog every day that will touch on how to monitor specific software components, but also network devices from Ubiquity, third-party API’s and Office365. I will also be showing how you can integrate this monitoring in current RMM packages such as Solarwinds N-Central, Solarwinds RMM MSP and even include the required files to import the  monitoring set directly into your system.

Continue reading

Mini-blog: Wait for VM to come online, then execute Powershell direct

During my labbing I’ve noticed I often need to wait for the VM to get online before executing some script or commands, to do that I use the following script:

First we get the VM Name, and enter the credentials for that specific VM:

$VMName = read-host "Please enter the VM-Name"
$VM = get-vm $VMName
$cred = Get-Credential -Message "Please enter credentials for the VM"

By getting the VM status we can use the VM.Heartbeat to check the actual status. We’re currently counting on the VM to be an unmonitored VM so the result we expect is “OkApplicationsUnknown” – This means the OS is up but the hypervisor has no idea if the VM applications are “healthy”.

To wait for the VM to get online we use a while loop to keep checking the heartbeat and if the status changes.

do
{
$VM = get-vm $VMName
} while ($vm.Heartbeat -ne "OkApplicationsUnknown")

Directly after the loop we are sure the VM is online, so we can execute our script via PowerShell Direct, here I simply print the hostname. 🙂

invoke-command -vmname $vmname -Credential $cred -ScriptBlock {write-host "My name is $env:COMPUTERNAME"}

Happy scripting!