46

A very simple PowerCLI script to gather VM creation dates

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
}
}

Matt Bradford

46 Comments

  1. 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’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

  2. 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

  3. 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?

  4. Matt,
    Yes, the vcenter was upgraded from 5.0 to 5.5 about two months ago.
    Thanks again for the script and quick replies.

  5. 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!

      • 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!

  6. 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!

  7. 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!!

  8. 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.

  9. Thanks for the explaination Matt.Can you share any script that provides the resource utilization ( CPU, Storage consumption , memory utilization ) please

  10. Thanks Matt, this works great!! What would be the easiest way to add the guest OS version to this script?

  11. 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!

  12. You are a legend. This script has just saved me a bunch of time, thank you so much!

  13. Thanks Matt, it works as a charmed. One question, I saw multiple entries for the same vm,why was that?

  14. 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

  15. 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?

  16. Hi Matt. I think your -ge should be -lt to pull back the last 30 days worth?!

  17. Hi Matt, anyway to set script to only look at one datacenter instead of doing every VM in VC?

  18. 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?

Leave a Reply