You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务器升级至2022后PowerShell脚本运行异常求助

问题:PowerShell脚本在Windows Server 2022上运行异常,邮件内容为空且报错

我有一段脚本曾在Windows Server 2012 R2连接代理上稳定运行,将连接代理升级至2022后,脚本运行异常:虽能发送邮件,但邮件内容为空。手动运行脚本时出现如下错误:

You cannot call a method on a null-valued expression.
At C:\PS-Scripts\rdstats.ps1:28 char:5

  • $ob = [PSCustomObject]@{
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (:) [], RuntimeException
    • FullyQualifiedErrorId : InvokeMethodOnNull

我推测是$ob = [PSCustomObject]@{部分被判定为空,但将以下循环代码单独在PowerShell窗口运行时无报错:

foreach ( $rdhost in $rdhosts )
{
    $rdp = Test-NetConnection -ComputerName $rdhost.SessionHost -Port 3389

    $ob = [PSCustomObject]@{
        CollectionName      = $rdhost.CollectionName
        SessionHost         = $rdhost.SessionHost
        InCluster           = $rdhost.NewConnectionAllowed
        RemotePort          = $rdp.RemotePort
        PortAlive           = $rdp.TcpTestSucceeded
        PingSucceeded       = $rdp.PingSucceeded
        PingReplyDetails    = $rdp.PingReplyDetails.RoundtripTime.ToString() + " ms"
        }

    $objs += $ob
}

另外,在2012R2机器上针对2022连接代理运行该脚本可成功,因此问题可能并非出在连接代理,而是2012R2与2022的PowerShell版本差异(4.0 vs 5.1)。请问为何PowerShell 5.1会判定$ob = [PSCustomObject]@{为空?以下是完整脚本:

###BEGIN TODO CONFIG EMAIL

#$Username = 'user@domain.com'
#$Password = ''
$emailTo = "user@domain.com"
$bccTo = "dg@domain.com"
$emailFrom = "status@domain.com"

###END TODO CONFIG EMAIL

#$pass = ConvertTo-SecureString -AsPlainText $Password -Force

# Users you password securly
#$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$pass 



Import-Module RemoteDesktop
$rdhosts = Get-RDSessionHost -CollectionName "RD Collection 1"

$objs = @()

foreach ( $rdhost in $rdhosts )
{
    $rdp = Test-NetConnection -ComputerName $rdhost.SessionHost -Port 3389

    $ob = [PSCustomObject]@{
        CollectionName      = $rdhost.CollectionName
        SessionHost         = $rdhost.SessionHost
        InCluster           = $rdhost.NewConnectionAllowed
        RemotePort          = $rdp.RemotePort
        PortAlive           = $rdp.TcpTestSucceeded
        PingSucceeded       = $rdp.PingSucceeded
        PingReplyDetails    = $rdp.PingReplyDetails.RoundtripTime.ToString() + " ms"
        }

    $objs += $ob
}

$str = Out-String -InputObject $objs -Width 100

Send-MailMessage -From $emailFrom -To $emailTo -BCC $bccTo -Subject "RD Collection TS Audit" -Body $str -SmtpServer mail.domain.com -Port 25

问题原因与解决方法

错误提示的InvokeMethodOnNull并非是[PSCustomObject]@{...}本身为空,而是构建对象时,某属性调用了空值的方法。具体问题出在$rdp.PingReplyDetails.RoundtripTime.ToString()这一行:

  • PowerShell 4.0(Windows Server 2012 R2)中,即使Ping失败,$rdp.PingReplyDetails会返回默认对象(比如RoundtripTime为0),不会为null;
  • PowerShell 5.1(Windows Server 2022)中,Ping失败时$rdp.PingReplyDetails直接为null,此时调用.RoundtripTime就会触发空值调用错误,导致$ob对象创建失败,最终$objs数组为空,邮件内容无数据。

单独运行循环时无报错,大概率是测试环境中所有主机都能Ping通,$rdp.PingReplyDetails不为null,未触发问题。

解决步骤

  1. 添加空值判断:在访问$rdp.PingReplyDetails.RoundtripTime前先检查是否为null,避免空对象调用:
PingReplyDetails    = if ($rdp.PingReplyDetails) { $rdp.PingReplyDetails.RoundtripTime.ToString() + " ms" } else { "Ping Failed" }
  1. 优化数组构建:PowerShell中+=扩展数组效率低,建议直接将循环输出的对象赋值给变量:
$objs = foreach ( $rdhost in $rdhosts )
{
    $rdp = Test-NetConnection -ComputerName $rdhost.SessionHost -Port 3389

    [PSCustomObject]@{
        CollectionName      = $rdhost.CollectionName
        SessionHost         = $rdhost.SessionHost
        InCluster           = $rdhost.NewConnectionAllowed
        RemotePort          = $rdp.RemotePort
        PortAlive           = $rdp.TcpTestSucceeded
        PingSucceeded       = $rdp.PingSucceeded
        PingReplyDetails    = if ($rdp.PingReplyDetails) { $rdp.PingReplyDetails.RoundtripTime.ToString() + " ms" } else { "Ping Failed" }
    }
}
  1. 验证运行:修改后重新执行脚本,即使有主机Ping失败,也能正常生成PSCustomObject,$objs不会为空,邮件内容可正常展示。

内容的提问来源于stack exchange,提问作者SubnetMask

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:15:01