I just thought I’d share a simple PowerCLI script I wrote to find when all VM’s were created and dump it out to a CSV. I wrote it quickly for our vSphere 5.5 environment, so mileage on other versions may vary. It’s not elegant but it’s comprehensive for most environments and even looks for events like when a VM was restored from backup, or discovered by vCenter. Just replace the value for $vcenter at the top with the host name of your vCenter server. Enjoy!
#Enter your vCenter Host below $vcenter = "your_vcenter_server" #Enter the CSV file to be created $csvfile = "VM_Birthdays.CSV" ################################ #Load the VMware Powershell snapin if the script is being executed in PowerShell Add-PSSnapin VMware.VimAutomation.Core -ErrorAction 'SilentlyContinue' #Connect to the vCenter server defined above. Ignore certificate errors Write-Host "Connecting to vCenter" Connect-VIServer $vcenter -wa 0 Write-Host "Connected" Write-Host "" #Check to see if the file exists, if it does then overwrite it. if (Test-Path $csvfile) { Write-Host "Overwriting $csvfile" del $csvfile } #Create the CSV title header Add-Content $csvfile "VM,Born on,Creator,Creation Type,Event Message" #Gather all VM's from vCenter $vms = Get-VM | sort Name foreach ($VM in $vms) { Write-Host "Gathering info for $VM" #Search for events where the VM was deployed from a template $vmevents = Get-VIEvent $VM -MaxSamples([int]::MaxValue) | Where-Object {$_.FullFormattedMessage -like "Deploying*"} |Select CreatedTime, UserName, FullFormattedMessage if ($vmevents) { $type = "From Template" } #If no events were found, search for events where the VM was created from scratch if (!$vmevents) { $vmevents = Get-VIEvent $VM -MaxSamples([int]::MaxValue) | Where-Object {$_.FullFormattedMessage -like "Created*"} |Select CreatedTime, UserName, FullFormattedMessage Write-Host "Searching by Created" $type = "From Scratch" } #If no events were found, search for events where the VM was cloned if (!$vmevents) { $vmevents = Get-VIEvent $VM -MaxSamples([int]::MaxValue) | Where-Object {$_.FullFormattedMessage -like "Clone*"} |Select CreatedTime, UserName, FullFormattedMessage Write-Host "Searching by Cloned" $type = "Cloned" } #If no events were found, search for events where the VM was discovered if (!$vmevents) { $vmevents = Get-VIEvent $VM -MaxSamples([int]::MaxValue) | Where-Object {$_.FullFormattedMessage -like "Discovered*"} |Select CreatedTime, UserName, FullFormattedMessage Write-Host "Searching by Discovered" $type = "Discovered" } #If no events were found, search for events where the VM was connected (typically from Backup Restores) if (!$vmevents) { $vmevents = Get-VIEvent $VM -MaxSamples([int]::MaxValue) | Where-Object {$_.FullFormattedMessage -like "* connected"} |Select CreatedTime, UserName, FullFormattedMessage Write-Host "Searching by Connected" $type = "Connected" } #I have no idea how this VM came to be. if (!$vmevents) { Write-Host "No clue how this VM got here!" $type = "Immaculate Conception" } #In some cases there may be more than one event found (typically from VM restores). This will include each event in the CSV for the user to interpret. foreach ($event in $vmevents) { #Prepare the entries $birthday = $event.CreatedTime.ToString("MM/dd/yy") $parent = $event.Username $message = $event.FullFormattedMessage #Add the entries to the CSV $write = "$VM, $birthday, $parent, $type, $message" Add-Content $csvfile $write } }
Great post — I am haivng trouble having my csv populate with data other than the headers.
Hey Mike,
When executing the script you should see the following output:
Connecting to vCenter
Name Port User
—- —- —-
VC1 443 VMSPOT\mbradford
Connected
My guess would be that the script is unable to connect to your vCenter server. Assuming you filled in your vCenter server in line 2, the script will attempt to log in with your current Windows credentials. If you need to log in with another account you could modify line 12 to something like this…
Connect-VIServer $vcenter -User your_username -Password your_password -wa 0
I hope this helps.
Cheers!
Matt
Hi Matt,
I need a script that will poll the VMs in vcenter for a file located at D:\graphics of VMs. The Vms are windows based. Can you please help me with a script.
Thanks
VD
hi Matt, I need your urgent help on the above . can you please help.
Hi VD,
Please see my comment below.
Thanks,
Matt
Hi Matt,
I’ve tried to use your script but the output file contains only the headers. I have changed the connection statement successfully, bat… no result.
The console prints are:
PowerCLI C:\Temp> .\Abc.ps1
Connecting to vCenter
Name Port User
—- —- —-
wafivm5.iit.cnr.it 443 root
Connected
Overwriting VM_Birthdays.txt
Gathering info for anomaly
vmevents =
Searching by Created
Searching by Cloned
Searching by Discovered
Searching by Connected
No clue how this VM got here!
Gathering info for bellomo
vmevents =
Searching by Created
Searching by Cloned
Searching by Discovered
Searching by Connected
No clue how this VM got here!
Gathering info for bellomo2
vmevents =
Searching by Created
Searching by Cloned
Searching by Discovered
Searching by Connected
No clue how this VM got here!
Ando so on… The $vmevents is always empty.
Thank you.
Alessandro Prosperi
Pisa (Italy)
Hi Alessandro,
It could be that the event history has been purged from your VCDB or you’ve stumbled upon a condition that the script is not looking for. Considering nothing is populating, I’m guessing it’s the former. When you run Get-VIEvent bellomo2 -MaxSamples([int]::MaxValue), what is the earliest entry? If it’s a new condition I’d be happy to add it to the script.
Cheers!
Matt
Hi Matt,
thank you for your reply. After started the PowerCLI shell I got a connection with the server with “Connect-VIServer -Server wafivm5.iit.cnr.it” (giving the required account and passord) and I obtained this output:
Name Port User
—- —- —-
wafivm5.iit.cnr.it 443 root
Then I have obtained a list of the VM hosted on this server with “Get-VM”, so I guess the connection is correctly established, but when I run “Get-VIEvent bellomo2 -MaxSamples([int]::MaxValue)” I don’t have any result.
My best wishes for a wonderful new year.
Alessandro
Matt — thank you for your quick reply. I ended up running the script in two parts and it works great! Thank you very much!!
All the best.
Mike
Matt , i ran the script, ran without any errors however it only wrote the info about just one VM (last vm on the list of output on the screen) to the csv file. i have more that 500 on this vcenter. only changes i made were on line 2 and 12 adding the vcnenter info. any idea why this is. Thanks
Hi Amar,
Just to be clear, the script is displaying “Gathering info for (VM name)” for each of your VM’s, correct?
Do you see two curly brackets ( } ) after line 82 (Add-Content $csvfile $write)?
Matt
Matt, Thank you for your quick response.
That was it, i missed the two curly brackets at the end,when i copied the script.
The report is created successfully now, however the dates in the “born on” column for all VMs are very recent (within about last two months) even for the VMs that were created years ago. Any Idea why that might be. Thanks
Hi Amar,
The script is polling VM events that are stored in the vCenter database. Was your vCenter server upgraded/replaced two months ago?
Matt,
Yes, the vcenter was upgraded from 5.0 to 5.5 about two months ago.
Thanks again for the script and quick replies.
Hey Matt, Good script… is there any way to add in a date range… so… I would like to pull this once a month and only see the last say X amount of days…Thx
Hi Shaun,
You could add the following IF statement to check the date before writing it to the CSV file
If ($event.CreatedTime -ge (get-date).AddDays(-30))
Adjust -30 to whatever number of days you want to go back.
So lines 74 through 85 should look like this…
If ($event.CreatedTime -ge (get-date).AddDays(-30)) #If events took place in the last 30 days
{
#Prepare the entries
$birthday = $event.CreatedTime.ToString("MM/dd/yy")
$parent = $event.Username
$message = $event.FullFormattedMessage
#Add the entries to the CSV
$write = "$VM, $birthday, $parent, $type, $message"
Add-Content $csvfile $write
}
}
}
Cheers!
Thx Bud… I will give this a bash and let you know… thanks for taking the time to help!
No problem.
Hey Matt… Thanks for quick reply, its appreciated, I will give it a bash on Monday… its Friday and about beer’o’clock now 🙂 … I will let you know how I got on!
Sounds good, Shaun! Enjoy your weekend. Cheers!
Hey Matt… sorry for the delay… tested this and it works a peach, THX!!!!
One thing, I had to remove the last two “}” for it to run… but again thx for code!
Glad to hear it! Thanks for the update.
Hello Matt, the script worked great!!! Thanks for it. However can you help how we can pull the info for a certain cluster alone. Pulling up the entire vCenter VM info is taking time, instead if can limit it for the cluster that I need, will be better.
Thanks again!!
Thank you so much for this script!! Works perfectly
Hello Matt
I executed the script but it is capturing multiple entries for a single VM. What could be the reason?
Kindly assist
Hi Subhasis,
The most common reason for this is if the VM was restored from a backup as this would cause multiple event entries in vCenter.
Thanks for the explaination Matt.Can you share any script that provides the resource utilization ( CPU, Storage consumption , memory utilization ) please
Thanks Matt, this works great!! What would be the easiest way to add the guest OS version to this script?
I get multiple rows with the same VM names
Thanks for this! I was able to modify it for what I needed.
Hi Matt,
I need a script that will poll VMs in vcenter for a particular file . The VMs are windows based and the file is located at D\\Pic\Standard\ResourceFile.txt. I have around 600 VMs in my vcenter but this file is present only in database VMs.
Thanks
RItu
Hi Ritu,
Your best bet will be to use the test-path command against each VM’s hidden D: share. I would start with a foreach loop against all VM’s returned from the Get-VM Command. Inside the loop run test-path against each. For example “test-path \\$vm\D$\Pic\Standard\Resourcefile.txt” where $vm is the variable used to identify each VM. This of course assumes that your VM names match your DNS names and that the script is being run as a user with admin access to the VM’s.
I hope this helps. Good luck!
Thanks Matt. I will try this.
Regards
VD
thanks Matt. I will try this and let you know.
regards
VD
You are a legend. This script has just saved me a bunch of time, thank you so much!
You’re most welcome! Glad it’s helped.
Thanks Matt, it works as a charmed. One question, I saw multiple entries for the same vm,why was that?
The most common reason for this is if the VM was restored from a backup as this would cause multiple event entries in vCenter.
Hi Matt,
I am getting the below error while executing the script.
Searching by Created
Searching by Cloned
Searching by Discovered
Searching by Connected
No clue how this VM got here!
You cannot call a method on a null-valued expression.
At C:\Scripts\VMBirthday.ps1:76 char:40
+ $birthday = $event.CreatedTime.ToString <<<< ("MM/dd/yy")
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
No errors running the script. The csv file contains 438 servers but the dates are not correct. Oldest date is 4/4/2016. Could this be coinciding with a vcenter upgrade that we did?
Hi Matt. I think your -ge should be -lt to pull back the last 30 days worth?!
how can we find VM’s which are deleted for the past month?
Thank you Matt. The script working in my environment.
Hi Matt, anyway to set script to only look at one datacenter instead of doing every VM in VC?
Hey there! Thanks a lot for this script. I’m getting “No clue how this VM got here” for every single of the 500 VMs in my vCenter 🙁 any clue?
Hello Matt.Is it possible not to overwrite the file, but to create a new one with the date?
Thanks
Hi Matt,
Could you help to get cloned VMs details like when it was created, date and username in Vsphere 6?
Hey Matt this script works great
Is there any way to specify in between two specific dates and not just the last 30 days ?