VMware Cloud Community
BrianDGeorge
Enthusiast
Enthusiast

PowerCLI to list all Powered Off VMs and Date of Event

I am trying to get this script to work but it doesn't even seem close at this point.  I am looking to run a report on Powered Off VMs and information about them.  I need to be able to clean the environment and have to wait 60 days before I permanently delete anything.  Any help would be great.

Connect-VIServer -Server XXX-vcenter1 -User administrator@vsphere.local -Password XXXXXXXXXXXX

Connect-VIServer -Server XXX-vcenter1 -User administrator@vsphere.local -Password XXXXXXXXXXXX

$Report = @()

$VMs = get-vm |Where-object {$_.powerstate -eq "poweredoff"}

$Datastores = Get-Datastore | select Name, Id

$VMHosts = Get-VMHost | select Name, Parent

foreach ($vm in Get-VM){

$view = Get-View $VMs

Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) |

where {$_ -is [VMware.Vim.VmPoweredOffEvent]}

Group-Object -Property {$_.Vm.Name} | %{

  $lastPO = $_.Group | Sort-Object -Property CreatedTime -Descending | Select -First 1

  $row = '' | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PowerOFF

    $row.VMName = $VMs.Name

    $row.Powerstate = $VMs.Powerstate

    $row.OS = $VMs.Guest.OSFullName

    $row.Host = $VMs.host.name

    $row.Cluster = $VMs.host.Parent.Name

    $row.Datastore = ($Datastores | where {$_.ID -match (($vmview.Datastore | Select -First 1) | Select Value).Value} | Select Name).Name

    $row.NumCPU = $VMs.NumCPU

    $row.MemMb = (($VMs.MemoryMB),2)

    $row.DiskGb = ((($VMs.HardDisks | Measure-Object -Property CapacityKB -Sum).Sum * 1KB / 1GB),2)

    $row.PowerOFF = $lastPO.CreatedTime

  $report += $row

}}

$report | Sort Name | Export-Csv -Path "C:\XXXXX\Powered_Off_VMs.csv"

disconnect-viserver * -confirm:$false

I don't get an export to CSV and a display on screen of the following:

Template             : False

Key                  : 165369

ChainId              : 165369

CreatedTime          : 6/28/2016 10:19:35 AM

UserName             :

Datacenter           : VMware.Vim.DatacenterEventArgument

ComputeResource      : VMware.Vim.ComputeResourceEventArgument

Host                 : VMware.Vim.HostEventArgument

Vm                   : VMware.Vim.VmEventArgument

Ds                   :

Net                  :

Dvs                  :

FullFormattedMessage : ServerName on  XXX-prodesxi-10.xxxxx.com in ClusterName is powered off

ChangeTag            :

26 Replies
meyeaard
Contributor
Contributor

I'm another who has benefited from this old thread. Many thanks, especially to LucD for the examples provided!

For my solution I've reworked LucD's example inline above as well as another of his postings for Get-VMLog which copies the VM's log to local storage.

This modifies LucD's Get-VMLog to instead copy the logfile to local storage where it can be parsed, pull the last event and return the datestamp, log source, and logged event as objects. Then  modified LucD's example above to attempt to pull vm power off event first and fail back to the slow logfile method.

Error checking could be improved, but this works for my quick and dirty needs and I have not found any blocking or critical errors, usually just cases where the vmware.log file doesn't exist.

Also note the returned date object from Get-VMLogLastEvent may have issues with non-US timestamps which I understand is a normal problem with "Get-Date" conversions so be aware.

Many thanks to LucD for sharing how to post pretty code. Shame they don't support the old BBCode markup [code][/code] blocks or anything similar.


function Get-VMLogLastEvent{
    param(
    [
parameter(Mandatory=$true,ValueFromPipeline=$true)][PSObject[]]$VM,
    [
string]$Path=$env:TEMP
    )

   
process{  
       
$report = @()

       
foreach($obj in $VM){
           
if($obj.GetType().Name -eq "string"){
               
$obj = Get-VM -Name $obj
            }
           
$logpath = ($obj.ExtensionData.LayoutEx.File | ?{$_.Name -like "*/vmware.log"}).Name
           
$dsName = $logPath.Split(']')[0].Trim('[')
           
$vmPath = $logPath.Split(']')[1].Trim(' ')
           
$ds = Get-Datastore -Name $dsName
           
$drvName = "MyDS" + (Get-Random)
           
$localLog = $Path + "\" + $obj.Name + ".vmware.log"
           
New-PSDrive -Location $ds -Name $drvName -PSProvider VimDatastore -Root '\' | Out-Null
           
Copy-DatastoreItem -Item ($drvName + ":" + $vmPath) -Destination $localLog -Force:$true
           
Remove-PSDrive -Name $drvName -Confirm:$false
       
           
$lastEvent = Get-Content -Path $localLog -Tail 1
           
Remove-Item -Path $localLog -Confirm:$false
           
           
$row = "" | Select VM, EventType, Event, EventTime
           
$row.VM = $obj.Name
            (
$row.EventTime, $row.EventType, $row.Event) = $lastEvent.Split("|")
           
$row.EventTime = $row.EventTime | Get-Date
           
$report += $row
         }
        
$report       
    }
}

$Report = @()  
$VMs = Get-VM | Where {$_.PowerState -eq "PoweredOff"
$Datastores = Get-Datastore | Select Name, Id 
$PowerOffEvents = Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} | Group-Object -Property {$_.Vm.Name
 
foreach ($VM in $VMs) { 
   
$lastPO = ($PowerOffEvents | Where { $_.Group[0].Vm.Vm -eq $VM.Id }).Group | Sort-Object -Property CreatedTime -Descending | Select -First 1
   
$lastLogTime = "";
   
   
# If no event log detail, revert to vmware.log last entry which takes more time...
    if (($lastPO.PoweredOffTime -eq "") -or ($lastPO.PoweredOffTime -eq $null)){
       
$lastLogTime = (Get-VMLogLastEvent -VM $VM).EventTime
    }
 
   
$row = "" | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PoweredOffTime,PoweredOffBy,LastLogTime
   
$row.VMName = $vm.Name 
   
$row.Powerstate = $vm.Powerstate 
   
$row.OS = $vm.Guest.OSFullName 
   
$row.Host = $vm.VMHost.name 
   
$row.Cluster = $vm.VMHost.Parent.Name 
   
$row.Datastore = $Datastores | Where{$_.Id -eq ($vm.DatastoreIdList | select -First 1)} | Select -ExpandProperty Name 
   
$row.NumCPU = $vm.NumCPU 
   
$row.MemMb = $vm.MemoryMB 
   
$row.DiskGb = Get-HardDisk -VM $vm | Measure-Object -Property CapacityGB -Sum | select -ExpandProperty Sum 
   
$row.PoweredOffTime = $lastPO.CreatedTime 
   
$row.PoweredOffBy   = $lastPO.UserName
   
$row.LastLogTime = $lastLogTime
   
$report += $row 

 
# Output to screen 
$report | Sort Cluster, Host, VMName | Select VMName, Cluster, Host, NumCPU, MemMb, @{N='DiskGb';E={[math]::Round($_.DiskGb,2)}}, PoweredOffTime, PoweredOffBy | ft -a 
 
# Output to CSV - change path/filename as appropriate 
$report | Sort Cluster, Host, VMName | Export-Csv -Path "output\Powered_Off_VMs.csv" -NoTypeInformation -UseCulture 
Reply
0 Kudos
LucD
Leadership
Leadership

Thanks for sharing that.

And on the pretty code, have a look at Some ways to enter PowerCLI code under the new forum SW


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

Reply
0 Kudos
vijayrana968
Virtuoso
Virtuoso

This script is working fine where events are traced. But some vcenters has overrite logs as per purge settings and for some Powered off VMs lets say powered off 2-3 years ago..... 'VmPoweredOffEvent' event doesn't exist on vCenter so how can we fetch info for those VMs.

Reply
0 Kudos
LucD
Leadership
Leadership

You can't.
The only solution is to export the events that are of interest of you to an external source, before they are purged.

Same goes for the statistical data.


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

lokeshcheerla
Contributor
Contributor

Hi#Connect-VIServer -Server XXX-vcenter1 -User administrator@vsphere.local -Password XXXXXXXXXXXX
 
$Report = @()
 
$VMs = get-vm |Where-object {$_.powerstate -eq "poweredoff"}
 
$Datastores = Get-Datastore | select Name, Id
 
Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) |
 
where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |
 
Group-Object -Property {$_.Vm.Name} | %{
 
  $lastPO = $_.Group | Sort-Object -Property CreatedTime -descending | Select -First 1
 
  $vm = Get-VIObjectByVIView -MORef $_.Group[0].VM.VM
 
  $row = '' | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PowerOFF
 
    $row.VMName = $vm.Name
 
    $row.Powerstate = $vm.Powerstate
 
    $row.OS = $vm.Guest.OSFullName
 
    $row.Host = $vm.VMHost.name
 
    $row.Cluster = $vm.VMHost.Parent.Name
 
    $row.Datastore = $Datastores | Where{$_.Id -eq ($vm.DatastoreIdList | select -First 1)} | Select -ExpandProperty Name
 
    $row.NumCPU = $vm.NumCPU
 
    $row.MemMb = $vm.MemoryMB
 
    $row.DiskGb = Get-HardDisk -VM $vm | Measure-Object -Property CapacityGB -Sum | select -ExpandProperty Sum
 
    $row.PowerOFF = $lastPO.CreatedTime
 
       $report += $row
    
}
#Connect-VIServer -Server XXX-vcenter1 -User administrator@vsphere.local -Password XXXXXXXXXXXX
 
$Report = @()
 
$VMs = get-vm |Where-object {$_.powerstate -eq "poweredoff"}
 
$Datastores = Get-Datastore | select Name, Id
 
Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) |
 
where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |
 
Group-Object -Property {$_.Vm.Name} | %{
 
  $lastPO = $_.Group | Sort-Object -Property CreatedTime -descending | Select -First 1
 
  $vm = Get-VIObjectByVIView -MORef $_.Group[0].VM.VM
 
  $row = '' | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PowerOFF
 
    $row.VMName = $vm.Name
 
    $row.Powerstate = $vm.Powerstate
 
    $row.OS = $vm.Guest.OSFullName
 
    $row.Host = $vm.VMHost.name
 
    $row.Cluster = $vm.VMHost.Parent.Name
 
    $row.Datastore = $Datastores | Where{$_.Id -eq ($vm.DatastoreIdList | select -First 1)} | Select -ExpandProperty Name
 
    $row.NumCPU = $vm.NumCPU
 
    $row.MemMb = $vm.MemoryMB
 
    $row.DiskGb = Get-HardDisk -VM $vm | Measure-Object -Property CapacityGB -Sum | select -ExpandProperty Sum
 
    $row.PowerOFF = $lastPO.CreatedTime
 
       $report += $row
    
}
#Connect-VIServer -Server XXX-vcenter1 -User administrator@vsphere.local -Password XXXXXXXXXXXX
 
$Report = @()
 
$VMs = get-vm |Where-object {$_.powerstate -eq "poweredoff"}
 
$Datastores = Get-Datastore | select Name, Id
 
Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) |
 
where {$_ -is [VMware.Vim.VmPoweredOffEvent]} |
 
Group-Object -Property {$_.Vm.Name} | %{
 
  $lastPO = $_.Group | Sort-Object -Property CreatedTime -descending | Select -First 1
 
  $vm = Get-VIObjectByVIView -MORef $_.Group[0].VM.VM
 
  $row = '' | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PowerOFF
 
    $row.VMName = $vm.Name
 
    $row.Powerstate = $vm.Powerstate
 
    $row.OS = $vm.Guest.OSFullName
 
    $row.Host = $vm.VMHost.name
 
    $row.Cluster = $vm.VMHost.Parent.Name
 
    $row.Datastore = $Datastores | Where{$_.Id -eq ($vm.DatastoreIdList | select -First 1)} | Select -ExpandProperty Name
 
    $row.NumCPU = $vm.NumCPU
 
    $row.MemMb = $vm.MemoryMB
 
    $row.DiskGb = Get-HardDisk -VM $vm | Measure-Object -Property CapacityGB -Sum | select -ExpandProperty Sum
 
    $row.PowerOFF = $lastPO.CreatedTime
 
       $report += $row
    
}
Reply
0 Kudos
LucD
Leadership
Leadership

Is there a question in there?


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

Reply
0 Kudos
cloudteam
Contributor
Contributor

Script works great . need to run for mutiple vcenters,  i am giving vcname, IP from inputCSV,  i am tried to connect one vcenter and collect the poweredoff VM's and append in the output sheet but i dono how to append this output details for poweredoff . Please help and modify which can pull from multiple VC and save in a CSV format.

Reply
0 Kudos