All About Windows - SS67/project-docs GitHub Wiki

# vSphere-SnapshotReport.ps1

$vCenter = "vcenter.company.local"

Import-Module VMware.PowerCLI -ErrorAction Stop
Set-PowerCLIConfiguration -Scope User -InvalidCertificateAction Ignore -ParticipateInCEIP $false -DisplayDeprecationWarnings $false -Confirm:$false | Out-Null

$user = Read-Host "Username"
$pass = Read-Host "Password" -AsSecureString
$cred = New-Object System.Management.Automation.PSCredential($user, $pass)

Connect-VIServer -Server $vCenter -Credential $cred -ErrorAction Stop | Out-Null

function Get-SnapReport {
    param($VMs, $Tenant)
    foreach ($vm in $VMs) {
        $snaps = Get-Snapshot -VM $vm -ErrorAction SilentlyContinue
        $owner = (Get-TagAssignment -Entity $vm -Category "VM Owner" -ErrorAction SilentlyContinue).Tag.Name -join ","
        if (-not $owner) { $owner = "N/A" }
        $t = if ($Tenant) { $Tenant } else { (Get-ResourcePool -VM $vm -ErrorAction SilentlyContinue).Name -join "," }

        [PSCustomObject]@{
            Tenant        = $t
            VMName        = $vm.Name
            IPAddress     = ($vm.Guest.IPAddress -join ",")
            Owner         = $owner
            SnapshotCount = @($snaps).Count
            Snapshots     = if ($snaps) { ($snaps | ForEach-Object { "$($_.Name) [$($_.Created)] $([math]::Round($_.SizeGB,2))GB" }) -join " | " } else { "None" }
        }
    }
}

Write-Host "1. Query entire Tenant (Resource Pool)"
Write-Host "2. Query a specific VM"
$choice = Read-Host "Select option (1/2)"

switch ($choice) {
    "1" {
        $tenant = Read-Host "Enter Tenant / Resource Pool name"
        $rp = Get-ResourcePool -Name $tenant -ErrorAction SilentlyContinue
        if (-not $rp) {
            Write-Host "Resource Pool '$tenant' not found." -ForegroundColor Red
            Disconnect-VIServer -Confirm:$false; return
        }
        $vms = Get-VM -Location $rp
        if (-not $vms) {
            Write-Host "No VMs found in '$tenant'." -ForegroundColor Yellow
            Disconnect-VIServer -Confirm:$false; return
        }
        $report = Get-SnapReport -VMs $vms -Tenant $rp.Name
    }
    "2" {
        $vmName = Read-Host "Enter VM name"
        $vms = Get-VM -Name $vmName -ErrorAction SilentlyContinue
        if (-not $vms) {
            Write-Host "VM '$vmName' not found." -ForegroundColor Red
            Disconnect-VIServer -Confirm:$false; return
        }
        $report = Get-SnapReport -VMs $vms
    }
    default {
        Write-Host "Invalid option." -ForegroundColor Red
        Disconnect-VIServer -Confirm:$false; return
    }
}

$report | Format-List
$report | Export-Csv -Path ".\SnapshotReport_$(Get-Date -f yyyyMMdd_HHmm).csv" -NoTypeInformation

Disconnect-VIServer -Server $vCenter -Confirm:$false

version 2

# vSphere-SnapshotReport.ps1

$vCenter = "vcenter.company.local"

Import-Module VMware.PowerCLI -ErrorAction Stop
Set-PowerCLIConfiguration -Scope User -InvalidCertificateAction Ignore -ParticipateInCEIP $false -DisplayDeprecationWarnings $false -Confirm:$false | Out-Null

$user = Read-Host "Username"
$pass = Read-Host "Password" -AsSecureString
$cred = New-Object System.Management.Automation.PSCredential($user, $pass)

Connect-VIServer -Server $vCenter -Credential $cred -ErrorAction Stop | Out-Null

function Get-SnapReport {
    param($VMs, $Tenant)
    foreach ($vm in $VMs) {
        $snaps = @(Get-Snapshot -VM $vm -ErrorAction SilentlyContinue)
        $owner = (Get-TagAssignment -Entity $vm -Category "VM Owner" -ErrorAction SilentlyContinue).Tag.Name -join ","
        if (-not $owner) { $owner = "N/A" }
        $t = if ($Tenant) { $Tenant } else { (Get-ResourcePool -VM $vm -ErrorAction SilentlyContinue).Name -join "," }

        [PSCustomObject]@{
            Tenant         = $t
            VMName         = $vm.Name
            IPAddress      = ($vm.Guest.IPAddress -join ",")
            Owner          = $owner
            SnapshotCount  = $snaps.Count
            OldestSnapshot = if ($snaps) { ($snaps | Sort-Object Created | Select-Object -First 1).Created } else { $null }
            NewestSnapshot = if ($snaps) { ($snaps | Sort-Object Created | Select-Object -Last 1).Created } else { $null }
            Snapshots      = if ($snaps) { ($snaps | ForEach-Object { "$($_.Name) [$($_.Created)] $([math]::Round($_.SizeGB,2))GB" }) -join " | " } else { "None" }
        }
    }
}

Write-Host "1. Query entire Tenant (Resource Pool)"
Write-Host "2. Query a specific VM"
$choice = Read-Host "Select option (1/2)"

switch ($choice) {
    "1" {
        $tenant = Read-Host "Enter Tenant / Resource Pool name"
        $rp = Get-ResourcePool -Name $tenant -ErrorAction SilentlyContinue
        if (-not $rp) {
            Write-Host "Resource Pool '$tenant' not found." -ForegroundColor Red
            Disconnect-VIServer -Confirm:$false; return
        }
        $vms = Get-VM -Location $rp
        if (-not $vms) {
            Write-Host "No VMs found in '$tenant'." -ForegroundColor Yellow
            Disconnect-VIServer -Confirm:$false; return
        }
        $scopeName = $rp.Name
        $report = Get-SnapReport -VMs $vms -Tenant $rp.Name
    }
    "2" {
        $vmName = Read-Host "Enter VM name"
        $vms = Get-VM -Name $vmName -ErrorAction SilentlyContinue
        if (-not $vms) {
            Write-Host "VM '$vmName' not found." -ForegroundColor Red
            Disconnect-VIServer -Confirm:$false; return
        }
        $scopeName = $vmName
        $report = Get-SnapReport -VMs $vms
    }
    default {
        Write-Host "Invalid option." -ForegroundColor Red
        Disconnect-VIServer -Confirm:$false; return
    }
}

$report | Format-List

$reportName = "SnapshotReport_$($scopeName)_$(Get-Date -f yyyyMMdd_HHmm).csv"
$reportPath = Join-Path (Get-Location).Path $reportName
$report | Export-Csv -Path $reportPath -NoTypeInformation

$now        = Get-Date
$withSnaps  = @($report | Where-Object { $_.SnapshotCount -gt 0 })
$olderMonth = @($withSnaps | Where-Object { $_.OldestSnapshot -lt $now.AddMonths(-1) })
$recentWeek = @($withSnaps | Where-Object { $_.NewestSnapshot -ge $now.AddDays(-7) })
$multiSnap  = @($withSnaps | Where-Object { $_.SnapshotCount -gt 1 })

Write-Host ""
Write-Host "================ SUMMARY ================"
Write-Host "Scope                      : $scopeName"
Write-Host "VMs scanned                : $(@($report).Count)"
Write-Host "VMs with snapshots         : $($withSnaps.Count)"
Write-Host "Total snapshots            : $(($report | Measure-Object SnapshotCount -Sum).Sum)"
Write-Host "VMs with snapshots > 1 mo  : $($olderMonth.Count)"
Write-Host "VMs with snapshots < 1 wk  : $($recentWeek.Count)"
Write-Host "VMs with >1 snapshot       : $($multiSnap.Count)"
Write-Host "-----------------------------------------"
if ($olderMonth) { Write-Host "Older than a month : $(($olderMonth.VMName) -join ', ')" -ForegroundColor Red }
if ($multiSnap)  { Write-Host "Multiple snapshots : $(($multiSnap.VMName) -join ', ')" -ForegroundColor Yellow }
Write-Host "-----------------------------------------"
Write-Host "Report name                : $reportName"
Write-Host "Report location            : $reportPath"
Write-Host "========================================="

Disconnect-VIServer -Server $vCenter -Confirm:$false