PSGUIHelper.psm1
Using Namespace System.Collections.Generic Using Namespace System.ComponentModel Using Namespace System.Linq Using Namespace System.Reflection Using Namespace System.Text Using Namespace System.Windows Using Namespace System.Windows.Input Using Namespace System.Windows.Markup Using Namespace System.Windows.Media Using Namespace System.Windows.Threading function Hide-Console { Write-Verbose 'Hiding PowerShell console...' # .NET method for hiding the PowerShell console window # https://stackoverflow.com/questions/40617800/opening-powershell-script-and-hide-command-prompt-but-not-the-gui Add-Type -Name Window -Namespace Console -MemberDefinition ' [DllImport("Kernel32.dll")] public static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); ' $consolePtr = [Console.Window]::GetConsoleWindow() [Console.Window]::ShowWindow($consolePtr, 0) # 0 = hide } Function Add-PSGUIActions { <# .SYNOPSIS Adds Actions to Controls .PARAMETER XAMLfile Path of the WPF XAML file .PARAMETER Control Sets the control in question .PARAMETER EditorMode Allows live editing of control actions .EXAMPLE Add-PSGUIActions -XAMLFile "test.xaml" -Control $Control -EditorMode $false #> [CmdletBinding()] param( [Parameter(Position = 0, Mandatory = $true)] [ValidateScript( { Test-Path $_ })] [string]$XAMLfile, [Parameter(Position = 1, Mandatory = $true)] $control, [Parameter(Position = 2)] [bool]$EditorMode = $False ) begin { $xamlpath = Get-Item -Path $XAMLfile [xml]$xaml = Get-Content -Path $XAMLfile $FileRootFolder = $xamlpath.Directory | Split-path IF (!($EDITORMODE)) { . $FileRootFolder\GUIScripts\$($xamlpath.BaseName)-guiscripts.ps1 } } process { $xaml.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $control.FindName($_.Name) -Scope Global IF ($_.Tag -ne $null) { $name = $_.Name $_.Tag -split ',' | ForEach-Object { $tag = ($_).Trim() $btntemp = $xamlpath.BaseName + "_" + $name + "_" + $tag Write-Verbose "Registering Action $btntemp" # Load all available buttons, and execute via external script file IF ($EDITORMODE) { $action2 = @' param ([object]$Sender, [Object]$e) $actionname = $e.RoutedEvent.Name '@ $action2 += @" Write-Verbose "Viewing $btntemp" & "$FileRootFolder\GUIScripts\$($xamlpath.BaseName)\$btntemp.ps1" "@ $scriptblock = [scriptblock]::Create($action2) Write-Verbose "Editor Mode Enabled - $name - $Tag" Try { (Get-Variable -Name $name).Value.$("Add_$tag")($scriptblock) } Catch { Write-Verbose "ERROR: " } IF (!(Test-Path $FileRootFolder\GUIScripts\$($xamlpath.BaseName)\$btntemp.ps1)) { new-item $FileRootFolder\GUIScripts\$($xamlpath.BaseName)\$btntemp.ps1 -force } } ELSE { (Get-Variable -Name $name).Value.$("Add_$tag")($((Get-Variable -Name $btntemp).Value)) } #END ELSE } # END Tag Split } # IF TAG END } # END XAML Node } # END PROCESS end { } } Function Export-PSGUIScripts { [CmdletBinding()] param( [ValidateScript({Test-Path $_})] [string]$xamlpath) $xamlpath = Get-Item -Path $xamlpath [xml]$xaml = Get-Content -Path $xamlpath $FileRootFolder = $xamlpath.Directory | Split-path $xaml.SelectNodes("//*[@Name]") | Select-Object Name, Tag | Where-Object {$_.Tag -ne $null} | ForEach-Object { $name = $_.Name $_.Tag -split ',' | ForEach-Object { $tag = ($_).Trim() $btntemp = $xamlpath.BaseName + "_" + $Name + "_" + $tag Write-Verbose "Exporting Script" $filepath = $(Join-Path -Path "$FileRootFolder\GUIScripts\$($xamlpath.BaseName)" -ChildPath "$btntemp.ps1") IF (TEST-path $filepath) { $action2 += "`$$btntemp = `{`r`n" $action2 += 'param ([object]$Sender, [Object]$e)' + "`r`n`r`n" $action2 += [IO.File]::ReadAllText($filepath) + "`r`n" $action2 += "`}`r`n`n" } } } $action2 | Out-File "$FileRootFolder\GUIScripts\$($xamlpath.BaseName)-guiscripts.ps1" -Encoding UTF8 -force } Function New-PSGUIWPF { <# .SYNOPSIS Start the WPF application .PARAMETER XAMLfile Path of the WPF XAML file .PARAMETER EditorMode To edit your GUI WPF scripts live without closing the GUI .EXAMPLE New-PSGUIWPF -XAMLFile "test.xaml" #> [CmdletBinding()] param( [Parameter(Position=0,Mandatory=$true)] [ValidateScript({Test-Path $_})] [string]$XAMLfile, [Parameter(Position=1)] [ValidateSet('True', 'False')] [bool]$EditorMode=$False, $DataContext, $ScriptRootFolder ) $xamlfile = Get-Item -Path $xamlfile #region Add required assemblies Write-Verbose "Loading Assembly" [System.Windows.Forms.Application]::EnableVisualStyles() #endregion required assemblies #region XAML Main Window $Global:Window = Read-PSGUIXaml -XAMLfile $xamlfile IF ($EDITORMODE) { $Window.Title += " - Editor Mode Enabled" } ELSE{ Hide-Console } Add-PSGUIActions -XAMLfile $xamlfile -Control $Window -Editormode $EDITORMODE #endregion XAML Main Window #region Setup DataContext $Window.DataContext = $DataContext #endregion Setup DataContext # If code is running in ISE, use ShowDialog()... if ($psISE -or $isCode) { $null = $Window.ShowDialog() # ...otherwise run as an application } Else { #$app = [Windows.Application]::New() #$null = $app.Run($Window) $null = $Window.ShowDialog() # Force garbage collection just to start slightly lower RAM usage. [System.GC]::Collect() } #endregion RUN APP IF ($output -ne "") { $output } } function Read-PSGUIXaml { <# .SYNOPSIS Reads the XAML File Content .PARAMETER XAMLfile Path of the WPF XAML file .EXAMPLE Read-PSGUIXaml -XAMLFile "test.xaml" #> [CmdletBinding()] param( [Parameter(Position = 0, Mandatory = $true)] [ValidateScript( { Test-Path $_ })] [string]$XAMLfile ) Write-Verbose "Loading XAML $xaml - $FileRootFolder" $xamlContent = Get-Content -Path $XAMLfile -raw [xml]$xamlxml = $xamlContent.Replace('{0}', $((Get-Item -Path $XAMLfile).Directory | Split-path)) $xamlReader = New-Object System.Xml.XmlNodeReader $xamlxml [Windows.Markup.XamlReader]::Load($xamlReader) } Function Update-PSGUIWPF { <# .SYNOPSIS Updates WPF Control in a dynamic way .PARAMETER XAMLfile Path of the WPF XAML file .PARAMETER ControlName Target the Control to be updated .EXAMPLE Update-PSGUIWPF -XAMLFile "test.xaml" -ControlMame $control #> [CmdletBinding()] param( [Parameter(Position=0,Mandatory=$True)] [ValidateScript({Test-Path $_})] [string]$XAMLfile, [Parameter(Position = 1, Mandatory = $True)] $ControlName, [Parameter(Position = 2)] [bool]$EditorMode = $False ) begin { } ### CHange XAML Views process { $xaml = Read-PSGUIXaml -XAMLfile $XAMLfile (get-variable -Name "$ControlName").Value.Content = $xaml $control = (get-variable -Name "$ControlName").Value.Content Add-PSGUIActions -XAMLfile $xamlpath -Control $control -Editormode $EDITORMODE } end { Write-Verbose $xamlpath } } |