Last active
January 24, 2024 13:42
-
-
Save anonhostpi/6b687757ba0582adfd3793956e5b9d02 to your computer and use it in GitHub Desktop.
Demonstration of PSObjects, Dispatchers, ScriptBlocks, and SessionStates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add-Type -AssemblyName "WindowsBase" | |
$synchash = [hashtable]::Synchronized(@{}) | |
$t = "should not get this" | |
$sb = & { | |
@( | |
{ | |
$t | |
}, | |
{ <# dummy #> }, | |
{ <# dummy #> } | |
) | |
} | |
$sb[1] = $sb[0].Ast.GetScriptBlock() | |
$sb[2] = [scriptblock]::Create( $sb[0].ToString() ) | |
$obj = @( | |
(New-Object PSObject), | |
(New-Object PSObject), | |
(New-Object PSObject) | |
) | |
$obj[0] | Add-Member -MemberType ScriptMethod -Name "Method" -Value { $t } | |
$obj[0] | Add-Member -MemberType ScriptProperty -Name "Property" -Value { $t } | |
$obj[0] | Add-Member -MemberType ScriptProperty -Name "Selfed" -Value { $this.Property } | |
$obj[1] | Add-Member -MemberType ScriptMethod -Name "Method" -Value $sb[0].Ast.GetScriptBlock() | |
$obj[1] | Add-Member -MemberType ScriptProperty -Name "Property" -Value $sb[0].Ast.GetScriptBlock() | |
$obj[1] | Add-Member -MemberType ScriptProperty -Name "Selfed" -Value { $this.Property }.Ast.GetScriptBlock() | |
$obj[2] | Add-Member -MemberType ScriptMethod -Name "Method" -Value ( [scriptblock]::Create( $sb[0].ToString() ) ) | |
$obj[2] | Add-Member -MemberType ScriptProperty -Name "Property" -Value ( [scriptblock]::Create( $sb[0].ToString() ) ) | |
$obj[2] | Add-Member -MemberType ScriptProperty -Name "Selfed" -Value ( [scriptblock]::Create( { $this.Property }.ToString() ) ) | |
$synchash.sb = $sb | |
$synchash.obj = $obj | |
$dispatchers = [hashtable]::Synchronized(@{}) | |
$end = 0; | |
while( $end -lt 1 ){ | |
# get the number of threads user wants to create (default is 1) | |
# use console (not WPF) C# for this, because you can't set default values for Read-Host | |
$end = Read-Host "How many threads do you want to create? (default: 1)" | |
if ( [string]::IsNullOrEmpty( $end ) ){ | |
$end = 1 | |
} elseif ( $end -lt 1 ){ | |
Write-Host "Please enter a number greater than 0" | |
} | |
} | |
foreach( $i in 1..$end ){ | |
$script = @( | |
"`$dispatchers.Dispatcher$i = [System.Windows.Threading.Dispatcher]::CurrentDispatcher", | |
"`$t = `"thread $i`"", | |
{ | |
[void][System.Windows.Threading.Dispatcher]::Run() | |
}.ToString() | |
) -join "`n" | |
$script = [scriptblock]::Create( $script ) | |
$runspace = [runspacefactory]::CreateRunspace( $Host ) | |
$runspace.ApartmentState = "STA" | |
$runspace.Name = "thread $i" | |
$runspace.ThreadOptions = "ReuseThread" | |
$runspace.Open() | Out-Null | |
$runspace.SessionStateProxy.PSVariable.Set( "synchash", $synchash ) | Out-Null | |
$runspace.SessionStateProxy.PSVariable.Set( "dispatchers", $dispatchers ) | Out-Null | |
$powershell = [powershell]::Create() | |
$powershell.Runspace = $runspace | |
$powershell.AddScript( $script ) | Out-Null | |
$powershell.BeginInvoke() | Out-Null | |
# ensures dispatchers are set in the correct order | |
# we do this instead of $powershell.Invoke() or $powershell.EndInvoke(), because of Dispatcher.Run() | |
while( -not $dispatchers."Dispatcher$i" ){ | |
Start-Sleep -Milliseconds 100 | |
} | |
} | |
$t = "main" | |
$dispatchers.GetEnumerator() | ForEach-Object { | |
$name = $_.Key | |
$dispatcher = $_.Value | |
Write-Host | |
Write-Host "Dispatcher: $name" | |
$dispatcher.InvokeAsync({ | |
Write-Host | |
Write-Host "InvokeAsync - bound" | |
Write-Host "`$sb[0].Invoke() - bound: " $synchash.sb[0].Invoke() | |
Write-Host "`$sb[1].Invoke() - unbound(AST): " $synchash.sb[1].Invoke() | |
Write-Host "`$sb[2].Invoke() - unbound(Create()):" $synchash.sb[2].Invoke() | |
}) | Out-Null | |
$dispatcher.InvokeAsync({ | |
Write-Host | |
Write-Host "InvokeAsync - unbound" | |
Write-Host "`$sb[0].Invoke() - bound: " $synchash.sb[0].Invoke() | |
Write-Host "`$sb[1].Invoke() - unbound(AST): " $synchash.sb[1].Invoke() | |
Write-Host "`$sb[2].Invoke() - unbound(Create()):" $synchash.sb[2].Invoke() | |
}.Ast.GetScriptBlock()) | Out-Null | |
$dispatcher.InvokeAsync({ | |
Write-Host | |
Write-Host "InvokeAsync - bound" | |
Write-Host "`$obj[0].Method() - bound: " $synchash.obj[0].Method() | |
Write-Host "`$obj[1].Method() - unbound(AST): " $synchash.obj[1].Method() | |
Write-Host "`$obj[2].Method() - unbound(Create()):" $synchash.obj[2].Method() | |
Write-Host "`$obj[0].Property - bound: " $synchash.obj[0].Property | |
Write-Host "`$obj[1].Property - unbound(AST): " $synchash.obj[1].Property | |
Write-Host "`$obj[2].Property - unbound(Create()):" $synchash.obj[2].Property | |
Write-Host "`$obj[0].Selfed - bound: " $synchash.obj[0].Selfed | |
Write-Host "`$obj[1].Selfed - unbound(AST): " $synchash.obj[1].Selfed | |
Write-Host "`$obj[2].Selfed - unbound(Create()):" $synchash.obj[2].Selfed | |
}) | Out-Null | |
$output = $dispatcher.InvokeAsync({ | |
Write-Host | |
Write-Host "InvokeAsync - unbound" | |
Write-Host "`$obj[0].Method() - bound: " $synchash.obj[0].Method() | |
Write-Host "`$obj[1].Method() - unbound(AST): " $synchash.obj[1].Method() | |
Write-Host "`$obj[2].Method() - unbound(Create()):" $synchash.obj[2].Method() | |
Write-Host "`$obj[0].Property - bound: " $synchash.obj[0].Property | |
Write-Host "`$obj[1].Property - unbound(AST): " $synchash.obj[1].Property | |
Write-Host "`$obj[2].Property - unbound(Create()):" $synchash.obj[2].Property | |
Write-Host "`$obj[0].Selfed - bound: " $synchash.obj[0].Selfed | |
Write-Host "`$obj[1].Selfed - unbound(AST): " $synchash.obj[1].Selfed | |
Write-Host "`$obj[2].Selfed - unbound(Create()):" $synchash.obj[2].Selfed | |
}.Ast.GetScriptBlock()) | |
While( -not $output.Task.IsCompleted ){ | |
# calling GetAwaiter().GetResult() immediately will cause a deadlock | |
Start-Sleep -Milliseconds 100 | |
} | |
$output.Task.GetAwaiter().GetResult() | |
$dispatcher.InvokeShutdown() | |
} | |
Write-Host | |
Write-Host "done" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment