VMware Cloud Community
DZ1
Hot Shot
Hot Shot
Jump to solution

I'm so close, but I can't get some objects to appear on a new line

The portion below is part of a bigger script, I just played with this to get the formatting right for one section.  I basically want to have my results appear like this:

Top ten VMs with the most memory assigned to them:

Name, Memory

Name, Memory

Name, Memory

Thanks to help on this site (a lot from LucD), I was able to look back at notes, and I'm very close to getting the results that I want, but it's not quite there.

From the portion of script that I have included, my results look like this:

Top ten VMs with the most memory assigned to them : {

                                                    VMName 12(GB),

                                                    VMname 12(GB),

                                                    VMName 12(GB),

                                                    VMName 8(GB)...}

I only changed the actual name of the VM with "VMName", the rest is exactly how my output looks.  Thanks for any help, I'm glad that I at least was able to output the results kind of sort of the way that I wanted.

I did try joining strings, and using the -ExpandProperty of Select, but obviously I did it wrong, but I'm making progress.

Function Write-Summary {
$AllVM = Get-VM
$TopMemVM = New-Object PSObject
$TopMemVM | Add-Member -MemberType NoteProperty -Name "Top ten VMs with the most memory assigned to them" -Value $($AllVM | where { $_.Powerstate -eq 'PoweredOn' } | Sort MemoryMB -Descending | Select -First 10 Name, MemoryMB | Foreach {
"`n" + $_.Name, [Math]::round($_.MemoryMB /1024) +'(GB)' } )
Write $TopMemVM | fl
}

Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" -body (Write-Summary | Out-String)

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

The trick to order the properties pre-V3 is with a Select-Object.

Like this

function Write-Summary {
  Get-VM | where { $_.Powerstate -eq 'PoweredOn' } | 
  Sort MemoryMB -Descending | Select -First 10 | %{
    New-Object PSObject -Property @{
       Name = $_.Name
       MemoryGB = [Math]::round($_.MemoryMB /1024) +'(GB)'
    }   } } Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" `
  -body (Write-Summary | Select Name,MemoryGB | Out-String)

In your variation you are in fact only creating 1 object, and you're placing all the top-10 VMs in 1 property of that object.

So there is no need to use the New-Object.

Something like this

function Write-Summary {
  $AllVM = get-vm
  $($AllVM |        Sort workingset -Descending | Select -First 10 Name, workingset | foreach {         $_.Name + " " + [string][Math]::round($_.MemoryMB /1024) +'(GB)'
      }) } Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" `
  -body (Write-Summary | Out-String)


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

View solution in original post

0 Kudos
11 Replies
LucD
Leadership
Leadership
Jump to solution

Why don't you try it like this (it's a bit more the PowerSHell way of doing this) ?

function Write-Summary {
  Get-VM | where { $_.Powerstate -eq 'PoweredOn' } | 
  Sort MemoryMB -Descending | Select -First 10 | %{
    New-Object PSObject -Property @{
       Name = $_.Name
      
MemoryMB = [Math]::round($_.MemoryMB /1024) +'(GB)'
    }   } } Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" `  -body (Write-Summary | Out-String)

For each of the top-10 VMs will a new object will be created that is placed in the pipeline.


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

DZ1
Hot Shot
Hot Shot
Jump to solution

LucD,

As always, thanks for the response.  I was writing my script that way, but then I read that when you put the results in a hash table, the results don't always come out the way that you put them in.  I also tried it tried the new-object with a hash table and I saw the unordered way for myself.  I saw that Powershell v3 has an [ordered] way of making sure things are in order, but this isn't going to run on a machine with v3 of powershell. 

Is there a way to make a hash table ordered without using [ordered] in v3?

Regardless, I do appreciate your solution, but just for the sake of knowing, how could it be done the other way?  I also owe you dinner, your help is always on point. Smiley Happy

0 Kudos
LucD
Leadership
Leadership
Jump to solution

The trick to order the properties pre-V3 is with a Select-Object.

Like this

function Write-Summary {
  Get-VM | where { $_.Powerstate -eq 'PoweredOn' } | 
  Sort MemoryMB -Descending | Select -First 10 | %{
    New-Object PSObject -Property @{
       Name = $_.Name
       MemoryGB = [Math]::round($_.MemoryMB /1024) +'(GB)'
    }   } } Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" `
  -body (Write-Summary | Select Name,MemoryGB | Out-String)

In your variation you are in fact only creating 1 object, and you're placing all the top-10 VMs in 1 property of that object.

So there is no need to use the New-Object.

Something like this

function Write-Summary {
  $AllVM = get-vm
  $($AllVM |        Sort workingset -Descending | Select -First 10 Name, workingset | foreach {         $_.Name + " " + [string][Math]::round($_.MemoryMB /1024) +'(GB)'
      }) } Send-MailMessage -SmtpServer '12.8.1.6' -From "<m..com>" -To "<r@.com>" -Subject "Test" `
  -body (Write-Summary | Out-String)


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

0 Kudos
DZ1
Hot Shot
Hot Shot
Jump to solution

LucD,

Thanks for your help, one issue that I have is that the sample I posted is just a small portion of my overall script.  There are more objects created and more things written.  I took that portion out because it was giving me problems with the output.  So I'm outputting a lot of objects, and I have them in sections, at the end, I write them all out like this:

"Datacenters, Clusters, and ESXi Hosts:",
$vDataCenter,
$Cluster,
$ESXiInfo, $('*'*100),
"VM and template information:",
$VM,
($TopMemVM | Select MemoryGB, Name),  (This is the section that I posted, I just didn't include the actual object created for the other stuff)
$('*'*100) | fl

If it really comes down to it, I will just use the hash table that you posted, because it does work just fine.  How could I use select-object though, with multiple outputs?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

I haven't seen the rest of your script, but I guess using calculated properties on a Select-Object cmdlet would do the trick.

In the Expression part of a calculated property you can have complete code blocks.


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

DZ1
Hot Shot
Hot Shot
Jump to solution

I didn't post the whole script orginally because I'm only having issues with that one section from my original post, which I bolded.

Function Get-DailySummary {

$AllDataCenter = Get-Datacenter | Select -ExpandProperty Name

$AllCluster = Get-Cluster | Sort

$AllESXiHost = Get-VMHost

$AllTemplate = Get-Template

$AllVM = Get-VM

$VMView = $ALLVM | Get-View

$AllSnapshots = ($AllVM | Get-Snapshot).count

$XPCount = 0

$VistaCount = 0

$7Count = 0

$2003Count = 0

$2008Count = 0

$LinuxCount = 0

$OtherCount = 0

switch ($AllVM) {

{ @(($_ | Get-View).config.GuestFullName -match "XP") } { $XPCount++ }

{ @(($_ | Get-View).config.GuestFullName -match "Vista") } { $VistaCount++ }

{ @(($_ | Get-View).config.GuestFullName -match "7") } { $7Count++ }

{ @(($_ | Get-View).config.GuestFullName -match "2003") } { $2003Count++ }

{ @(($_ | Get-View).config.GuestFullName -match "2008") } { $2008Count++ }

{ @(($_ | Get-View).config.GuestFullName -match "Linux" -and "Cent") } { $LinuxCount++ }

{ @(($_ | Get-View).config.GuestFullName -notmatch "XP" -and ($_ | Get-View).config.GuestFullName -notmatch "Vista" -and ($_ | Get-View).config.GuestFullName -notmatch "7"`

  -and ($_ | Get-View).config.GuestFullName -notmatch "2003" -and ($_ | Get-View).config.GuestFullName -notmatch "2008" -and ($_ | Get-View).config.GuestFullName -notmatch "Linux") } { $OtherCount++ }

}

#Creating a new Powershell Object to store information (for Datacenter)

$vDataCenter = New-Object -TypeName PSObject

$vDataCenter | Add-Member -MemberType NoteProperty -Name "vSphere Datacenter(s)" -Value ([string]::Join(", ",$ALLDataCenter))

#Creating a new Powershell Object to store Cluster information

$Cluster = New-Object PSObject

$Cluster | Add-Member -MemberType NoteProperty -Name "vSphere Clusters" -Value ([string]::Join(", ",$ALLCluster))

#Creating a new Powershell Object to store information (for ESXi Hosts)

$ESXiInfo = New-Object -TypeName PSObject

$vVersions = $AllESXiHost | Group Version | Select Name, Count

$HWModel = $AllESXiHost | Group Model | Select Name, Count

$ESXiInfo | Add-Member -MemberType NoteProperty -Name "Total ESXi hosts" -Value ($AllESXiHost).count

$vVersions | Foreach { Add-Member -InputObject $ESXiInfo -MemberType NoteProperty -Name "vSphere Version: $($_.Name)" -Value $_.Count }

$HWModel | Foreach { Add-Member -InputObject $ESXiInfo -MemberType NoteProperty -Name "HW Model: $($_.Name)" -Value $_.Count }

#Creating a new Powershell Object to store information (for VMs and templates)

$VM = New-Object PSObject

$VM | Add-Member -MemberType NoteProperty -Name "Total Templates" -Value ([string]::Join(',',($AllTemplate).count ))

#$VM | Add-Member -MemberType NoteProperty -Name "Total Snapshots" -Value ([string]::Join(',',($AllSnapshots) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total XP VMs" -Value ([string]::Join(',',($XPCount) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Vista VMs" -Value ([string]::Join(',',($VistaCount) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Windows 7 VMs" -Value ([string]::Join(',',($7Count) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Windows Server 2003 VMs" -Value ([string]::Join(',',($2003Count) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Windows Server 2008 VMs" -Value ([string]::Join(',',($2008Count) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Linux VMs" -Value ([string]::Join(',',($LinuxCount) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total Other VMs" -Value ([string]::Join(',',($OtherCount) ))

$VM | Add-Member -MemberType NoteProperty -Name "Total VMs" -Value ([string]::Join(',',($AllVM).count ) + ' (' + "of those $(($AllVM).count)," + " $(($AllVM | where { $_.Powerstate -eq 'Poweredoff' }).count)" + " are powered off" + ')' )

#$VM | Add-Member -MemberType NoteProperty -Name "Powered Off VMs" -Value ($ALLVM | where { $_.Powerstate -eq "PoweredOff" }).count

#Creating a new PS Object to store VMs with the most memory

#$TopMemVM = New-Object PSObject

#$TopMemVM | Add-Member -MemberType NoteProperty -Name "Top ten VMs with the most memory assigned to them" -Value ($AllVM | where { $_.Powerstate -eq 'PoweredOn' } | Sort MemoryMB -Descending | Select Name, @{ N='Memory(GB)'; E={ [Math]::Round($_.MemoryMB / 1024) } })

$TopMemVM = $AllVM | where { $_.Powerstate -eq 'PoweredOn' } |

Sort MemoryMB -Descending | Select -First 10 | Foreach {

New-Object PSObject -Property @{

    Name = $_.Name

    MemoryGB = [Math]::Round($_.MemoryMB / 1024)

}

}

Write $('*'*100),

"Datacenters, Clusters, and ESXi Hosts:",

$vDataCenter,

$Cluster,

$ESXiInfo, $('*'*100),

"VM and template information:",

$VM,

$TopMemVM,

$('*'*100) | fl

}

Send-MailMessage -SmtpServer '' -From "<@..com>" -To "<.@.com>" -Subject "Test" -body (Get-DailySummary | Out-String)

0 Kudos
DZ1
Hot Shot
Hot Shot
Jump to solution

The script works, the section that I orginally posted is working, but I am curious how I could use Select-Object with a hash table to order the list when I have many objects.  Thanks for your help LucD, I hope I need less of it as time passes.  Smiley Happy

0 Kudos
LucD
Leadership
Leadership
Jump to solution

No problem.

I'm not sure what you mean with the hash table, or do you mean a regular array ?


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

0 Kudos
DZ1
Hot Shot
Hot Shot
Jump to solution

I was talking about the

$TopMemVM = $AllVM | where { $_.Powerstate -eq 'PoweredOn' } |

Sort MemoryMB -Descending | Select -First 10 | Foreach {

New-Object PSObject -Property @{

    Name = $_.Name

    MemoryGB = [Math]::Round($_.MemoryMB / 1024)

}

Mainly using New-Object and having the -Property @{}  I actually wanted the entire script that way, but the order of my objects was not coming out right.  It does hapeen to come out right in this case. 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

That is a known annoyance in PowerShell v2.

The properties order in an object created by New-Object is not guaranteed.

The good news, in PowerShell v3 this was fixed.


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

0 Kudos
DZ1
Hot Shot
Hot Shot
Jump to solution

I read about the [ordered] feature in Powershell v3, I'm just too nervous to upgrade all of my servers to it, I'm worried about something breaking with current scripts that are already scheduled to run.  Thanks again for all of your help, I have definitely become a better scripter because of your help.  Smiley Happy

0 Kudos