NelsonCandela
Enthusiast
Enthusiast

Snapshot report with different VM details (on different hierarchies)

Jump to solution

Hey guys!

I know there are plenty of one- and two-liners out there giving you detailed information on how to create snapshot reports. I know, I have been using these myself but now my question is a more technical one.

Why?

Because I'd like to get a list of VMs including their snapshot info but also some more VM details like the parent vCenter and the ESXi host the VM resides on etc..

Example:

Get-VM | select Name,VMHost

This statement produces the VM names and the ESXi host names. OK.

But if I go into depths to chain up objects like so:

Get-VM | Get-Snapshot | Select-Object VM,@{N='VMHost';E={$_.VMHost}}

the statement only produces the VM names but VMHost fields remain empty.

I'm pretty sure that's because the $_. thingy points to the last object in the chain which is the snapshot detail and that does not include a parent host name field.

But being halfway sure about that doesn't solve the mystery of how do I reference an element in a prior part of this chain?

My report is supposed to list

  • VM name
  • vCenter name
  • VM Host
  • Power State
  • OS Version
  • Snapshot
  • Age
  • Size

At least the three highlighted fields are somewhere to be found within the $vm object itself and therefore are on a different hierarchy level.

Does anyone know how I can solve this?

Thanks in advance, hopefully this is interesting also to other readers. *sigh* why don't I understand programming?!

BR
NC

Labels (6)
0 Kudos
1 Solution

Accepted Solutions
vXav
Expert
Expert

You may want to put the one-liners aside and include loops to keep things readable and easily customizable.

 

Something like that ?

 

foreach ($vm in (get-vm)) {

    foreach ($snap in ($vm | get-snapshot)) {

        [pscustomobject]@{
            VM = $VM.Name
            vCenter = $VM.Uid.Split(":")[0].Split("@")[1]
            VMHost = $VM.VMHost
            PowerState = $VM.powerstate
            OSVersion = $vm.guest.OSFullName
            Snapshot = $snap.name
            AgeDays = ((get-date)-$snap.created).days
            SizeMB = [math]::round($snap.sizeMB,1)
        }

    }

}

 

 

 

You could even turn it into a function if you're going to use it now and again.

View solution in original post

0 Kudos
6 Replies
vXav
Expert
Expert

You may want to put the one-liners aside and include loops to keep things readable and easily customizable.

 

Something like that ?

 

foreach ($vm in (get-vm)) {

    foreach ($snap in ($vm | get-snapshot)) {

        [pscustomobject]@{
            VM = $VM.Name
            vCenter = $VM.Uid.Split(":")[0].Split("@")[1]
            VMHost = $VM.VMHost
            PowerState = $VM.powerstate
            OSVersion = $vm.guest.OSFullName
            Snapshot = $snap.name
            AgeDays = ((get-date)-$snap.created).days
            SizeMB = [math]::round($snap.sizeMB,1)
        }

    }

}

 

 

 

You could even turn it into a function if you're going to use it now and again.

View solution in original post

0 Kudos
NelsonCandela
Enthusiast
Enthusiast

Hey vXav,

that works exceptionally well, thank you very much!

I should probably get acquainted with the concepts of putting together a collection of properties myself. I have amended your script lightly to be able to create a list I can send via email or output directly when in ISE for example:

 

$SnapshotListe = @()

foreach ($vm in (get-vm)) {

    foreach ($snap in ($vm | get-snapshot)) {

        $obj = [pscustomobject]@{
            VM         = $VM.Name
            vCenter    = $VM.Uid.Split(":")[0].Split("@")[1]
            VMHost     = $VM.VMHost
            PowerState = $VM.powerstate
            OSVersion  = $vm.guest.OSFullName
            Snapshot   = $snap.name
            AgeDays    = ((get-date)-$snap.created).days
            SizeGB     = [math]::round($snap.sizeGB,2)
        }

        $SnapshotListe += $obj
        Clear-Variable obj
    }
}

$SnapshotListe | Out-GridView

 

 

 

Again thank you for your kind & quick help. 👍

Totally okay with putting aside one-liners, yet I'd still be interested if what I originally tried to do is possible at all.

BR
NC

0 Kudos
LucD
Leadership
Leadership

Yes, you can, with the help of the PipelineVariable.

Get-VM -PipelineVariable vm | 
Get-Snapshot | 
Select-Object @{N='VM';E={$vm.Name}},
    @{N='vCenter';E={([uri]$vm.ExtensionData.Client.ServiceUrl).Host}},
    @{N='VMHost';E={$vm.VMHost.Name}},
    @{N='PowerState';E={$vm.PowerState}},
    @{N='OSVersion';E={$vm.guest.OSFullName}},
    @{N='Snapshot';E={$_.Name}},
    @{N='AgeDays';E={(New-TimeSpan -Start $_.Created -End (Get-Date)).TotalDays}},
    @{N='SizeMB';E={[math]::Round($_.sizeMB,1)}}

 


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

vXav
Expert
Expert

To be clear there's nothing wrong with one liners, it's just that it gets pretty messy as you add more and more properties. Especially when you add some math, split and stuff like that.

Edit thanks to LucD's comment: You can also just pipe the foreach into ogv like that:

foreach ($vm in (get-vm)) {
BLAH
} | out-gridview

 

 

Now if the goal is to send it via email you can try something like that:

 

 

$bodyhtml = foreach ($vm in (get-vm)) {
   BLAH
} 
Send-MailMessage -SmtpServer smtp.blah.blah -Subject "snapshots" -Body ($bodyhtml | ConvertTo-Html | Out-String) -BodyAsHtml -From from@blah.blah -To to@blah.blah

 

0 Kudos
LucD
Leadership
Leadership

Just a small note, the foreach does not put anything in the pipeline.
So that pipe to Out-Gridview will not work I'm afraid.


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

0 Kudos
vXav
Expert
Expert

Thanks for the correction, my bad, I got mixed up with " | foreach-object".

Corrected (edited) .

0 Kudos