Automatically Enable and Disable Trace Logs Using PowerShell

Automatically Enable and Disable Trace Logs Using PowerShell

  • Comments 1
  • Likes

Summary: Use Windows PowerShell to automatically enable and disable trace logs.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! Your articles have been right on target—they hit me where I live. I am wondering if I could actually automate some of this? Suppose I am trying to install software using WMI, and I would like to see the log entries you talked about the other day. Could I do all of this in the same script?

—AS
 

Hey, Scripting Guy! AnswerHello AS,

Microsoft Scripting Guy Ed Wilson here. One does not have to be a night owl to work in IT, but it seems to help. Last night, I was working on some problems with third-hop WMI delegation, and I happened to look up and it was 4:00 in the morning. I said to myself, “Cool, my friends in Australia are awake.” So I exchanged a number of email messages with my Australian friends. In fact, Chris Bellee and Pete both had some great suggestions to help me with troubleshooting my problem. I also exchanged email with my good friend Jit; unfortunately, neither he nor Brent (one of my Tim Tam connections) is going to be at the TechReady conference I will be speaking at in Seattle in a few weeks. As a matter of a fact, I am speaking at a large number of events in the next few weeks: the Virtual PowerShell User group, the Central Ohio PowerShell Users Group, and SQL Saturday #80 in Wheeling West Virginia, in addition to TechReady. There are a lot of events. I use the Community page on the Script Center to keep track of where I will be and when. Lisa is doing a great job keeping this page up to date, and we are putting my commitments on the page as soon as I know them. 

In Saturday’s Weekend Scripter post, I talked about working with Event Tracing for Windows (ETW) logs. I discussed how to enable and disable the logs, and how to use the Get-WinEvent cmdlet to find and to read the trace. On Monday, I continued the ETW discussion by examining the datetime stamp that is generated for each event. On Tuesday, I explored parsing the message property of the WMI Activity Trace log. Yesterday, I talked about using Windows PowerShell to troubleshoot software installation. 

AS, I know I have been writing quite a bit recently about the importance of writing functions and not writing scripts, and today’s script is no exception. What I am going to do today is write a script. This means that what I am producing is pretty much limited to a specific scenario. This is really the way that advanced functions and modules are produced—they start out as a quick line of code that gets collected into a script and migrates to functions, advanced functions, and modules. In fact, nearly every function that is in my Local User Management module began as a quick script. The complete EnableLogDisableLogInstallSoftware.ps1 script is shown here.

EnableLogDisableLogInstallSoftware.ps1

$WmiLog = (Get-WinEvent -ListLog *wmi*trace* -force).logname

echo y | Wevtutil.exe sl $wmiLog /e:true

Invoke-WmiMethod -class win32_product -Name install `

    -ArgumentList @($true, $null, "\\hyperv1\data\HelloWorld.msi")

echo y | Wevtutil.exe sl $wmiLog /e:false

Get-WinEvent -LogName $wmiLog -Oldest 

AS, the first thing I do is find the exact name for the trace log with which I want to work. I use a wildcard character (*) to simplify typing and because I might not know the exact name of the log in the first place. Keep in mind, this wildcard character pattern resolves to the WMI Activity/Trace log on my Windows 7 Ultimate system. It is entirely possible that other software could create its own ETW trace log, and my wildcard character pattern might pick up those log files. You should therefore test the pattern to ensure that your pattern resolves to the log you wish to use. Identifying ETW logs and working with them is discussed in Saturday’s post.

$WmiLog = (Get-WinEvent -ListLog *wmi*trace* -force).logname 

The next line of code in the script combines several cool tricks, one really powerful technique, and an idea for future exploration. With all this going for it, let’s dive right in and show the code before discussing it:

echo y | Wevtutil.exe sl $wmiLog /e:true

I will admit the line of code does not look like much, but it is really powerful stuff. The first part, echo y, allows me to pass a y (for yes) to the prompt from the command. This technique will be discussed in two days in the July 16, 2011, blog post by Sean Kearney (a.k.a. Energized Tech).

The best way to understand the echo y thing is to see what happens without it. When running the wevtutil.exe command to enable a trace log, a prompt displays a warning that the command will clear the previous contents of the log. These types of prompts, common for lots of command-line utilities, play havoc with scripts. The command and associated prompt are shown here:

PS C:\Windows\system32> Wevtutil.exe sl $wmiLog /e:true

**** Warning: Enabling this type of log clears it.  Do you want to enable and

clear this log? [y/n]: 

By using the echo command (echo is an alias for the Write-Output cmdlet) and piping the results to the wevtutil command, I am able to respond to the prompt and to allow script execution to continue. This powerful technique permits the use of literally hundreds of legacy commands (these types of techniques and the importance of being able to use currently available legacy commands are the reason I invited Sean to write his Interact with the Legacy series of articles. The command wevtutil is extremely powerful and it is used to perform many more tasks than simply enabling or disabling event trace logs. The sl command is the set log command from wevtutil, and it does not have anything to do with an alias for the Set-Location cmdlet. It is important to note that in this context, Windows PowerShell is smart enough to distinguish the two, and is not expecting an alias to appear here. This fact greatly simplifies the syntax because if Windows PowerShell were not so smart, I would be required to encase the command inside quotation marks and have to invoke the expression. Or I might be required to escape the sl. The next thing that is pretty cool is the command is smart enough to interpret the value stored in the $wmiLog variable. This makes it easy to work with the command, and to automate it via Windows PowerShell.

On the next line in the script, I use the Invoke-WmiMethod cmdlet to call the install method from the Win32_Product WMI class. In general, I like to use the WMI class accelerator ([wmiclass]), but using the Invoke-WmiMethod cmdlet makes configuring advanced WMI options (such as using packet privacy, Kerberos authentication, and impersonation levels) much easier. The big problem with using the Invoke-WmiMethod cmdlet is the lack of useful examples. Even using the online switch from help (help Invoke-WmiMethod –online), does not unearth much additional detail. Most Windows PowerShell books simply repeat the same example from the online content.

There are several things to realize about using the Invoke-WmiMethod cmdlet. First, help states that the class parameter is used when calling a static method. This does not mean the method is discovered using the static switch from the Get-Member cmdlet, but rather that the method is not an instance method from WMI. An instance method from WMI is a method that is available from an instance of the class. For example, if I want to terminate a process, I have to use WMI to connect to a specific instance of a process. I cannot terminate a process without connecting to it first. By a similar token, if I want to uninstall software, I need to connect to an instance of the Win32_Product class. However, to install the software package, I do not connect to an instance (because Win32_Product represents installed software); instead, I use a static method from the class itself. Instance methods and static methods are detailed on MSDN. (By the way, if I want to use the Invoke-WmiMethod cmdlet to work with an instance method, I must provide the path to a specific instance of the class, which would generally involve using the key to the class. It does get complicated).

The name of the method is simple. It is the name of the method. I used a backtick (`) character for line continuation in the output. The command gets really long, and can be difficult to read. (When troubleshooting a command, the first thing I do is remove all backtick characters and place the command on a single line.)

The arguments are the next hurdle and are the most difficult portion of working with the command. The argumentlist parameter requires an array of arguments. I added the @() to force evaluation as an array, but it probably is not required. I think it does make the command a bit easier to understand. The thing that is really weird is that the ArgumentList parameter is supposed to accept arguments in the order required by the method. The order for Win32_Product install method is package location, options, and all users. This is even confirmed by using the Get-Member cmdlet as seen here.

PS C:\Windows\system32> [wmiclass]"Win32_product" | gm install

   TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Product

 

Name    MemberType Definition                                                                                                                  

----    ---------- ----------                                                                                                                   

Install Method     System.Management.ManagementBaseObject Install(System.String PackageLocation, System.String Options, System.Boolean AllUsers) 

Unfortunately, when using the Invoke-WmiMethod cmdlet, I had to supply the arguments as AllUsers, Options, and finally PackageLocation.

Invoke-WmiMethod -class win32_product -Name install `

    -ArgumentList @($true, $null, "\\hyperv1\data\HelloWorld.msi") 

After the software package installs, I use the wevtutil utility to disable the trace logging. As a last step, I use the Get-WinEvent cmdlet to display information from the newly created event log. The command to disable logging is essentially the same command to enable logging. The only change is to set the value of /e (for enable log) to false.

echo y | Wevtutil.exe sl $wmiLog /e:false

Get-WinEvent -LogName $wmiLog -Oldest

When I run the script, the return code from the install method is shown, followed by the newly created trace log entries. The script and associated output are shown in the following figure.

Image of script and associated output

AS, that is all there is to using automating logging. Troubleshooting Windows Week will continue tomorrow.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hello Ed,

    I never heard of the wevtutil and so I really can add something new to my tool box!

    Thanks, Klaus