![Powershell Runspace ジョブ内の Server 2012R2 でホストされている VM に対して Get-VHD ファイル サイズが 0 を返すのはなぜですか?](https://rvso.com/image/718157/Powershell%20Runspace%20%E3%82%B8%E3%83%A7%E3%83%96%E5%86%85%E3%81%AE%20Server%202012R2%20%E3%81%A7%E3%83%9B%E3%82%B9%E3%83%88%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%20VM%20%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%20Get-VHD%20%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%20%E3%82%B5%E3%82%A4%E3%82%BA%E3%81%8C%200%20%E3%82%92%E8%BF%94%E3%81%99%E3%81%AE%E3%81%AF%E3%81%AA%E3%81%9C%E3%81%A7%E3%81%99%E3%81%8B%3F.png)
Hyper-V クラスターでホストされている VM の CSV を作成するためのスクリプトがあります。うまく機能しており、各 VM をジョブに分離することさえできました。
補足: スケジュールをより効率的に行う方法についてアドバイスをいただければ幸いです。主な問題は、一部のクラスターが WS 2016 で、他のクラスターが WS 2012R2 であり、古い Hyper-V PowerShell モジュールが必要であることです。異なるモジュールを並列化する方法がよくわからないため、各 Hyper-V ノードの VM リストを取得して並列化し、次のノードに必要な場合はモジュールを変更します。
とにかく、私の問題です。これが私のスクリプトです。
$numThreads = 4
$ScriptBlock = {
Param (
[string]$Cluster,
[string]$Node,
$VM
)
If ($ADComputer = (Get-ADComputer $VM.Name -Properties OperatingSystem)) {
$OS = $ADComputer.OperatingSystem
}
Else {
$OS = 'Unknown (not on domain)'
}
try {
Return [pscustomobject] @{
Cluster = $Cluster
Node = $Node
Name = $VM.Name
OS = $OS
State = $VM.State
Status = $VM.Status
Uptime = "{0:dd} days {0:hh} hours" -f $VM.Uptime
CPUUsage = $VM.CPUUsage
ProcessorCount = $VM.ProcessorCount
'MemoryDemand (GB)' = [math]::Round( $VM.MemoryDemand / 1GB, 2 )
'MemoryAssigned (GB)' = [math]::Round( $VM.MemoryAssigned / 1GB, 2 )
'VHD Size (GB)' = [math]::Round( ((Get-VHD -ComputerName $Node -VMId $VM.Id).FileSize | Measure-Object -Sum).Sum / 1GB, 2 )
Version = $VM.Version
'VLAN IDs' = ($VM | Select-Object -ExpandProperty NetworkAdapters | Select-Object -ExpandProperty VlanSetting).AccessVlanId -Join ", "
'IP Addresses' = ($VM | Select-Object -ExpandProperty NetworkAdapters).IPAddresses -Join ", "
}
}
catch {
Return [pscustomobject] @{
Cluster = $Cluster
Node = $Node
Name = $VM.Name
State = "Script Fail"
Status = $_.Exception.Message
}
}
}
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $numThreads)
$RunspacePool.Open()
$Jobs = @()
$VMInfoList = @()
ForEach ($Cluster in 'USHOMECLU0', 'USHOMECLU1') {
If ((Get-ADComputer $Cluster -Property OperatingSystem).OperatingSystem -Match '2016') {
Remove-Module Hyper-V
Import-Module Hyper-V -RequiredVersion 2.0.0.0
}
Else {
Remove-Module Hyper-V
Import-Module Hyper-V -RequiredVersion 1.1
}
ForEach ($Node in Get-ClusterNode -Cluster $Cluster) {
Get-VM -ComputerName $Node | ForEach-Object {
$Job = [powershell]::Create().AddScript($ScriptBlock).AddParameter("Cluster", $Cluster).AddParameter("Node", $Node).AddParameter("VM", $_)
$Job.RunspacePool = $RunspacePool
$Jobs += New-Object PSObject -Property @{
Job = $Job
Result = $Job.BeginInvoke()
}
}
}
}
# EndInvoke returns the objects from the background threads
ForEach ($Job in $Jobs) {
$VMInfoList += $Job.Job.EndInvoke($Job.Result)
}
$VMInfoList | Export-Csv -NoTypeInformation C:\PSReports_vms.csv
私が抱えている問題は、Windows Server 2012R2 ノード上の VM のジョブが常に 0 を返すことです。
'VHD Size' = ((Get-VHD -ComputerName $Node -VMId $VM.Id).FileSize | Measure-Object -Sum).Sum
ただし、Windows Server 2016 ノードの場合、すべての VM が適切な値を返します。また興味深いのは、Server 2012R2 でホストされている VM の VHD サイズに割り当てられている正確な式をキャプチャし (変数を直接文字列に置き換えます)、ジョブのスクリプト ブロックの外部で実行すると、正確な値が得られることです。