Fed up of chasing those people who constantly create snapshots and leave them hanging around for weeks or even months on end ?
You no longer have to do the chasing, just use the following script to automatically find the offending snapshot, find the person who created it, get their email address from AD and send them an email reminding them of their mortal sin.
The email address is taken fromΒ the Email field as shown below:
A few requirements:
- The accounts must have the E-Mail field filled out
- The account you run the script as must have read permissions to AD (Any member of the domain should have this)
- You need to fill in the smtp server address, VI Server name and the from address at the top of this script
- You can run this as a scheduled task to constantly email the offending parties π
- The below script is set to remind of anything over 2 weeks old but this can easily be amended
- Once completed the offending person will receive an email as below:

Thanks to LucD for helping with finding the user who created the snapshot on the PowerCLI Forum.
The Script:
# - SnapReminder V1.0 By Virtu-Al - http://virtu-al.net # # Please use the below variables to define your settings before use # $smtpServer = "mysmtpserver.mydomain.com" $MailFrom = "me@mydomain.com" $VISRV = "MYVISERVER" function Find-User ($username){ if ($username -ne $null) { $usr = (($username.split("\"))[1]) $root = [ADSI]"" $filter = ("(&(objectCategory=user)(samAccountName=$Usr))") $ds = new-object system.DirectoryServices.DirectorySearcher($root,$filter) $ds.PageSize = 1000 $ds.FindOne() } } function Get-SnapshotTree{ param($tree, $target) $found = $null foreach($elem in $tree){ if($elem.Snapshot.Value -eq $target.Value){ $found = $elem continue } } if($found -eq $null -and $elem.ChildSnapshotList -ne $null){ $found = Get-SnapshotTree $elem.ChildSnapshotList $target } return $found } function Get-SnapshotExtra ($snap){ $guestName = $snap.VM # The name of the guest $tasknumber = 999 # Windowsize of the Task collector $taskMgr = Get-View TaskManager # Create hash table. Each entry is a create snapshot task $report = @{} $filter = New-Object VMware.Vim.TaskFilterSpec $filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime $filter.Time.beginTime = (($snap.Created).AddSeconds(-5)) $filter.Time.timeType = "startedTime" $collectionImpl = Get-View ($taskMgr.CreateCollectorForTasks($filter)) $dummy = $collectionImpl.RewindCollector $collection = $collectionImpl.ReadNextTasks($tasknumber) while($collection -ne $null){ $collection | where {$_.DescriptionId -eq "VirtualMachine.createSnapshot" -and $_.State -eq "success" -and $_.EntityName -eq $guestName} | %{ $row = New-Object PsObject $row | Add-Member -MemberType NoteProperty -Name User -Value $_.Reason.UserName $vm = Get-View $_.Entity $snapshot = Get-SnapshotTree $vm.Snapshot.RootSnapshotList $_.Result $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString()) $report[$key] = $row } $collection = $collectionImpl.ReadNextTasks($tasknumber) } $collectionImpl.DestroyCollector() # Get the guest's snapshots and add the user $snapshotsExtra = $snap | % { $key = $_.vm.Name + "&" + ($_.Created.ToString()) if($report.ContainsKey($key)){ $_ | Add-Member -MemberType NoteProperty -Name Creator -Value $report[$key].User } $_ } $snapshotsExtra } Function SnapMail ($Mailto, $snapshot) { $msg = new-object Net.Mail.MailMessage $smtp = new-object Net.Mail.SmtpClient($smtpServer) $msg.From = $MailFrom $msg.To.Add($Mailto) $msg.Subject = "Snapshot Reminder" $MailText = @" This is a reminder that you have a snapshot active on $($snapshot.VM) which was taken on $($snapshot.Created). Name: $($snapshot.Name) Description: $($snapshot.Description) "@ $msg.Body = $MailText $smtp.Send($msg) } Connect-VIServer $VISRV foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-14))})){ $SnapshotInfo = Get-SnapshotExtra $snap $mailto = ((Find-User $SnapshotInfo.Creator).Properties.mail) SnapMail $mailto $SnapshotInfo }
Hi
In VMWare 6 – line 72 is returning local time:
$key = $_.vm.Name + “&” + ($_.Created.ToString())
However $snapshot.CreateTime is in UTC.
Therefore the key doesn’t match and you don’t get the Creator filled in.
This works better for me:
$key = $_.vm.Name + “&” + ($_.Created.ToUniversalTime().ToString())
I don’t know if this is a new problem in VMware 6, or because I’m based in New Zealand.
I had the same issue with another script that I have. How I accomplished this is I import the ActiveDirectory module and lookup the first and last name of the user running the script, in AD:
$currentUser = Get-ADUser -Identity $env:USERNAME -Properties *
$lastName = $currentUser.Surname
$firstName = $currentUser.GivenName
$suffix = “@YOURDOMAIN.COM”
$emailAddr = $firstName + “.” + $lastName + $suffix
And then I build the email address using this information. So if your email addresses follow the format of “firstname.lastname@yourdomain.com” then this will work. The only issue is when you have users that don’t match this criteria.
How to Run This script and When I m trying to Run this Script Getting Error:
I just did this – here you go:
Modify the “SnapMail” function as follows:
Function SnapMail ($names, $MailTo, $snapshot)
{
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = $smtpFrom
$msg.To.Add($MailTo)
$msg.Subject = $noticeName
$MailText = @”
$names,
You have an active snapshot on the VM ($($snapshot.VM)) created on $($snapshot.Created).
Name: $($snapshot.Name)
Description: $($snapshot.Description)
Snapshot size: $([math]::Round($snapshot.SizeMB))MB
Please can you review this Snapshot and the justification for keeping it. If not, please
“@
$msg.Body = $MailText
$smtp.Send($msg)
}
The little foreach loop at the bottom – now looks like this:
foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-$daysOld))})){
$SnapshotInfo = Get-SnapshotExtra $snap
$mailto = ((Find-User $SnapshotInfo.Creator).Properties.mail)
$smtpGivenname = ((Find-User $SnapshotInfo.Creator).Properties.givenname)
$smtpSurname = ((Find-User $SnapshotInfo.Creator).Properties.sn)
$smtpFullname = ((Find-User $SnapshotInfo.Creator).Properties.displayName)
#SnapMail $mailto $SnapshotInfo
SnapMail $smtpGivenname $smtpTo $SnapshotInfo
#SnapMail $smtpSurname $smtpTo $SnapshotInfo
#SnapMail $smtpFullname $smtpTo $SnapshotInfo
}
Uncomment the line you want to use – comment out givenName if you don’t need it.
I’ve exactly the same case where we prefix the user with Admin-
i would like to know how to trim the same so I can make use of the script
At my company we use an admin account that is based on our domain user account appended with “_admin”. So if my username is ghr, my admin account is ghr_admin. Unfortunately, there are no email addresses associated with the admin account and the admin account will be the “creator” of the snapshot.
How do I “trim” the creator so the it is the username without the _admin so the $Mailto will work?
Thanks
Yeah, I have got the same problem with the creator attribute .
Do you have any idea ?
I keep getting the “You cannot call a method on a null-valued expression too.
At C:\Scripts\SnapshotCreator.ps1:63 char:4” error. It seems to come from transient snapshots. That is, our backup procedures create and delete many snapshots. The snapshot creation shows up in the event tasks but when the snapshots no longer exist you get the null error. Adding the line “if (!$snapshot) { return }” after $snapshot is defined around line 64 skips the deleted snapshots. There may be a better solution. I am new to PS and PowerCLI.
Pingback: Yet another PowerCLI script for VM snapshot reporting . - VMwaremine - Mine of knowledge about virtualization
Pingback: PowerCLI – How do I use it? | vcdx133.com
Pingback: Troubleshooting VMware snapshots | Ginka's World
I found the answer. Depending on whether you want to add another ‘To’, ‘Cc’ or Bcc’ email address, add the following lines in Snapmail function:
$msg.To.Add(first.last@company.com)
$msg.CC.Add($EmailCc)
$msg.BCC.Add($EmailBCc)
Is there a way to add a second email in addition to the snapshot creator?
I really need to get this script working as there are several people in my office that create snapshots and never go back and delete them. After putting in my details at the top, I’ve changed the date of creation time from 14 days to 2 days. When I run this I get:
You cannot call a method on a null-valued expression.
At C:\Scripts\SnapshotCreator.ps1:63 char:4
+ $key = $_.EntityName + “&” + ($snapshot.CreateTime.ToString())
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorID : InvokeMethodOnNull
If I run this it gives me the VM Name, CreationDate, and the User (which isn’t Local Admin account):
$myVMs = Get-VM
$VMsWithSnaps = @()
foreach ($vm in $myVMs) {
$vmView = $vm | Get-View
if ($vmView.snapshot -ne $null) {
Write-Host “VM $vm has a snapshot”
$SnapshotEvents = Get-VIEvent -Entity $vm -type info -MaxSamples 1000 | Where {
$_.FullFormattedMessage.contains(“Create virtual machine snapshot”)}
try {
$user = $SnapshotEvents[0].UserName
$time = $SnapshotEvents[0].CreatedTime
} catch [System.Exception] {
$user = $SnapshotEvents.UserName
$time = $SnapshotEvents.CreatedTime
}
$VMInfo = ββ | Select “VM”,”CreationDate”,”User”
$VMInfo.”VM” = $vm.Name
$VMInfo.”CreationDate” = $time
$VMInfo.”User” = $user
$VMsWithSnaps += $VMInfo
}
}
$VMsWithSnaps | Sort CreationDate
What do I need to change in the SnapReminder script to get it to work properly and email the SnapShot creator?
hi,
how can I see the list of task snapshot failure on VM ?
As seen in the ESX Task view panel (not Event view).
I do not want to have the list of event but list task thougt PowerCLI.
thank you
Any way to be able to poll 2 vcenter servers in the one script? I get an error when I add multiples.
Pingback: Informacion de todos los Snapshots en vmWare | While(1){ }
Any solutions about this? Looks like a problem since upgrading to vCenter 5.0??!
Pingback: Check if Snapshot Consolidation is Occurring in the Background on an ESX(i) Host - VirtuallyHyper
Hello,
This appears to have stopped working after we upgraded our vcenter to 5.0, are you planning on releasing an updated version?
Also, is it possible to add the ability to ignore certain machines, for example Veeam now snapshots each replica so we would want to ignore all machines ending in “_replica”.
Cheers
Lloyd
Cannot get it working.
Getting the same error as P on the line 63. From what I read it has to do something with the time format. Removing the line won’t help.
Hello i came across this script and this is exactly what we need. My problem is I can’t get it to work in our environment. I keep getting the follow error when I execute it.
You cannot call a method on a null-valued expression.
At C:\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + “&” + ($snapshot.CreateTime.ToString <<<<
())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString <<<<
())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString <<<<
())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString <<<<
())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString <<<<
())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : InvokeMethodOnNull
Exception calling "Add" with "1" argument(s): "Value cannot be null.
Parameter name: item"
At C:\SnapReminder.ps1:85 char:13
+ $msg.To.Add <<<< ($Mailto)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Exception calling "Send" with "1" argument(s): "A recipient must be specified.
At C:\SnapReminder.ps1:98 char:12
+ $smtp.Send <<<< ($msg)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Any help would be great. I have read through the treads and tried changing some of the lines as suggested and still no go. Any thoughts?
I just can’t get this script to work it just keeps saying that it doesn’t expect $smptServer at he beginning.nplease please help
Thanks Steve
This is a great script you can run on a daily scheduled basis. Just modify the following statement in the ‘foreach’ loop towards the bottom of the script: “(Get-Date).AddDays(0)”. Awesome script and works as described. Kudos to the author!
Dumped some more objects and actually it WAS what Jurgen suggested. Probably works nicely in UK as-is, but if the timezone isn’t GMT/UTC you’re generating two different $key’s in the code.
This resolved some of the problems, but still _old_ (over 2yrs or so) snapshots are missing the creator – for which I can see two plausible reasons – too many tasks and/or this damn DST (making the deviation an ever-changing target).
But this is a minor issue, since who would want daily e-mails for lengthy periods of time π
Thanks for the script anyway.
Whew, I’m not alone!
I too have spent the day trying to get SnapReminder able to email the creator of the snapshot. It seems that there is not a “Creator” attribute (value? variable?). When I run the script through the PowerGUI Script Editor, I can expand the$SnapshotInfo variable, I do not see “Creator” – or any reference to the creator of the snapshot.
I’ve found a script that pulls out snapshot creator information from the VPX_TASK table in the vCenter database, so the information is in there. I’m not sure where else it might recorded.
Thanks for the swift response. Unfortunately the output is (for each snapshot) “Snapshot ***** has a creator of .”
I can see the use that initiated the taks in vSphere client, so the info has to be somewhere. I also already tried that timedeviation-trick that Jurgen suggested, although I’m not quite sure why it would help since all the servers are on the same timezone.
What do you get if you change the last loop to this, do you get a username ?
I tried the script on 4.1 and it gets all the snapshots (and sizes with a small modification) but the creator can not be found for ANY of the dozen or so snapshots. Any ideas why? The snapshots have been created using vSphere client, either while on ESX 4.0 or on ESXi 4.1 – no difference in results. I tried to dump the whole SnapshotInfo-object, but couldn’t find anything pointing to the creator of the snapshot.
Or change the following rule:
$key = $_.EntityName + “&” + ($snapshot.CreateTime.ToString())
To:
$timedeviation = get-date -uformat “%Z”
$key = $_.EntityName + “&” + (($snapshot.CreateTime.AddHours($timedeviation)).ToString())
Chris
Remove the following line:
$key = $_.vm.Name + “&” + ($_.Created.ToString())
That works for me because i’m in a not UCT/GMT timezone
Can anyone help me. I keep getting the same error running this script. It seems like it can’t get the username.
Exception calling “Add” with “1” argument(s): “Value cannot be null.
Parameter name: item”
At C:\Users\gateway\Desktop\snap.ps1:86 char:13
+ $msg.To.Add <<<< ($Mailto)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Exception calling "Send" with "1" argument(s): "A recipient must be specified."
At C:\Users\gateway\Desktop\snap.ps1:99 char:12
+ $smtp.Send <<<< ($msg)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
How can I have the following script omit removing snaps from certain vm’s? I want to remove majority of snapshots from vm’s, but not all of my vm’s but this would be very tedious to do by hand!
script –
$vcserver=”xxxxxx”
Add-PSsnapin VMware.VimAutomation.Core
#Initialize-VIToolkitEnvironment.ps1
connect-VIServer $vcserver
get-vm | get-snapshot | where { $_.name -eq “xxxxxxxxxx” } | remove-snapshot -confirm:$false
@Andreea –
Should be – just change this line:
$mailto = ((Find-User $SnapshotInfo.Creator).Properties.mail)
Where it refers to .mail, find out what the Web Page field is called and use it here.
To login to vC we are using OU accounts and we can’t add the email to the E-Mail field because it’s already in use by our regular accounts. Is there any way I can put the email under Web Page filed and point to that field for the emails to be sent?
Thanks
How can I tell this script to get all snapshots regardless. I tried changing the line
foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-14))
to
foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(0))
but I get a NULL value error.
Thanks
All fixed…
so not to worry anymore π
I believe that it could be done through some sort of css and html formatting as well
Hi Frank,
I have done this like that:
$MailText = @”
This is a reminder that you have a snapshot active on $($snapshot.VM) which was taken on $($snapshot.Created).
Created by: $($(Find-User $SnapshotInfo.Creator).Properties.name)
Email: $($(Find-User $SnapshotInfo.Creator).Properties.mail)
Name: $($snapshot.Name)
Description: $($snapshot.Description)
Snapshot size: $([math]::Round($snapshot.SizeMB))MB
“@
$msg.Body = $MailText
$smtp.Send($msg)
}
So you will have nice presentation of who/when/why/size and you probably can put whatever info youd like to π just need to add few lines…
My question on the other hand is:
how could I create only one email with all of the snapshots taken?
i am thinking on putting a loop on the end of the script but not sure where…
Pingback: Who created that VM ? « Virtu-Al
Pingback: PowerCLI to SQL Databases « Virtu-Al
Is it also possible to add the users fullname. So you can personalize the mail.
Hi $fullname
blablabla
I tried to alter the script but i’m a complete noob without people I know with the rigt knowledge.
Sorry I didn’t get to this for a few days. I changed the for loop and am getting the same result. One thing that I notice is that I get lots (LOTS) of errors while running the script like this:
You cannot call a method on a null-valued expression.
At C:\Users\pat\Desktop\SnapReminder.ps1:63 char:63
+ $key = $_.EntityName + “&” + ($snapshot.CreateTime.ToString <<<< ())
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Daniel's post from 2009 indicates that this is because the administrator created the snapshot which isn't the case in my situation although the script says that the local administrator ("meteor") did create it.
Anyway, I'm running it against my test lab cluster where there are 3 snapshots. Here's an example of the information from one of the snapshots:
Creator : meteor
Description :
Created : 11/29/2010 2:30:44 PM
Quiesced : False
PowerState : PoweredOn
VM : centrify3
VMId : VirtualMachine-vm-3883
Parent :
ParentSnapshotId :
Children :
SizeMB : 7721.44
IsCurrent : True
IsReplaySupported : False
Id : VirtualMachineSnapshot-snapshot-3886
Name : before centrify install
Here's the information on the same snapshot taken from a daily vCheck report generated this morning at 3AM:
centrify3 before centrify install 51 Allen, Pat 8714.44 11/29/2010 2:30:44 PM
It shows the correct creator, "Allen, Pat". It's interesting to note that the size is different. At 3AM it was 8714MB whereas at 2PM it's 7721MB.
Any thoughts would certainly be appreciated! THANKS!
Pat
This script doesn’t work if the snap was created with a scheduled task – there is no email recipient. Is there a way around this?
That is strange, what happens if you replace the bottom foreach loop with this:
foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-14))})){
Get-SnapshotExtra $snap
}
Do you get the creator for each snapshot listed ?
Hi Al,
I’ve run vCheck on a daily basis for quite a while now and it’s GREAT! Thanks for putting this and everything else out in the community.
I decided to put together a script to automate reminding folks about snapshots. My first idea was parsing the output of vCheck but then I checked your site and found SnapRemind! This is EXACTLY what I need to put together and it would save me a tremendous amount of work. (Especially considering that I’m an old Unix nerd and I’m just starting to learn Power CLI.) But I’m having a little problem with things. When I run your vCheck script, it shows me all the snapshots with the correct creator names. When I run the SnapReminder script, it always shows the name of the local administrator as the creator of the snapshot. The local admin doesn’t have an email address so no mail is sent. I’m running vSphere 4.1 in case that matters.
Any idea what might be wrong?
THANKS again!
Pat
Pingback: Modified SnapReminder
Can someone tell me where i can find the V2 of this excellent Script ?? π
Mr G
Sure, just change line 104 to the following:
foreach ($snap in (Get-Datacenter “MyDC” | Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-14))})){
Excellent script and works very well! Is there anyway to have this script focus on a specific datacenter in vCenter?
Excellant write-up! Thanks for the tip, works like a charm! Nagging has begun! π
Pingback: VMware Snapshot Alerting and Reporting | VirtualPro
Where do you stand on a v2 of the snapshot reminder?
Pingback: How to ease the management and monitoring of VMware Snapshots « TheSaffaGeek
Pingback: How to ease the management and monitoring of VMware Snapshots « TheSaffaGeek
Pingback: How to ease the management and monitoring of VMware Snapshots « TheSaffaGeek
Pingback: How to ease the management and monitoring of VMware Snapshots « TheSaffaGeek
Pingback: VMware Scripting: Snapshots auf der Spur
@Falko
I had this error also. In my case it was because the Administrator made the snapshot an there is no email adress for Administrator in the AD. My Solution:
Line 10:
if ($username -ne $null -and $username -ne “Administrator”)
Line 86:
if($Mailto -eq $null){
$msg.To.Add(“vmadmin@blah.bla”)
}
else{
$msg.To.Add($Mailto)
}
Hth
Well, for me it is semi-working. I get emails, but the script gives me the following error:
You cannot call a method on a null-valued expression.
At :line:63 char:83
+ $key = $_.EntityName + “&” + ($snapshot.CreateTime.ToString <<<< ())
Index operation failed; the array index evaluated to null.
At :line:64 char:32
+ $report[ <<<< $key] = $row
Good script,thanks. I had a problem with the timing, so I changed the line 50 to:
$filter.Time.beginTime = (($snap.Created).AddMinutes(-30)
@chris
My blog mangled the code, I have now moved it over to a different hosting method so please try the above.
Let me know if you have any further issues.
I get an error when running the script error line 93 char 13
+ $MailText = @ <<<< "
If I remove the @ I get another error with another @ symbol farther down.
Pingback: Virtu-Al Β» PowerCLI: SnapReminder « ben.neise.co.uk
Pingback: VMware vSphere 4 has a Snapshot Alarm | VCritical
@Jason Boche
Thanks man
@Ivo Beerens
Good thinking V2 Coming up !
Love it!
Hey Allan, a suggestion it would be nice to see the size of the snapshot file(s) in GB the e-mail