1

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
Dom
  • 168
  • 8

1 Answers1

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 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? – Dom May 23 '23 at 15:45
  • 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. – mklement0 May 23 '23 at 15:49