Skip to content

Instantly share code, notes, and snippets.

@romero126
Last active February 15, 2021 07:39
Show Gist options
  • Save romero126/8d178f82a162dae067a759963d41c96e to your computer and use it in GitHub Desktop.
Save romero126/8d178f82a162dae067a759963d41c96e to your computer and use it in GitHub Desktop.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Background="#35333a" BorderThickness="0" BorderBrush="#666374" Foreground="#514e5d" OpacityMask="#5b586d" Name="LoginPageWPF" WindowStartupLocation="CenterScreen" ResizeMode="CanResizeWithGrip" Title="TEAMS MIGRATION TOOL" WindowChrome.IsHitTestVisibleInChrome="True">
<Window.Resources>
<ResourceDictionary>
<Style TargetType="Button" x:Key="TabButton">
<Setter Property="Background" Value="#E0E0E2"/>
<Setter Property="Foreground" Value="#000000"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="7"/>
</Style>
</Style.Resources>
</Style>
<Style TargetType="TextBox" x:Key="TBOX">
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="Foreground" Value="#000000"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="BorderThickness" Value=".7"/>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="7"/>
</Style>
</Style.Resources>
</Style>
<Style TargetType="PasswordBox" x:Key="PBOX">
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="Foreground" Value="#000000"/>
<Setter Property="BorderThickness" Value=".7"/>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="7"/>
</Style>
</Style.Resources>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid Background="#ffffff" ShowGridLines="False" Name="MainGrid" Margin="0,-1,0,1">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="150*"/>
<RowDefinition Height="5"/>
<RowDefinition Height="300*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="25"/>
</Grid.ColumnDefinitions>
<Button Name="ColorBT" Content="☀" Background="#ffffff" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" BorderThickness="0" Width="20" Height="20" Margin="0" Grid.Row="0" Grid.Column="2"/>
<Button Name="LeftBT" Content="◀" Grid.Row="1" Grid.Column="0" Background="#ffffff" Foreground="#B78CDE" BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="20" Margin="0" Height="20"/>
<Button Name="RightBT" Content="▶" Grid.Row="1" Grid.Column="2" Background="#ffffff" Foreground="#B78CDE" BorderThickness="0" HorizontalAlignment="Right" VerticalAlignment="Center" Width="20" Margin="2" Height="20"/>
<TabControl Name="TabNav" Grid.Row="1" Grid.Column="1" SelectedIndex="1" Padding="-1">
<TabItem Name="ConnectGraphTab" Header="Tab 1" Visibility="Collapsed">
<Grid Name="ConnectGraphGrid" Background="#ffffff" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Button Name="SelectSourceTenantBT" Grid.Column="0" Style="{StaticResource TabButton}" Content="Select Source" Margin="0,0,0,40" Height="24" Width="200" IsDefault="True" VerticalAlignment="Top"/>
<TextBlock Name="OR1" Foreground="#000000" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Top" Text="-OR-" FontSize="12" Height="18" Margin="0,22,0,0"/>
<Button Name="AddSourceTenantBT" Grid.Column="0" Style="{StaticResource TabButton}" Content="Add Source" Margin="0,40,0,0" Height="24" Width="200" IsDefault="True" VerticalAlignment="Top"/>
<Button Name="SelectDestTenantBT" Grid.Column="1" Style="{StaticResource TabButton}" Content="Select Destination" Margin="0,0,0,40" Height="24" Width="200" IsDefault="True" VerticalAlignment="Top"/>
<TextBlock Name="OR2" Foreground="#000000" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Top" Text="-OR-" FontSize="12" Height="18" Margin="0,22,0,0"/>
<Button Name="AddDestTenantBT" Grid.Column="1" Style="{StaticResource TabButton}" Content="Add Destination" Margin="0,40,0,0" Height="24" Width="200" IsDefault="True" VerticalAlignment="Top"/>
<Button Name="ConnectGraphBT" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource TabButton}" Content="Connect Graph" Margin="0,80,0,0" Height="24" Width="200" IsDefault="True" VerticalAlignment="Top"/>
</Grid>
</TabItem>
<TabItem Name="SelectSourceTab" Grid.Row="1" Header="Tab 2" Visibility="Collapsed">
<Grid Name="SelectSourceGrid" Background="#ffffff" Margin="0">
<Button Name="SelectSourceBT" Style="{StaticResource TabButton}" Content="Select source teams" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="SelectSourceTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
<TabItem Name="ViewTeamTab" Grid.Row="1" Header="Tab 3" Visibility="Collapsed">
<Grid Name="ViewTeamGrid" Background="#ffffff" Margin="0">
<Button Name="ViewTeamBT" Style="{StaticResource TabButton}" Content="View selected teams" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="ViewTeamTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
<TabItem Name="CloneTeamTab" Grid.Row="1" Header="Tab 4" Visibility="Collapsed">
<Grid Name="CloneTeamGrid" Background="#ffffff" Margin="0">
<Button Name="CloneTeamBT" Style="{StaticResource TabButton}" Content="Clone teams" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="CloneTeamTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
<TabItem Name="SnapFileTab" Grid.Row="1" Header="Tab 5" Visibility="Collapsed">
<Grid Name="SnapFileGrid" Background="#ffffff" Margin="0">
<Button Name="SnapFileBT" Style="{StaticResource TabButton}" Content="Backup team files" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="SnapFileTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
<TabItem Name="CloneChatTab" Grid.Row="1" Header="Tab 6" Visibility="Collapsed">
<Grid Name="CloneChatGrid" Background="#ffffff" Margin="0">
<Button Name="CloneChatBT" Style="{StaticResource TabButton}" Content="Clone chat messages" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="CloneChatTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
<TabItem Name="MigrateFileTab" Grid.Row="1" Header="Tab 7" Visibility="Collapsed">
<Grid Name="MigrateFileGrid" Background="#ffffff" Margin="0">
<Button Name="MigrateFileBT" Style="{StaticResource TabButton}" Content="Migrate files" Height="25" Width="200" Margin="0,0,0,0"/>
<TextBlock Name="MigrateFileTB" FontStyle="Italic" Foreground="#3dfc03" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text=" " FontSize="14" Height="21"/>
</Grid>
</TabItem>
</TabControl>
<Button Name="Circle1" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="0,0,120,0"/>
<Button Name="Circle2" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="0,0,80,0"/>
<Button Name="Circle3" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="0,0,40,0"/>
<Button Name="Circle4" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="0,0,0,0"/>
<Button Name="Circle5" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="40,0,0,0"/>
<Button Name="Circle6" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="80,0,0,0"/>
<Button Name="Circle7" Style="{StaticResource TabButton}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="10" Width="10" Margin="120,0,0,0"/>
<GridSplitter Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Height="5" Background="#ffffff" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<DataGrid Name="DataGrid" ScrollViewer.PanningMode="None" ItemsSource="{Binding gridData}" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" Background="#FFFFFF" Margin="0,0,0,0" AlternatingRowBackground="LightBlue" AlternationCount="2" HorizontalGridLinesBrush="#FFBBBBBB" VerticalGridLinesBrush="#FFBBBBBB" HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</Window>
#Import-Module "$PSScriptRoot\..\Module\WindowsPresentationFramework" -Force
. "$PSScriptRoot\WindowsPresentationFramework.ps1"
#Region ThreadSafe
# Bind Variables
[WindowsPresentationFrameworkThreadSafe()]
[PSObject] $Variable = "Herro World from Proxy Scope"
[WindowsPresentationFrameworkThreadSafe()]
$Sync = [hashtable]::Synchronized(@{})
[WindowsPresentationFrameworkThreadSafe()]
[PSCustomObject] $State = [PSCustomObject]@{}
# Fastest State
[WindowsPresentationFrameworkThreadSafe()]
[System.Collections.ObjectModel.ObservableCollection[Object]] $Log = [System.Collections.ObjectModel.ObservableCollection[Object]]::new()
function Write-Log
{
[WindowsPresentationFrameworkThreadSafe()]
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $Message
)
$item = [PSCustomObject]@{
Id = [Guid]::NewGuid().Guid
TimeStamp = [DateTime]::Now
Message = $Message
IsAsync = $false
}
if ([Runspace]::DefaultRunspace.Name -ne "AsyncOperation")
{
$Log.Add($item)
}
else {
$item.IsAsync = $true
Start-Dispatch -Sender $Log -Event $item -ScriptBlock {
param($sender, $event)
[void]$sender.Add($event)
}
}
}
#EndRegion ThreadSafe
$Script:PSTeamsMigratePath = Join-Path -Path $Env:USERPROFILE -ChildPath '.PSTeamsMigrate'
$Script:ConfigPath = Join-Path -Path $PSTeamsMigratePath -ChildPath 'Configurations'
$Script:TenantPath = Join-Path -Path $ConfigPath -ChildPath 'Tenants'
if (-not ($null = Test-Path $TenantPath)) {
$ItemSplat = @{
Type = 'Directory'
Force = $true
ErrorAction = 'SilentlyContinue'
}
$null = New-Item $PSTeamsMigratePath @ItemSplat
$null = New-Item $ConfigPath @ItemSplat
$null = New-Item $TenantPath @ItemSplat
}
function Select-Tenant {
(Get-ChildItem $TenantPath -Directory | Where-Object {
$_.Name -ne 'Files'
} | Select-Object Name | Out-GridView -Title 'Select the tenant and click OK' -OutputMode Single).name
}
function Select-Source
{
[WindowsPresentationFrameworkEventBinding("SelectSourceTenantBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Write-Host "Click from", $sender.Name
#$Script:SourceConnect = Select-Tenant
#$Script:SourceConfig = Join-Path $TenantPath -ChildPath "$SourceConnect\Config.xml"
#$Script:SourceCred = Join-Path $TenantPath -ChildPath "$SourceConnect\Cred.xml"
#$State.AppHash['SourceConnect'] = $SourceConnect
#$State.AppHash['SourceConfig'] = $SourceConfig
#$State.AppHash['SourceCred'] = $SourceCred
async -Passthru {
$variable = [Guid]::NewGuid().Guid
$sync.Value = "Rubbish"
} | await | Out-Host | Write-Host
$variable | out-host
$sync | Out-Host
}
function Add-Source
{
[WindowsPresentationFrameworkEventBinding("AddSourceTenantBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Write-Host "Click from", $sender.Name
# This is fast
async {
$ts = [DateTime]::Now
foreach ($i in 0..1000)
{
Write-Log -Message "* Long running Asyncronous Loop"
#Start-Sleep -Milliseconds 20
}
$longTask = [DateTime]::Now - $ts
#Write-Log -Message "Finished at $ts"
Write-Log -Message "Duration was $LongTask"
}
}
function Select-Destination
{
[WindowsPresentationFrameworkEventBinding("SelectDestTenantBT", "Click")]
[CmdletBinding()]
param($sender, $event)
$Script:DestConnect = Select-Tenant
$Script:DestConfig = Join-Path $TenantPath -ChildPath "$DestConnect\Config.xml"
$Script:DestCred = Join-Path $TenantPath -ChildPath "$DestConnect\Cred.xml"
$State.AppHash['DestConnect'] = $DestConnect
$State.AppHash['DestConfig'] = $DestConfig
$State.AppHash['DestCred'] = $DestCred
}
function Add-Destination
{
[WindowsPresentationFrameworkEventBinding("AddDestTenantBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Register-TeamsGraphApplication
}
function Connect-SourceAndDestination
{
[WindowsPresentationFrameworkEventBinding("ConnectGraphBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Start-Async {
Connect-GTeams
}}
function Get-Source
{
[WindowsPresentationFrameworkEventBinding("SelectSourceBT", "Click")]
[CmdletBinding()]
param($sender, $event)
$State.AppHash['PSTeamsMigratePath'] = $PSTeamsMigratePath
$State.AppHash['ConfigPath'] = $ConfigPath
$State.AppHash['TenantPath'] = $TenantPath
Get-SourceTeam
Get-SourceChannel
}
function Start-GetMap
{
[WindowsPresentationFrameworkEventBinding("ViewTeamBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Get-Map | Out-GridView -Title 'Current mapping between source and target'
}
function Start-Clone
{
[WindowsPresentationFrameworkEventBinding("CloneTeamBT", "Click")]
[CmdletBinding()]
param($sender, $event)
Get-Dupe
Write-TargetTeamsAndChannels
Start-Sleep -Seconds 20 # this could probably be shorter now that we've identified the provisioning issue. Commenting for later
Get-DriveID
}
function Circle_Click {
#function Set-Circle {
[WindowsPresentationFrameworkEventBinding("Circle1", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle2", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle3", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle4", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle5", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle6", "Click")]
[WindowsPresentationFrameworkEventBinding("Circle7", "Click")]
[CmdletBinding()]
param($sender, $event)
$controlList = $Circle1, $Circle2, $Circle3, $Circle4, $Circle5, $Circle6, $Circle7
$tabNavList = $ConnectGraphTab, $SelectSourceTab, $ViewTeamTab, $CloneTeamTab, $SnapFileTab, $CloneChatTab, $MigrateFileTab
foreach ($control in $controlList) {
if ($control -eq $sender) {
$sender.Height = 15
$sender.Width = 15
$sender.Background = "#B78CDE"
continue
}
$control.Height = 10
$control.Width = 10
$control.Background = "#E0E0E2"
}
# Set Tab to be visible
$tabIndex = $controlList.IndexOf($sender)
$TabNav.SelectedItem = $tabNavList[$tabIndex]
}
function LeftRightBT_Click {
[WindowsPresentationFrameworkEventBinding("LeftBT", "Click")]
[WindowsPresentationFrameworkEventBinding("RightBT", "Click")]
[CmdletBinding()]
param($sender, $event)
$controlList = $Circle1, $Circle2, $Circle3, $Circle4, $Circle5, $Circle6, $Circle7
$tabNavList = $ConnectGraphTab, $SelectSourceTab, $ViewTeamTab, $CloneTeamTab, $SnapFileTab, $CloneChatTab, $MigrateFileTab
$circle = $controlList.Where({
$_.Height -eq 15 -and
$_.Width -eq 15
})
$pos = $controlList.IndexOf($circle[0])
switch ($sender.Name)
{
"LeftBT" { $pos = $pos - 1 }
"RightBT" { $pos = $pos + 1 }
}
if ($pos -lt 0) {
$pos = $controlList.Count - 1
}
elseif ($pos -ge $controlList.Count) {
$pos = 0
}
Circle_Click $controlList[$pos]
}
function DataGrid_ScrollEventChanged
{
[WindowsPresentationFrameworkEventBinding("DataGrid", "System.Windows.Controls.ScrollViewer", "ScrollChangedEvent")]
[CmdletBinding()]
param($sender, $event)
if ($DataGrid.Items.Count -eq 0) { return }
$DataGrid.ScrollIntoView(
$DataGrid.Items[$DataGrid.Items.Count - 1]
);
}
function LoginPageWPF_Loaded {
[WindowsPresentationFrameworkEventBinding("LoginPageWPF", "Loaded")]
[CmdletBinding()]
param($sender, $event)
$sender.Activate()
$sender.Focus()
Circle_Click $Circle1
# Set Binding
# This should Syncronize across different locations
$DataGrid.ItemsSource = $Log
Write-Log -Message "Initial Thread"
# async {
# $ts = [DateTime]::Now
# foreach ($i in 0..500)
# {
# Write-Log -Message "* Long running Asyncronous Loop"
# }
# $longTask = $ts - [DateTime]::Now
# Write-Log -Message "Finished at $ts"
# Write-Log -Message "Duration was $LongTask"
#
# }
Write-Log -Message "* Current Thread Called"
async {
# This fires but fails as Write-Log does not exist in the Dispatchers context
Start-Dispatch {
Write-Log "Async/Dispatch/Log"
}
}
}
Import-Window -Path $PSScriptRoot\KevWindow.xaml -ShowDialog
Add-Type -AssemblyName PresentationCore, PresentationFramework
function Import-Window {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[System.IO.FileInfo]$Path,
[Parameter()]
[switch] $ShowDialog,
[object] $Type
)
begin {
if (-not $Path.Exists) {
Write-Error -Message "Path to xml does not exist" -Category OpenError -ErrorAction Stop
}
$PathScript = [System.IO.FileInfo]("{0}.ps1" -f $Path.FullName)
if (-not $PathScript.Exists) {
Write-Error -Message "Path to ps1 does not exist" -Category OpenError -ErrorAction Stop
}
}
process {
$xamlRaw = Get-Content $Path -Raw
$xaml = [xml]$xamlRaw
#https://github.com/GetFunctional/DillyDally/blob/6a9f6cd5fc5be5282602cb3fc38d5d2c90622bfb/GF.DillyDally.Wpf/GF.DillyDally.Wpf.Client/Core/DataTemplates/DataTemplateFactory.cs
# SetApp
# $xamlTypeMapper = [System.Windows.Markup.XamlTypeMapper]::new($type.Assembly.FullName)
# Build Parser Context for XMLNS
# Quick Notes: This allows you to specify a xmlnamespace like x:name="value"
$windowParserContext = New-Object System.Windows.Markup.ParserContext
$xmlNamespaceManager = [System.Xml.XmlNamespaceManager]::new($xaml.NameTable)
foreach ($attribute in $xaml.Window.Attributes)
{
if ($attribute.Name.StartsWith("xmlns"))
{
$contextName = $attribute.LocalName
if ($attribute.LocalName -eq "xmlns") {
$contextName = ""
}
#[void]$xamlTypeMapper.AddMappingProcessingInstruction($contextName, $type.NameSpace, $type.Assembly.GetName().Name)
[void]$windowParserContext.XmlnsDictionary.Add($contextName, $attribute.Value)
[void]$xmlNamespaceManager.AddNameSpace($contextName, $attribute.Value)
}
}
$windowParserContext.XamlTypeMapper = $xamlTypeMapper
[WindowsPresentationFrameworkThreadSafe()]$Window = [Windows.Markup.XamlReader]::Parse($xamlRaw, $windowParserContext)
Set-Variable -Name Window -Value $Window -Scope 1
#& $PathScript
$resolvedNodes = @{}
foreach ($namespace in $xmlNamespaceManager.ForEach({$_}))
{
$nodeQuery = "{0}:Name" -f $namespace
if ([string]::IsNullOrEmpty($namespace)) { $nodeQuery = "Name" }
foreach ($node in $xaml.SelectNodes("//*[@$nodeQuery]", $xmlNamespaceManager))
{
# Set the node in the Script Scope
$nodeName = $node.Name
$nodeValue = $Window.FindName($node.Name)
#[void]$resolvedNodes.Add($nodeName, $nodeValue)
$resolvedNodes[$nodeName] = $nodeValue
$variable = Set-Variable -Passthru -Name $nodeName -Value $nodeValue # -Scope 2
$variable.Attributes.Add( [WindowsPresentationFrameworkThreadSafeAttribute]::new())
}
}
$commands = Get-Command -CommandType Function
foreach ($command in $commands) {
if ($null -eq $command.ScriptBlock.Attributes) { continue }
$isBinding = $command.ScriptBlock.Attributes.FindAll(
{
$args[0].TypeId.Name -eq "WindowsPresentationFrameworkEventBindingAttribute"
}
)
if (-not $isBinding) {
continue
}
foreach ($binding in $isBinding) {
try {
if ($binding.isSimple) {
$control = $resolvedNodes.Item( $binding.Name )
$null = $control."Add_$($binding.EventName)"( $command.ScriptBlock )
}
else {
$control = $window.FindName($binding.Name)
$handlerEvent = ($binding.ControlName -as [Type])::$($binding.EventName)
$control.AddHandler(
$handlerEvent,
$command.ScriptBlock -as ($handlerEvent.Handlertype)
)
}
}
catch {
$exceptionMessage = "Canning bind {0} to control {1} with the event {2}" -f $command.Name, $binding.Name, $binding.EventName
throw $_
#$exceptionMessage
}
}
}
# Bind SessionState Variables
[void]$Window.Focus()
if ($ShowDialog) {
return $Window.ShowDialog()
}
$Window
}
end {
}
}
function Start-Async {
[CmdletBinding()]
[Alias("Async")]
param(
[Parameter(Mandatory)]
[ScriptBlock] $ScriptBlock,
[Parameter()]
[PSObject] $InputObject,
[switch] $Passthru
)
# Cleanup all completed runspaces
$AllRunspaces = Get-Runspace -Name AsyncOperation
$AllRunspaces.Where({ $_.RunspaceAvailability -eq "Available" }).ForEach({$_.Dispose() })
if (-not $Script:Async) {
$Global:Async = @{}
$Global:Async.Pool = [RunspaceFactory]::CreateRunspacePool(1, [int]$env:NUMBER_OF_PROCESSORS+1)
$Global:Async.Pool.ApartmentState = "MTA"
$Global:Async.Pool.Open()
$Global:Async.Runspaces = New-Object "System.Collections.Generic.List[PSObject]"
}
$initialSessionState = [initialsessionstate]::CreateDefault()
$PSCallStack = (Get-PSCallStack)[1]
$result = (New-Object PSCustomObject @{
Command = $PSCallStack.Command
Pipeline = $null
Output = [System.Collections.Arraylist]::new()
Status = $null
# DataAddedAction = $null
Index = $Global:Async.Runspaces.Count
})
$runspace = [RunspaceFactory]::CreateRunspace($initialSessionState)
$runspace.ApartmentState = 'STA'
$runspace.ThreadOptions = 'ReuseThread'
$runspace.Open()
$runspace.Name = "AsyncOperation"
# Bind Functions to SessionState
$commands = $ExecutionContext.SessionState.InvokeCommand.GetCommands("*", [System.Management.Automation.CommandTypes]::Function, $true)
foreach ($command in $commands) {
if ($null -eq $command.ScriptBlock.Attributes) { continue }
$isBinding = $command.ScriptBlock.Attributes.FindAll({ $args[0].TypeId.Name -eq "WindowsPresentationFrameworkThreadSafeAttribute" })
if (-not $isBinding) { continue }
#$initialSessionState.Commands.Add(
# (New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $command.Name, $command.ScriptBlock.ToString().Replace("[WindowsPresentationFrameworkThreadSafe()]", ""))
#)
$runspace.SessionStateProxy.SetVariable("function:$($Command.Name)", $command.ScriptBlock.ToString().Replace("[WindowsPresentationFrameworkThreadSafe()]", ""))
}
# Bind Variables to SessionState
$variables = Get-Variable
foreach ($variable in $variables)
{
$isBinding = $variable.Attributes.Where({$_.TypeId.Name -eq "WindowsPresentationFrameworkThreadSafeAttribute"})
if (-not $isBinding) { continue; }
$runspace.SessionStateProxy.SetVariable($variable.Name, $variable.Value)
}
# Create Pipeline
$pipeline = [PowerShell]::Create()
$pipeline.Runspace = $runspace
$null = $pipeline.AddScript($ScriptBlock)
$null = $pipeline.AddArgument($InputObject)
# Attach hooks
$StreamCallback = {
param( $value, $sender )
$index = {0}
$Global:Async.Runspaces[$index].Output.Add($value[$sender.Index])
}
$StreamCallBack = $StreamCallBack.ToString().Replace("{0}", $Global:Async.Runspaces.Count)
$StreamCallBack = [ScriptBlock]::Create($StreamCallback).GetNewClosure()
if (-not $Passthru) {
return [void]$pipeline.BeginInvoke()
}
$pipeline.Streams.Error.Add_DataAdded( $StreamCallback )
# $pipeline.Streams.Progress.Add_DataAdded( $StreamCallback )
$pipeline.Streams.Verbose.Add_DataAdded( $StreamCallback )
$pipeline.Streams.Debug.Add_DataAdded( $StreamCallback )
$pipeline.Streams.Warning.Add_DataAdded( $StreamCallback )
$pipeline.Streams.Information.Add_DataAdded( $StreamCallback )
#Bind Variables to SessionState
$result.Pipeline = $pipeline
$result.Status = $pipeline.BeginInvoke()
if ($Passthru) {
$Global:Async.Runspaces.Add(
$result
)
return $result
}
}
function Start-Dispatch {
[CmdletBinding()]
[WindowsPresentationFrameworkThreadSafe()]
[Alias("DAsync")]
param(
[Parameter(Mandatory)]
[ScriptBlock] $ScriptBlock,
[Parameter()]
[System.Windows.Threading.DispatcherPriority] $Priority = [System.Windows.Threading.DispatcherPriority]::Normal,
[Parameter()]
[object] $Sender = $null,
[Parameter()]
[object] $Event = $null
)
[void]$Window.Dispatcher.BeginInvoke(
$Priority,
[action[object, object]] $ScriptBlock.Ast.GetScriptBlock(),
$sender,
$event
)
}
function Wait-Async {
[CmdletBinding()]
[Alias("await")]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[PSCustomObject] $InputObject
)
if (-not $InputObject) { return }
do {
if ($Window) {
# [void]$Window.Dispatcher.Invoke({ }, "Render")
# $Window.UpdateLayout()
}
Start-Sleep -Milliseconds 5
} until ($InputObject.Status.IsCompleted -eq $true)
# Receive Jobs we waited for.
$InputObject.Pipeline.EndInvoke($InputObject.Status)
$InputObject.Output
# Cleanup runspaces
$InputObject.Pipeline.Runspace.Close()
$InputObject.Pipeline.Runspace.Dispose()
}
class WindowsPresentationFrameworkEventBindingAttribute : System.Attribute {
[string] $Name
[string] $EventName
[string] $ControlName
[bool] $isSimple = $false
WindowsPresentationFrameworkEventBindingAttribute([string]$Name, [string]$EventName) {
$this.isSimple = $true
$this.Name = $Name
$this.EventName = $EventName
}
WindowsPresentationFrameworkEventBindingAttribute([string]$Name, [string] $ControlName, [string] $EventName) {
$this.isSimple = $false
$this.Name = $Name
$this.ControlName = $ControlName
$this.EventName = $EventName
}
}
class WindowsPresentationFrameworkThreadSafeAttribute : System.Attribute { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment