2

Im testing a script I found on https://learn-powershell.net/2012/10/14/powershell-and-wpf-writing-data-to-a-ui-from-a-different-runspace/. It is about PowerShell and WPF: Writing Data to a UI From a Different Runspace.

I copied the whole code and saved it to a test.ps1 file:

$syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"         
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)          
$psCmd = [PowerShell]::Create().AddScript({   
    Add-Type -AssemblyName presentationframework
    [xml]$xaml = @"
        <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen"
            Width = "600" Height = "800" ShowInTaskbar = "True">
            <TextBox x:Name = "textbox" Height = "400" Width = "600"/>
        </Window>
    "@
      
    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
    $syncHash.TextBox = $syncHash.window.FindName("textbox")
    $syncHash.Window.ShowDialog() | Out-Null
    $syncHash.Error = $Error
})
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()

The only thing I added was the line "Add-Type -AssemblyName presentationframework" over the xaml. It is working in both the console and in ISE. The Form pops up and the console is responding. However, when I check the $synchhash in the console I get no result, its a Null variable. When I check it in ISE I get the desired response:

PS C:\Windows\System32\WindowsPowerShell\v1.0> $syncHash

Name Value

---- -----

TextBox System.Windows.Controls.TextBox

Window System.Windows.Window

Im running Powershell 5 / 1 / 17763 / 3770, same user on same machine. I checked for admin privileges with this:

$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

Both cases false. I have another script witch is way bigger and there it is the opposite way round i cant get it to start up in ISE, but in console it works fine. I need to know whats going on here!

I tried to run the script with forced STA in the console but it wont come up.

powershell.exe -Sta -File MyScript.ps1

1 Answer 1

1

The ISE implicitly and invariably dot-sources scripts run in it, so that any variables, function definitions, ... inside the script become available in the caller's scope.

  • This behavior - which is especially treacherous when you run scripts repeatedly, because state lingering from previous runs can affect subsequent ones - is one of the reasons to avoid (bottom section) the obsolescent Windows PowerShell ISE.

  • The actively developed, cross-platform editor that offers the best PowerShell development experience is Visual Studio Code with its PowerShell extension; you can configure the latter to start a new, temporary session for every debugging run, which avoids the lingering-state problem while still giving you access to the script's variables, ... while inside the temporary session.

Therefore, if you want to inspect the $syncHash variable defined inside your script after running your script in a regular console window or Windows Terminal, you must explicitly invoke it dot-sourced:

. .\test.ps1

If you invoke your script as just .\test.ps1 or with & .\test.ps1 (using &, the call operator) it runs in a child scope, meaning that its variables, ... go out of scope when the script terminates and are not seen by the caller.

Sign up to request clarification or add additional context in comments.

2 Comments

Understood, tested and works! Optional follow up question: Is it possible to run the script via context menu ( right click ) "run with powershell" in the same way?
Glad to hear it, @Dom. Re follow-up question: In principle, yes, but, given that the script terminates right after .BeginInvoke(), an invocation via the context menu will also terminate the whole PowerShell session, so you'd have to modify your script to keep it running until the WPF window is closed. If you need help with that, I suggest creating a new question post.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.