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

PowerShell脚本离线重启电脑时变量值为空问题求助

PowerShell脚本离线重启问题排查与修复建议

我编写了一个PowerShell脚本,目标是仅在电脑离线时重启设备。脚本中获取用户信息的功能正常,但底部重启逻辑部分的$Online和$Computername变量值为空($null)。使用PDQ Inventory部署该脚本,仅针对单用户场景,脚本示例如下:

Function Get-LoggedOnUser
    {
    Param
    (
        $ComputerName = $env:COMPUTERNAME,
        $Credential
    )

    Function Test-RemoteRegistry
    {
    Param
        (
        [Parameter(Mandatory = $False)]
        [switch]$Enable
        ,
        [Parameter(Mandatory = $False)]
        [switch]$Disable
        ,
        [Parameter(ValueFromPipeline=$True)]
        [String[]]$ComputerName = $env:COMPUTERNAME
        )
    Begin
        {
        $PipelineInput = (-not $PSBOUNDPARAMETERS.ContainsKey("ComputerName")) -and (-not $ComputerName)
        
        Function Test ($Computer)
            {
            Try
                {
                [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $Computer) | Out-Null 
                #20ms faster than Get-Service per computer! Not sure how to handle/check things like the firewall though...


                #If we hit here without error Remote Reg is enabled.
                If ($Disable)
                    {
                    Try
                        {
                        Get-Service -Name RemoteRegistry -ComputerName $Computer | Set-Service -Status Stopped -ErrorAction Stop
                        Return $False
                        #If we hit here without error Remote Reg is now disabled.
                        }
                    Catch
                        {
                        Return $True
                        #If we hit here, we couldn't stop remote registry.
                        }
                    }
                Else
                    {
                    Return $True 
                    }
                }
            Catch
                {
                If ($Enable)
                    {
                    Try
                        {
                        Get-Service -Name RemoteRegistry -ComputerName $Computer | Set-Service -Status Running -ErrorAction Stop
                        Return $True 
                        #If we hit here without error Remote Reg is now enabled.
                        }
                    Catch
                        {
                        Return $False
                        #If we hit here, we couldn't start remote registry.
                        }
                    }
                Else
                    {
                    Return $False
                    #If we hit here remote registry is disabled.
                    }
                }
            }
        
        }
    Process
        {
        If ($PipelineInput)
            {
            Test $_
            }
        Else
            {
            $ComputerName | ForEach-Object {
                Test $_
                }
            }
        }

    }


    Foreach ($Computer in $Computername)
        {
        $Online = $False
        $User = $False
        $Locked = $False
        If (Test-Connection $Computer -Count 2 -Quiet) 
            {
            $Online = $True 
            If ($Credential) 
                {
                $User = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Computer -Credential $Credential | Select-Object -ExpandProperty UserName -ErrorAction Stop
                }
            Else
                {
                $User = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Computer | Select-Object -ExpandProperty UserName -ErrorAction Stop
                }
            If (Test-RemoteRegistry -Enable -ComputerName $Computer)
                {
                If ((Get-Process logonui -ComputerName $Computer -ErrorAction SilentlyContinue) -and ($user))
                    {
                    $Locked = $True
                    }
            }
            }
        $Output = New-Object PSObject
        $Output | Add-Member noteproperty ComputerName $Computer
        $Output | Add-Member noteproperty Online $Online
        $Output | Add-Member noteproperty Username $User
        $Output | Add-Member noteproperty Locked $Locked
        $Output
        }
    }



Get-LoggedOnUser




If (($Online) -eq $False)
    {Shutdown /r t 0 /m \$Computername}

ELSE
    {Write-host 'HELLO  $Online $Computername'}

问题根源

核心问题是变量作用域限制:

  • $Online和$Computername是定义在Get-LoggedOnUser函数内部的局部变量,函数外部无法直接访问这些变量。
  • 函数外的$Online属于全局作用域,未被赋值所以默认是$null;$Computername也未在全局作用域定义,自然也是$null。
  • 原脚本中Write-host 'HELLO $Online $Computername'使用单引号,单引号不会解析变量,即使变量有值也无法正确显示。

修复方案与修正脚本

方案1:捕获函数返回对象提取属性(推荐)

通过变量捕获Get-LoggedOnUser返回的自定义对象,从中获取ComputerName和Online属性进行判断:

Function Get-LoggedOnUser
{
    Param
    (
        $ComputerName = $env:COMPUTERNAME,
        $Credential
    )

    Function Test-RemoteRegistry
    {
        Param
        (
            [Parameter(Mandatory = $False)]
            [switch]$Enable
            ,
            [Parameter(Mandatory = $False)]
            [switch]$Disable
            ,
            [Parameter(ValueFromPipeline=$True)]
            [String[]]$ComputerName = $env:COMPUTERNAME
        )
        Begin
        {
            $PipelineInput = (-not $PSBOUNDPARAMETERS.ContainsKey("ComputerName")) -and (-not $ComputerName)
            
            Function Test ($Computer)
            {
                Try
                {
                    [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $Computer) | Out-Null 

                    If ($Disable)
                    {
                        Try
                        {
                            Get-Service -Name RemoteRegistry -ComputerName $Computer | Set-Service -Status Stopped -ErrorAction Stop
                            Return $False
                        }
                        Catch
                        {
                            Return $True
                        }
                    }
                    Else
                    {
                        Return $True 
                    }
                }
                Catch
                {
                    If ($Enable)
                    {
                        Try
                        {
                            Get-Service -Name RemoteRegistry -ComputerName $Computer | Set-Service -Status Running -ErrorAction Stop
                            Return $True 
                        }
                        Catch
                        {
                            Return $False
                        }
                    }
                    Else
                    {
                        Return $False
                    }
                }
            }
        }
        Process
        {
            If ($PipelineInput)
            {
                Test $_
            }
            Else
            {
                $ComputerName | ForEach-Object {
                    Test $_
                }
            }
        }
    }

    Foreach ($Computer in $Computername)
    {
        $Online = $False
        $User = $False
        $Locked = $False
        If (Test-Connection $Computer -Count 2 -Quiet) 
        {
            $Online = $True 
            If ($Credential) 
            {
                $User = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Computer -Credential $Credential | Select-Object -ExpandProperty UserName -ErrorAction Stop
            }
            Else
            {
                $User = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Computer | Select-Object -ExpandProperty UserName -ErrorAction Stop
            }
            If (Test-RemoteRegistry -Enable -ComputerName $Computer)
            {
                If ((Get-Process logonui -ComputerName $Computer -ErrorAction SilentlyContinue) -and ($user))
                {
                    $Locked = $True
                }
            }
        }
        $Output = New-Object PSObject
        $Output | Add-Member noteproperty ComputerName $Computer
        $Output | Add-Member noteproperty Online $Online
        $Output | Add-Member noteproperty Username $User
        $Output | Add-Member noteproperty Locked $Locked
        $Output
    }
}

# 捕获函数返回的状态对象
$computerStatus = Get-LoggedOnUser

# 从对象中提取属性执行逻辑
If (-not $computerStatus.Online)
{
    # 远程关机命令需要双反斜杠
    Shutdown /r /t 0 /m \\$($computerStatus.ComputerName)
}
Else
{
    # 双引号解析变量,正确显示状态
    Write-Host "设备 $($computerStatus.ComputerName) 处于在线状态,在线标记:$($computerStatus.Online)"
}

方案2:单用户场景简化脚本

如果仅需要判断离线状态并重启,可简化逻辑,直接在函数内完成所有操作,避免变量作用域问题:

Function Restart-OfflineComputer
{
    Param
    (
        $ComputerName = $env:COMPUTERNAME,
        $Credential
    )

    # 先判断设备是否在线
    $online = Test-Connection $ComputerName -Count 2 -Quiet
    if (-not $online) {
        Write-Host "设备 $ComputerName 离线,执行重启..."
        Shutdown /r /t 0 /m \\$ComputerName
    }
    else {
        # 在线时保留原逻辑获取用户信息
        try {
            $user = if ($Credential) {
                Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName -Credential $Credential | Select-Object -ExpandProperty UserName -ErrorAction Stop
            }
            else {
                Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName | Select-Object -ExpandProperty UserName -ErrorAction Stop
            }
            Write-Host "设备 $ComputerName 在线,当前登录用户:$user"
        }
        catch {
            Write-Host "设备 $ComputerName 在线,但无法获取登录用户信息:$_"
        }
    }
}

# 执行函数
Restart-OfflineComputer

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:16:16