When was vm created, how vm was created and who has created this vm ?

by Grzegorz Kulikowski
who and when created the vm

I wanted to know where it is possible, who has created virtual machine. When the virtual machine was created and how it was created.
The idea is very simple. As an input i will take a virtual machine, and the output should be an object with few properties. VM can be created in several ways, right ? So i need to search for different events. When vm is being created/deployed it will create an event for this fact. Those events are as follows:

VmBeingCreatedEvent – Vm is created manually. Right-click New-VM. When we do VM in this way, a second event joins VmRegisteredEvent. So To check for vms there were manually created, we have to browse for events and check if 2 types of events have occured.
VmBeingDeployedEvent – When vm was deployed from template it will make this type of event
VmRegisteredEvent – When vm was registered, for example, open datastore browser, right click on vmx – register.
VmClonedEvent – When vm was cloned.

Since i have already written a function few days ago that queries for events i will use it here. I use Get-VMEvents, to query for specific events types regarding virtual machine object. So first let’s load this function to our powercli environment. Copy/paste this source code into your powershell/powercli/powergui/ise session.

[sourcecode language=”powershell”]
function Get-VMEvents {
<#
.Synopsis

Get events for an entity or for query all events.

.Description

This function returns events for entities. It’s very similar to
get-vievent cmdlet.Note that get-VMEvent can handle 1 vm at a time.
You can not send array of vms in this version of the script.

.Example

Get-VMEvents 0All -types “VmCreatedEvent”,”VmDeployedEvent”,”VmClonedEvent”

This will receive ALL events of types “VmCreatedEvent”,”VmDeployedEvent”,
“VmClonedEvent”.

.Example

Get-VMEvents -name ‘vm1’ -types “VmCreatedEvent”

Will ouput creation events for vm : ‘vm1’. This was is faster than piping vms from
get-vm result. There is no need to use get-vm to pass names to get-vmevents.
Still, it is ok when you will do it, it will make it just a little bit slower 😉

.Example

Get-VMEvents -name ‘vm1’ -category ‘warning’

Will ouput all events for vm : ‘vm1’. This was is faster than piping names from
get-vm cmdlet. Category will make get-vmevent to search only defined category
events.

.Example

get-vm ‘vm1’ | Get-VMEvents -types “VmCreatedEvent”,”VmMacAssignedEvent”

Will display events from vm1 which will be regarding creation events,
and events when when/which mac address was assigned

.Parameter VM

This parameter is a single string representing vm name. It expects single vm name that
exists in virtual center. At this moment in early script version it will handle only a case
where there is 1 instance of vm of selected name. In future it will handle multiple as
well.

.Parameter types

If none specified it will return all events. If specified will return
only events with selected types. For example : “VmCreatedEvent”,
“VmDeployedEvent”, “VmMacAssignedEvent” “VmClonedEvent” , etc…

.Parameter category

Possible categories are : warning, info, error. Please use this parameter if you
want to filter events.

.Parameter All

If you will set this parameter, as a result command will query all events from
virtual center server regarding virtual machines.

.Notes

NAME: VMEvents

AUTHOR: Grzegorz Kulikowski

LASTEDIT: 11/09/2012

NOT WORKING ? #powercli @ irc.freenode.net

.Link

http://psvmware.wordpress.com

#>

param(
[Parameter(ValueFromPipeline=$true)]
[ValidatenotNullOrEmpty()]
$VM,
[String[]]$types,
[string]$category,
[switch]$All
)
$si=get-view ServiceInstance
$em= get-view $si.Content.EventManager
$EventFilterSpec = New-Object VMware.Vim.EventFilterSpec
$EventFilterSpec.Type = $types
if($category){
$EventFilterSpec.Category = $category
}

if ($VM){
$EventFilterSpec.Entity = New-Object VMware.Vim.EventFilterSpecByEntity
switch ($VM) {
{$_ -is [VMware.Vim.VirtualMachine]} {$VMmoref=$vm.moref}
{$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]}{$VMmoref=$vm.Extensiondata.moref}
default {$vmmoref=(get-view -ViewType virtualmachine -Filter @{‘name’=$VM}).moref }
}
$EventFilterSpec.Entity.Entity = $vmmoref
$em.QueryEvents($EventFilterSpec)
}
if ($All) {
$em.QueryEvents($EventFilterSpec)
}
}

[/sourcecode]
Ok, once we have this loaded we can start actually querying with this function:

[sourcecode language=”powershell”]
function get-vmcreationdate {
<#
.Synopsis

Gets where possible vm creation date.

.Description

This function will return object with information about creation time, method, month,
creator for particular vm.
VMname : SomeVM12
CreatedTime : 8/10/2012 11:48:18 AM
CreatedMonth : August
CreationMethod : Cloned
Creator : office\greg

This function will display NoEvent value in properties in case when your VC does no
longer have information about those particular events, or your vm events no longer have
entries about being created. If your VC database has longer retension date it is more possible
that you will find this event.

.Example

Get-VMCreationdate -VMnames “my_vm1″,”My_otherVM”

This will return objects that contain creation date information for vms with names
myvm1 and myvm2

.Example

Get-VM -Location ‘Cluster1’ |Get-VMCreationdate

This will return objects that contain creation date information for vms that are
located in Cluster1

.Example

Get-view -viewtype virtualmachine -SearchRoot (get-datacenter ‘mydc’).id|Get-VMCreationDate

This will return objects that contain creation date information for vms that are
located in datacenter container ‘mydc’. If you are using this function within existing loop where you
have vms from get-view cmdlet, you can pass them via pipe or as VMnames parameter.

.Example

$report=get-cluster ‘cl-01’|Get-VMCreationdate
$report | export-csv c:\myreport.csv
Will store all reported creationtimes object in $report array variable and export report to csv file.
You can also filter the report before writing it to csv file using select
$report | Where-Object {$_.CreatedMonth -eq “October”} | Select VMName,CreatedMonth
So that you will see only vms that were created in October.

.Example
get-vmcreationdate -VMnames “my_vm1”,testvm55
WARNING: my_vm1 could not be found, typo?
VMname : testvm55
CreatedTime : 10/5/2012 2:24:03 PM
CreatedMonth : October
CreationMethod : NewVM
Creator : home\greg
In case when you privided vm that does not exists in yor infrastructure, a warning will be displayed.
You can still store the whole report in $report variable, but it will not include any information about
missing vm creation dates. A warning will be still displayed only for your information that there was
probably a typo in the vm name.

.Parameter VMnames

This parameter should contain virtual machine objects or strings that represents vm
names. It is possible to feed this function wiith VM objects that come from get-vm or
from get-view.

.Notes

NAME: Get-VMCreationdate

AUTHOR: Grzegorz Kulikowski

LASTEDIT: 27/11/2012

NOT WORKING ? #powercli @ irc.freenode.net

.Link

http://psvmware.wordpress.com

#>

param(
[Parameter(ValueFromPipeline=$true,Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[Object[]]$VMnames
)
process {
foreach ($vm in $VMnames){
$ReportedVM = “”|Select VMname,CreatedTime,CreatedMonth,CreationMethod,Creator
if ($CollectedEvent=$vm|Get-VMEvents -types ‘VmBeingDeployedEvent’,’VmRegisteredEvent’,’VmClonedEvent’,’VmBeingCreatedEvent’ -ErrorAction SilentlyContinue)
{
if($CollectedEvent.gettype().isArray){$CollectedEvent=$CollectedEvent|?{$_ -is [vmware.vim.VmRegisteredEvent]}}
$CollectedEventType=$CollectedEvent.gettype().name
$CollectedEventMonth = “{0:MMMM}” -f $CollectedEvent.CreatedTime
$CollectedEventCreationDate=$CollectedEvent.CreatedTime
$CollectedEventCreator=$CollectedEvent.Username
switch ($CollectedEventType)
{
‘VmClonedEvent’ {$CreationMethod = ‘Cloned’}
‘VmRegisteredEvent’ {$CreationMethod = ‘RegisteredFromVMX’}
‘VmBeingDeployedEvent’ {$CreationMethod = ‘VmFromTemplate’}
‘VmBeingCreatedEvent’ {$CreationMethod = ‘NewVM’}
default {$CreationMethod=’Error’}
}
$ReportedVM.VMname=$CollectedEvent.vm.Name
$ReportedVM.CreatedTime=$CollectedEventCreationDate
$ReportedVM.CreatedMonth=$CollectedEventMonth
$ReportedVM.CreationMethod=$CreationMethod
$ReportedVM.Creator=$CollectedEventCreator
}else {
if ($?) {
if($vm -is [VMware.Vim.VirtualMachine]){$ReportedVM.VMname=$vm.name} else {$ReportedVM.VMname=$vm.ToString()}
$ReportedVM.CreatedTime = ‘NoEvent’
$ReportedVM.CreatedMonth = ‘NoEvent’
$ReportedVM.CreationMethod = ‘NoEvent’
$ReportedVM.Creator = ‘NoEvent’

} else {
$ReportedVM = $null
Write-Warning “$VM could not be found, typo?”
}
}
$ReportedVM
}
}
}
[/sourcecode]

Ok, so now we have 2 functions that we can use.
Get-VMEvents that will query for events regarding a VM, and Get-VMCreationdate that uses the first function. There are couple of ways to use it.
The most basic approach i guess will be:
[sourcecode language=”powershell”]
greg#19:58:02> get-vm testvm55 | Get-VMCreationDate

VMname : testvm55
CreatedTime : 10/5/2012 2:24:03 PM
CreatedMonth : October
CreationMethod : NewVM
Creator : home\Gregu
[/sourcecode]

It also gives you a warning when you are querying a vm that does not exist in your infrastructure.
[sourcecode language=”powershell”]
gkulikowski#19:59:14> get-vmcreationdate -VMnames ‘testvm55′,’testvm112′,’this_vm_does_not_exist’

VMname : testvm55
CreatedTime : 10/5/2012 2:24:03 PM
CreatedMonth : October
CreationMethod : NewVM
Creator : home\gregu

VMname : testvm112
CreatedTime : 11/25/2012 4:14:11 PM
CreatedMonth : November
CreationMethod : RegisteredFromVMX
Creator : home\gregu

WARNING: this_vm_does_not_exist could not be found, typo?
[/sourcecode]

When you will query for a VM that no longer has event information about being created, it will result in sending an object with a vm name and other properties with NoEvent value. It’s up to you then what do in that case. Maybe you want to query Active Directory and check registration there when NoEvent is returned. Maybe you do not have AD in your environment, and you are fine with marking creation date as a date of the oldest event for a virtualmachine. Like i said, its up to you what to do in this case.
All sorts of selecting vms are possible to feed Get-VMCreationdate
get-vm -Location X | …
get-cluster ‘some_cluster’ | …
get-datacenter ‘X’ | …

And of course you can filter information about creation dates for your virtual machines. Let’s say that you have already a report

$vms=get-vm -Location ‘My_folder1’
$report=Get-VMCreationdate -VMnames $vmnames

$report |Where-Object {$_.CreatedMonth -eq “July”} | Select VMname
Would for example output only vm names for vms that where created in July.

$report |Where-Object {$_.Creator -eq “Grzegorz”} | Select VMname
Would for example output only vm names for vms that where created by Grzegorz.

$report |Where-Object {$_.CreationMethod -eq “RegisteredFromVMX”} | Select VMname
Would for example output only vm names for vms that were created using method: Registered from vmx.

$report |Where-Object {$_.CreationMethod -eq “Cloned”} | Select VMname
Would for example output only vm names for vms that were cloned.

If you want to store your report as an CSV there is no problem with that:
$report | Export-csv c:\myreport.csv

You will probably see a lot of vms without any data , i mean they will have NoEvent value. How to fight with that ? If you want to track the creationdate, and have this information always available for virtualmachine, you can for example create an annotation with name : CreatedDate , and you can check your vms once a day to see if a vm does not have this annotation completed. If there is no information in the annotation you can simply use Get-VMCreationdate, to get this information and store i within vm annotation field. If after some months you VC will lose information about creation events, created dated will be still in the annotation. If you have any other ideas about this, write a comment !

What can be done more ? You will notice that command like :
get-vm|get-vmcreationdate
Will take some time. It should take 1.5 second to obtain information for 1 vm. If you have a large infrastructure like 1000,5000, and more vms it will take some time to complete this report. There is a way though to obtain report for ALL vms in your infrastructure in around ~20-30 seconds i believe. Unfortunately i don’t have that much free time to write it. But if you want to try it, please share your work with us in comments or thoughts about this idea.
You can use get-vmevents with -all switch and -types that will indicatate creation of virtual machine.
$creationevents=get-vmevents -all -types ‘VmBeingDeployedEvent’,’VmRegisteredEvent’,’VmClonedEvent’,’VmBeingCreatedEvent’
In order to complete this it will need around 2-3 seconds.
This way of doing this is very quick BUT, it will include information of virtual machines that no longer exists in your infrastructure, so we have to filter these out.
$creationevents array will include events objects that have vm moref property. So you have to store it somewhere.
$morefs=$creationevents|%{$_.vm.vm}
Like this for example
Then you have to compare those morefs with morefs for vms that you actually have in your vc , for example using compare-object.
Once this is done You can now feed get-vmcreationdate with those events that have proper moref property.
When i will have more time i will try this idea out 😉 For now, no time ;(
Big thanks goes to Bartosz Bielawski for helping me out with some parts of the script!

Advertisements

You may also like

23 comments

vanzerhous February 21, 2013 - 9:16 pm

Brilliant! Thank you!

Reply
p3opl3sh3ro March 19, 2013 - 5:21 pm

I am having a difficult time trying to figure out how to use this information. I want to be able to run a report for all creation methods and have it go to a file so that I can sort. It looks like I am after the 2nd function you have shown. I have loaded it, but am having trouble going from there. How do I actually run the report needed and save the output?

Reply
psvmware March 27, 2013 - 2:34 pm

Hi, can you let me know what is wrong ? It’s not clear for me what is not working. Post includes information how to invoke report and save it to file.

Reply
p3opl3sh3ro March 27, 2013 - 8:44 pm

I actually created some SQL queries instead and have them available to my team via SSRS. Thank you.

Reply
Anonymous August 22, 2013 - 3:17 pm

Awesome !! Thx a lot

Reply
Rob October 16, 2013 - 4:31 pm

Love your script! Question though, when I run it, it shows me the original name of the VM, not the current name.

EG,

Machine42_NEW 10/1/2013 18:27 October Cloned Durdle

I used

$report=get-vm|get-vmcreationdate
$report | export-csv x:\report.csv

Reply
Rob October 16, 2013 - 4:32 pm

to Clarify, the ‘real’ name of that machine would be WebServer42, as that I renamed it months ago.

Reply
psvmware October 21, 2013 - 5:37 pm

Hi Rob, thanks for comments. To be honest i was not thinking about this possibility. Like you wrote, this will be his default behaviour in returning the names due to the fact that vm name is being collected from event from the past.
If you would like to get name not from the event but the current vm, please look at line 113 in this script.
$ReportedVM.VMname=$CollectedEvent.vm.Name
Please change this line to
$ReportedVM.VMname=$vm.name

i think that will help.

Reply
Scotty November 26, 2013 - 6:26 pm

Hi good job. Exactly what i was looking for.

But don’t work in my case 🙁
vSphere is running version 4.1

>get-vm Vm-test |get-vmcreationdate
VMname : Vm-test
CreatedTime : NoEvent
CreatedMonth : NoEvent
CreationMethod : NoEvent
Creator : NoEvent

Any Idea ?

Reply
Anonymous February 19, 2014 - 6:09 pm

Doubting you’re still looking for info on the NoEvent after all this time, but from what I can tell, that comes up if the VM is really old.

Reply
psvmware February 19, 2014 - 7:53 pm

That is correct. If we would like to keep events/tasks for longer period of time we would have to change te virtual center database retention policy as described in documentation https://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.vsphere.vcenterhost.doc%2FGUID-DD999601-2F41-498D-A577-DDC7C06648EE.html

Reply
wojcieh February 20, 2014 - 5:10 pm

Hi Greg,

Excellent work. I was able to find when VM was created. I checked script against VMware ESX 4.1 U3 and VMware ESXi 5.1 & 5.5

Best Regards
Wojciech

Reply
Find when Virtual Machine was created using SQL query | w o j c i e h . n e t February 20, 2014 - 11:05 pm

[…] if it is possible to find when virtual machine was created and by who. I found great post on Grzegorz blog. I tested it and it works from ESX 4.1 U3 up to ESXi […]

Reply
JB April 22, 2014 - 12:31 am

Greg, I have this error when load the function Get-VMEvents. Appreciate if someone can guide me through it.

The ‘<' operator is reserved for future use.
At line:60 char:36
+ $EventFilterSpec = New-Object < <<<VMware.Vim.EventFilterSpec
+ CategoryInfo : ParserError: ( if ($VM){
>> $EventFilterSpec.Entity = New-Object VMware.Vim.EventFilterSpecByEntity
>> switch ($VM) {
>> {$_ -is [VMware.Vim.VirtualMachine]} {$VMmoref=$vm.moref}
>> {$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
]}{$VMmoref=$vm.Extensiondata.moref}
>> default {$vmmoref=(get-view -ViewType virtualmachine -Filter @{‘name’=$VM}).moref }
>> }
>> $EventFilterSpec.Entity.Entity = $vmmoref
>> $em.QueryEvents($EventFilterSpec)
>> }
>> if ($All) {
>> $em.QueryEvents($EventFilterSpec)
>> }
>> }
>>
The ‘<' operator is reserved for future use.
At line:2 char:43
+ $EventFilterSpec.Entity = New-Object < <<<VMware.Vim.EventFilterSpecByEntity
+ CategoryInfo : ParserError: (<:OperatorToken) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RedirectionNotSupported

Reply
psvmware April 22, 2014 - 7:32 am

could you please paste what you are trying to load in powershell ? I think either you have added something somewhere, or you are pasting it with some special characters maybe. When i copy/paste what is in the post i got no errors. Would be best if you would just paste on some pastebin, the code you are trying to execute.

Reply
JB April 22, 2014 - 8:35 pm

Thank you for reply. I copy and paste the whole function, got error then I took out the comment & examples part and got the same error. I used 3 different machines to load the same function and got the same error. Here is the shorter version of the function
===============================================
PS C:\MyPS> function Get-VMEvents {
>> param(
>> [Parameter(ValueFromPipeline=$true)]
>> [ValidatenotNullOrEmpty()]
>> $VM,
>> [String[]]$types,
>> [string]$category,
>> [switch]$All
>> )
>> $si=get-view ServiceInstance
>> $em= get-view $si.Content.EventManager
>> $EventFilterSpec = New-Object VMware.Vim.EventFilterSpec
>> $EventFilterSpec.Type = $types
>> if($category){
>> $EventFilterSpec.Category = $category
>> }
>>
The ‘<' operator is reserved for future use.
At line:12 char:36
+ $EventFilterSpec = New-Object < <<<VMware.Vim.EventFilterSpec
+ CategoryInfo : ParserError: ( if ($VM){
>> $EventFilterSpec.Entity = New-Object VMware.Vim.EventFilterSpecByEntity
>> switch ($VM) {
>> {$_ -is [VMware.Vim.VirtualMachine]} {$VMmoref=$vm.moref}
>> {$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
]}{$VMmoref=$vm.Extensiondata.moref}
>> default {$vmmoref=(get-view -ViewType virtualmachine -Filter @{‘name’=$VM}).moref }
>> }
>> $EventFilterSpec.Entity.Entity = $vmmoref
>> $em.QueryEvents($EventFilterSpec)
>> }
>> if ($All) {
>> $em.QueryEvents($EventFilterSpec)
>> }
>> }
>>
The ‘<' operator is reserved for future use.
At line:2 char:43
+ $EventFilterSpec.Entity = New-Object < <<<VMware.Vim.EventFilterSpecByEntity
+ CategoryInfo : ParserError: (<:OperatorToken) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RedirectionNotSupported

Reply
psvmware April 23, 2014 - 6:56 am

JB. you are not pasting the function you are trying to load. You are pasting some fragment of function + error output. Can you please just paste the entire script you are trying to load on some pastebin ?

Reply
JB April 23, 2014 - 4:57 pm

Sorry, I misunderstood.
==========================================================
function Get-VMEvents {
param(
[Parameter(ValueFromPipeline=$true)]
[ValidatenotNullOrEmpty()]
$VM,
[String[]]$types,
[string]$category,
[switch]$All
)
$si=get-view ServiceInstance
$em= get-view $si.Content.EventManager
$EventFilterSpec = New-Object VMware.Vim.EventFilterSpec
$EventFilterSpec.Type = $types
if($category){
$EventFilterSpec.Category = $category
}

if ($VM){
$EventFilterSpec.Entity = New-Object VMware.Vim.EventFilterSpecByEntity
switch ($VM) {
{$_ -is [VMware.Vim.VirtualMachine]} {$VMmoref=$vm.moref}
{$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]}{$VMmoref=$vm.Extensiondata.moref}
default {$vmmoref=(get-view -ViewType virtualmachine -Filter @{‘name’=$VM}).moref }
}
$EventFilterSpec.Entity.Entity = $vmmoref
$em.QueryEvents($EventFilterSpec)
}
if ($All) {
$em.QueryEvents($EventFilterSpec)
}
}

Reply
JB April 23, 2014 - 8:39 pm

I found the issue. I just need to remove all and from both functions. Appreciate your responses and many thanks to creator.

Reply
BravoDelta June 2, 2014 - 10:35 pm

This is superballs! Did exactly what I needed it to do, thanks so much!

Reply
psvmware June 3, 2014 - 8:29 am

you are welcome 😉

Reply
Nicholas Ferguson December 4, 2014 - 12:14 am

Great scripts! Thank you so very much.

Reply
Jody January 17, 2018 - 11:35 pm

Why in the hell should we have to do all of this heavy scripting to get a creation date for a VM? How in the hell is it that VMWare doesn’t simply have this in a VM’s summary? Typical half-ass engineering from half-ass VMWare. Ludicrous…

Reply

Leave a Reply

Chinese (Simplified)DutchEnglishFrenchGermanHindiPolishRussianSpanish