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
相关产品推荐
相关产品推荐

