在 Powershell 中,在文本框中显示服务器重启检查脚本会冻结 WPF GUI

In Powershell, displaying a server restart check script in the textbox, freezes the WPF GUI

我创建了一个使用 WPF GUI 的 PowerShell 脚本。它具有从组合框中选择服务器的选项(稍后将添加更多服务器)。单击重新启动按钮可以重新启动所选服务器。然后,将检查重启过程的脚本将 运行 in Button.Add_Click,结果将显示在文本框中。

问题是 GUI 冻结,直到 Button.Add_Click 完成,然后才会在文本框中显示信息。

我试图通过实施 运行space 来解决这个问题。但是现在我运行陷入了新的困境。 在 ComboBox.add_SelectionChanged 部分,我无法获取选定的组合框内容。我想将内容存储在变量 $computer.

Button.Add_Click 部分我无法写入文本框。当我使用 $Global:uiHash.Window.Dispatcher.Invoke([action] $Global:uiHash.TextBox.AppendText("Check that reboot is initiated properlyn")},"Normal")` 时,GUI 会冻结。

完整代码如下:

$Global:uiHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"          
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("uiHash",$Global:uiHash)



$psCmd = [PowerShell]::Create().AddScript({   
$Global:uiHash.Error = $Error
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase
$xaml = @"
 <Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    Title="CSS Server Reboot" Height="450" Width="800">
<Grid>
    <ComboBox Name="Server_Combobox" HorizontalAlignment="Left" Margin="240,107,0,0" VerticalAlignment="Top" Width="120">
         <ComboBoxItem Name="Server1">10.15.12.148</ComboBoxItem>          
    </ComboBox>
    <Label Name="Title_Label" Content="CSS – Console Quentris, Server Reboot&#xD;&#xA;" HorizontalAlignment="Left" Margin="240,41,0,0" VerticalAlignment="Top" Height="34" Width="284" FontSize="16"/>
    <Button Name="Reboot_Button" Content="Reboot" HorizontalAlignment="Left" Margin="449,107,0,0" VerticalAlignment="Top" Width="75"/>
    <TextBox Name="Reboot_Textbox" Grid.Column="1" HorizontalAlignment="Left" Height="173" Margin="81,180,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="294"/>
</Grid>

 "@



$Global:uiHash.Window=[Windows.Markup.XamlReader]::Parse($xaml )
$Global:uiHash.TextBox = $Global:uiHash.window.FindName("Reboot_Textbox")
$Global:uiHash.Button = $Global:uiHash.window.FindName("Reboot_Button")
$Global:uiHash.ComboBox = $Global:uiHash.window.FindName("Server_Combobox")
$Global:uiHash.Window.ShowDialog() | out-null
})

$psCmd.Runspace = $newRunspace
$handle = $psCmd.BeginInvoke()


Start-Sleep -Milliseconds 100


$computer = ""

$Global:uiHash.ComboBox.add_SelectionChanged({

$Script:computer = $Global:uiHash.Combobox.SelectedItem.Content

})


$Global:uiHash.Button.Add_Click({
$Username = 'xxxx'
$Password = 'xxxx'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$SecureString = $pass
$MySecureCreds = New-Object -TypeName 
System.Management.Automation.PSCredential -ArgumentList 
$Username,$SecureString 

Restart-Computer -ComputerName $computer -Force -Credential $MySecureCreds

$timeout=5
$MAX_PINGTIME = $timeout * 60            
$max_iterations = $MAX_PINGTIME/5            
$Notification_timeout = 10 # in seconds


function ping-host {            
param($pc)            
$status = Get-WmiObject -Class Win32_PingStatus -Filter "Address='$pc'"            
if( $status.statuscode -eq 0) {            
   return 1            
} else {            
 return 0            
}            
}            

if(ping-host -pc $computer) {   

 $status = "online`n" 

for ($i=0; $i -le $max_iterations; $i++) {
如果 (!(ping-host -pc $computer )) {
休息
}
开始睡眠 - 秒 5
如果($i -eq $max_iterations){
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("$computer 在最后 $timeout 分钟n")},"Normal") $Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("Check that reboot is initiated properlyn")},"Normal")
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("$computer is still ONLINE; Check that reboot is initiated properly`n")},"Normal")
退出
}
}

$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("$computer is offline now; monitoring for online status`n")},"Normal")            

}否则{
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("$computer is offline; Monitoring for online statusn")},"Normal")<br> $status = "offlinen"
}

for ($i=0; $i -le $max_iterations; $i++) {
如果 ((ping-host -pc $computer )) {
休息
}

开始-睡眠-秒 5
如果($i -eq $max_iterations){
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("Your computer never came back online in last $MAX_PINGTIME secondsn")},"Normal")<br> $Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("Check that nothing is preventing starupn")},"Normal")
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.TextBox.AppendText("$Computer 未上线;某事阻止其启动`n")},"Normal")
退出
}

}            

 $Global:uiHash.Window.Dispatcher.Invoke([action]  
 {$Global:uiHash.TextBox.AppendText("Your computer is Online Now; Task done; 
 exiting")},"Normal")            


 })

GUI 冻结的原因是您运行正在执行的作业在同一个实例中。 由于 GUI 运行s 在同一个实例中,它必须等到任何代码 运行ning 完成后才能返回以获取新输入。

您可以尝试解决这个 运行 当您单击按钮作为作业时要执行的代码,这样代码将 运行 在机器上的新进程中并且不阻止 GUI 运行正在进入的会话。

这可以通过 Start-Job cmdlet