我还需要从 vmware.log 文件中提取最后一个事件,以便回溯没有 vCenter 事件历史记录的 VM 的关机时间。我查看了文件时间戳,但发现某些 VM 进程和可能的备份解决方案会使它们变得无用。
我尝试就地读取文件,但遇到了 PSDrive 类型不支持就地获取内容的问题。因此,对于我的解决方案,无论好坏,我都从 LucD 的脚本之一开始 - 来自http://www.lucd.info/2011/02/27/virtual-machine-logging/的“检索日志”脚本,它拉动了一个虚拟机vmware.log 文件并将其复制到本地存储。然后我修改它以将 vmware.log 文件复制到本地临时文件夹,在删除文件之前从文件中读取最后一行并将日志的最后一行作为 PS 对象返回。
请注意,这很慢,我确信我对 LucD 脚本的破解并不优雅,但它确实有效,我希望能对某人有所帮助。
注意:这通过简单地将字符串时间戳从文件传送到 Get-Date 将时间值从日志转换为 PS 日期对象。我已经读到这对于非美国日期格式无法正常工作。对于美国以外的人,您可能想要查看此内容,或者只是从日志中传递原始时间戳字符串而不是对其进行转换。
#Examples:
#$lastEventTime = (Get-VM -Name "SomeVM" | Get-VMLogLastEvent).EventTime
#$lastEventTime = Get-VMLogLastEvent -VM "SomeVM" -Path "C:\alternatetemp\"
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
}
}
这应该涵盖您的要求,但为了进一步说明为什么我需要详细信息,字里行间的阅读也可能使您受益,我将继续。
我继承了数百个因过去的各种收购和剥离而关闭的旧 VM,其中许多已在 vCenter 实例之间移动,丢失了所有事件日志详细信息。当我在一个数据中心开始清理工作时,我有超过 60TB 的已关闭虚拟机。由于这些旧虚拟机的遗留性质,也没有关于谁拥有或了解这些旧虚拟机的详细信息。
为此,我破解了我发现的另一个脚本,同样来自 LucD:https ://communities.vmware.com/thread/540397 。
这将包含所有关闭的虚拟机,尝试通过 vCenter 事件历史记录确定关闭的时间。如果事件日志详细信息不可用,我将其修改为回退到上述 Get-VMLogLastEvent 函数以获取 VM 的最终断电时间。
可以改进错误捕获 - 这将在由于某种原因没有 vmware.log 文件的虚拟机上出错。但是又快又脏,我发现这很有效,并提供了超过 90% 所需的详细信息。
这再次依赖于上述函数,对我来说,至少错误只是通过传递空值而失败。可以通过在尝试复制之前添加对 vmware.log 存在性的检查来消除错误,尽管由于数据存储的 PSDrive 接口速度较慢,这会增加执行时的延迟。
$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_Report.csv" -NoTypeInformation -UseCulture
干杯! 我祈祷这可以偿还我使用的一些业力。
迈亚德