VMware Cloud Community
BrianDGeorge
Enthusiast
Enthusiast

PowerCLI SnapShot Creator in Report

I have asked a few similar questions but my report that contains snapshots is in sore need of expanding in order to call out some culprits and to ensure that our backup software is not abandoning snaps in the environment.  So far I have the following snippet from my report as a lead in example:

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join ','}},

    @{N="Days Old";E={(New-TimeSpan -End (Get-Date) -Start $script:snaps.CreateTime).Days}},

    @{N='Created By';E={$snapevent = Get-VIEvent -Entity $_ -Types Info -Finish $_.created -MaxSamples 1 | Where-Object {$_.FullFormattedMessage -imatch 'Task: Create virtual machine snapshot'}

$snapevent.UserName}}

Everything works except the Created By

If I run this on a single server I get all Created by results from the Event Log including ones that have been deleted.

$snapevent = Get-VIEvent -Entity ServerA -Types Info -Finish ServerA.Created -MaxSamples 1 | Where-Object {$_.FullFormattedMessage -imatch 'Task: Create virtual machine snapshot'}

$snapevent.UserName

Any help is greatly appreciated.

27 Replies
LucD
Leadership
Leadership

There are a couple of flaws in there.

  • The script will list all snapshots for a VM for the Snapshot, SnapShot Created and Days Old properties, while the Created By will only show the user that created the last snapshot
  • The object in the pipeline when you reach the Select-Object is a VirtualMachine, so the $_.Created makes no sense. You want to use $script:snaps here.
  • You should use a Start parameter on the Get-VIEvent, otherwise the Get-VIEvent might run for a very long time.
    • Use a Start parameter and set it to the creation time of the oldest snapshot
  • The MaxSamples 1 is definitely not needed. If the last event is not a TaskEvent for a snapshot, it will not report anything.

Try the following

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'}} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},

    @{N="Days Old";E={

        $now = Get-Date

        ($script:snaps | %{(New-TimeSpan -End $now -Start $_.CreateTime).Days}) -join '|'}},

    @{N='Created By';E={

        $start = $script:snaps.CreateTime | Sort-Object | Select -First 1

        (Get-VIEvent -Entity $_.Name -Start $start -MaxSamples ([int]::MaxValue) |

            Where-Object {$_ -is [VMware.Vim.TaskEvent] -and $_.Info.DescriptionId -eq 'VirtualMachine.createSnapshot'} |

            Select -ExpandProperty UserName) -join '|'}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

Thanks LucD for the quick response.  I also want to thank you for the education.  Unfortunately the script modifications return the created by results of every created by event in the event logs not just for snapshots that currently exist. Any ideas?

I was originally trying to model it after the following

#

foreach ($snap in Get-VM | Get-Snapshot)

{$snapevent = Get-VIEvent -Entity $snap.VM -Types Info -Finish $snap.Created -MaxSamples 1 | Where-Object {$_.FullFormattedMessage -imatch 'Task: Create virtual machine snapshot'}

if ($snapevent -ne $null){Write-Host ( "VM: "+ $snap.VM + ". Snapshot '" + $snap + "' created on " + $snap.Created.DateTime + " by " + $snapevent.UserName +".")}

else {Write-Host ("VM: "+ $snap.VM + ". Snapshot '" + $snap + "' created on " + $snap.Created.DateTime + ". This event is not in vCenter events database")}}

#

LucD
Leadership
Leadership

You could try to verify the event's CreateTime against the Created times of the snapshots.

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'}} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},

    @{N="Days Old";E={

        $now = Get-Date

        ($script:snaps | %{(New-TimeSpan -End $now -Start $_.CreateTime).Days}) -join '|'}},

    @{N='Created By';E={

        $startEvents = $script:snaps.CreateTime

        $start = $startEvents | Sort-Object | Select -First 1

        (Get-VIEvent -Entity $_.Name -Start $start -MaxSamples ([int]::MaxValue) |

            Where-Object {$_ -is [VMware.Vim.TaskEvent] -and

                          $_.Info.DescriptionId -eq 'VirtualMachine.createSnapshot' -and

                          $startEvents -contains $_.CreateTime} |

            Select -ExpandProperty UserName) -join '|'}}

But there might be slight differences in these timestamp.

I normally add a margin of 5 seconds plus and minus, but the margin depends on the load in your environment.
Let's first check if a straight timestamp comparison works.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
LucD
Leadership
Leadership

This is an example where I accept 1 2 second difference between the time in the Event and the time on the Snapshot.

$timeDiff = 2

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'}} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},

    @{N="Days Old";E={

        $now = Get-Date

        ($script:snaps | %{(New-TimeSpan -End $now -Start $_.CreateTime).Days}) -join '|'}},

    @{N='Created By';E={

        $startEvents = $script:snaps.CreateTime

        $start = $startEvents | Sort-Object | Select -First 1

        (Get-VIEvent -Entity $_.Name -Start $start -MaxSamples ([int]::MaxValue) |

            Where-Object {$_ -is [VMware.Vim.TaskEvent] -and $_.Info.DescriptionId -eq 'VirtualMachine.createSnapshot'} |

            ForEach-Object -Process {

                $event = $_

                $startEvents | ForEach-Object -Process {

                    if([math]::Abs((New-TimeSpan -Start $event.CreateTime -End $_).TotalSeconds) -lt $timeDiff){

                        $event

                    }

                }

            } | Select-Object -ExpandProperty UserName) -join '|'}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

LucD,

I have tried both and even ran it against the entire environment and had no results returned.  I have verified that I am storing tasks for 120 days before cleanup is run.

Reply
0 Kudos
LucD
Leadership
Leadership

Just remembered that datetime values in events are always reported in UTC, while the snapshot timestamp are in local time.

Try this version, it converts the event timestamp to local time.

You alse might want to expriment with the value in $timeDiff.
It is currently set to 2 seconds.

$timeDiff = 2

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'}} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},

    @{N="Days Old";E={

        $now = Get-Date

        ($script:snaps | %{(New-TimeSpan -End $now -Start $_.CreateTime).Days}) -join '|'}},

    @{N='Created By';E={

        $startEvents = $script:snaps.CreateTime

        $start = $startEvents | Sort-Object | Select -First 1

        (Get-VIEvent -Entity $_.Name -Start $start -MaxSamples ([int]::MaxValue) |

            Where-Object {$_ -is [VMware.Vim.TaskEvent] -and $_.Info.DescriptionId -eq 'VirtualMachine.createSnapshot'} |

            ForEach-Object -Process {

                $event = $_

                $startEvents | ForEach-Object -Process {

                    if([math]::Abs((New-TimeSpan -Start $event.CreateTime.ToLocalTime() -End $_).TotalSeconds) -lt $timeDiff){

                        $event

                    }

                }

            } | Select-Object -ExpandProperty UserName) -join '|'}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

So I ran the update and I have picked a recent snapshot and the creator data is still not showing in the report.  Below is a screenshot.

2019-10-15_10-32-43.png

Here are the results of the $report

2019-10-15_10-35-32.png

Here is what is listed under tasks for the snapshot that was taken by the administrator

2019-10-15_10-37-37.png

I hope this information helps in some way, you have been a great help so far.

Reply
0 Kudos
LucD
Leadership
Leadership

I'm a bit confused, the report seems to say the snapshot was created on 10/10/2019 at 04:33, while the event seems to say 09/10/2019 at 11:33.

From that I would conclude that you are in a timezone UTC-5.

Is that correct?

If yes, the ToLocalTime function should have converted the event's CreateTime to 10/10/2019 04:33.

This could mean that the difference between the timestamps might be more than 2 seconds.

Did you try it with a higher $timeDiff, let's say 60 seconds?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

Modified to time offset to be 60 and still no results.

ran  Get-VIEvent -Entity servername -Types Info

2019-10-15_12-53-40.png

Reply
0 Kudos
LucD
Leadership
Leadership

Yes, that is approximately the same time of the Task event you showed earlier.

But are you in UTC-5?
Can you run this for that VM and the snapshot event?

Get-VIEvent -Entity ServerName -Types Info |

Select CreatedTime,@{N='Local time';E={$_.CreatedTime.ToLocal()}},FullFormattedMessage


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

10/9/2019 11:33:03 PM         Task: Create virtual machine snapshot

PS C:\Scripts> Get-TimeZone

Id                         : Central Standard Time

DisplayName                : (UTC-06:00) Central Time (US & Canada)

StandardName               : Central Standard Time

DaylightName               : Central Daylight Time

BaseUtcOffset              : -06:00:00

SupportsDaylightSavingTime : True

Reply
0 Kudos
LucD
Leadership
Leadership

Ok, that 1 hour difference is probably due to DST.

Did you run the snippet from my previous reply?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

Yes, it was the top line

10/9/2019 11:33:03 PM         Task: Create virtual machine snapshot
Reply
0 Kudos
LucD
Leadership
Leadership

Ok, that seems to be very close to the Created timestamp on the snapshot.
Can you run the following short experiment against that test VM.
It will create a snapshot, and display the timestamps from the event and the snapshot.

$vmName = 'ServerName'

$now = Get-Date

$vm = Get-VM -Name $vmName

$task = New-Snapshot -VM $vm -Name Test -RunAsync

while($task.ExtensionData.Info.State -ne 'success'){

    sleep 2

    $task.ExtensionData.UpdateViewData('Info.State')

}

$task.ExtensionData.UpdateViewData('Info')

Get-VIEvent -Entity $vm -Start $now | where{$task.Id -eq $_.Info.Task} |

Select @{N='Task StartTime';E={$task.ExtensionData.Info.StartTime.ToLocalTime().ToString('dd-MM-yyyy HH:mm:ss.fff')}},

    @{N='Task FinishTime';E={$task.ExtensionData.Info.CompleteTime.ToLocalTime().ToString('dd-MM-yyyy HH:mm:ss.fff')}},

    @{N='Event Created';E={$_.CreatedTime.ToString('dd-MM-yyyy HH:mm:ss.fff')}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
BrianDGeorge
Enthusiast
Enthusiast

Task StartTime                   Task FinishTime                Event Created

15-10-2019 13:37:14.056 15-10-2019 13:37:15.268 15-10-2019 13:37:14.053

Reply
0 Kudos
LucD
Leadership
Leadership

Perfect.
It looks like I swapped to conversion to local time.
Try this version

$timeDiff = 2

Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn'} |

Select -First 50 Name,

    @{N='SnapShot';E={

        function Get-Snap{

             param([PSObject]$snap)

             $snap

             if($snap.ChildSnapshotList){

             $snap.ChildSnapshotList | %{

                 Get-Snap -Snap $_

             }

            }

         }

         $script:snaps = $_.Snapshot.RootSnapshotList | %{

             Get-Snap -Snap $_

         }

         ($script:snaps | sort-Object -property Name).Name -join '|'}},

    @{N='SnapShot Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},

    @{N="Days Old";E={

        $now = Get-Date

        ($script:snaps | %{(New-TimeSpan -End $now -Start $_.CreateTime).Days}) -join '|'}},

    @{N='Created By';E={

        $startEvents = $script:snaps.CreateTime

        $start = $startEvents | Sort-Object | Select -First 1

        (Get-VIEvent -Entity $_.Name -Start $start.AddSeconds(- $timeDiff) -MaxSamples ([int]::MaxValue) |

            Where-Object {$_ -is [VMware.Vim.TaskEvent] -and $_.Info.DescriptionId -eq 'VirtualMachine.createSnapshot'} |

            ForEach-Object -Process {

                $event = $_

                $startEvents | ForEach-Object -Process {

                    if([math]::Abs((New-TimeSpan -Start $event.CreatedTime -End $_.ToLocalTime()).TotalSeconds) -lt $timeDiff){

                        $event

                    }

                }

            } | Select-Object -ExpandProperty UserName) -join '|'}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

BrianDGeorge
Enthusiast
Enthusiast

PURE GENIUS!!!

Reply
0 Kudos
LucD
Leadership
Leadership

Sorry, it took me a while to realise the root of the problem where the timestamps and the timezone.
All's well...


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
James57
Contributor
Contributor

I followed this thread with great interest.  However, it is not working for me with vCenter 6.7U3.  Latest version of PowerCLI.  First I have to remove a "}"  before it will run.  Then the output I receive is like this:

Name             : server1

SnapShot         :

SnapShot Created :

Days Old         :

Created By       :

Name             : server2

SnapShot         :

SnapShot Created :

Days Old         :

Created By       :

Name             : server3

SnapShot         :

SnapShot Created :

Days Old         :

Created By       :

It is listing snapshots that do not currently exist (maybe they did in the past?) without any other information.  I tried different versions of the script presented here and that is the best I get.  I am at UTC -5.  Any further advice or suggestions would be appreciated.   Amazing how involved it is to acquire this simple bit of data.

Reply
0 Kudos