How to direct command output to a window or textbox

Jun 6, 2013 at 5:35 PM
Hi,

I'm still very green when it comes to ShowUI, most of my code is peiced together from examples seen in the net. In any case, I hope you can help me with this code. I'm sure I'm way off base here. I have to following program (mostly taken from the showui_converter). I would like to show to output from the various function in the bottom window of the interface. I understand how to output to the text box by saving the output to $SystemResults.text, but I would like to output to be progressing, as the program is running.
Import-Module showui
$Windowparam = @{
    Width = 800
    Height = 600
    Title = 'System Configuration'
    Background = '#C4CBD8'
    WindowStartupLocation = 'CenterScreen'
    AsJob = $True
}

#Create Window
New-Window @Windowparam {
    New-Grid -Rows Auto,10,Auto,10,Auto,* -Children {
        New-Grid -Row 0 -Columns Auto,5,Auto -Children {
            New-Label -Column 0 'Select a ship'
            New-ComboBox -Name SystemName -Column 2 -IsReadOnly:$True -SelectedIndex 0 -Items {
                New-TextBlock -Text 'System 1 Name'
                New-TextBlock -Text 'System 2 Name'
                New-TextBlock -Text 'System 3 Name'
                New-TextBlock -Text 'System 34 Name' 
            }
        }
        New-Grid -Row 2 -Rows Auto,Auto -Columns Auto,5,75 -Children {
            New-Label -Row 0 -Column 0 'Administrator'
            New-TextBox -row 0 -Column 2 -Name AdminAccount
            New-Label -Row 1 -Column 0 'Password'
            New-PasswordBox -Name AdminPassword -row 1 -Column 2 
        }
        New-StackPanel -Row 4 -Orientation Horizontal {
            New-Button -Name PrepSystem -Width 85 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Prep System' -On_Click {
                Run-PrepSystem $SystemName.Text $AdminAccount.text $AdminPassword.password
            }
            New-Label
            New-Button -Name ConfigSystem -Width 85 -Height 25 -Row 0 -Column 2 -HorizontalAlignment Left -Content 'Config System' -On_Click {
                Run-ConfigSystem $SystemName.Text
            }
            New-Label
            New-Button -Name CloseWindow -Width 85 -Height 25 -Row 0 -Column 4 -HorizontalAlignment Left -Content E_xit -On_Click {
                Close-Control
            }
            
        }
        New-TextBox -Row 5 -Name SystemResults -IsReadOnly:$True -TextWrapping Wrap -VerticalScrollBarVisibility Auto
    }
} -On_Loaded {
    Function Run-PrepSystem {
        [cmdletbinding()]
        Param (
            [parameter(ValueFromPipeLine='True')]    
            $strSystemName,
            $strAdmin,
            $pswd
        )
         Begin {
        }
        Process {
            "`nImporting System Configuration Data`n"
            $objSystemData = Import-Csv .\ststemdata.csv | Where-Object {$_.systemname -eq $strSystemName}
            "`nCopying Configuration files to C:\temp`n"
            # Other configuration steps here
            # would like the output of some commends to show in the Outputbox text field
            "`nSystem is ready for final configuration"
            "`nSystem will reboot in 10 seconds"
            Start-Sleep -Seconds 10
            Restart-Computer -Force
        }
        End {
        }
    }

    Function Run-ConfigSystem {
        [cmdletbinding()]
        Param (
            $strSystemName,
            $strAdmin,
            $pswd
        )
        Begin {
        }
        Process {
            #Perform Configuration here
        }
        End {
        }
    }

}
Also, where is a good place to start learning how to use some of the more advances features of ShowUI.

Regards,

Mike
Coordinator
Jun 6, 2013 at 11:30 PM
Edited Jun 7, 2013 at 6:20 AM
I wrote a nice long reply here, but then I accidentally clicked this button on the form and rebooted my computer ... no kidding.

Anyway, the short version is, you can just do this:
            New-Button -Name ConfigSystem -Width 85 -Height 25 -Row 0 -Column 2 -HorizontalAlignment Left -Content 'Config System' -On_Click {
                Run-ConfigSystem $SystemName.Text | % { $SystemResults.Text += "$_`n" }
            }
But as you're no doubt aware, that won't actually update the UI because the UI is FROZEN waiting for the On_Click event handler (scriptblock) to exit ...

In order to keep the UI responsive while you do work, you have to use Invoke-Background (or some other function like it). This is the least used part of ShowUI, and hasn't been properly documented, but it does work. Basically, take your Run-PrepSystem function and pull it right into the event handler on the button, like this:
            New-Button -Name PrepSystem -Width 85 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Prep System' -On_Click {
                # The control specified to Invoke-Background 
                # will have its DataContext set to the background job results
                Invoke-Background -Control $PrepSystem {
                    [cmdletbinding()]
                    # The values to these have to be passed in the -Parameter hashtable
                    Param ( $strSystemName, $strAdmin, $pswd )
                    End {
                        "`nImporting System Configuration Data`n"

                        Start-Sleep -milli 500 # simulate work ...
                        # $objSystemData = Import-Csv .\ststemdata.csv | Where-Object {$_.systemname -eq $strSystemName}

                        "`nCopying Configuration files to C:\temp`n"
                        
                        # Other configuration steps here
                        # would like the output of some commands to show up ...
                        Start-Sleep 5 # simulate work ...

                        "`nSystem is ready for final configuration"
                        "`nSystem will reboot in 10 seconds"

                        Start-Sleep -Seconds 10

                        "`nRestarting remote computer  $strSystemName"
                        Restart-Computer -ComputerName $strSystemName -Force
                    }

                } -On_OutputChanged {
                    # In the event handlers, we use the control's DataContext
                    $SystemResults.Text = $PrepSystem.DataContext.Output;
                } -Parameter @{ 
                    # NOTE THESE MUST MATCH THE PARAM BLOCK EXACTLY
                    strSystemName = $SystemName.Text
                    strAdmin = $AdminAccount.text
                    pswd = $AdminPassword.password
                }
            }
Marked as answer by Jaykul on 11/14/2013 at 2:57 PM
Coordinator
Jun 7, 2013 at 5:56 AM
Jun 7, 2013 at 12:50 PM
Excellent, works like a charm.

I have a library file that I load with all my scripts and I often create other functions that are unique to each script. When I call a function from my library file, or a function in the script, it does not work. I tried to include the function in the -On_loaded event of the window and I also tried to add it at the top of my script, before creating the window, but neither works. How can I call these functions?

Other than the youtube videos where can I find some andvanced program documentation. For example the Invoke-Background, I would never have figured that out without asking.

Thank you,

Mike
Coordinator
Jun 7, 2013 at 2:02 PM
Honestly, I normally recommend my blog for learning ShowUI, but lately the forums here are outpacing my blog (I try very hard to give complete answers with relatively complete code examples, and the forum is user-driven). Sadly, we've never gone through a systematic book-style from beginner to expert "how to write ShowUI" series of articles anywhere, so right now the best bet for learning ShowUI is reading blog posts and example code ... and learning about WPF and PowerShell in general separately, of course.

I guess I should work on a series of articles for getting started to continue from my original walk-through to present more advanced topics...

You should be able to call any functions that are defined globally from within your event handlers, but Invoke-Background is slightly different because it's spinning out a new thread and a totally new runspace. It's basically like Start-Job or Invoke-Command -AsJob: you have a new PowerShell instance (a new runspace), so you have to re-import your commands in order to use them. That's why you have to use the -Parameter hashtable to send over anything that you need inside the Invoke-Background script block. The event handlers (even the ones for Invoke-Background) of course, are running on this thread (the one running your UI), so they don't have that problem.
Jun 7, 2013 at 3:36 PM
Thank you for the quick responce. I have a good grasp of PowerShell, I guess WPF is what I should be working on.

I have a number of global variables that are common to both the PrepSystem and ConfigSystem routine. I now have them in the -On_Loaded event when I create my frist grid and I pass the variables to the Invoke-Background parameter event. So it looks like this now.
$Windowparam = @{
    Width = 800
    Height = 600
    Title = 'System Configuration'
    Background = '#C4CBD8'
    WindowStartupLocation = 'CenterScreen'
    AsJob = $True
}

#Create Window
New-Window @Windowparam {
    New-Grid -Rows Auto,10,Auto,10,Auto,* -Children {
        New-Grid -Row 0 -Columns Auto,5,Auto -Children {
            New-Label -Column 0 'Select a ship'
            New-ComboBox -Name SystemName -Column 2 -IsReadOnly:$True -SelectedIndex 0 -Items {
                New-TextBlock -Text 'System 1 Name'
                New-TextBlock -Text 'System 2 Name'
                New-TextBlock -Text 'System 3 Name'
                New-TextBlock -Text 'System 34 Name' 
            }
        }
        New-Grid -Row 2 -Rows Auto,Auto -Columns Auto,5,75 -Children {
            New-Label -Row 0 -Column 0 'Administrator'
            New-TextBox -row 0 -Column 2 -Name AdminAccount
            New-Label -Row 1 -Column 0 'Password'
            New-PasswordBox -Name AdminPassword -row 1 -Column 2 
        }
        New-StackPanel -Row 4 -Orientation Horizontal {
            New-Button -Name PrepSystem -Width 85 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Prep System' -On_Click  {
                Invoke-Background -Control $PrepSystem {
                    Param ( $strSystemName, $strAdmin, $pswd , $GVar1, $GVar2, $GVar3)
                    End {
                        #Run My program here
                    }
                } -On_OutputChanged {
                    $SystemResults.Text = $PrepSystem.DataContext.Output;
                } -Parameter @{ 
                    strSystemName = $SystemName.Text
                    strAdmin = $AdminAccount.text
                    pswd = $AdminPassword.password
                    GVar1 = $GlobalVar1
                    GVar2 = $GlobalVar2
                    GVar3 = $GlobalVar3
                }
            }
            New-Label
            New-Button -Name ConfigSystem -Width 85 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Config System' -On_Click  {
                Invoke-Background -Control $ConfigSystem {
                    Param ( $strSystemName, $strAdmin, $pswd , $GVar1, $GVar2, $GVar3)
                    End {
                        #Run My program here
                    }
                } -On_OutputChanged {
                    $SystemResults.Text = $ConfigSystem.DataContext.Output;
                } -Parameter @{ 
                    strSystemName = $SystemName.Text
                    strAdmin = $AdminAccount.text
                    pswd = $AdminPassword.password
                    GVar1 = $GlobalVar1
                    GVar2 = $GlobalVar2
                    GVar3 = $GlobalVar3
                }
            }
            New-Label
            New-Button -Name CloseWindow -Width 85 -Height 25 -Row 0 -Column 4 -HorizontalAlignment Left -Content E_xit -On_Click {
                Close-Control
            }
        }
        New-TextBox -Row 5 -Name SystemResults -IsReadOnly:$True -TextWrapping Wrap -VerticalScrollBarVisibility Auto
    } -On_Loaded {
        $GlobalVar1 = "My Global Var1"
        $GlobalVar2 = "My Global Var2"
        $GlobalVar3 = "My Global Var3"
    }
}
I'm still not sure how to call a function or use a function in my library. Where do I put the function and at what point should I load my library file?

Mike
Coordinator
Jun 7, 2013 at 4:07 PM
If you need them in Invoke-Background, then you need to load the library file INSIDE the Invoke-Background scriptblock.

NOTE: A library of functions is called a "module" in PowerShell, so you can just use import-module C:\Path\File.ps1

Basically, the first command in your END block should be Import-Module. Or, you can add a BEGIN { Import-Module YourModuleName } to preload it and keep the import separate from your code.

Note: modules can be .ps1 files, but it makes sense to rename them to psm1 and even to put them in your PSModulesPath. E.g.: C:\users\YourName\Documents\WIndowsPowerShell\Modules\LibraryName\LibraryName.psm1 Then you can just Import-Module LibraryName

See also: Installing Modules

Also note: if you're on PowerShell 3, by moving your library to a folder that's inside a folder in your PSModulesPath you get auto-discovery, so you'd be able to skip the Import-Module (or dotsourcing or whatever you're doing right now) and just call the functions -- PowerShell would find them in the module and import it when needed.
Sep 3, 2013 at 4:00 PM
Sorry to bring up one of my old threads.

I have been trying to figure how to enble and disable buttons based on conditions in the invoke-Background process. Using the example above, my ConfigSystem button should be disabled until my PrepSystem process has successfully complete. I know how to disable and enable the buttons when the window opens and everything loads for the first time, but I can't seem to change the state of a button after a backgrount process runs.

How would this be done?

Thank you,

Mike
Coordinator
Sep 4, 2013 at 3:14 AM
When you're running UI and code that needs to interact with it, one or both of these should be true:
1) you're running the UI -AsJob
2) you're running the "background" work using Invoke-Background from the UI.

The simplest thing is to run the UI -AsJob ... and update it from another script in the console (you just use Update-WPFJob to change things in the UI whenever you want to.

The more flexible thing to do is use Invoke-Background from an event handler (e.g. the On_Load event) and change things in the scriptblocks for -ON_* events for that command.

I can post examples of either/both if you need them.
Sep 4, 2013 at 1:56 PM
I think I understand the first part, that is starting the UI with -AsJob and then using Update-WPFJob for make changes, however I can't seem get it to work.

This is my code.
$Windowparam = @{
    Width = 800
    Height = 600
    Title = 'SCCM System Configuration'
    Background = '#C4CBD8'
    WindowStartupLocation = 'CenterScreen'
    
}

#Create Window
New-Window -Name MainWindow @Windowparam  {
    New-Grid -Rows Auto,5,Auto,5,* -Children {
        New-Grid -Row 0 -Rows Auto,5,Auto,5,Auto,5,Auto  -Columns Auto,5,Auto,10,Auto,5,Auto,5,Auto,5,Auto -Children {
            
            New-Label -Row 2 -Column 0 'Version Installed' 
            New-TextBox -row 2 -Column 2 -Name VersionNum -Width 130 -BorderThickness 2 
            
            New-Label -Row 4 -Column 0 'Total Updates Installed'
            New-TextBox -row 4 -Column 2 -Name UpdatesInstalled -Width 130 -BorderThickness 2 
            
        }
        New-StackPanel -Row 2 -Orientation Horizontal {
            New-Button -Name PrepSystem -Width 100 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Install' `
                -On_Loaded {
                    $PrepSystem.IsEnabled = $EnablePrepButton

                } -On_Click {
                Invoke-Background -control $PrepSystem {
                    End {
                        
                        #Install Software, Updates and configure System
                        
                        #Validate if system us updates before proceeding to next configuration step
                        # if validation passed, enable ConfigSystem1 Button and update the Version and Update information
                        Get-Job MainWindow | Update-WPFJob {
                            $ConfigSystem1.IsEnabled = $true
                            $VersionNum.text = "12345"
                            $UpdatesInstalled.text = "99"
                        }
                                    
                    }
                } -On_OutputChanged {
                    $SystemResults.text = $PrepSystem.DataContext.Output
                }
            }
            
            New-Label
            New-Button -Name ConfigSystem1 -Width 100 -Height 25 -Row 0 -Column 2 -HorizontalAlignment Left -Content 'Configure System' `
                -On_Loaded {
                    $ConfigSystem1.IsEnabled = $EnableConfig1Button
                } -On_Click {
                Invoke-Background -control $ConfigSystem1 {
                    End {
                        
                        #Do other stuff here if successful enable ConfigButton2
                                                
                    }

                } -On_OutputChanged {
                    $SystemResults.text = $ConfigSystem1.DataContext.Output
    
                }
            }
            New-Label
            New-Button -Name ConfigSystem2 -Width 100 -Height 25 -Row 0 -Column 4 -HorizontalAlignment Left -Content 'Cleanup' `
                -On_Loaded {
                    $ConfigSystem2.IsEnabled = $EnableConfig2Button
                } -On_Click {
                Invoke-Background -control $ConfigSystem2 {

                    End {
                        
                    } 
                } -On_OutputChanged {
                    $SystemResults.text = $ConfigSystem2.DataContext.Output
                }
            }
            New-Label
            New-Button -Name CloseWindow -Width 85 -Height 25 -Row 0 -Column 12 -HorizontalAlignment Left -Content E_xit -On_Click {
                Get-ParentControl | Set-UIValue -passThru | Close-Control
            }
            
        }
        New-TextBox -Row 4 -Name SystemResults -IsReadOnly:$True -TextWrapping Wrap -VerticalScrollBarVisibility Auto -FontSize 14
    } -On_Loaded {
        
        #Validate what is installed to intialize what buttons need to be enabled
        #If nothing Installed start with only $EnablePrepButton     
            $EnablePrepButton = $True
            $EnableConfig1Button = $False
            $EnableConfig2Button = $False
    }
            
} -AsJob
Normally when the window opens for the fisrt time only the PrepSystem button is enabled. After PrepSystem is run then I want to enable ConfigSystem1 and update some text boxes but this does not seem to work.

Mike
Coordinator
Sep 5, 2013 at 8:13 AM
Alright ... looking good, but a few problems.

First of all, you have Loaded events which depend on each other (that is, the Loaded event for the PrepSystem button requires the variable to be set -- and it's set in the Loaded event for the window ... I can't find anything which specifies an order, but I think the order in which they get Loaded isn't guaranteed, but if it is, the inner controls will load first. Anyway, you should initialize the window variables -On_Initialized instead of -On_Loaded ... however -- you can't just share variables like that.

PowerShell modules have a limited scope, and in this case, you're in event handlers. Creating a variable in one event handler won't make it available to another handler unless you stick it in the global scope, or attach it to a control (that's one reason that we have Set-UIValue/Get-UIValue). The simplest thing is to write-output an object which has the data you need:

$Windowparam = @{
    Width = 800
    Height = 600
    Title = 'SCCM System Configuration'
    Background = '#C4CBD8'
    WindowStartupLocation = 'CenterScreen'
    
}

#Create Window
New-Window -Name MainWindow @Windowparam  {
    New-Grid -Rows Auto,5,Auto,5,* -Children {
        New-Grid -Row 0 -Rows Auto,5,Auto,5,Auto,5,Auto  -Columns Auto,5,Auto,10,Auto,5,Auto,5,Auto,5,Auto -Children {
            
            New-Label -Row 2 -Column 0 'Version Installed' 
            New-TextBox -row 2 -Column 2 -Name VersionNum -Width 130 -BorderThickness 2 
            
            New-Label -Row 4 -Column 0 'Total Updates Installed'
            New-TextBox -row 4 -Column 2 -Name UpdatesInstalled -Width 130 -BorderThickness 2 
            
        }
        New-StackPanel -Row 2 -Orientation Horizontal {
            New-Button -Name PrepSystem -Width 100 -Height 25 -Row 0 -Column 0 -HorizontalAlignment Left -Content 'Install' `
                -On_Click {
                Invoke-Background -control $PrepSystem {
                    End {
                        
                        #Install Software, Updates and configure System
                        
                        #Validate if system us updates before proceeding to next configuration step
                        # if validation passed, enable ConfigSystem1 Button and update the Version and Update information
                        New-Object PSObject -Property @{
                            ConfigSystem1Enabled = $true
                            VersionNum = "12345"
                            UpdatesInstalled = "99"
                        }
                                    
                    }
                } -On_OutputChanged {
                    # $SystemResults.text = $PrepSystem.DataContext.Output
                    $ConfigSystem1.IsEnabled = $PrepSystem.DataContext.LastOutput.ConfigSystem1Enabled
                    $VersionNum.Text = $PrepSystem.DataContext.LastOutput.VersionNum
                    $UpdatesInstalled.Text = $PrepSystem.DataContext.LastOutput.UpdatesInstalled
                }
            }
            
            New-Label
            New-Button -Name ConfigSystem1 -Width 100 -Height 25 -Row 0 -Column 2 -HorizontalAlignment Left -Content 'Configure System' `
                -On_Click {
                Invoke-Background -control $ConfigSystem1 {
                    End {
                        
                        #Do other stuff here if successful enable ConfigButton2
                                                
                    }

                } -On_OutputChanged {
                    $SystemResults.text = $ConfigSystem1.DataContext.Output
    
                }
            }
            New-Label
            New-Button -Name ConfigSystem2 -Width 100 -Height 25 -Row 0 -Column 4 -HorizontalAlignment Left -Content 'Cleanup' `
                -On_Click {
                Invoke-Background -control $ConfigSystem2 {

                    End {
                        
                    } 
                } -On_OutputChanged {
                    $SystemResults.text = $ConfigSystem2.DataContext.Output
                }
            }
            New-Label
            New-Button -Name CloseWindow -Width 85 -Height 25 -Row 0 -Column 12 -HorizontalAlignment Left -Content E_xit -On_Click {
                Get-ParentControl | Set-UIValue -passThru | Close-Control
            }
            
        }
        New-TextBox -Row 4 -Name SystemResults -IsReadOnly -TextWrapping Wrap -VerticalScrollBarVisibility Auto -FontSize 14
    } -On_Loaded {
        
        #Validate what is installed to intialize what buttons need to be enabled
        #If nothing Installed start with only $EnablePrepButton
        $EnablePrepButton = $True
        $EnableConfig1Button = $False
        $EnableConfig2Button = $False

        # Write-Host "$EnablePrepButton, $EnableConfig1Button, $EnableConfig2Button"

        $PrepSystem.IsEnabled = $EnablePrepButton
        $ConfigSystem1.IsEnabled = $EnableConfig1Button
        $ConfigSystem2.IsEnabled = $EnableConfig2Button
    }
            
} -AsJob
Sep 6, 2013 at 11:16 AM
OK, I see what you mean and it works now.

In what situation would Update-WPFjob be used though?

Mike
Coordinator
Sep 6, 2013 at 2:24 PM
Edited Sep 6, 2013 at 2:52 PM
I think you could have used it there, if you'd played with it. I have to look at a couple of things about it (I'm not 100% sure that we set all the magic variables for it). However, you should only need it when you're spinning up UIs from the main console and want to update them from there -- if you're running in an event handler, Invoke-Background has events, and the DataSource that it creates has collections and Last* properties for each output stream (including Progress and Verbose) so you can do stuff like this:
Grid -Rows 2 -ControlName Progression {
    ProgressBar -name progress -height 28 -maximum 100
    Label -name report -zindex 1 -background Transparent
        # -DataBinding @{ "Value" = "LastProgress.PercentComplete" }
    Button "Click Me" -Name "Click" -Row 1 -on_Click {
        $this.IsEnabled = $false
        $window.Cursor = "Wait"
        Invoke-Background -Scriptblock { 
            1..10 | % {
                sleep -milli 200  # imagine this was doing real work
                write-progress -percent ($_ * 10) -activity "Super"
            }
            Write-Warning "IsFinished event doesn't work"
            sleep -milli 100
        } -On_Progress { 
            # Write-Host ($this.DataContext.LastProgress |Out-String)
            if($this.DataContext.LastProgress.RecordType -ne "Completed") {
                $progress.Value = $this.DataContext.LastProgress.PercentComplete
            }
        } -On_Warning {
            $report.Content = $this.DataContext.LastWarning.Message
            if($this.DataContext.LastWarning.Message -match "Finished") {
                $progress.Value = $progress.Maximum
                $window.Cursor = "Arrow"
                $Click.IsEnabled = $true
            }
        }
    }
} -show
Sep 18, 2013 at 8:18 PM
Hi Again,


Everything is working well so far but now I have another small issue. I'm tryng to launch a new Show-UI window from within the Invoke-Background but I get nothing. I tried to use Start-Job, Invoke-Background, and Invoke-Command but I get nothing.

For example, if I use your code from above and I insert New-Label "Hello World" -show in the Invoke-Background scriptblock the Hello World window does not show when I select the Click Me button.
Grid -Rows 2 -ControlName Progression {
    ProgressBar -name progress -height 28 -maximum 100
    Label -name report -zindex 1 -background Transparent
        # -DataBinding @{ "Value" = "LastProgress.PercentComplete" }
    Button "Click Me" -Name "Click" -Row 1 -on_Click {
        $this.IsEnabled = $false
        $window.Cursor = "Wait"
        Invoke-Background -Scriptblock { 
           
    New-Label "Hello World" -show

     1..10 | % {
                sleep -milli 200  # imagine this was doing real work
                write-progress -percent ($_ * 10) -activity "Super"
            }
            Write-Warning "IsFinished event doesn't work"
            sleep -milli 100
        } -On_Progress { 
            # Write-Host ($this.DataContext.LastProgress |Out-String)
            if($this.DataContext.LastProgress.RecordType -ne "Completed") {
                $progress.Value = $this.DataContext.LastProgress.PercentComplete
            }
        } -On_Warning {
            $report.Content = $this.DataContext.LastWarning.Message
            if($this.DataContext.LastWarning.Message -match "Finished") {
                $progress.Value = $progress.Maximum
                $window.Cursor = "Arrow"
                $Click.IsEnabled = $true
            }
        }
    }
} -show
Is it possible to laucnh a show-ui windows either -asjob or -show from within a show-ui windows or Invoke-backgroup process?

Thank you,

Mike