PowerShell服务器巡检脚本遇无响应服务器挂起问题求助
解决PowerShell巡检脚本遇无响应服务器挂起的问题
你的PowerShell服务器巡检脚本在遇到无响应/冻结的服务器时会挂起,无法继续执行。需要实现超时机制跳过故障服务器,或者通过预Ping过滤不可达机器,同时希望保持脚本简洁,对-AsJob的使用有困惑。
核心解决方案
1. 预Ping过滤无响应服务器
在执行巡检前先对目标服务器做快速Ping测试,只保留能响应的机器,直接过滤掉完全不可达的服务器,减少后续卡住的概率:
# 预Ping测试,只保留能响应的Windows服务器 $reachableWinServers = $winservers | Where-Object { Test-Connection -ComputerName $_ -Count 1 -Quiet -ErrorAction SilentlyContinue }
2. 给Invoke-Command设置超时
无需使用复杂的-AsJob,直接用Invoke-Command自带的-TimeoutSec参数指定超时时间(比如30秒),到时间后自动终止对该服务器的执行并继续下一台:
Invoke-Command -ComputerName $reachableWinServers -ScriptBlock $scriptblock -HideComputerName -ErrorAction SilentlyContinue -TimeoutSec 30
修正后的完整脚本
同时修复了原脚本中的语法错误(如未闭合的引号、未定义的变量),优化了输出格式:
Import-Module ActiveDirectory # 修正引号闭合问题,筛选AD中的服务器 $allservers = Get-ADComputer -Filter * -SearchBase "xxxxx" -Properties OperatingSystem | Where-Object { $_.DistinguishedName -NotLike '*OU=NEC*' -and $_.DistinguishedName -NotLike '*OU=GPO_Testing*' } $winservers = ($allservers | Where-Object {$_.OperatingSystem -like "Windows Server*"}).Name $notwinservers = $allservers | Where-Object {$_.OperatingSystem -notlike "Windows Server*"} # 预Ping过滤可达的Windows服务器 $reachableWinServers = $winservers | Where-Object { Test-Connection -ComputerName $_ -Count 1 -Quiet -ErrorAction SilentlyContinue } $scriptblock = { # 获取服务器名称 $serverName = $env:COMPUTERNAME # 服务器状态(本地测试更准确) $status = 'Up' try { $null = Get-CimInstance -Class Win32_OperatingSystem -ErrorAction Stop } catch { $status = 'Down' } # 操作系统安装日期 $buildDate = (Get-CimInstance -Class Win32_OperatingSystem -ErrorAction SilentlyContinue).InstallDate # 证书信息处理 $certs = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { -Not $_.PSIsContainer } | Sort-Object -Property NotBefore $certcount = $certs.Count $certname = $certs.FriendlyName -join ', ' # 最后重启时间 $reboot = (Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction SilentlyContinue).LastBootUpTime # Trellix更新时间 $TrellixDate = try { [datetime](Get-ItemProperty 'C:\Program Files\Common Files\McAfee\Engine\AMCoreUpdater\amupdate.dat').LastWriteTime.DateTime } catch { 'n/a' } # 操作系统信息 $os = (Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue).OperatingSystem # 磁盘信息 $diskInfo = Get-CimInstance -Class Win32_LogicalDisk -Filter 'DriveType = 3' -ErrorAction SilentlyContinue # SQL版本(修正原脚本变量错误) $sqlver = 'n/a' if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' -ErrorAction SilentlyContinue) { $sqlInstances = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances $sqlVersions = foreach ($instance in $sqlInstances) { $instancePath = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$instance (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instancePath\Setup").Version } $sqlver = $sqlVersions -join ', ' } # IIS版本 $IIS = 'n/a' if (Get-Service -Name W3SVC -ErrorAction SilentlyContinue) { $IIS = (Get-ItemProperty -PATH 'HKLM:\SOFTWARE\Microsoft\InetStp\').VERSIONSTRING } # 生成输出对象(处理多磁盘/多证书的对应问题) for ($i = 0; $i -lt [System.Math]::Max($certs.Count, $diskInfo.Count); $i++) { $disk = $diskInfo[$i] $cert = $certs[$i] [PSCustomObject]@{ ServerName = $serverName Status = $status OperatingSystem = $os ?? 'n/a' BuildDate = if ($buildDate) { '{0:u}' -f $buildDate } else { 'n/a' } LastReboot = if ($reboot) { '{0:u}' -f $reboot } else { 'n/a' } CertName = if ($cert) { $cert.FriendlyName } else { 'n/a' } CertCreated = if ($cert) { $cert.NotBefore } else { 'n/a' } CertExpiration = if ($cert) { $cert.NotAfter } else { 'n/a' } CertCount = $certcount TrellixLastUpdate = $TrellixDate SQLVersion = $sqlver IISVersion = $IIS DiskLabel = if ($disk) { $disk.DeviceID } else { 'n/a' } Freespace = if ($disk) { '{0:N2} Gb' -f ($disk.FreeSpace / 1GB) } else { 'n/a' } DiskSize = if ($disk) { '{0:N2} Gb' -f ($disk.Size / 1GB) } else { 'n/a' } PercentFree = if ($disk) { '{0:P0}' -f ($disk.FreeSpace / $disk.Size) } else { 'n/a' } } } } # 执行巡检,设置30秒超时 Invoke-Command -ComputerName $reachableWinServers -ScriptBlock $scriptblock -HideComputerName -ErrorAction SilentlyContinue -TimeoutSec 30 | Select-Object * -ExcludeProperty RunspaceId, PSComputerName, PSShowComputerName | Export-Csv "e:\activetasks\server_checks\DailyMissionReport_$((Get-Date).ToString('dd-MM-yyyy')).csv" -NoTypeInformation # 处理非Windows服务器 foreach ($nonwin in $notwinservers) { $status = if (Test-Connection -ComputerName $nonwin.Name -Count 1 -Quiet -ErrorAction SilentlyContinue) { 'Up' } else { 'Down' } [PSCustomObject]@{ ServerName = $nonwin.Name Status = $status OperatingSystem = "Linux or Other" BuildDate = "n/a" LastReboot = "n/a" CertName = "n/a" CertCreated = "n/a" CertExpiration = "n/a" CertCount = "n/a" TrellixLastUpdate = "n/a" SQLVersion = "n/a" IISVersion = "n/a" DiskLabel = "n/a" Freespace = "n/a" DiskSize = "n/a" PercentFree = "n/a" } | Export-Csv "e:\activetasks\server_checks\DailyMissionReport_$((Get-Date).ToString('dd-MM-yyyy')).csv" -NoTypeInformation -Append }
内容的提问来源于stack exchange,提问作者BobSnarley
相关产品推荐
相关产品推荐

