functions/Trace.ps1
|
function Trace-Message { [cmdletbinding(DefaultParameterSetName = 'message')] [alias('trace')] [OutputType('none')] param( [Parameter(HelpMessage = 'Specify a title for the trace window.', ParameterSetName = 'init')] [ValidateNotNullOrEmpty()] [string]$Title = 'Trace Messages', [Parameter(HelpMessage = 'Specify a background color for the trace window', ParameterSetName = 'init')] [ValidateNotNullOrEmpty()] [string]$BackgroundColor = '#FFFFF8DC', [Parameter(HelpMessage = 'Specify the width of the trace window.', ParameterSetName = 'init')] [ValidateNotNullOrEmpty()] [int32]$Width = 800, [Parameter(HelpMessage = 'Specify the width of the trace window.', ParameterSetName = 'init')] [ValidateNotNullOrEmpty()] [int32]$Height = 500, [Parameter(Position = 0, Mandatory, HelpMessage = 'Specify a message to write to the trace window.', ValueFromPipeline, ParameterSetName = 'message')] [string]$Message ) begin { #tags are used for categorizing the command #cmdTags = scripting,graphical Write-Verbose "Starting $($MyInvocation.MyCommand)" Write-Verbose "Running under PowerShell version $($PSVersionTable.PSVersion)" function _SetTraceMessage { [cmdletbinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [string]$Message ) begin { $hash = $global:traceSynchHash } process { Write-Verbose "Adding message $message" $content = "$((Get-Date).TimeOfDay) - $message" $hash.TextBox.Dispatcher.Invoke([action] { $hash.TextBox.AppendText("$Content`n") }, 'Normal') } end {} } } #begin process { #must be running Windows if ($IsLinux -or $IsMacOS) { Write-Warning 'This command only works on Windows platforms.' #bail out return } Write-Verbose "Using parameter set $($PSCmdlet.ParameterSetName)" if ($global:TraceEnabled) { if ($PSCmdlet.ParameterSetName -eq 'init') { Write-Verbose "Defining synchronized hashtable `$global:traceSynchHash" $global:traceSynchHash = [hashtable]::Synchronized(@{Date = (Get-Date) }) Write-Verbose 'Initializing a new runspace' $newRunspace = [RunspaceFactory]::CreateRunspace() $newRunspace.ApartmentState = 'STA' $newRunspace.ThreadOptions = 'ReuseThread' Write-Verbose 'Open the new runspace' $newRunspace.Open() Write-Verbose 'Setting synchronized hashtable variable' $newRunspace.SessionStateProxy.SetVariable('traceSynchHash', $global:traceSynchHash) $newRunspace.SessionStateProxy.GetVariable('traceSynchHash') | Out-String | Write-Verbose $formParams = @{ Title = $title BackgroundColor = $BackgroundColor Width = $width Height = $Height } Write-Verbose 'Creating runspace script' $PSCmd = [PowerShell]::Create().AddScript( { param([string]$Title, [object]$BackgroundColor, [int]$width, [int]$height) Add-Type -AssemblyName PresentationFramework -ErrorAction stop Add-Type -AssemblyName PresentationCore -ErrorAction stop Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop $form = New-Object System.Windows.Window $form.Title = $Title $form.Height = $height $form.Width = $width $form.ResizeMode = 'noResize' $form.Background = $BackgroundColor $Form.Left = 100 $form.Top = 100 #$form.WindowStartupLocation = [System.Windows.WindowStartupLocation]::CenterScreen $grid = New-Object System.Windows.Controls.Grid $text = New-Object System.Windows.Controls.TextBox $text.text = '' #$text.Text = "Starting...`n" $text.Padding = 5 $text.Width = $form.width - 25 $text.Height = $form.Height - 100 $text.Margin = '5,5,5,5' $text.TextWrapping = [System.Windows.TextWrapping]::Wrap $text.VerticalAlignment = 'top' $text.IsEnabled = $True $text.AcceptsReturn = $True $text.VerticalScrollBarVisibility = 'Auto' $text.FontFamily = 'Consolas' $text.HorizontalAlignment = 'stretch' $text.VerticalAlignment = 'top' $grid.AddChild($text) $Quit = New-Object System.Windows.Controls.Button $quit.Content = '_Quit' $quit.Width = 75 $quit.Height = 25 $quit.Margin = '10,10,0,10' $quit.HorizontalAlignment = 'Left' $quit.VerticalAlignment = 'bottom' $quit.Add_click( { $form.close() $traceSynchHash.clear() Remove-Variable -Name traceSynchHash -Scope global }) $grid.AddChild($quit) $Save = New-Object System.Windows.Controls.Button $save.Content = '_Save' $save.Width = 75 $save.Height = 25 $save.Margin = '10,10,10,10' $save.HorizontalAlignment = 'right' $save.VerticalAlignment = 'bottom' $save.Add_click( { $SaveDialog = New-Object System.Windows.Forms.SaveFileDialog $SaveDialog.InitialDirectory = "$ENV:Temp" $SaveDialog.Filter = 'txt Files (*.txt)|*.txt |All files (*.*)|*.*' [void]$SaveDialog.ShowDialog() if ($SaveDialog.Filename) { $text.text | Out-File -FilePath $SaveDialog.filename [System.Windows.Forms.MessageBox]::Show("Trace log exported to $($SaveDialog.Filename)", 'Trace Export | Trace Message') } }) $grid.AddChild($Save) $form.AddChild($grid) #add keys to the synchronized hashtable $traceSynchHash.TextBox = $text $traceSynchHash.Form = $Form #show the form [void]$traceSynchHash.Form.ShowDialog() $traceSynchHash.Error = $Error }) #add parameters [void]$PSCmd.AddParameters($formParams) $PSCmd.Runspace = $newRunspace Write-Verbose 'Invoking runspace command' $handle = $PSCmd.BeginInvoke() Write-Verbose 'Using this global synchronized hashtable' $global:traceSynchHash | Out-String | Write-Verbose #wait for hashtable to initialize with runspace values $i = 0 do { $i++ Start-Sleep -Seconds 1 #uncomment for troubleshooting #Write-host $i -ForegroundColor yellow -NoNewline } until ($global:traceSynchHash.TextBox) Write-Verbose 'Creating a runspace cleanup job' [void](New-RunspaceCleanupJob -Handle $handle -powerShell $PSCmd -sleep 30 -PassThru) Write-Verbose 'Getting trace metadata' $elevated = ([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.SecurityIdentifier]'S-1-5-32-544') $os = Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption, Version, OSArchitecture $init = @( '*************************************************', "User : $($env:USERDOMAIN)\$($env:USERNAME)", "Elevated : $Elevated", "Computer : $env:Computername", "PSVersion : $($PSVersionTable.PSVersion)", "OS : $($os.caption)", "Version : $($os.version)", "Architecture : $($os.OSArchitecture)", '*************************************************' ) Write-Verbose 'Init' $init | Write-Verbose Write-Verbose 'Setting trace metadata' $init | _SetTraceMessage } #if init else { Write-Verbose "Setting message $message" _SetTraceMessage -Message $Message } } else { Write-Verbose 'TraceEnabled is set to False' } } #process end { Write-Verbose "Ending $($MyInvocation.MyCommand)" } #end } #EOF |