{"id":3538,"date":"2013-11-01T11:30:40","date_gmt":"2013-11-01T15:30:40","guid":{"rendered":"http:\/\/jdhitsolutions.com\/blog\/?p=3538"},"modified":"2015-11-20T13:35:50","modified_gmt":"2015-11-20T18:35:50","slug":"friday-fun-create-a-powershell-trace-window","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/","title":{"rendered":"Friday Fun: Create a PowerShell Trace Window"},"content":{"rendered":"<p><a href=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-thumbnail wp-image-3539\" alt=\"magnifying-glass\" src=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png\" width=\"150\" height=\"150\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png 150w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass.png 288w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><\/a>Way back in the day, it was all VBScript and HTAs for me. I built a number of HTA tools for other people to use. As you might expect they didn't always work and troubleshooting something I couldn't see was difficult. So I came up with a solution to use an Internet Explorer window as a sort of immediate or trace window. In my HTA I added code to use this trace window. The user could then copy and paste the contents of the window and I would have a much better idea about what went wrong. I always thought this was a cool trick and figured why not do it in PowerShell?<\/p>\n<p>Using the COM object you can create an instance of Internet Explorer and then use DOM methods and properties to configure the window and write text to it. Here's the PowerShell version of what I used to do in VBScript.<\/p>\n<pre class=\"lang:ps decode:true\">#requires -version 2.0\r\n\r\nFunction Trace-Message {\r\n&lt;#\r\n.Synopsis\r\nDisplay script trace messages\r\n.Description\r\nThis command will launch an instance of Internet Explorer and display user\r\ndefined trace messages. The trace message will automatically include a time\r\nstamp. After your script has completed, the window will remain open until you \r\nmanually close it. If you use this command in the PowerShell ISE, you can use \r\nthe -Terminate parameter to close it and clean up the COM object.\r\n\r\nThe function has parameters to adjust the positioning, size and format of the\r\nInternet Explorer window. You can't change the position or window size once the\r\nwindow is first created, although you can manually reposition and resize. But\r\nit is possible to specify different values for these settings on a per message\r\nbasis:\r\n\r\n    Title\r\n    Background Color\r\n    Font\r\n    FontSize\r\n\r\nThe beginning of every trace window will include information about the user and\r\ncomputer running the script. This can be useful when troubleshooting a script\r\nthat someone else is running.\r\n\r\nIMPORTANT: The trace window will only be created if the function detects a\r\nvariable in the current scope, usually the script, called TraceEnabled with a\r\nvalue of $True. This means your script can have trace commands but they won't\r\ndo anything unless $TraceEnabled is set to $True.\r\n\r\n.Notes\r\nLast Updated: October 30, 2013\r\nVersion     : 0.9\r\n\r\n.Link\r\n<blockquote class=\"wp-embedded-content\" data-secret=\"oXf8MIUa6y\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/\">Friday Fun: Create a PowerShell Trace Window<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Friday Fun: Create a PowerShell Trace Window&#8221; &#8212; The Lonely Administrator\" src=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/embed\/#?secret=Is8THENQOd#?secret=oXf8MIUa6y\" data-secret=\"oXf8MIUa6y\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\r\n#&gt;\r\n\r\n[cmdletbinding(DefaultParameterSetName=\"Trace\")]\r\n\r\nParam (\r\n[Parameter(Position=0,Mandatory=$True,HelpMessage=\"Enter a trace message\",\r\nParameterSetName=\"Trace\")]\r\n[string]$Message,\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[int]$Top=10,\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[int]$Left=10,\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[int]$Width=600,\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[int]$Height=600,\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[string]$BGColor=\"#ffff00\",\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[string]$Title=\"Trace Messages\",\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[string]$Font=\"Verdana\",\r\n[Parameter(ParameterSetName=\"Trace\")]\r\n[int]$FontSize=2,\r\n[Parameter(ParameterSetName=\"Kill\")]\r\n[alias(\"kill\")]\r\n[switch]$Terminate\r\n)\r\n\r\nif ($Terminate) {\r\n  $script:IEWindow.Quit()\r\n  if ($IEWindow) {\r\n    Remove-Variable -name IEWindow -Scope Script\r\n  }\r\n  return\r\n}\r\n\r\n#only run if $TraceEnabled is True\r\nif ($script:TraceEnabled) {\r\n#if there isn't an IE window object, create it\r\nIf (-NOT $script:IEWindow) {\r\n    $script:IEWindow = New-Object -ComObject \"InternetExplorer.Application\" \r\n    $script:IEWindow.navigate(\"about:blank\")\r\n    $script:IEWindow.ToolBar = $False\r\n    $script:IEWindow.AddressBar = $False\r\n    $script:IEWindow.Top = $Top\r\n    $script:IEWindow.Left = $Left\r\n    $script:IEWindow.Width = $Width\r\n    $script:IEWindow.Height = $Height\r\n    $script:IEWindow.Visible = $True\r\n    $script:IEWindow.menubar = $False\r\n    $script:IEWindow.StatusBar = $False   \r\n    $script:IEWindow.Document.IHTMLDocument2_Title = $Title\r\n    $script:IEWindow.document.IHTMLDocument2_bgColor= $BGColor\r\n    #include some default information\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - User: $($env:USERDOMAIN)\\$($env:USERName) &lt;br&gt;\")\r\n    $elevated = ([security.principal.windowsprincipal]([security.principal.windowsidentity]::Getcurrent())).IsInRole([system.security.principal.securityidentifier]\"S-1-5-32-544\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - Elevated: $Elevated &lt;br&gt;\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - Computer: $env:Computername &lt;br&gt;\")\r\n    $os = Get-WmiObject win32_operatingsystem\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - OS: $($os.caption) &lt;br&gt;\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - Ver.: $($os.version) &lt;br&gt;\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - Service Pack: $($os.ServicePackMajorVersion).$($os.ServicePackMinorVersion) &lt;br&gt;\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - Architecture: $($os.OSArchitecture) &lt;br&gt;\")\r\n    $script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - ******************************&lt;br&gt;\")\r\n}\r\n\r\n#write the message to the window\r\n$script:IEWindow.Document.IHTMLDocument2_writeln(\"&lt;font face=$Font size=$FontSize&gt; $(Get-Date) - $Message &lt;br&gt;\")\r\n$script:IEWindow.Document.IHTMLDocument2_Title = $Title\r\n$script:IEWindow.document.IHTMLDocument2_bgColor= $BGColor\r\n\r\n} #if $TraceEnabled\r\n\r\n} #close Trace-Message function\r\n\r\nSet-Alias -Name Trace -Value Trace-Message<\/pre>\n<p>The function is written with the assumption that you will use it within a script. I'll have an example in a moment. The function first checks for a variable, presumably in the script scope, called TraceEnabled. If it is set to True, the function will continue. Then it checks to see if an existing trace window has already been created. If not, it creates it using some default properties for size, position, and color all of which you can change via parameters. Once the the window is created, your message string is written to the Internet Explorer window. I prepend the current date and time to the message. I also include some default user and system information when the IE window is first created. In the past this was often helpful, especially when dealing with less tech savvy users.<\/p>\n<p>When you include the function in a script, everything should be cleaned up when you close the windows. The IE window will remain even after the script ends. This is handy because you can print from it, copy and paste or whatever. If you run your script from the PowerShell ISE, things don't always clean up nicely so I added a -Terminate parameter (with an alias of -Kill). When you use this in the ISE run Trace -Kill to close the window and clean up.<\/p>\n<p>So how would you use this?<\/p>\n<p>Well, here's a version of a script (which I don't think I've published before so you get a bonus today) that gets some basic server health information and creates an HTML report.<\/p>\n<pre class=\"lang:ps decode:true\">#requires -version 3.0\r\n\r\n&lt;#\r\nServerHealth.ps1\r\nA script to do a quick health check and create an HTML report.\r\nThis version includes my trace function.\r\n\r\n  ****************************************************************\r\n  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *\r\n  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *\r\n  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *\r\n  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *\r\n  ****************************************************************\r\n\r\n#&gt;\r\n\r\n[cmdletbinding()]\r\nParam(\r\n[Parameter(Position=0,HelpMessage=\"Enter the computer name for the report\")]\r\n[ValidateNotNullorEmpty()]\r\n[Alias(\"name\",\"cn\")]\r\n[string]$Computername=$env:computername,\r\n[Parameter(Position=1,HelpMessage=\"Enter the path for the html report\")]\r\n[ValidateNotNullorEmpty()]\r\n[string]$Path=\"ServerHealth.htm\",\r\n[Alias(\"RunAs\")]\r\n[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,\r\n[switch]$Trace\r\n\r\n)\r\n#dot source the Trace function\r\n. C:\\scripts\\Trace.ps1\r\nif ($trace) {\r\n  $script:TraceEnabled = $True\r\n}\r\n\r\n# !!!!!! \r\n#dot source the Trace function\r\n. C:\\scripts\\Trace.ps1\r\n\r\nif ($trace) {\r\n  #set the variable to turn tracing on\r\n  $script:TraceEnabled = $True\r\n}\r\n\r\n#!!!!!!!\r\n\r\n#the trace commands will only work if $TraceEnabled = $True\r\nTrace \"Starting $($MyInvocation.MyCommand)\"\r\n\r\nWrite-Verbose \"Starting $($MyInvocation.MyCommand)\"\r\n#initialize an array for HTML fragments\r\nTrace \"initializing fragments\"\r\n$fragments=@()\r\n\r\n$ReportTitle = \"Server Health Report: $($Computername.toUpper())\"\r\nTrace $ReportTitle\r\nTrace \"Defining head\"\r\n\r\n#this must be left justified        \r\n$head = @\"\r\n&lt;Title&gt;$ReportTitle&lt;\/Title&gt;\r\n&lt;style&gt;\r\nbody { background-color:#FFFFFF;\r\n       font-family:Tahoma;\r\n       font-size:12pt; }\r\ntd, th { border:1px solid black; \r\n         border-collapse:collapse; }\r\nth { color:white;\r\n     background-color:black; }\r\ntable, tr, td, th { padding: 2px; margin: 0px }\r\ntr:nth-child(odd) {background-color: lightgray}\r\ntable { width:95%;margin-left:5px; margin-bottom:20px;}\r\n.alert {background-color: red ! important}\r\n.warn {background-color: yellow ! important}\r\n&lt;\/style&gt;\r\n&lt;br&gt;\r\n&lt;H1&gt;$ReportTitle&lt;\/H1&gt;\r\n\"@\r\n\r\n#build a hashtable of parameters for New-CimSession\r\n$cimParams=@{\r\nErrorAction=\"Stop\"\r\nErrorVariable=\"myErr\"\r\nComputername=$Computername\r\n}\r\n\r\nTrace \"Reporting on computer $Computername\"\r\nif ($credential.username) {\r\n    Write-Verbose \"Adding a PSCredential for $($Credential.username)\"\r\n    Trace \"Adding a PSCredential for $($Credential.username)\"\r\n    $cimParams.Add(\"Credential\",$Credential)\r\n}\r\n\r\nTry {\r\n    #verify if computer is running PowerShell 2 or 3\r\n    Write-Verbose \"Test-WSMan $Computername\"\r\n    Trace \"Test-WSMan $Computername\"\r\n    $wsman = Test-WSMan -ComputerName $Computername -ErrorAction Stop -ErrorVariable myErr\r\n    Trace ($wsman | out-string)\r\n}\r\nCatch {\r\n    Write-Warning \"Failed to test WSMan for $Computername\"\r\n    Write-Warning $myErr.ErrorRecord\r\n    Trace \"Oops\"\r\n    Trace \"Failed to test WSMan for $Computername\"\r\n    Trace \"Breaking out\"\r\n    Break\r\n}\r\n\r\nif ([int]($wsman.ProductVersion.Substring(25)) -lt 3) {\r\n#running less than PowerShell 3 so create a DCOM option\r\n Write-Verbose \"$Computername running PowerShell 2.0\"\r\n Trace \"$Computername running PowerShell 2.0\"\r\n Trace \"Creating new CimSessionOption\"\r\n $cimOption = New-CimSessionOption -Protocol Dcom\r\n $cimParams.Add(\"SessionOption\",$cimOption)\r\n}\r\n\r\n#create a CIM Session\r\nWrite-Verbose \"Creating a CIM Session\"\r\nTrace \"Creating a CIM Session\"\r\nTry {\r\n    $cs = New-CimSession @cimParams\r\n}\r\nCatch {\r\n    Write-Warning \"Failed to create CIM session for $Computername\"\r\n    Write-Warning $myErr.ErrorRecord\r\n    Trace \"Oops\"\r\n    Trace \"Failed to create CIM session for $Computername\"\r\n    Trace \"Breaking\"\r\n    Break\r\n}\r\n\r\n#get OS data and uptime\r\nWrite-Verbose \"Getting OS and uptime\"\r\nTrace \"Getting OS and uptime\"\r\n$os = $cs | Get-CimInstance -ClassName Win32_OperatingSystem\r\n$fragments+=\"&lt;h2&gt;Operating System&lt;\/h2&gt;\"\r\n\r\nTrace \"Converting OS data to HTML fragment\"\r\n$fragments+= $os | select @{Name=\"Computername\";Expression={$_.CSName}},\r\n@{Name=\"Operating System\";Expression={$_.Caption}},\r\n@{Name=\"Service Pack\";Expression={$_.CSDVersion}},LastBootUpTime,\r\n@{Name=\"Uptime\";Expression={(Get-Date) - $_.LastBootUpTime}} |\r\nConvertTo-HTML -Fragment\r\n\r\nWrite-Verbose \"Getting memory usage\"\r\nTrace \"Converting memory usage to HTML fragment\"\r\n$fragments+=\"&lt;h2&gt;Memory Usage&lt;\/h2&gt;\"\r\n[xml]$html= $os | \r\nSelect @{Name=\"TotalMemoryMB\";Expression={[int]($_.TotalVisibleMemorySize\/1mb)}},\r\n@{Name=\"FreeMemoryMB\";Expression={[math]::Round($_.FreePhysicalMemory\/1MB,2)}},\r\n@{Name=\"PercentFreeMemory\";Expression={[math]::Round(($_.FreePhysicalMemory\/$_.TotalVisibleMemorySize)*100,2)}},\r\n@{Name=\"TotalVirtualMemoryMB\";Expression={[int]($_.TotalVirtualMemorySize\/1mb)}},\r\n@{Name=\"FreeVirtualMemoryMB\";Expression={[math]::Round($_.FreeVirtualMemory\/1MB,2)}},\r\n@{Name=\"PercentFreeVirtualMemory\";Expression={[math]::Round(($_.FreeVirtualMemory\/$_.TotalVirtualMemorySize)*100,2)}} |\r\nConvertTo-Html -Fragment\r\n\r\n#parse html to add color attributes\r\nTrace \"Parsing memory fragment\"\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the percent free memory column and assign a class to the row\r\n  if (($html.table.tr[$i].td[2] -as [double]) -le 10) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[2] -as [double]) -le 20) {                                               \r\n    $class.value = \"warn\"    \r\n    $html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null\r\n  }\r\n}\r\n#add the new HTML to the fragment\r\nTrace \"adding fragment\"\r\n$fragments+= $html.innerXML\r\n\r\n#get disk drive status\r\nWrite-Verbose \"Getting drive status\"\r\nTrace \"Getting drive status\"\r\n$drives = $cs | Get-CimInstance -ClassName Win32_Logicaldisk -filter \"DriveType=3\"\r\n$fragments+=\"&lt;h2&gt;Disk Usage&lt;\/h2&gt;\"\r\n\r\nTrace \"Converting disk usage to HTML fragment\"\r\n\r\n[xml]$html= $drives | Select DeviceID,\r\n@{Name=\"SizeGB\";Expression={[int]($_.Size\/1GB)}},\r\n@{Name=\"FreeGB\";Expression={[math]::Round($_.Freespace\/1GB,4)}},\r\n@{Name=\"PercentFree\";Expression={[math]::Round(($_.freespace\/$_.size)*100,2)}} |\r\nConvertTo-Html -Fragment\r\n\r\n#parse html to add color attributes\r\nTrace \"Parsing memory fragment\"\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the percent free column and assign a class to the row\r\n  if (($html.table.tr[$i].td[3] -as [double]) -le 10) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[3] -as [double]) -le 20) {                                               \r\n    $class.value = \"warn\"    \r\n    $html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null\r\n  }\r\n}\r\nTrace \"adding disk fragment\"\r\n$fragments+=$html.InnerXml\r\nClear-Variable html\r\n\r\n#get recent errors and warning in all logs\r\nWrite-Verbose \"Getting recent eventlog errors and warnings\"\r\nTrace \"Getting recent eventlog errors and warnings\"\r\n#any errors or audit failures in the last 24 hours will be displayed in red\r\n#warnings in last 24 hours will be displayed in yellow\r\n\r\n$Yesterday = (Get-Date).Date.AddDays(-1)\r\nTrace \"Yesterday is $yesterday\"\r\n\r\n$after = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($yesterday)\r\nTrace \"Converted $yesterday to $after\"\r\n\r\n#get all event logs with entries\r\nTrace \"get all event logs with entries\"\r\n$logs = $cs | Get-CimInstance win32_ntEventlogFile -filter \"NumberOfRecords &gt; 0\"\r\n\r\n#exclude security log\r\n$fragments+=\"&lt;h2&gt;Event Logs&lt;\/h2&gt;\"\r\n\r\n#process security event log for Audit Failures\r\n$fragments+=\"&lt;h3&gt;Security&lt;\/h3&gt;\"\r\n\r\nTrace \"Getting security event log data and converting to HTML fragment\"\r\n\r\n[xml]$html = $cs | \r\nGet-CimInstance Win32_NTLogEvent -filter \"Logfile = 'Security' AND Type = 'FailureAudit' AND TimeGenerated &gt;= \"\"$after\"\"\" |\r\nSelect -property TimeGenerated,Type,EventCode,SourceName,Message |\r\nConvertTo-Html -Fragment\r\n\r\nTrace \"Parsing event log fragment\"\r\nif ($html.table) {\r\n   #if a failure in the last day, display in red\r\n    if (($html.table.tr[$i].td[1] -eq 'FailureAudit')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n    Trace \"Adding event log fragment\"\r\n    $fragments+=$html.InnerXml\r\n}\r\nElse {\r\n  #no recent audit failures\r\n  Write-Verbose \"No recent audit failures\"\r\n  $fragments+=\"&lt;p style='color:green;'&gt;No recent audit failures&lt;\/p&gt;\"\r\n}\r\n\r\nClear-Variable html\r\nTrace \"Getting all other event logs\"\r\nforeach ($log in ($logs | where logfilename -ne 'Security')) {\r\nWrite-Verbose \"Processing event log $($log.LogfileName)\"\r\n$fragments+=\"&lt;h3&gt;$($log.LogfileName)&lt;\/h3&gt;\"\r\n\r\nTrace \"Converting event log data to HTML fragment\"\r\n\r\n[xml]$html = $cs | \r\nGet-CimInstance Win32_NTLogEvent -filter \"Logfile = \"\"$($log.logfilename)\"\" AND Type &lt;&gt; 'Information' AND TimeGenerated &gt;= \"\"$after\"\"\" |\r\nSelect -property TimeGenerated,Type,EventCode,SourceName,Message |\r\nConvertTo-Html -Fragment\r\n\r\nTrace \"Parsing fragment\"\r\nif ($html.table) {\r\n#color errors in red\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the entry type column and assign a class to the row if within the last day\r\n  if (($html.table.tr[$i].td[1] -eq 'Error')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[1] -eq 'Warning')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"warn\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n} #for\r\n\r\n$fragments+=$html.InnerXml\r\n}\r\nelse {\r\n  #no errors or warnings\r\n  Write-Verbose \"No recent errors or warnings for $($log.logfilename)\"\r\n  Trace \"No recent errors or warnings for $($log.logfilename)\"\r\n  $fragments+=\"&lt;p style='color:green;'&gt;No recent errors or warnings&lt;\/p&gt;\"\r\n}\r\nClear-Variable html\r\n} #foreach\r\n\r\n#get services that should be running but aren't\r\nWrite-Verbose \"Getting services that should be running but aren't\"\r\nTrace \"Getting services that should be running but aren't\"\r\n$services = $cs | Get-CimInstance -ClassName win32_service -filter \"startmode='Auto' AND state &lt;&gt; 'Running'\"\r\n$fragments+=\"&lt;h2&gt;Services&lt;\/h2&gt;\"\r\n\r\nTrace \"Converting service data to HTML fragment\"\r\n$fragments+= $services | Select Name,Displayname,Description,State | \r\nConvertTo-Html -Fragment\r\n\r\n$fragments+=\"&lt;br&gt;&lt;i&gt;Created $(Get-Date)&lt;\/i&gt;\"\r\n\r\n#create the HTML report\r\nWrite-Verbose \"Creating an HTML report\"\r\nTrace \"Creating an HTML report\"\r\nTrace \"Writing to $path\"\r\nConvertTo-Html -Head $head -Title $reportTitle -body $Fragments | Out-File -FilePath $path -Encoding ascii\r\nTrace (get-item $path | out-string)\r\nWrite-Verbose \"Saving the HTML report to $Path\"\r\nWrite-Verbose \"Ending $($MyInvocation.MyCommand)\"\r\nTrace \"Ending $($MyInvocation.MyCommand)\"\r\n\r\nWrite-Host \"Report saved to $path\" -ForegroundColor Green<\/pre>\n<p>As you look through this you'll see a number of Trace commands. The trace script, which is dot sourced in this script, creates an alias of Trace. These commands won't do anything unless $TraceEnabled is set to $True. This version of the script includes a -Trace switch which does just that. From there the script runs and all of my trace messages are written to an IE window.<\/p>\n<pre class=\"lang:batch decode:true\">S:\\ServerHealth-Trace.ps1 -Computername CHI-HVR2.GLOBOMANTICS.LOCAL -Credential globomantics\\administrator -Trace -Path c:\\work\\hvr2-health.htm<\/pre>\n<p><a href=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/trace.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3540\" alt=\"trace\" src=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/trace.png\" width=\"600\" height=\"600\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/trace.png 600w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/trace-150x150.png 150w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/trace-300x300.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>If there is a problem, then I can see where the script is breaking down or failing. If all goes well, I end up with a report like this:<\/p>\n<p><a href=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3541\" alt=\"serverhealth\" src=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth-1024x702.png\" width=\"625\" height=\"428\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth-1024x702.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth-300x205.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth-624x428.png 624w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/serverhealth.png 1134w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p>The server health script gets some information using Get-CIMInstance on memory, disk usage and event logs from that last day. The script will dynamically create a DCOM option if it detects that the remote computer is not running PowerShell 3.<\/p>\n<p>You can use my Trace-Message function in conjunction with Write-Verbose. You can display the same information or different. It is up to you. You could probably accomplish the same result by using a Windows form or WPF via ShowUI. But everyone has Internet Explorer and this was pretty easy to pull together.<\/p>\n<p>By the way, if you just want a copy of the server health script without the Trace commands, here you go:<\/p>\n<pre class=\"lang:ps decode:true \" >#requires -version 3.0\r\n\r\n&lt;#\r\nServerHealth.ps1\r\nA script to do a quick health check and create an HTML report\r\n\r\n  ****************************************************************\r\n  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *\r\n  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *\r\n  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *\r\n  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *\r\n  ****************************************************************\r\n#&gt;\r\n\r\n[cmdletbinding()]\r\nParam(\r\n[Parameter(Position=0,HelpMessage=\"Enter the computer name for the report\")]\r\n[ValidateNotNullorEmpty()]\r\n[Alias(\"name\",\"cn\")]\r\n[string]$Computername=$env:computername,\r\n[Parameter(Position=1,HelpMessage=\"Enter the path for the html report\")]\r\n[ValidateNotNullorEmpty()]\r\n[string]$Path=\"ServerHealth.htm\",\r\n[Alias(\"RunAs\")]\r\n[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty\r\n)\r\n\r\nWrite-Verbose \"Starting $($MyInvocation.MyCommand)\"\r\n#initialize an array for HTML fragments\r\n$fragments=@()\r\n\r\n$ReportTitle = \"Server Health Report: $($Computername.toUpper())\"\r\n\r\n#this must be left justified        \r\n$head = @\"\r\n&lt;Title&gt;$ReportTitle&lt;\/Title&gt;\r\n&lt;style&gt;\r\nbody { background-color:#FFFFFF;\r\n       font-family:Tahoma;\r\n       font-size:12pt; }\r\ntd, th { border:1px solid black; \r\n         border-collapse:collapse; }\r\nth { color:white;\r\n     background-color:black; }\r\ntable, tr, td, th { padding: 2px; margin: 0px }\r\ntr:nth-child(odd) {background-color: lightgray}\r\ntable { width:95%;margin-left:5px; margin-bottom:20px;}\r\n.alert {background-color: red ! important}\r\n.warn {background-color: yellow ! important}\r\n&lt;\/style&gt;\r\n&lt;br&gt;\r\n&lt;H1&gt;$ReportTitle&lt;\/H1&gt;\r\n\"@\r\n\r\n#build a hashtable of parameters for New-CimSession\r\n$cimParams=@{\r\nErrorAction=\"Stop\"\r\nErrorVariable=\"myErr\"\r\nComputername=$Computername\r\n}\r\n\r\nif ($credential.username) {\r\n    Write-Verbose \"Adding a PSCredential for $($Credential.username)\"\r\n    $cimParams.Add(\"Credential\",$Credential)\r\n}\r\n\r\nTry {\r\n    #verify if computer is running PowerShell 2 or 3\r\n    Write-Verbose \"Test-WSMan $Computername\"\r\n    $wsman = Test-WSMan -ComputerName $Computername -ErrorAction Stop -ErrorVariable myErr\r\n}\r\nCatch {\r\n    Write-Warning \"Failed to test WSMan for $Computername\"\r\n    Write-Warning $myErr.ErrorRecord\r\n    Break\r\n}\r\n\r\nif ([int]($wsman.ProductVersion.Substring(25)) -lt 3) {\r\n#running less than PowerShell 3 so create a DCOM option\r\n Write-Verbose \"$Computername running PowerShell 2.0\"\r\n $cimOption = New-CimSessionOption -Protocol Dcom\r\n $cimParams.Add(\"SessionOption\",$cimOption)\r\n}\r\n\r\n#create a CIM Session\r\nWrite-Verbose \"Creating a CIM Session\"\r\nTry {\r\n    $cs = New-CimSession @cimParams\r\n}\r\nCatch {\r\n    Write-Warning \"Failed to create CIM session for $Computername\"\r\n    Write-Warning $myErr.ErrorRecord\r\n    Break\r\n}\r\n\r\n#get OS data and uptime\r\nWrite-Verbose \"Getting OS and uptime\"\r\n$os = $cs | Get-CimInstance -ClassName Win32_OperatingSystem \r\n$fragments+=\"&lt;h2&gt;Operating System&lt;\/h2&gt;\"\r\n$fragments+= $os | select @{Name=\"Computername\";Expression={$_.CSName}},\r\n@{Name=\"Operating System\";Expression={$_.Caption}},\r\n@{Name=\"Service Pack\";Expression={$_.CSDVersion}},LastBootUpTime,\r\n@{Name=\"Uptime\";Expression={(Get-Date) - $_.LastBootUpTime}} |\r\nConvertTo-HTML -Fragment\r\n\r\nWrite-Verbose \"Getting memory usage\"\r\n$fragments+=\"&lt;h2&gt;Memory Usage&lt;\/h2&gt;\"\r\n[xml]$html= $os | \r\nSelect @{Name=\"TotalMemoryMB\";Expression={[int]($_.TotalVisibleMemorySize\/1mb)}},\r\n@{Name=\"FreeMemoryMB\";Expression={[math]::Round($_.FreePhysicalMemory\/1MB,2)}},\r\n@{Name=\"PercentFreeMemory\";Expression={[math]::Round(($_.FreePhysicalMemory\/$_.TotalVisibleMemorySize)*100,2)}},\r\n@{Name=\"TotalVirtualMemoryMB\";Expression={[int]($_.TotalVirtualMemorySize\/1mb)}},\r\n@{Name=\"FreeVirtualMemoryMB\";Expression={[math]::Round($_.FreeVirtualMemory\/1MB,2)}},\r\n@{Name=\"PercentFreeVirtualMemory\";Expression={[math]::Round(($_.FreeVirtualMemory\/$_.TotalVirtualMemorySize)*100,2)}} |\r\nConvertTo-Html -Fragment\r\n\r\n#parse html to add color attributes\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the percent free memory column and assign a class to the row\r\n  if (($html.table.tr[$i].td[2] -as [double]) -le 10) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[2] -as [double]) -le 20) {                                               \r\n    $class.value = \"warn\"    \r\n    $html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null\r\n  }\r\n}\r\n#add the new HTML to the fragment\r\n$fragments+= $html.innerXML\r\n\r\n#get disk drive status\r\nWrite-Verbose \"Getting drive status\"\r\n$drives = $cs | Get-CimInstance -ClassName Win32_Logicaldisk -filter \"DriveType=3\"\r\n$fragments+=\"&lt;h2&gt;Disk Usage&lt;\/h2&gt;\"\r\n[xml]$html= $drives | Select DeviceID,\r\n@{Name=\"SizeGB\";Expression={[int]($_.Size\/1GB)}},\r\n@{Name=\"FreeGB\";Expression={[math]::Round($_.Freespace\/1GB,4)}},\r\n@{Name=\"PercentFree\";Expression={[math]::Round(($_.freespace\/$_.size)*100,2)}} |\r\nConvertTo-Html -Fragment\r\n\r\n#parse html to add color attributes\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the percent free column and assign a class to the row\r\n  if (($html.table.tr[$i].td[3] -as [double]) -le 10) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[3] -as [double]) -le 20) {                                               \r\n    $class.value = \"warn\"    \r\n    $html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null\r\n  }\r\n}\r\n\r\n$fragments+=$html.InnerXml\r\nClear-Variable html\r\n\r\n#get recent errors and warning in all logs\r\nWrite-Verbose \"Getting recent eventlog errors and warnings\"\r\n\r\n#any errors or audit failures in the last 24 hours will be displayed in red\r\n#warnings in last 24 hours will be displayed in yellow\r\n\r\n$Yesterday = (Get-Date).Date.AddDays(-1)\r\n$after = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($yesterday)\r\n\r\n#get all event logs with entries\r\n$logs = $cs | Get-CimInstance win32_ntEventlogFile -filter \"NumberOfRecords &gt; 0\"\r\n#exclude security log\r\n$fragments+=\"&lt;h2&gt;Event Logs&lt;\/h2&gt;\"\r\n\r\n#process security event log for Audit Failures\r\n$fragments+=\"&lt;h3&gt;Security&lt;\/h3&gt;\"\r\n\r\n[xml]$html = $cs | \r\nGet-CimInstance Win32_NTLogEvent -filter \"Logfile = 'Security' AND Type = 'FailureAudit' AND TimeGenerated &gt;= \"\"$after\"\"\" |\r\nSelect -property TimeGenerated,Type,EventCode,SourceName,Message |\r\nConvertTo-Html -Fragment\r\n\r\nif ($html.table) {\r\n   #if a failure in the last day, display in red\r\n    if (($html.table.tr[$i].td[1] -eq 'FailureAudit')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n    \r\n    $fragments+=$html.InnerXml\r\n}\r\nElse {\r\n  #no recent audit failures\r\n  Write-Verbose \"No recent audit failures\"\r\n  $fragments+=\"&lt;p style='color:green;'&gt;No recent audit failures&lt;\/p&gt;\"\r\n}\r\n\r\nClear-Variable html\r\n\r\n#process all the other logs\r\nforeach ($log in ($logs | where logfilename -ne 'Security')) {\r\nWrite-Verbose \"Processing event log $($log.LogfileName)\"\r\n$fragments+=\"&lt;h3&gt;$($log.LogfileName)&lt;\/h3&gt;\"\r\n\r\n[xml]$html = $cs | \r\nGet-CimInstance Win32_NTLogEvent -filter \"Logfile = \"\"$($log.logfilename)\"\" AND Type &lt;&gt; 'Information' AND TimeGenerated &gt;= \"\"$after\"\"\" |\r\nSelect -property TimeGenerated,Type,EventCode,SourceName,Message |\r\nConvertTo-Html -Fragment\r\n\r\nif ($html.table) {\r\n#color errors in red\r\nfor ($i=1;$i -le $html.table.tr.count-1;$i++) {\r\n  $class = $html.CreateAttribute(\"class\")\r\n  #check the value of the entry type column and assign a class to the row if within the last day\r\n  if (($html.table.tr[$i].td[1] -eq 'Error')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"alert\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n  elseif (($html.table.tr[$i].td[1] -eq 'Warning')  -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {                                          \r\n    $class.value = \"warn\"  \r\n    $html.table.tr[$i].Attributes.Append($class) | Out-Null\r\n  }\r\n} #for\r\n\r\n$fragments+=$html.InnerXml\r\n}\r\nelse {\r\n  #no errors or warnings\r\n  Write-Verbose \"No recent errors or warnings for $($log.logfilename)\"\r\n  $fragments+=\"&lt;p style='color:green;'&gt;No recent errors or warnings&lt;\/p&gt;\"\r\n}\r\nClear-Variable html\r\n} #foreach\r\n\r\n#get services that should be running but aren't\r\nWrite-Verbose \"Getting services that should be running but aren't\"\r\n$services = $cs | Get-CimInstance -ClassName win32_service -filter \"startmode='Auto' AND state &lt;&gt; 'Running'\"\r\n$fragments+=\"&lt;h2&gt;Services&lt;\/h2&gt;\"\r\n$fragments+= $services | Select Name,Displayname,Description,State | \r\nConvertTo-Html -Fragment\r\n\r\n$fragments+=\"&lt;br&gt;&lt;i&gt;Created $(Get-Date)&lt;\/i&gt;\"\r\n\r\n#create the HTML report\r\nWrite-Verbose \"Creating an HTML report\"\r\n\r\nConvertTo-Html -Head $head -Title $reportTitle -body $Fragments | Out-File -FilePath $path -Encoding ascii\r\n\r\nWrite-Verbose \"Saving the HTML report to $Path\"\r\nWrite-Verbose \"Ending $($MyInvocation.MyCommand)\"\r\n\r\nWrite-Host \"Report saved to $path\" -ForegroundColor Green<\/pre>\n<p>Today you get twice the fun. What do you think about all of this? As always, I look forward to hearing what you think.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Way back in the day, it was all VBScript and HTAs for me. I built a number of HTA tools for other people to use. As you might expect they didn&#8217;t always work and troubleshooting something I couldn&#8217;t see was difficult. So I came up with a solution to use an Internet Explorer window as&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Fresh Friday Fun: Create a #PowerShell Trace Window","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[359,231,8,19],"tags":[387,534,540,547],"class_list":["post-3538","post","type-post","status-publish","format-standard","hentry","category-powershell-3-0","category-powershell-ise","category-scripting","category-wmi","tag-cim","tag-powershell","tag-scripting","tag-wmi"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"Way back in the day, it was all VBScript and HTAs for me. I built a number of HTA tools for other people to use. As you might expect they didn&#039;t always work and troubleshooting something I couldn&#039;t see was difficult. So I came up with a solution to use an Internet Explorer window as...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2013-11-01T15:30:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-11-20T18:35:50+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Friday Fun: Create a PowerShell Trace Window\",\"datePublished\":\"2013-11-01T15:30:40+00:00\",\"dateModified\":\"2015-11-20T18:35:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/\"},\"wordCount\":665,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/11\\\/magnifying-glass-150x150.png\",\"keywords\":[\"CIM\",\"PowerShell\",\"Scripting\",\"WMI\"],\"articleSection\":[\"Powershell 3.0\",\"PowerShell ISE\",\"Scripting\",\"WMI\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/\",\"name\":\"Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/11\\\/magnifying-glass-150x150.png\",\"datePublished\":\"2013-11-01T15:30:40+00:00\",\"dateModified\":\"2015-11-20T18:35:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/11\\\/magnifying-glass.png\",\"contentUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/11\\\/magnifying-glass.png\",\"width\":288,\"height\":288},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/3538\\\/friday-fun-create-a-powershell-trace-window\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Powershell 3.0\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/powershell-3-0\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Friday Fun: Create a PowerShell Trace Window\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/","og_locale":"en_US","og_type":"article","og_title":"Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator","og_description":"Way back in the day, it was all VBScript and HTAs for me. I built a number of HTA tools for other people to use. As you might expect they didn't always work and troubleshooting something I couldn't see was difficult. So I came up with a solution to use an Internet Explorer window as...","og_url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/","og_site_name":"The Lonely Administrator","article_published_time":"2013-11-01T15:30:40+00:00","article_modified_time":"2015-11-20T18:35:50+00:00","og_image":[{"url":"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png","type":"","width":"","height":""}],"author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Friday Fun: Create a PowerShell Trace Window","datePublished":"2013-11-01T15:30:40+00:00","dateModified":"2015-11-20T18:35:50+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/"},"wordCount":665,"commentCount":4,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#primaryimage"},"thumbnailUrl":"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png","keywords":["CIM","PowerShell","Scripting","WMI"],"articleSection":["Powershell 3.0","PowerShell ISE","Scripting","WMI"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/","url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/","name":"Friday Fun: Create a PowerShell Trace Window &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#primaryimage"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#primaryimage"},"thumbnailUrl":"http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass-150x150.png","datePublished":"2013-11-01T15:30:40+00:00","dateModified":"2015-11-20T18:35:50+00:00","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#primaryimage","url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass.png","contentUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/magnifying-glass.png","width":288,"height":288},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3538\/friday-fun-create-a-powershell-trace-window\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Powershell 3.0","item":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell-3-0\/"},{"@type":"ListItem","position":2,"name":"Friday Fun: Create a PowerShell Trace Window"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":115,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/115\/vbscript-training-in-las-vegas\/","url_meta":{"origin":3538,"position":0},"title":"VBScript Training in Las Vegas","author":"Jeffery Hicks","date":"August 24, 2007","format":false,"excerpt":"I will be doing a live 2 day VBScript class this fall in Las Vegas (Oct. 22 and 23). I'll be covering ADSI, WMI, HTAs, WSF and more. This is a class for experienced VBScripters who want to take it to the next level. This is a hands on class\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3543,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/3543\/more-powershell-trace-window-fun\/","url_meta":{"origin":3538,"position":1},"title":"More PowerShell Trace Window Fun","author":"Jeffery Hicks","date":"November 6, 2013","format":false,"excerpt":"On my last Friday Fun, I posted an article about using Internet Explorer as a trace window. The idea was to put debug or trace messages in a separate application. I received a comment on the post that suggested I could do a similar thing using the Debug View utility\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"dbgview-trace","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/11\/dbgview-trace-300x290.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":137,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/137\/my-published-works\/","url_meta":{"origin":3538,"position":2},"title":"My Published Works","author":"Jeffery Hicks","date":"March 10, 2008","format":false,"excerpt":"I'm trying out a new Live Write plugin for Amazon. Here is a list of books I have currently authored or co-authored. This list will continue to grow as I'm working on a new book now about managing Active Directory with PowerShell. WSH and VBScript Core: TFM by Jeffery Hicks\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2848,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/2848\/wmi-explorer-from-the-powershell-guy\/","url_meta":{"origin":3538,"position":3},"title":"WMI Explorer from The PowerShell Guy","author":"Jeffery Hicks","date":"March 8, 2013","format":false,"excerpt":"Several years ago, The PowerShell Guy, aka MoW, wrote a fantastic graphical PowerShell script that was a WMI Explorer. With this script you could connect to a computer and namespace, browse classes and view instances. A great way for discovering things about WMI. However Marc has moved on to other\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"wmibrowser","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/03\/wmibrowser-1024x552.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/03\/wmibrowser-1024x552.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2013\/03\/wmibrowser-1024x552.png?resize=525%2C300 1.5x"},"classes":[]},{"id":33,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/33\/use-internet-explorer-in-powershell\/","url_meta":{"origin":3538,"position":4},"title":"Use Internet Explorer in PowerShell","author":"Jeffery Hicks","date":"May 23, 2006","format":false,"excerpt":"Here's a PowerShell Script that demonstates how to create COM objects in PowerShell, in this case an Internet Explorer instance. The script then takes the output of the Get-Service cmdlet and writes the results to the IE window.# IEServiceList.ps1# Jeffery Hicks# http:\/\/jdhitsolutions.blogspot.com# http:\/\/www.jdhitsolutions.com# May 2006#Display all running services in an\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":43,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/43\/more-free-scripting-tools\/","url_meta":{"origin":3538,"position":5},"title":"More free scripting tools","author":"Jeffery Hicks","date":"August 16, 2006","format":false,"excerpt":"SAPIEN Technologies has released some free tools for scripters at http:\/\/www.primalscript.com\/freetools\/. One of them is the PowerShell help viewer I discussed a few posts back. This is great when you're in PowerShell and can't remember a cmdlet's syntax.They also have a nifty WMI explorer. This tool lets you browse all\u2026","rel":"","context":"In &quot;Scripting&quot;","block_context":{"text":"Scripting","link":"https:\/\/jdhitsolutions.com\/blog\/category\/scripting\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/3538","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=3538"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/3538\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=3538"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=3538"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=3538"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}