When was the last time that VM was powered on?

It seems that VMWare ESX PowerCli has a nice cmdlet called Get-LastPowerOn to answer that question:
https://blogs.vmware.com/vipowershell/2009/10/when-was-the-last-time-that-vm-was-powered-on.html
and that you can smoothly do:

Get-VM | Get-LastPowerOn

This question was raised for Hyper-V in December 2012 and didn’t get a correct answer yet.
http://stackoverflow.com/questions/13873575/how-can-i-know-the-hyper-v-vms-last-poweroff-time

Even if Windows Server 2012 R2 hit GA a few days ago and has 14 new cmdlets in its Hyper-V module compared to its predecessor Server 2012…


(I’m digressing a little bit but here are the new cmdlets:

)… it doesn’t have a nice Get-VMLastPowerOn cmdlet yet 😦

No problem, Powershell to the rescue 😀

#Requires -version 3.0
Function Get-VMStateHistory {
[CmdletBinding()]
Param(
 [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
 [string[]]$ComputerName=$env:COMPUTERNAME
)
Begin {
    $HT = @{
        LogName = 'Microsoft-Windows-Hyper-V-Worker-Admin' ;
        Id = 18500,18502,18504,18508,18510,18512,18514,18516,18518,18596
    }
}
Process {
    foreach ($Computer in $ComputerName) {
        try {
            Get-WinEvent -FilterHashtable $HT -ComputerName $Computer -ErrorAction Stop | ForEach-Object {
                $obj = Switch ($_.Id) {
                    18500 { @{ Action = 'Started'             ; TurnedOn = $true } ; break}
                    18502 { @{ Action = 'Turned Off'          ; TurnedOn = $false} ; break}
                    18504 { @{ Action = 'Shutdown (by host)'  ; TurnedOn = $false} ; break}
                    18508 { @{ Action = 'Shutdown (by guest)' ; TurnedOn = $false} ; break}
                    18510 { @{ Action = 'Saved'               ; TurnedOn = $false} ; break}
                    18512 { @{ Action = 'Reset (by host)'     ; TurnedOn = $true } ; break}
                    18514 { @{ Action = 'Reset (by guest)'    ; TurnedOn = $true } ; break}
                    18516 { @{ Action = 'Paused'              ; TurnedOn = $false} ; break}
                    18518 { @{ Action = 'Resumed'             ; TurnedOn = $true } ; break}
                    18596 { @{ Action = 'Restored'            ; TurnedOn = $true } ; break}
                    default {}
                }        
                [pscustomobject]@{
                    VMName = $_.Properties[0].Value
                    TurnedOn = $obj['TurnedOn']
                    Action = $obj['Action']
                    Time = $_.TimeCreated
                }
            } 
        } catch {
            Write-Warning -Message "Failed to get events from $Computer because $($_.Exception.Message)"
        }
    }
}
End {}
} 

Function Get-VMLastPowerOn {
[CmdletBinding()]
Param(
 [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
 [alias("VMName")]
 [string[]]$Name,

 [Parameter(ValueFromPipelineByPropertyName)]
 [string[]]$ComputerName
)

Begin {
    if ($ComputerName) {
        $VMStatesEvents = Get-VMStateHistory -ComputerName $ComputerName| ? TurnedOn
    } else {
        $VMStatesEvents = Get-VMStateHistory | ? TurnedOn
    }
}
Process {
    Switch (([int]$PSBoundParameters.ContainsKey('Name'))) {
        1 {
            foreach ($VM in $Name) {
                $VMStatesEvents | ? VMName -Like $VM | Sort-Object -Descending -Property Time | Select -First 1
            }
        }
        0 {
            foreach ($VM in (($VMStatesEvents).VMName | Sort-Object -Unique)) {
                $VMStatesEvents | ? VMName -Like $VM | Sort-Object -Descending -Property Time | Select -First 1
            }
        }
    }
}
End{}
}

I wish I had more time and I known I should have written the help assiociated with the 2 cmdlets. Instead here’s how to use it:

Case 1: Get the last power on time of an specific VM passed as parameter

Get-VMLastPowerOn -Name MyVMName | ft -AutoSize

Case 2: List last power on info for all VMs on the current host

Get-VMLastPowerOn | ft -AutoSize

Case 3: Pipe the original Get-VM cmdlet of the Hyper-V module and Get-VMLastPowerOn.

Get-VM | ? Name -match "R" |             
Get-VMLastPowerOn -ComputerName localhost

Did I already say that Powershell rocks 😎

Bonus: You may have noticed I chose specific event Ids. There are more on Windows 2012 R2 (18594 = fast-saved and 18592 = fast-restored, for example)
Here’s how I made up my mind and chose the above specific Ids:

(Get-WinEvent -ListProvider Microsoft-Windows-Hyper-V-Worker).Events |            
? id -match "^185" |ft id,Description -AutoSize
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s