Well, PowerCLI makes my life a little bit easier. Believe it or not, each of us vCenter infrastructure admins has one of these: a Windows admin, thinking a snapshot is also a backup. Thankfully, Alan Renouf over at virtu-al.net wrote the SnapReminder, which already helped me a lot! However, occasionally the script isn’t finding the snapshot author (for whatever reason).

Since I want a notification in that case, I modified the script a little bit to suit my needs.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# - SnapReminder V1.0 By Virtu-Al - http://virtu-al.net
#
# Please use the below variables to define your settings before use
#
$smtpServer = "smtp.home.barfoo.org"
$MailFrom = "vcenter@barfoo.org"
$adminmail = "christian.heim@barfoo.org"
$VISRV = "vcenter.home.barfoo.org"

# Add the VI-Snapin if it isn't loaded already
if ( (Get-PSSnapin -Name "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue) -eq $null )
{
    Add-PSSnapin -Name "VMware.VimAutomation.Core"
}

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 -Force -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.ReplyTo = $adminmail
    if (!$mailto) {
        $msg.To.Add($adminmail)
    } else {
        $msg.To.Add($mailto)
        $msg.CC.Add($adminmail)
    }

    $msg.Subject = "Snapshot Reminder for $($snapshot.VM)"

$MailText = @"
There is an existing snapshot for the VM $($snapshot.VM) wurde am $($snapshot.Created.ToString("dddd, d. MMMM yyyy um HH:mm:ss")).
Please check, whether this snapshot is still needed, otherwise please delete it!

Just a short reminder: A snapshot doesn't replace a backup!

Name: $($snapshot.Name)
Description: $($snapshot.Description)
Snapshot size: $([math]::Round($snapshot.SizeMB * 1MB / 1GB))GB

"@

    $msg.Body = $MailText
    $smtp.Send($msg)
}

Connect-VIServer $VISRV

foreach ($snap in (Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-5))})){
    Get-SnapshotExtra $snap
    $SnapshotInfo = Get-SnapshotExtra $snap
    $mailto = ((Find-User $SnapshotInfo.Creator).Properties.mail)
    SnapMail $mailto $SnapshotInfo
}