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

时间:2018-07-25 10:48:57

标签: wpf powershell user-interface hashtable runspace

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

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

我试图通过实现运行空间来解决此问题。但是现在我遇到了新的问题。 在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&#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 ++){
  if(!(ping-host -pc $ computer)){
   休息
  }
  开始睡眠-第二个5
  if($ i -eq $ max_iterations){
   $ Global:uiHash.Window.Dispatcher.Invoke([操作] {$ 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”)< br />    $ Global:uiHash.Window.Dispatcher.Invoke([操作] {$ Global:uiHash.TextBox.AppendText(“ $ computer仍然在线;检查重新启动是否已正确启动`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([操作] {$ Global:uiHash.TextBox.AppendText(“ $计算机离线;监视在线状态n")},"Normal")
$status = "offline
n”
}

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

开始睡眠-第二个5
 if($ i -eq $ max_iterations){
  $ Global:uiHash.Window.Dispatcher.Invoke([action] {$ Global:uiHash.TextBox.AppendText(“您的计算机在过去的$ MAX_PINGTIME秒内从未恢复在线n")},"Normal")
$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")            


 })

1 个答案:

答案 0 :(得分:0)

GUI冻结的原因是您正在运行的作业在同一实例中。 由于GUI在同一实例中运行,因此必须等到所有代码运行完毕后,才能返回新的输入。

您可以尝试解决此问题,并在单击按钮作为作业时运行要执行的代码,这样,代码将在计算机上的新进程中运行,而不会阻止GUI在其中运行的会话。 / p>

这可以通过Start-Job cmdlet

完成