在 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 properly
n")},"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
" 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 properly
n")},"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 = "offline
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("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 starup
n")},"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
我创建了一个使用 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 properly
n")},"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
" 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 properly
n")},"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 = "offline
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("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 starup
n")},"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