I got a snapshot report that is designed to show VM's with snapshots that are 5 days old and then show the description of the snapshot, the size of the snapshot, the date it was created, the age, and the creator of the snapshot and I am not sure it is working. It is showing some VMs with no snapshots at all and rarely shows some of the details I was trying to pull. Here is the script:
#############################
# Variables #
#############################
$date = Get-Date -format "yyyy-MMM-dd"
$datetime = Get-Date
$filelocation = "\var\www\Snapshots\snapshot-$date.htm"
#############################
# Content #
#############################
$timeDiff = 2
$report = Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn';'Snapshot'=".+"} |
Select -First 50 name,
@{N='Description';E={
function Get-Snap{
param([PSObject]$snap)
$snap
if($snap.ChildSnapshotList){
$snap.ChildSnapshotList | %{
Get-Snap -Snap $_
}
}
}
$script:snaps = $_.Snapshot.RootSnapshotList |
where{$_.CreateTime -le (Get-Date).AddDays(-5) | % {
Get-Snap -Snap $_ }
}
($script:snaps | sort-Object -property Name).Name -join '|'}},
@{N='Size';E={
((Get-VM -Name $_.Name | Get-Snapshot -Name $script:snaps.Name).SizeGB | %{"{0:N1}" -f $_}) -join '|'
}},
@{N='Date Created';E={($script:snaps | sort-Object -property Name).CreateTime -join '|'}},
@{N="Age";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 '|'}}
## Build Count Var
$count = $report | where{$_.Snapshot -ne ''}
#############################
# Add Text to the HTML file #
#############################
$report | where{$_.Snapshot -ne ''} | ConvertTo-Html –Title "VMware Snapshot Check " –Body "<H1>VMware Snapshot Check</H1>" -Head "<link rel='stylesheet' href='style.css' type='text/css' />" | Out-File $filelocation
ConvertTo-Html –title "VMware Snapshot Check " -body "<H4>Date and time</H4>",$datetime -head "<link rel='stylesheet' href='style.css' type='text/css' />" | Out-File -Append $filelocation
ConvertTo-Html –title "VMware Snapshot Check " -body "<H4>VM Count</H4>",$count.Count -head "<link rel='stylesheet' href='style.css' type='text/css' />" | Out-File -Append $filelocation
You have to be a bit more specific on the "rarely shows some of the details I was trying to pull".
Which properties are not shown?
Note that the script uses events to obtain additional info on the snapshots.
If the event for a snapshot does not exist anymore, that info can not be retrieved.
To check why it shows VMs without Snapshots, you will have to check if the following returns such VMs.
Get-View -ViewType VirtualMachine -Filter @{'Runtime.PowerState'='poweredOn';'Snapshot'=".+"} |
Select Name,@{N='Snapshots';E={$_.Snapshot.Count}}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
ok I think the issue is its not applying the filter to show snapshots that are 5 days old. That command is showing some VMs with snapshots but they are not past that expiration date.
The Get-View is returning any VMs that are powered on and that do have a snapshot.
Only in the Description calculated property, the script limits the traversal of the root snapshot tree to entries that are 5 or more days old.
This script will not be limited to snapshots that are 5 days or older
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
How do I fix it?
You tell me.
You apparently used my script from Re: PowerCLI SnapShot Creator in Report - VMware Technology Network VMTN and added that Where-clause.
You must have had an idea what that Where-clause was supposed to be doing?
Also, note that the script only looks at the first 50 VM returned by Get-View.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I am trying to only look at snapshot that are older than 5 days, but not sure I did it right or where to filter it at.
Here's a script I use with Saved Credentials in a secure cred file and run with Task scheduler to delete snapshots older than 3 days:
Import-Module VMware.PowerCLI
#Make sure invalid certificate errors don't halt the script
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -confirm:$false
#Turn off CEIP
Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $false -confirm:$false
#Interactive use
#connect-viserver -Server <vcenter IP or name> -Verbose
#Script use
$creds = Get-VICredentialStoreItem -file "C:\Scripts\vmware\vmservicecred.xml"
Connect-viserver -Server $creds.Host -User $creds.User -Password $creds.Password
:: Delete snapshots older than 3 days ::
Get-VM | Get-Snapshot | Where {$_.Created -lt (Get-Date).AddDays(-3)} | Remove-Snapshot -Confirm:$false
You can just delete or comment out "Remove-Snapshot -Confirm:$false" from the last like and run the script interactively. Adjust to the number of days you want.
Here' another script that can be run interactively or as a scheduled task to Email a formatted report of all snapshots:
#$vCenterServer = "<IP or Name>"
# Connect to the vcenter server
#connect-viserver -Server $vCenterServer -Verbose
#Script use
$creds = Get-VICredentialStoreItem -file “C:\Scripts\vmservicecred.xml”
Connect-viserver -Server $creds.Host -User $creds.User -Password $creds.Password
# Set Email Variables
$fromemail = "vcenter@domain.tld"
$users = "vcadmin@doman.tld"
$server = "smtp.domain.tld"
$subject = "VMware Snapshot Report for " + (get-date -Format d/M/yyyy)
#---uncomment to use email authentication---#
#$username = ""
#$smtppassword = ""
#$secpasswd = ConvertTo-SecureString $smtppassword -AsPlainText -Force
#$smtpCredential = New-Object System.Management.Automation.PSCredential ($smtpusername, $secpasswd)
#Get all snapshots
$Snapshots = Get-VM | Get-Snapshot | select Description,Created,VM,SizeMB,SizeGB
# Format snapshot Size
function Get-SnapshotSize ($Snapshot)
{
if ($snapshot.SizeGB -ge "1")
{
$Snapshotsize = [string]([math]::Round($snapshot.SizeGB,3)) + " GB"
}
else {
$Snapshotsize = [string]([math]::Round($snapshot.SizeMB,3)) + " MB"
}
Return $Snapshotsize
}
# Style the dates - colourise
function set-SnapshotDate ($snapshot)
{
$greenValue = (get-date).AddDays(-1)
$RedValue = (get-date).AddDays(-3)
if ($snapshot.created -gt $greenValue)
{
$backgroundcolor = "green"
}
elseif ($snapshot.Created -lt $greenValue -and $snapshot.Created -gt $RedValue)
{
$backgroundcolor = "yellow"
}
else
{
$backgroundcolor = "red"
}
return $backgroundcolor
}
#Format the HTML
function Format-HTMLBody ($body)
{
$newbody = @()
foreach ($line in $body)
{
## Remove the Format Header
if ($line -like "*<th>Format</th>*")
{
$line = $line -replace '<th>Format</th>',''
}
## Format all the Red rows
if ($line -like "*<td>red</td>*")
{
$line = $line -replace '<td>red</td>',''
$line = $line -replace '<tr>','<tr style="background-color:Tomato;">'
}
## Formating all the Yellow Rows
elseif ($line -like "*<td>yellow</td>*")
{
$line = $line -replace '<td>yellow</td>',''
$line = $line -replace '<tr>','<tr style="background-color:Orange;">'
}
## Formating all the Green Rows
elseif ($line -like "*<td>green</td>*")
{
$line = $line -replace '<td>green</td>',''
$line = $line -replace '<tr>','<tr style="background-color:MediumSeaGreen;">'
}
## Building the new HTML file
$newbody += $line
}
return $newbody
}
# --------------------------------Create the report-------------------------------- #
# ----------Header and Style-------------- #
$date = (get-date -Format d/M/yyyy)
$header =@"
<Title>Snapshot Report - $date</Title>
<style>
body { font-family: 'Helvetica Neue', Helvetica, Arial;
font-size: 14px;
line-height: 20px;
font-weight: 400;
color: black;
}
table{
margin: 0 0 40px 0;
width: 100%;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
display: table;
border-collapse: collapse;
border: 1px solid black;
}
th {
font-weight: 900;
color: #ffffff;
background: black;
}
td {
border: 0px;
border-bottom: 1px solid black
}
</style>
"@
# ----------Header and Style-------------- #
# Create title for the Table
$PreContent = "<H1> Snapshot Report for " + $date + "</H1>"
# Convert to HTML
$HTMLmessage = $Snapshots | select VM,Created,@{Label="Size";Expression={Get-SnapshotSize($_)}},Description,@{Label="Format";Expression={Get-SnapshotDateStyle($_)}}| sort Created -Descending | ConvertTo-Html -Head $header -PreContent $PreContent
# -------Formay the HTML Report ------------- #
$Report = Format-HTMLBody ($HTMLmessage)
# --------------------------------Create the report-------------------------------- #
# Email report
send-mailmessage -from $fromemail -to $users -subject $subject -BodyAsHTML -body ([string]$Report) -priority Normal -smtpServer $server #-Credential $smtpCredential
# Logoff the server
Disconnect-VIServer -Confirm:$false
The procedure to create a saved credential file is as follows:
The credential file creation must be done in the context of the user that will be reading the saved and encrypted credentials.
This user needs VM power user permission in vCenter and runasbatch in windows.
#> New-VICredentialStorItem -host <IP or name of vCenter> -User "DOMAIN\VCAdmin" -password "<accountpassword>" -file c:\script\vmservicecred.xml
You are aware that the VICredentialStore does not work on PSv7?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi @LucD,
No I was not aware of that.
What command should you use as a replacement?
All these scripts run with 6.7.
There is no PowerCLI native solution, but there are others like the SecretManagement and SecretStore modules.
They require a bit more work but the SecretStore module allows one to plug in some of the more common secret storage solutions.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Can anyone help to modify this script to add more 3 rows for the datastore name, datastore size, datastore free size