VMware Cloud Community
mars0077
Enthusiast
Enthusiast
Jump to solution

Script for reporting and removing VMs older than 2 weeks.

Hi guys,

I need some help in putting a script together that will remove all powered off virtual machines that have been powered off longer than 14 days and will send out an e-mail with the virtual machines that were removed. Using the code below I am able to retrieve the desired virtual machines that match the date but can't seem to be able to use the same variables to pipe them into the Remove-VM commandlet.

Code:

$vms = Get-VM | where {$_.PowerState -eq "PoweredOff"}

$vmPoweredOff = $vms | %{$_.Name}

$events = Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vms | where{$_.FullFormattedMessage -like "*is powered off"}

Send-MailMessage -From virtualadmin@company.com -To vadmin@company.com -SmtpServer smtprelay.company.com

-Subject "Removed $($14day) VM" -Body ($vmNames | Out-String) ----> The body would only include the virtual machines that were removed.

Much appreciated. Thanks!!

Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

I'm a bit confused.
Originally you said "...remove all powered off virtual machines that have been powered off longer than 14 days"

That's what my script does.

Now you seem to ask that the VMs that have been powered off during the last 14 days should be removed.

Which is it?

In any case, to remove the VMs that have been powered off longer than 14 days ago, you can do

$vms = @{}

Get-VM | where {$_.PowerState -eq "PoweredOff"} | % {$vms.Add($_.Name, $_)}

Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |

  Sort-Object -Property CreatedTime -Unique | % {

  $vms.Remove($_.VM.Name)

}

Remove-VM -VM $vms.Values -DeletePermanently -Confirm:$false -WhatIf

$sMail = @{

  From   = 'virtualadmin@company.com'

  To   = 'vadmin@company.com'

  SmtpServer = 'smtprelay.company.com'

  Subject   = "Removed $($vms.Keys.Count) VM powered off more than 14 days"

  Body   = ($vms.Keys | Out-String)

}

Send-MailMessage @sMail

And to remove that VMs that have been powered off during the last 14 days, you can do

$vms = @{}

$vm = Get-VM | where{$_.PowerState -eq 'PoweredOff'}

Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vm -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |

  Sort-Object -Property CreatedTime -Unique | % {

  $vms.Add($_.VM.Name,(Get-VM -Name $_.VM.Name))

}

Remove-VM -VM $vms.Values -DeletePermanently -Confirm:$false -WhatIf

$sMail = @{

  From   = 'virtualadmin@company.com'

  To   = 'vadmin@company.com'

  SmtpServer = 'smtprelay.company.com'

  Subject   = "Removed $($vms.Keys.Count) VM powered during the last 14 days"

  Body   = ($vms.Keys | Out-String)

}

Send-MailMessage @sMail


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

View solution in original post

Reply
0 Kudos
7 Replies
LucD
Leadership
Leadership
Jump to solution

Try something like this.
Since you stated that you wanted to remove VMs powered off more than 14 days ago, I used a hash table with all powered off VMs.

Then I remove the VMs that have been powered off during the last 14 days from that hash table.

Note that I used the Unique switch on the Sort-Object, since a VM can be powered off more than once during the last 14 days.

And I used splatting for the Send-MailMessage parameters to improve readability.

$vms = @{}

Get-VM | where {$_.PowerState -eq "PoweredOff"} | % {$vms.Add($_.Name, $_)}

Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |

  Sort-Object -Property CreatedTime -Unique | % {

  $vms.Remove($_.VM.Name)

}


$sMail = @{

  From   = 'virtualadmin@company.com'

  To   = 'vadmin@company.com'

  SmtpServer = 'smtprelay.company.com'

  Subject   = "Removed $($vms.Keys.Count) VM powered off more than 14 days"

  Body   = ($vms.Keys | Out-String)

}

Send-MailMessage @sMail


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

Reply
0 Kudos
mars0077
Enthusiast
Enthusiast
Jump to solution

Hi Luc,

Thank you for helping me on this one, I do appreciate it. I modified your code a little so that I can use it to test recently powered off virtual machines. So far it is able to retrieve the desired virtual machines based on the Get-VIEvent being specified and is also able to send out the e-mail but it did not remove the any of the virtual machines that made the list.

Code:

$vms = @{}

Get-VM | where {$_.PowerState -eq "PoweredOff"} | % {$vms.Add($_.Name, $_)}

Get-VIEvent -Start (Get-Date).AddHours(-1) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} | Sort-Object -Property CreatedTime -Unique | % {$vms.Remove($_.VM.Name)}

I used the AddHours so that I can test with virtual machines that were recently powered off since I don't want to remove the older ones yet until I know the script will work as intended. The above modification does produce the list but does not remove them. Btw - Is this line of code "$vms.Remove($_.VM.Name" actually doing the same thing as "Remove-VM"?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

That is correct, there is no Remove-VM in the script I posted.
I based myself on the lines of code you posted.

And no, the expression $vms.Remove($_.VM.Name) removes the VM from the hash table that is used.

That is not removing the VM itself.

You can remove all the selected VMs by placing this line before the Send-MailMessage lines

$vms.Values | Remove-VM -DeletePermanently -Confirm:$false -WhatIf

Remove the WhatIf switch when you are sure the correct VMs are removed.


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

Reply
0 Kudos
mars0077
Enthusiast
Enthusiast
Jump to solution

Thanks Luc! Great tip on the "-WhatIf" statement cause if looks like the code would have removed 13 powered off virtual machines. Here's what I have found in executing the code with different values.

If I execute the code (below) without the "| % {$vms.Remove($_.VM.Name)}" line, I will see the virtual machines that I recently powered off and will also see that the code would have removed all of the virtual machines that are in a powered off state.  See output below.

Code:

Get-VIEvent -Start (Get-Date -Hour 12 -Minute 00) -Finish (Get-Date -Hour 15 -Minute 40) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} | Sort-Object -Property CreatedTime -Unique

Template             : False

Key                  : 7736027

ChainId              : 7736024

CreatedTime          : 10/15/2018 2:16:03 PM

UserName             : *******

Datacenter           : VMware.Vim.DatacenterEventArgument

ComputeResource      : VMware.Vim.ComputeResourceEventArgument

Host                 : VMware.Vim.HostEventArgument

Vm                   : VMware.Vim.VmEventArgument

Ds                   :

Net                  :

Dvs                  :

FullFormattedMessage : TEST-T02 on  esx.somecompany in Texas is powered off

ChangeTag            :

Template             : False

Key                  : 7736099

ChainId              : 7736097

CreatedTime          : 10/15/2018 2:32:57 PM

UserName             : ******

Datacenter           : VMware.Vim.DatacenterEventArgument

ComputeResource      : VMware.Vim.ComputeResourceEventArgument

Host                 : VMware.Vim.HostEventArgument

Vm                   : VMware.Vim.VmEventArgument

Ds                   :

Net                  :

Dvs                  :

FullFormattedMessage : TEST-T03 on  esx.somecompany in Texas is powered off

ChangeTag            :

Template             : False

Key                  : 7736775

ChainId              : 7736771

CreatedTime          : 10/15/2018 3:38:47 PM

UserName             :  ******

Datacenter           : VMware.Vim.DatacenterEventArgument

ComputeResource      : VMware.Vim.ComputeResourceEventArgument

Host                 : VMware.Vim.HostEventArgument

Vm                   : VMware.Vim.VmEventArgument

Ds                   :

Net                  :

Dvs                  :

FullFormattedMessage : TEST-T03 on  esx.somecompany in Texas is powered off

ChangeTag            :

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-01'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T03'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-02'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T01'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-03'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T02'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-04'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-05'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-06'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-07'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-08'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-09'

If I execute the same code (below) and include the "| % {$vms.Remove($_.VM.Name)}" line, then I will NOT see the virtual machines that I recently powered off and will only see the ones that have been powered for almost a month. The e-mail also does NOT include the recently powered off virtual machines and only includes the ones below. See output below.

Code:

Get-VIEvent -Start (Get-Date -Hour 12 -Minute 00) -Finish (Get-Date -Hour 15 -Minute 40) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} | Sort-Object -Property CreatedTime -Unique | % {$vms.Remove($_.VM.Name)}

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-01'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T03'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-02'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T01'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-03'

What if: Performing operation 'Removing VM from disk.' on VM 'TEST-T02'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-04'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-05'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-06'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-07'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-08'

What if: Performing operation 'Removing VM from disk.' on VM 'ABC-09'

Is it possible for the logic of the script to only include the VMs what will be removed or that have been removed as long as they meet the event criteria?

Thanks again for your help sir.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I'm a bit confused.
Originally you said "...remove all powered off virtual machines that have been powered off longer than 14 days"

That's what my script does.

Now you seem to ask that the VMs that have been powered off during the last 14 days should be removed.

Which is it?

In any case, to remove the VMs that have been powered off longer than 14 days ago, you can do

$vms = @{}

Get-VM | where {$_.PowerState -eq "PoweredOff"} | % {$vms.Add($_.Name, $_)}

Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vms.Values -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |

  Sort-Object -Property CreatedTime -Unique | % {

  $vms.Remove($_.VM.Name)

}

Remove-VM -VM $vms.Values -DeletePermanently -Confirm:$false -WhatIf

$sMail = @{

  From   = 'virtualadmin@company.com'

  To   = 'vadmin@company.com'

  SmtpServer = 'smtprelay.company.com'

  Subject   = "Removed $($vms.Keys.Count) VM powered off more than 14 days"

  Body   = ($vms.Keys | Out-String)

}

Send-MailMessage @sMail

And to remove that VMs that have been powered off during the last 14 days, you can do

$vms = @{}

$vm = Get-VM | where{$_.PowerState -eq 'PoweredOff'}

Get-VIEvent -Start (Get-Date).AddDays(-14) -Entity $vm -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |

  Sort-Object -Property CreatedTime -Unique | % {

  $vms.Add($_.VM.Name,(Get-VM -Name $_.VM.Name))

}

Remove-VM -VM $vms.Values -DeletePermanently -Confirm:$false -WhatIf

$sMail = @{

  From   = 'virtualadmin@company.com'

  To   = 'vadmin@company.com'

  SmtpServer = 'smtprelay.company.com'

  Subject   = "Removed $($vms.Keys.Count) VM powered during the last 14 days"

  Body   = ($vms.Keys | Out-String)

}

Send-MailMessage @sMail


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

Reply
0 Kudos
mars0077
Enthusiast
Enthusiast
Jump to solution

My mistake for not being specific and clear sir. I will test these and will let you know how it goes. Thank you very much!

Reply
0 Kudos
mars0077
Enthusiast
Enthusiast
Jump to solution

Hi Luc,

All is working with the scripts you provided as you would expect. Thank you for this!! BTW - Is there a way I can include a line in the script to exclude a VM from being removed even though they have been powered off longer than 14 days? This is in case a user wants to keep the VM around for what ever reason.

Here's a sampIe of another script I use to clean up snapshots older than 3 days but exclude any snaps that need to remain longer.

Code:

Get-VM | where-object {$_.Name -notmatch "VM"} | Get-Snapshot | Where {$_.Created -lt (Get-Date).AddDays(-3)} | Remove-Snapshot -confirm:$false

Thanks again sir!

Reply
0 Kudos