简体   繁体   中英

Calling scriptblock from different runspace

I am working on a project to create a GUI Wizard tool, this GUI Wizard Tool first gets some data from the user and in the same time performing validation (such as connectivity, DNS Resolution, API Connection, etc..). After the GUI Wizard Tool gets all the required data from the user, then it will start calling other subscripts.

To make the GUI Wizard faster and to overcome this unresponsiveness issue, I am using Runspaces, the GUI itself will run in a Runspace and any further tasks (such as performing a validation check) will also run in a different Runspace.

To simplify my code and to make it easier and more organized, I am using script blocks. I have created a number of script block within the GUI Runspace to be used whenever a submit button in the GUI is clicked. for each submits button there would be a different script block and also some submit buttons will execute the same script block.

My issue is in calling the script blocks. whenever I add a script block in an Add_Click action, the script block does not get executed, I have tried using Wait-Debugger within the script block and I do not even see any runspace in the InBreakpoint state.

Can you please let me know if I am doing something wrong as I am new to runspaces and WPF in PowerShell. Thank you for your help.

#   Create an Array that will hold all the XAML pages variables.
$XamlFilesArray = @($WizardMainWindowXaml, $WizardMainPageXaml, $WizardVCPageXaml, $WizardHostingVCPageXaml, $WizardControllerPageXaml, $WizardPrimaryNsxPageXaml, $WizardPrimaryVCPageXaml, $WizardFinalPageXaml)

#   Create  Sync HashTable (GuiHash) to allow readability across different Runscpases and add required variables.
$Global:GuiHash = [hashtable]::Synchronized(@{ })
$Global:GuiHash.IPCehckPattern = $IPCehckPattern #  Add the IPCehckPattern Variable to be used within other runspaces

#   Crate the Runspace that will be used for the GUI and configure settings. After, Open the Runspace and import variables.
#   You must import variables that will be used in other Runspaces, thus importing the required variables to this Runspace.
$GuiRunspace =[runspacefactory]::CreateRunspace()
$GuiRunspace.ApartmentState = "STA"
$GuiRunspace.ThreadOptions = "ReuseThread"         
$GuiRunspace.Open()
$GuiRunspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)  
$GuiRunspace.SessionStateProxy.SetVariable("XamlFilesArray",$XamlFilesArray)

#   Create a PowerShell Session and add it to the Runspace.
$GuiPSSession = [PowerShell]::Create()
$GuiPSSession.Runspace = $GuiRunspace

#   Create the GUI PowerShell Session ScriptBlock. This will be the main code of the tool.
[void]$GuiPSSession.AddScript({
    $ScriptBlockMainPageSubmitButton1 = {

        #   This Script block will be called when the first Submit Button in the Main page is clicked.
        #   This will handle the NSX Manager FQDN and perform the required checks
        #   Actions this Script Block will perform are as follow:
        #       1- Check if the input value is empty, if so print error.
        #       2- Check if the Provided FQDN is resolvable.
        #       3- Check if the provided FQDN is reachable on port 443.

        Param($GuiHash)

        Process {
            # Check if WizardMainPageInputBox2 is enabled and if so then disable it.
            If ($GuiHash.WizardMainPageInputBox2.IsEnabled -Eq "False") {$GuiHash.WizardMainPageInputBox2.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox2.IsEnabled= "True"})}

            # Check if the input data is empty and if so Write Error
            If ($GuiHash.WizardMainPageInputBox1.Text.Length -Eq 0) {
                $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "Red"})  #   Make Sure Printing Color is Red.
                $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided Data is empty, please provide NSX FQDN."})  #   Print Error
                $GuiHash.WizardMainPageInputBox1.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox1.Text = "NSX Manager FQDN:"})   #   Revert Text in InputBox to default.
            }   Else {
                    # Check if the input FQDN from WizardMainPageInputBox1 is resolvable and if not print error
                    If (!(Resolve-DnsName -Name $GuiHash.WizardMainPageInputBox1.Text -ErrorAction SilentlyContinue)) {
                        $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "Red"})  #   Make Sure Printing Color is Red.
                        $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided NSX FQDN is not resolvable. Please try again."})    #   Print Error
                        $GuiHash.WizardMainPageInputBox1.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox1.Text = "NSX Manager FQDN:"})   #   Revert Text in InputBox to default.
                    }   Else {
                            # Check Reachability of provided FQDN using port 443.
                            # Print Activity Message.
                            $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "Green"})    #   Make Sure Printing Color is Green.
                            $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Please wait while checking reachability."})  #   Print Message

                            If (!((Test-NetConnection $NsxManagerFQDN -Port 443 -WarningAction SilentlyContinue).TcpTestSucceeded)) {
                                # Print Error and reset the Inputbox text to default.
                                $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground="Red"})       #   Make Sure Printing Color is Red.
                                $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided NSX FQDN is not reachable over port 443. Please try again."})       #   Print Error
                                $GuiHash.WizardMainPageInputBox1.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox1.Text = "NSX Manager FQDN:"})       #   Revert Text in InputBox to default.
                            }   Else {
                                    # Print Success, enable WizardMainPageInputBox2, Disable WizardMainPageSubmitButton1 and add NSX FQDN to Sync Hash
                                    $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "White"})        #   Make Sure Printing Color is White.
                                    $GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided NSX FQDN confirmed. Please provide credentials."})  #   Print Message
                                    $GuiHash.WizardMainPageInputBox2.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox2.IsEnabled= "True"})    #   Enable WizardMainPageInputBox2 to continue
                                    $GuiHash.WizardMainPageSubmitButton1.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageSubmitButton1.IsEnabled= "False"})   #   Disable WizardMainPageSubmitButton1
                                    $GuiHash.NsxManagerFQDN = $GuiHash.WizardMainPageInputBox1.Text     #   Add provided NSX FQDN to GuiHash
                                }
                        }
                }
        }
    }
    #   Run a ForEach Loop to Read each Xaml Page, load the page and lastly add each node within the Xaml to the (GuiHash).
    ForEach ($File in $XamlFilesArray) {
        $TempReadXamlFile=(New-Object System.Xml.XmlNodeReader $File)   #   Read Xaml Page
        $TempWindowForm=[Windows.Markup.XamlReader]::Load($TempReadXamlFile)    #   Load the Wizard XAML Files in a GUI Form
        $File.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach-Object {$Global:GuiHash.Add($_.Name, $TempWindowForm.FindName($_.Name))}    #   Add all XAML Nodes to the HashTable
    }

    #   Set the First page on the Wizard Window to be the WizardMainPageGrid.


$Global:GuiHash.WizardFram.NavigationService.Navigate($Global:GuiHash.WizardMainPageGrid) | Out-Null
$Global:GuiHash.WizardMainPageSubmitButton1.Add_Click({
                # Create new Runspace for this task. 
                $MPSB1Runspace = [runspacefactory]::CreateRunspace()
                $MPSB1PSSesion = [powershell]::Create()
                $MPSB1PSSesion.runspace = $MPSB1Runspace
                $MPSB1Runspace.Open()
                $MPSB1Runspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
                [void]$MPSB1PSSesion.AddScript({$ScriptBlockMainPageSubmitButton1}).AddArgument($Global:GuiHash)
                $ExecScriptObject = $MPSB1PSSesion.BeginInvoke()
            })
#   Show Wizard Window.
        $Global:GuiHash.WizardMainWindow.ShowDialog() | Out-Null

    })  

    $ShowGui = $GuiPSSession.BeginInvoke()

my expectations are when I click on the input box and provide an incorrect FQDN with the GUI will error out with the issue it has seen.

After performing a couple of tests and checks, it turned out that the issue is very simple and it was all my fault. When I was calling the AddScript I was using ({}) however you should have only used (). so after removing the {} and making it only (), it works fine. As an example,

            $Global:GuiHash.WizardMainPageSubmitButton1.Add_Click({
                # Create new Runspace for this task. 
                $MPSB1Runspace = [runspacefactory]::CreateRunspace()
                $MPSB1PSSesion = [powershell]::Create()
                $MPSB1PSSesion.runspace = $MPSB1Runspace
                $MPSB1Runspace.Open()
                $MPSB1Runspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
                [void]$MPSB1PSSesion.AddScript($ScriptBlockMainPageSubmitButton1).AddArgument($Global:GuiHash)
                $ExecScriptObject = $MPSB1PSSesion.BeginInvoke()
            })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM