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

PowerShell服务器RDP脚本异常:点击按钮均连接最后一台服务器

问题分析与解决

你的问题出在PowerShell的闭包延迟绑定特性上:在foreach循环中添加的点击事件脚本块,并不会立即捕获当前循环的$server变量值,而是在事件触发时才去读取$server的当前值。当循环结束后,$server已经指向列表的最后一个元素,所以所有按钮点击都会调用最后一台服务器的RDP。

解决方案

方法1:用局部变量捕获当前服务器名

在循环内部创建一个局部变量,保存当前迭代的$server值,让事件脚本块引用这个局部变量:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$servers = @("server1", "server2", "server3")
$credentials = Get-Credential

function Get-ServerStatus {
    param ($server, [PSCredential]$credentials)
      try {
        $sessionInfo = Invoke-Command -ComputerName $server -Credential $credentials -ScriptBlock {
            query user /server:$env:COMPUTERNAME
        } -ErrorAction SilentlyContinue
        $activeSessions = ($sessionInfo | Where-Object { $_ -match "Active" }).Count
        return $activeSessions
    } catch {
    return -1
    }
}

function Start-RDP {
    param ($server, [PSCredential]$credentials)
    cmdkey /generic:"$server" /user:"$($credentials.UserName)" /pass:"$($credentials.GetNetworkCredential().Password)"
    Start-Process "mstsc.exe" "/v:$server /f"
}

# New Window form
$form = New-Object System.Windows.Forms.Form
$form.Text = "Server Status"
$form.Size = New-Object System.Drawing.Size(300, 400)

# Title
$titleLabel = New-Object System.Windows.Forms.Label
$titleLabel.Text = "Stato dei server:"
$titleLabel.Size = New-Object System.Drawing.Size(280, 30)
$titleLabel.Location = New-Object System.Drawing.Point(10, 10)
$titleLabel.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 16, [System.Drawing.FontStyle]::Bold)
$titleLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$form.Controls.Add($titleLabel)

$y = 60
foreach ($server in $servers) {
    # 新增局部变量捕获当前服务器名
    $currentServer = $server
    $status = Get-ServerStatus -server $server -credentials $credentials
    $button = New-Object System.Windows.Forms.Button
    $button.Size = New-Object System.Drawing.Size(260, 30)
    $button.Location = New-Object System.Drawing.Point(10, $y)
    $y += 40

    if ($status -eq -1) {
        $button.Text = "$server not accessible"
        $button.BackColor = [System.Drawing.Color]::Red
    } elseif ($status -gt 2) {
        $button.Text = "$server is BUSY ($status users)"
        $button.BackColor = [System.Drawing.Color]::Red
    } else {
        $button.Text = "$server is FREE"
        $button.BackColor = [System.Drawing.Color]::Green
        # 引用局部变量$currentServer
        $button.Add_Click({ Start-RDP -server $currentServer -credentials $credentials })
    }

    $form.Controls.Add($button)
 }

$form.ShowDialog()

方法2:利用按钮的Tag属性存储服务器名

把服务器名绑定到按钮的Tag属性,在点击事件中通过触发按钮对象获取该值:

# 仅展示循环内的修改部分
$y = 60
foreach ($server in $servers) {
    $status = Get-ServerStatus -server $server -credentials $credentials
    $button = New-Object System.Windows.Forms.Button
    $button.Size = New-Object System.Drawing.Size(260, 30)
    $button.Location = New-Object System.Drawing.Point(10, $y)
    $y += 40
    # 将服务器名存入按钮Tag
    $button.Tag = $server

    if ($status -eq -1) {
        $button.Text = "$server not accessible"
        $button.BackColor = [System.Drawing.Color]::Red
    } elseif ($status -gt 2) {
        $button.Text = "$server is BUSY ($status users)"
        $button.BackColor = [System.Drawing.Color]::Red
    } else {
        $button.Text = "$server is FREE"
        $button.BackColor = [System.Drawing.Color]::Green
        # 通过$sender.Tag获取当前按钮对应的服务器名
        $button.Add_Click({ param($sender) Start-RDP -server $sender.Tag -credentials $credentials })
    }

    $form.Controls.Add($button)
 }

这两种方法都能解决变量延迟绑定的问题,让每个按钮点击时调用对应服务器的RDP会话。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:52:33