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 :
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
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
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.
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
Is there a question in there?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Script works great LucD. 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.