如何在If Else中执行操作并继续?PowerShell异常处理及$_.hostname为空问题
问题分析与解决方案
1. Catch块中$_.hostname为空的原因及解决
在catch块内,$_指向的是ErrorRecord异常对象,而非管道中遍历的CSV主机名对象,因此无法通过$_.hostname获取当前主机名。
解决方式:在循环开头将当前主机名存入独立变量,后续所有逻辑(包括catch)统一使用该变量:
$hostname | ForEach-Object { $currentHost = $_.hostname # 保存当前主机到独立变量 # 后续代码用$currentHost替代$_.hostname }
2. If/Else结构内执行操作并继续循环
当前脚本的If/Else已经嵌套在ForEach-Object循环中,每个主机的处理都是独立的,完成当前分支的操作后会自动进入下一个主机的循环。需要注意:
- 避免在分支内使用
exit这类终止整个脚本的命令,除非明确需要停止执行。 - 对远程连接这类耗时操作,可添加超时参数(如
Test-Connection的-TimeoutSeconds),避免阻塞后续处理。
3. 正确的异常处理实践
- 仅将可能抛出异常的命令放入
try块,不要混入无关代码。 - 必须指定
-ErrorAction Stop,否则PowerShell的非终止错误不会触发catch。 - 对
New-PSSession这类可能失败的命令,也要加入异常捕获,防止脚本意外终止。
修改后的完整脚本
# 导入主机列表 $hostList = Import-Csv C:\Users\jackie.cheng\Desktop\TestComputers2.csv # 使用泛型列表替代数组+=,提升大列表处理性能 $completedList = [System.Collections.Generic.List[PSObject]]@() $unreachableList = [System.Collections.Generic.List[PSObject]]@() $wmiBrokenList = [System.Collections.Generic.List[PSObject]]@() $hostList | ForEach-Object { $currentHost = $_.hostname Write-Host "处理主机: $currentHost" # 测试主机连通性,-Quiet直接返回布尔值,逻辑更清晰 if (Test-Connection -ComputerName $currentHost -Count 1 -Quiet -ErrorAction SilentlyContinue) { try { Write-Host "$currentHost 连通正常,执行远程命令..." # 替换为实际需要执行的远程操作,示例为WMI查询 Invoke-Command -ComputerName $currentHost -ScriptBlock { Get-WmiObject Win32_OperatingSystem } -ErrorAction Stop # 尝试创建会话(按需保留,用完及时关闭) if ($session = New-PSSession -ComputerName $currentHost -ErrorAction Stop) { Write-Host "$currentHost 会话创建成功,标记为完成" $completedList.Add([pscustomobject]@{ Name = $currentHost Status = "Complete" }) Remove-PSSession $session # 释放会话资源 } } catch { Write-Host "$currentHost 远程操作失败: $($_.Exception.Message)" $wmiBrokenList.Add([pscustomobject]@{ Name = $currentHost Status = "WMI Broken" Error = $_.Exception.Message # 可选:记录具体错误信息便于排查 }) } } else { Write-Host "$currentHost 无法连通" $unreachableList.Add([pscustomobject]@{ Name = $currentHost Down = "Unreachable" }) } } # 导出结果到CSV $completedList | Export-Csv 'C:\Users\jackie.cheng\Desktop\SCCM Laptop Update Pushed.csv' -NoTypeInformation $unreachableList | Export-Csv 'C:\Users\jackie.cheng\Desktop\Unreachable.csv' -NoTypeInformation $wmiBrokenList | Export-Csv 'C:\Users\jackie.cheng\Desktop\WMIBroken.csv' -NoTypeInformation
关键优化点说明
- 用
[System.Collections.Generic.List[PSObject]]替代数组+=,避免每次扩容带来的性能损耗。 Test-Connection添加-Quiet参数,直接返回布尔值简化判断逻辑。- 将实际远程操作(原脚本误写为
Test-Connection)放入try块,精准捕获远程执行异常。 - 及时关闭
PSSession,避免资源泄漏。 - 在
catch中记录具体错误信息,方便后续问题排查。
内容的提问来源于stack exchange,提问作者DrixlRey
相关产品推荐
相关产品推荐

