Windows Server 2019环境下PowerShell语句不等待执行完成问题求助
PowerShell磁盘准备脚本Windows Server 2019兼容异常分析
问题背景
原有用于服务器磁盘初始化的PowerShell脚本在Windows Server 2012、2016环境下运行稳定,迁移至Windows Server 2019后出现无有效结果输出的异常。
故障代码
#$disk_list = (Get-Disk | where { ($_.OperationalStatus -eq "Offline") -and ($_.IsClustered -eq $False) }) if ($disk_list) { Write-Host "$($disk_list.count) disks with partition style RAW are found" -ForegroundColor Green $overview_disks = [pscustomobject]@{ } foreach ($d in $disk_list) { $LUN = Get-WmiObject Win32_DiskDrive | where { ($_.InterfaceType -eq "SCSI") -and ($_.index -eq $d.Number) } | select Name, SCSILogicalUnit, Size $overview_disks | Add-Member -Name $LUN.Name -Value $("`tLUN:" + $LUN.SCSILogicalUnit + " `tDiskID: " + $d.Number + " `tSize: " + $([math]::Round($LUN.Size /1GB, 1)) + "GB") -MemberType NoteProperty } $overview_disks }
故障表现
脚本执行完成后返回的$overview_disks为空对象,无预期的磁盘LUN、容量等信息。
临时修复后的代码
通过在Get-WmiObject外层包裹Measure-Command强制等待语句执行完成,修复后的代码如下:
$disk_list = (Get-Disk | where { ($_.OperationalStatus -eq "Offline") -and ($_.PartitionStyle -eq "RAW") }) #$disk_list = (Get-Disk | where { ($_.OperationalStatus -eq "Offline") -and ($_.IsClustered -eq $False) }) if ($disk_list) { Write-Host "$($disk_list.count) disks with partition style RAW are found" -ForegroundColor Green $overview_disks = [pscustomobject]@{ } foreach ($d in $disk_list) { Measure-Command -Expression { $LUN = Get-WmiObject Win32_DiskDrive | where { ($_.InterfaceType -eq "SCSI") -and ($_.index -eq $d.Number) } | select Name, SCSILogicalUnit, Size} $overview_disks | Add-Member -Name $LUN.Name -Value $("`tLUN:" + $LUN.SCSILogicalUnit + " `tDiskID: " + $d.Number + " `tSize: " + $([math]::Round($LUN.Size /1GB, 1)) + "GB") -MemberType NoteProperty } $overview_disks }
问题成因分析
- WMI查询行为变更:Windows Server 2019内置的PowerShell 5.1更新版本中,对
Get-WmiObject类存储查询的结果枚举逻辑做了调整,旧版Server系统中该cmdlet为同步返回完整结果集,2019版本在查询SCSI磁盘这类需要和存储栈交互的对象时,会默认采用隐式异步枚举逻辑,管道结果还未完成返回就进入了下一行的Add-Member逻辑,此时$LUN对象未完成赋值,属性读取为空,导致添加成员操作失败,最终$overview_disks为空。 Measure-Command的作用:该cmdlet的原生逻辑是统计表达式的执行耗时,会强制等待表达式内所有逻辑完全执行完成才会返回,恰好阻塞了后续Add-Member的执行,等$LUN完成赋值后再执行后续操作,因此问题被临时解决,但该方案属于非正规的修复手段。- 最优修复建议:
Get-WmiObject已经被微软官方弃用,Windows Server 2019及更高版本建议替换为Get-CimInstance执行WMI查询,CIM类cmdlet的同步行为更可控,不会出现隐式异步的问题。也可以通过将查询结果用数组包裹的方式强制枚举完成,比如将$LUN = Get-WmiObject ...修改为$LUN = @(Get-WmiObject ...)[0],也能达到强制等待结果返回的效果。
内容的提问来源于stack exchange,提问作者Mainecoon21
相关产品推荐
相关产品推荐

