In a comment on my Events – Part 3 : Auditing VM device changes post, Ian asked if it was possible to report who started a VM.
To take away the suspense, yes that can be done by using the information from two of my earlier post.
Since I considered it a bit too long to give the solution in a comment, this post.
Logic
First you will have to find which event(s) to use for a power on of a guest. For that use the CSV file of all events that I blogged about in Events, Dear Boy, Events – Part 2.
It’s obvious that you will need the VmPoweredOnEvent.
The first script in Events: a great source of information – Part 1 shows how to get at the user information in the event object via the userName property.
The scripts
First the script with only PowerCLI cmdlets.
Turns out we can do this with a one-liner !
1 2 3 4 5 6 7 |
Get-VIEvent -Start (Get-Date).adddays(-10) | ` where {$_.gettype().Name -eq "VmPoweredOnEvent" -and $_.CreatedTime -lt (Get-Date).adddays(-30)} | ` select @{N="VMname"; E={$_.Vm.Name}}, @{N="CreatedTime"; E={$_.CreatedTime}}, @{N="Host"; E={$_.Host.Name}}, @{N="User"; E={$_.UserName}} | ` Export-Csv "C:\VM-powerod-audit.csv" -NoTypeInformation -UseCulture |
Annotation
Line 1: The Where-Object (alias ‘where’) cmdlet only passes the events we’re interested in
The second version of the script uses the event collector methods as described in Events: a great source of information – Part 1 (second script in that post).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
$days = 7 $eventnumber = 1000 $report = @() $serviceInstance = get-view ServiceInstance $eventMgr = Get-View eventManager if($eventMgr.Client.Version -eq "Vim4" -and $eventnumber -gt 1000){ Write-Host "Sorry, API 4.0 only allows a maximum event window of 1000 entries!" -foregroundcolor red Write-Host "Please set the variable `$eventnumber to 1000 or less" -foregroundcolor red exit } $efilter = New-Object VMware.Vim.EventFilterSpec $efilter.time = New-Object VMware.Vim.EventFilterSpecByTime $efilter.time.beginTime = (Get-Date).Adddays(- $days) $efilter.time.endtime = (Get-Date) $ecollectionImpl = Get-View ($eventMgr.CreateCollectorForEvents($efilter)) $ecollection = $ecollectionImpl.ReadNextEvents($eventnumber) while($ecollection -ne $null){ foreach($event in $ecollection){ switch($event.GetType()){ "VMware.Vim.VmPoweredOnEvent" { $report += New-Object PSObject -Property @{ VMname = $event.Vm.Name CreatedTime = $event.CreatedTimE Host = $event.Host.Name User = $event.UserName } } } } $ecollection = $ecollectionImpl.ReadNextEvents($eventnumber) } $ecollectionImpl.DestroyCollector() $report | Export-Csv "C:\VM-poweredon-audit-fast.csv" -NoTypeInformation -UseCulture |
Annotation
Line 9-13: VIM 4.0 has a limitation in the number of events.
Line 26-31: this way of building an object is new to PowerShell v2
Line 37: you can have a maximum of 32 event collectors in your session. So clean up !
Result
Both scripts produce a CSV file that gives all the information we’re after. See the first screenshot in this post.
The difference is in the execution time, the 2nd script ran nearly 35 times faster than the first script in my test environment. Quite important if you have to go back far in time or if you are auditing a big environment !
You can use any of the above scripts as skeletons to hunt for other audit information. Just plug in the event(s) you’re after 😉
A personal reflection, it would be useful that in a future PowerCLI build, the Get-VIEvent cmdlet would have a ‘filter‘ parameter. That would get rid of the Where-Object cmdlet through which we now have to pipe all the events.
Prasad
Hi, Thank you.
Is there a way that we can monitor VM information in depth? We are reaching our hardware limit and I need to free up some VMs. I know that some people are not using their VM anymore, how can I tell when the last time a VM was interactively logged into so I can produce the report if they really need an Idle VM?
Thanks
Prasad
LucD
Hi.
The start/stop of a VM does only tell you when the VM was running or not.
To actually see if someone logged on you would have to interpolate the Guest OS.
You could look at performance metrics like CPU, memory and disk IO, but that is not an absolute indication if someone is actually working in the Guest OS.
It could be that for example scheduled tasks are causing these fluctuations in those metrics.
The only true method is to iterpolate the Guest OS I’m afraid.
Luc
Luveshen
Hi LucD
Is there a way for me to access the configSpec property for a CloneVM_Task. I think its the VirtualMachineCloneSpec that I’m looking for, but I only see it being used as a parameter when calling the CloneVM_Task.
I’m unsure whether I can access task parameters via the TaskManager/eventManager.
My aim is to identify the configuration for CPU & memory for the target machine.
Thanks
LucD
@Luveshen, see my reply in Events – Part 3 : Auditing VM device changes
Skywalker
@LucD
Thanks much, Luc!
Skywalker
Hi Luc,
Is it possible to monitor manual migration event and have username (who), starttime, state, vm name, from, to displayed? I saw a script from you, which tracks DRS. Thanks again!
LucD
That shouldn’t be too difficult.
If you replace the code inside the switch statement (lines 25-32) by the following code, you should get a report on the vMotions.
"VMware.Vim.VmRelocatedEvent"{
$report += New-Object PSObject -Property @{
VMname = $event.Vm.Name
CreatedTime = $event.CreatedTimE
From = $event.SourceHost.Name
To = $event.Host.Name
User = $event.UserName
State = $event.FullFormattedMessage
}
}
I suspect that you can test on the presence of the User property to determine if it was a manual vMotion or one triggered by the system (DRS).
Luc.
Cody Bunch
Good stuff! I did a similar post a bit back: https://professionalvmware.com/2009/10/a-quick-powercli-lesson-digging-for-info-who-powered-off-that-vm/ Love the performance improvements tho… 35x is HUGE!
LucD
That is indeed a great post you did Cody.
Wouldn’t have done this one, if it wasn’t for the performance difference between the two methods.