使用Get-WmiObject查询C盘存储时结果延迟的问题求助
PowerShell存储查询脚本异常的原因与解决方法
问题描述
编写了一段PowerShell脚本用于查询计算机存储信息,遇到以下异常:
- 输入计算机名后,首次选择菜单选项1调用
Show-Storage函数查询C盘存储时无结果返回;再次选择选项1时,会同时返回两次查询的结果。 - 单独测试
Show-Storage函数或Get-WmiObject语句时运行正常。 - 测试单独的
Get-WmiObject代码段时发现:保留$result变量时,查询结果在"WMI End"前输出;移除该变量则结果在"WMI End"后输出。
相关脚本代码
主脚本
$ComputerNumber = (read-host "Provide computer number").trim() function Show-Storage{ Get-WmiObject -Class win32_logicaldisk -Filter "DeviceID='C:'" -ComputerName $ComputerNumber|select PSComputerName,DeviceID,@{n='size(GB)';e={$_.size/1gb -as [int]}},@{n='Free(GB)';e={$_.freespace/1gb -as [int]}} } function Show-Menu { param ( [string]$Title = 'Computer Info' ) Write-Host "================ $Title ================" Write-Host "" Write-Host "1: Press '1' to get Current Computer Usage" Write-Host "2: Press '2' to delete Local User Profile" Write-Host "Q: Press 'Q' to quit." } $a=1 While ($a -eq 1) { write-host "" Show-Menu write-host "" if ($ComputerNumber -ne $null){ write-host "Selected Computer '$ComputerNumber'" } else{write-host "No Computer selected"} $selection = Read-Host "Please make a selection" switch($selection) { '1'{ write-host "" Show-Storage write-host "" } '2'{ delete-profile } 'Q'{$a=0} } }
测试代码段
Write-Host "WMI Start" $result = Get-WmiObject -query "SELECT * FROM Win32_logicalDisk WHERE DeviceID = 'C:'" -ComputerName $PC $result $result |select PSComputerName,DeviceID,@{n='size(GB)';e={$_.size/1gb -as [int]}},@{n='Free(GB)';e={$_.freespace/1gb -as [int]}} Write-Host "WMI End"
异常原因分析
1. 输出流与缓冲机制差异
PowerShell存在两种核心输出流:
- Success输出流:用于传递脚本/命令的返回值,默认会被缓冲,直到当前执行块(如循环迭代、switch分支)完成后才统一输出到控制台。
- Host流:
Write-Host的输出直接发送到控制台,无缓冲,实时显示。
主脚本中,Show-Storage函数直接返回Get-WmiObject的结果(进入Success流),而后续的Write-Host ""属于Host流会先显示。第一次调用时,Success流的结果被缓冲,当循环进入下一次迭代(显示菜单)时,缓冲的输出被菜单内容覆盖,导致用户看不到结果;第二次调用时,两次的缓冲结果在执行块完成后一同输出,因此出现两次结果。
2. 变量赋值对输出顺序的影响
测试代码中:
- 当将
Get-WmiObject结果赋值给$result时,会自动抑制其向Success流的隐式输出,后续手动调用$result才会触发输出,此时输出位于Write-Host "WMI End"之前。 - 若不赋值,
Get-WmiObject的结果直接进入Success流,会在整个脚本执行完成后才输出,因此出现在"WMI End"之后。
解决方法
方法1:强制实时输出结果
在调用Show-Storage时,通过Out-Host强制将Success流的内容实时输出到控制台,绕过缓冲机制:
# switch分支中修改为: '1'{ write-host "" Show-Storage | Out-Host write-host "" }
方法2:显式控制函数输出
在Show-Storage函数内部捕获结果后,通过Write-Output显式输出,确保结果及时进入输出流:
function Show-Storage{ $storageData = Get-WmiObject -Class win32_logicaldisk -Filter "DeviceID='C:'" -ComputerName $ComputerNumber | select PSComputerName,DeviceID,@{n='size(GB)';e={$_.size/1gb -as [int]}},@{n='Free(GB)';e={$_.freespace/1gb -as [int]}} Write-Output $storageData }
方法3:改用推荐的CIM命令
Get-WmiObject已被PowerShell官方弃用,推荐使用Get-CimInstance替代,其输出行为更稳定,无延迟缓冲问题:
function Show-Storage{ Get-CimInstance -Class win32_logicaldisk -Filter "DeviceID='C:'" -ComputerName $ComputerNumber | select PSComputerName,DeviceID,@{n='size(GB)';e={$_.size/1gb -as [int]}},@{n='Free(GB)';e={$_.freespace/1gb -as [int]}} }
内容的提问来源于stack exchange,提问作者Leon J
相关产品推荐
相关产品推荐

