© Derek Schauland and Donald Jacobs 2016

Derek Schauland and Donald Jacobs, Troubleshooting Windows Server with PowerShell, 10.1007/978-1-4842-1851-8_2

2. Managing the Windows Event Log

Derek Schauland and Donald Jacobs2

(1)Greenville, Wisconsin, USA

(2)Appleton, Wisconsin, USA

Windows is a complex application, to say the least. Things happen that the user is aware of—for example, starting Microsoft Word—and things happen that the user may not be aware of, such as a privilege audit of a security access to a file on the C drive. In the latter case, the person sitting at the computer sees the folder open or an error about access being denied. The event log contains a record of these events to keep administrators informed about what actions are being taken on a computer.

In many cases, the logs will not be used to review the starting or stopping of Microsoft Word because this is fairly benign, but sometimes the timestamp captured to the log might be useful in figuring out why Word does not start. In this chapter, we examine how to get ahold of the events generated by Windows and other applications using PowerShell.

What Can Windows Capture?

Microsoft Windows captures more information about what is going on within a system than is likely to fit (nicely) within the pages of this book. Not only does it record things that are in error, but also things that might be a problem (warnings) and even service stops and starts (informational messages). There is a plethora of information captured to the event log.

As the Windows operating system evolves and new iterations are released, the items captured and the number of logs used to store this information continues to grow. In one of the later builds of Windows 10 (10240), there are five standard Windows logs, but there are countless more under the Applications and Services Logs folder. Most of these pertain to Windows internal applications and services and they are not used in general troubleshooting for the operating system, but it’s nice to know they exist.

In addition to these logs and the entries they contain, you can create logs and log entries for specific things you need to keep track of. We will look into that at the end of this chapter.

Accessing the Event Log Information

We know that PowerShell is the scope of this book—and there will be a fair amount of it coming up, first though, you should know where to look to find an event using the Event Viewer (eventvwr.msc) built-in tool. The reason for this is to show you what an event contains so that you can tailor PowerShell to access it and return just what you are expecting. This saves the hassle of combing through piles of output in the console to chase down the things that you need.

Note

PowerShell is a great tool, but it can be even greater when used to manipulate data that you already understand. Starting in the Event Viewer helps with that.

Figure 2-1 lists the details of an event, showing the time when the computer was shutdown. As you can see, there is the text description about the shutdown, but there is also the event id, log name, event source, and other useful information.

A371455_1_En_2_Fig1_HTML.jpg
Figure 2-1. A system shutdown event in the Event Viewer

Finding this information in the event log with PowerShell might look something like this:

Get-EventLog –LogName System | Where-Object {$_.Eventid –eq 1074}

You will notice that there are several events appearing and that they are all the same event—a shutdown. But which is the event found in Figure 2-1? From the bit of PowerShell used here, there is nothing that tells which is the precise event.

To get to the specific event shown, we need to give PowerShell a bit more information; but getting there is certainly possible.

Get-EventLog

When working in PowerShell, it is often times useful to start with broad results and work your way toward the specific, unless you know exactly what you are after right up front. For example, you might chase down information about an Active Directory computer object by specific name because you know you want to work with Engineering-PC, but in the case of an event log, working your way toward the specific result might be more useful. In addition to getting more familiar with PowerShell and the event log, you might come across additional information that serves your purpose and you can make a note to collect for later use.

We find PowerShell to be the land of opportunity when it comes to learning the tools and syntax; getting in there and doing it or using the shell is very helpful.

Now that you have seen the event log in the Event Viewer and in PowerShell, we can consider the information that we are going to collect using PowerShell. To do this, a scenario might work best because we have useful information to collect and for which to produce a report.

Scenario

As a systems administrator, Geoff gets a fair amount of questions about applications and servers within his environment. His boss generally asks him about the performance statistics of the E-mail server every day. Geoff is used to the questions from his boss, but he still finds himself chasing down the data.

He is looking for a way to produce a summary list of information regarding the E-mail server and wants to see information about this server from the event log. He has been reading a lot about PowerShell online and wonders if it will get him the information that his boss regularly requests.

That is the goal of this chapter: to find an easier method of getting the information requested of Geoff. The data can be reviewed as is, but it should also be placed in a report that can be quickly reviewed when Geoff’s boss inquires. Creating a report file allows you to email the information to anyone who might find it useful, such as Geoff’s boss and fellow team members.

Finding Information with PowerShell

Two cmdlets come to mind when considering ways to get things out of the Windows event log:

  • Get-EventLog

  • Get-WinEvent

The Get-EventLog cmdlet provides a list of information from the specified log that meets the specified criteria. As shown in Figure 2-2, the output is a list of the events requested by the following command:

A371455_1_En_2_Fig2_HTML.jpg
Figure 2-2. Capturing the newest 10 system logs
Get-EventLog -LogName System -Newest 10

We chose -newest 10 here to keep the returned output as short as possible. If you leave it out and run Get-EventLog -LogName System, you should see quite a bit of data scroll past.

Get-EventLog | Get-Member returns the properties for Get-EventLog as output:

  • Category

  • CategoryNumber

  • Container

  • Data

  • Entrytype

  • Index

  • InstanceID

  • MachineName

  • Message

  • ReplacementStrings

  • Site

  • Source

  • TimeGenerated

  • Timewritten

  • UserName

  • EventID

When the command is executed with no formatting parameters, PowerShell displays the output as a table if there are fewer than five parameter values returned for an item. If there are five or more values returned, the default output is a list. In this case, there are 11 items, so a table of results is shown.

The items shown are what were deemed most useful by the creators of the cmdlet, but you can pull out any information available, either in addition to or instead of what is listed by default.

By default, when running Get-EventLog -LogName System -Newest 10, we got a table showing Index, Time, EventType, Source, InstanceID, and Message. These are pretty good to start with, but what if the event occurred but it was not written immediately, or if you wanted to know the categoryNumber instead of the InstanceID?

To do that, you pipe the results of your original cmdlet to the Select-Object cmdlet and change the values returned.

Get-EventLog -LogName System -Newest 10 | Select-Object -Property Index, TimeGenerated, TimeWritten, EventType, Source, CategoryNumber, Message

This builds a table showing the properties you asked for in the select portion of the statement shown in Figure 2-3.

A371455_1_En_2_Fig3_HTML.jpg
Figure 2-3. Selecting different properties for event log entries

Get-WinEvent

Get-WinEvent is similar to Get-EventLog, but supports different properties (or names the properties differently with the same information). In addition, Get-WinEvent does seem to perform significantly faster when hitting remote systems.

Note

The -FilterHashTable parameter filters the cmdlet results by value pairs in a hash table. Supplying the names and their associated values speeds up the filtering process. In addition to the filtering being improved, some of the typing needed is reduced (or at least moved). This parameter only works on Windows 7 and Server 2008R2 and later versions of Windows operating systems. You have to use the -FilterXml parameter on older Windows versions.

In addition, Get-WinEvent manages the XML formatting of the event logs of Windows Vista and newer releases of Windows. Get-EventLog is great for simple and quick local queries, but Get-WinEvent seems much more responsive when used on remote computers.

The simple act of telling PowerShell that you would like specific properties returned is just one of the ways that PowerShell can help you find and analyze information.

Being able to get to the event log and pull back information helps you with creating reports that can show at a glance what is going on in the machines’ event logs.

Why Choose One cmdlet over Another?

Sometimes the choice of which cmdlet to use depends on what properties you are going to retrieve. Other times, the parameters accepted by the cmdlet might influence your choice; for example, many cmdlets in PowerShell support the -ComputerName parameter, which allows them to be executed against remote computers. Some cmdlets do not support this parameter and so other methods need to be employed to use them on other systems. Performance might be another reason to choose one cmdlet over another. Another thing to consider is backward compatibility.

Remember, there is often more than one way to accomplish a particular task in PowerShell. The method that works best for you and is easiest to understand is the best place to start. Building on what you learn is part of the fun of working with PowerShell.

You can see which parameters a cmdlet supports by reviewing the cmdlet’s help. Entering Get-Help Get-EventLog returns one of two things:

  • The stub help for the cmdlet, which is very sparse and may appear to be missing information. This means that your help needs to be updated. Running Update-Help cmdlet in an elevated shell downloads the latest help from Microsoft.

  • The basic help for the cmdlet; it contains an overview of what the cmdlet can do and the syntax that might be used. Adding the -Detailed, -Full, or -Example parameters to the Get-Help line shows more information about the cmdlet.

Getting Logs from Remote Computers

As mentioned earlier, sometimes you need to gather log information from remote computers. Since it is unlikely that you are using a server to do your job (and you shouldn’t be), you want to connect to one or more servers to retrieve information and produce some kind of output that others in the organization can understand. If people have trouble gleaning anything from the report, they will not use it and will continue to ask for assistance. Until now, the focus has been generally about the event log and how a systems administrator accesses a log for information, which is great if all the managed systems are local and there is no need to work with computers in far-flung locations. This section gets you started on access to event information on remote computers.

To execute a cmdlet against a remote computer, you do not need to remote desktop into the system or physically connect to it; typically, you can use the -ComputerName parameter of the cmdlet you want to run. This passes the cmdlet to the specified computer and retrieves the information from that system, rather than your local computer. For example, if we needed to get the system log information from a system named Server01, the following PowerShell command gets us what we need:

Get-EventLog –ComputerName Server01 –LogName System

When executed, that command connects to Server01 and retrieves the system event log, similarly to the previous command run against the local system.

You could also use Get-WinEvent -ComputerName Server01 -LogName System to access the remote computer’s log information. Comparing the performance of each using Measure-Command shows quite a performance improvement by Get-WinEvent on remote computers, but your mileage may vary with regard to performance testing.

The following uses Get-WinEvent and Get-EventLog while measuring performance:

Measure-Command {Get-WinEvent -LogName Application}: 1 second 510 milliseconds
Measure-Command {Get-EventLog -LogName Application}: 0 seconds 310 milliseconds

Both of these results were taken from the local event log. On a remote machine, the results were as follows:

Measure-Command {Get-WinEvent -ComputerName remote -LogName Application}: 22 seconds 118 milliseconds
Measure-Command {Get-EventLog -ComputerName remote -LogName Application}: 44 seconds 718 milliseconds

Now that the information has been collected, let’s do something useful with the data.

Shaping the Gathered Information

Raw event log data pulled back to PowerShell is not terribly useful, since it just scrolls past as fast as it is returned. With modifications, like selecting certain events or a set number of items, this may change somewhat because only the information specifically asked for is returned. Looking at five records in the PowerShell console is not so bad, but five thousand might be more work than its worth.

Now that we know how to get the information out of the event log, we can sculpt the results to display them in a friendlier format. PowerShell has cmdlets for formatting that can help with this, aside from just Format-List or Format-Table.

Returning to our previous example, we can build a formatted file that Geoff can use to review information found in the event logs of various machines within his organization. Because there was no formatting guideline specified, the data can (and should) be as flexible as possible. Providing output options for the data allows the individuals using it to work with it in a variety of ways.

Comma-Separated Values

Many applications can pull information from comma-separated values (CSV) files to improve processing and allow further data analysis to happen. If a database application needs to have information quickly imported for new products, a CSV file can list all of these products and then get imported to avoid lengthy inserts or updates to the system.

PowerShell is good at CSV. It can both generate and accept input from a CSV file, making this a great place to start.

In the case of event log reporting, a CSV can provide an input file for a database or other applications that can work with event log data. It is also fairly simple to create.

You start out by gathering the information that you need from the event log:

$systemlog = Get-EventLog –LogName System –Oldest 10

Notice that the values were put into the systemlog variable. This was done only to park the data for the time being; it is not required for a CSV file to be created.

With the data in a variable, it can be piped to the select-object cmdlet to choose the properties desired; from there, it can be turned into a CSV by piping the results to another cmdlet: Export-csv.

To step through the process, take the contents of the systemlog variable and pipe it to Select-Object.

$systemlog | Select-Object -Property InstanceId, Message, Source, TimeGenerated

Figure 2-4 shows the output of this command.

A371455_1_En_2_Fig4_HTML.jpg
Figure 2-4. Specifically selected properties from the event log

From here, the CSV can be generated using this selection, as you can see in Figure 2-5.

A371455_1_En_2_Fig5_HTML.jpg
Figure 2-5. A CSV file created from event log data
$systemlog | Select-Object -Property InstanceId, Message, Source, TimeGenerated | Export-Csv -Path "c:
eportssystemlog.csv"

You may notice something odd at the top of the CSV file: a message about TYPE shown in the first line of the file. This is object information about the CSV; it really doesn’t affect the data in the CSV at all. It is not something that has to be placed to help others determine the type of data that was exported. If you import the CSV file back into PowerShell, that tells PowerShell how to interpret that data. To remove that line of extra information, you can use the -NoTypeInformation switch on the Export-Csv cmdlet:

$systemlog | Select-Object -Property InstanceId, Message, Source, TimeGenerated | Export-Csv -Path "c:
eportssystemlog.csv" -NoTypeInformation

This suppresses that line from being added. If you re-execute the command with the new switch added, you may see an error in the PowerShell console. If the file is open, it cannot be rewritten by Export-Csv; closing the existing file and executing the command solves the problem.

The new, cleaner CSV file is shown in Figure 2-6.

A371455_1_En_2_Fig6_HTML.jpg
Figure 2-6. A CSV file without type information

Now we have generated a CSV file with the newest 10 entries in the system log. It can be opened in Notepad or in Microsoft Excel for viewing, or it can be imported into something else for processing.

Creating an HTML Report

Comma Separated Values files are nice and certainly have their usefulness, but when providing a report to management, they aren’t very appealing. With HTML output and formatting for things like SQL Reporting Services gaining popularity, people are well used to seeing data in a web-based format. They generally also find navigating this type of information simple and straightforward.

PowerShell can do this too, almost as easily as creating a CSV file.

Note

Creating HTML output is as simple as creating CSV files; however, with a bit of tweaking, the style and presentation of HTML data generated by PowerShell can be quite improved.

Remember, the systemlog variable still has the raw objects returned from the system log in the event log. This simplifies the process, or at least takes the redundancy out. This variable is stored in memory until the current PowerShell console closes. Once you close the current PowerShell console, all the variables used in that session are removed from memory. In addition, a variable can be overwritten with a new value, or simply removed by using Remove-Variable <variablename> to clear the contents.

Note

You can store variables, functions, and other frequently used things in your PowerShell profile, but configuring profiles is beyond the scope of this book.

What Else Can Be Done with this Information?

Once the output formatting is done (in our case as a CSV file or an HTML file), the next step is to either use the data in another application or script in PowerShell (in the case of the CSV) or dress up the data and push it out to HTML to be shared with others. This section goes through other types of formatting for information gathered from the event log, keeping in mind that much of the information gathered will need to be shared with colleagues.

Formatting HTML for Readability

Sending objects to an HTML file puts a basic formatting together that is very usable, but adding some formatting to alternate the row colors or put a more appropriate header and title on the document can bring some level of professional appearance to the document.

To put some formatting together for the file, we can define the header data as a Here-String variable. Then fill it full of all kinds of HTML header information, as shown here:

$htmlformat = @"
<style>
Table {border-width: 1px; border-style: solid; border-color: black;}
TH {border-width: 1px; padding: 3px; border-style: solid;}
TR:nth-child(even) {background: #CCC}
TR:nth-child(odd) {background: #FFF}
</style>
"@
Note

The Here-String in PowerShell is a way to include multiple lines of text “as is” within a single variable, without the need for line breaks, carriage returns, or other weird formatting. Using Here Strings allows you to pass this block of text as a variable to other code—plain and simple. Just include @" "@ as a wrapper around the text to include.

This way, the HTML file can be formatted using the stylesheet elements specified by PowerShell; the resulting output just includeS the styles.

Next up, since the event log data is already contained in a variable called systemlog, we can work on passing this data around a bit and converting it to HTML.

$HTMLformatted = $systemlog | ConvertTo-Html –fragment | Out-String

This set of code passes the event log information captured to the ConvertTo-Html cmdlet and produces a fragment of HTML, which is then converted to a formatted string and passed to a function (coming next) that prepares the formatting and other things to be displayed. Essentially, it applies CSS styling to the table and alternates the row color for display.

HTML Formatting with a Function

The function below can be used (and reused) to process the information collected across systems and output the data in a very useful HTML format for use at a later time or inclusion in an email.

Function Get-TSHtmlReport
{
        [CmdletBinding()]
        param (
                [Parameter(Mandatory = $true)]
                [ValidateSet("System", "Application", "Security")]
                [string]$LogName,
                [Parameter(Mandatory = $true)]
                [string]$SaveFile
        )
        Begin
        {
                $htmlformat = @"
<style>
Table {border-width: 1px; border-style: solid; border-color: black;}
TH {border-width: 1px; padding: 3px; border-style: solid;}
TR:nth-child(even) {background: #CCC}
TR:nth-child(odd) {background: #FFF}
</style>
"@
                $HTMLhead += "<H1>Event log information from $($env:COMPUTERNAME)</H1>"
                $HTMLhead += "<H2>Log name: $($LogName)</H2>"
        }
        Process
        {
                $events = Get-EventLog -LogName $LogName -Newest 50 | Select-Object -Property Index, EventID, Message
        }
        End
        {
                $events | ConvertTo-Html -head $HTMLhead -body $htmlformat | Out-File -FilePath $SaveFile
        }
}


}

The information passed to the formatting function is manipulated as a string, HTML, or XML data that is presented in a well-formatted HTML table.

We are not quite done yet; the body of the document, the titles, and other things still need some preparation. Remember, the preceding function just handles the table rows.

With the formatting completed, the data is ready to be pushed out to an actual file. Simply passing the entire bit of information out to the file will do nicely.

Please note that this is a bit more than is minimally needed to get things out to an HTML file; you can simply run the data out to a file:

$systemlog | Select-Object Eventid, Message | Convertto-Html | Out-File "c:
eportsunformatted-system-log.html"                                                                      

Both of these open in a browser and display the contents of the system log; however, the function includes formatting to draw the attention of the reader to the table.

Figures 2-7 and 2-8 show the unformatted and formatted HTML files, respectively.

A371455_1_En_2_Fig7_HTML.jpg
Figure 2-7. An unformatted HTML file
A371455_1_En_2_Fig8_HTML.jpg
Figure 2-8. A formatted HTML file
Note

A quick note about formatting and other general PowerShell tricks. This book focuses on troubleshooting with PowerShell, and although some other functions that help with formatting are shown, these are not the focus of the book. The authors may use these in examples and code samples to help call attention to certain information. These things may also help when using these reports to present information to others.

With the HTML file (formatted or unformatted) created, we can do all kinds of interesting things with it. If Geoff’s boss wants to see the report first thing every morning, that can be arranged as well. By using another cmdlet and an internal email server (or even a Gmail account, if needed), a report can be attached to an email and delivered to the boss every morning.

Note

You could use scheduled tasks to automate some of the things that we are doing here. We touch on scheduling tasks later in this book.

Recall that we were going to get the newest 10 items from the system log on the specified computer and return it for analysis. Once returned to a variable in PowerShell, we formatted it as a CSV and a formatted HTML file. Then we emailed the file to the boss at 5:15 every morning (working overnight may or may not make Geoff appear industrious).

If we put the whole thing together in a script, it might look like the following sample:

        Function Get-TSHtmlReport
{
        [CmdletBinding()]
        param (
                [Parameter(Mandatory = $true)]
                [ValidateSet("System", "Application", "Security")]
                [string]$LogName,
                [Parameter(Mandatory = $true)]
                [string]$SaveFile
        )
        Begin
        {
                $htmlformat = @"
<style>
Table {border-width: 1px; border-style: solid; border-color: black;}
TH {border-width: 1px; padding: 3px; border-style: solid;}
TR:nth-child(even) {background: #CCC}
TR:nth-child(odd) {background: #FFF}
</style>
"@
                $HTMLhead += "<H1>Event log information from $($env:COMPUTERNAME)</H1>"
                $HTMLhead += "<H2>Log name: $($LogName)</H2>"
        }
        Process
        {
                $events = Get-EventLog -LogName $LogName -Newest 50 | Select-Object -Property Index, EventID, Message
        }
        End
        {
                $events | ConvertTo-Html -head $HTMLhead -body $htmlformat | Out-File -FilePath $SaveFile
        }
}
Get-TSHtmlReport -LogName System -SaveFile C:Reports est2.html
Send-mailmessage –to [email protected], [email protected] –from [email protected] –smtpserver smtp.company.com –subject "Events Report" –body "Attached is the most recent events report" –attachment "c: eports est2.html"

The function outputs a file on the desktop following that the Send-MailMessage cmdlet sends the generated file to Geoff and his boss. This is fairly straightforward and extremely useful.

Can PowerShell Use the Event Log to Store Information?

So far, this chapter has mainly covered getting information for analysis out of the event log on Windows systems, but we should also look at putting data into the event log. PowerShell can certainly do that, and in some cases, this might be the best place to park information related to an application or process until you need it for later analysis.

To put information into an event log, you can use the following cmdlet:

Write-EventLog -LogName Application -Source "My Application" –EventID 1000 –Message "This is the message being logged"

As you will notice, there is an error when running this cmdlet. This happens because "My Application" is not a valid source that exists in the Application event log. This is fairly easy to fix: simply adding it as a valid source in the chosen log solves the problem.

New-EventLog -LogName Application -Source "My Application"

Adding the "My Application" source to the Application log allows events to be added to the log.

Putting data into the event log carries as much difficulty as getting it out. Sure, you need to pay attention to tags, sources, and log names, but that is true on the way out as well. It helps to ensure that you can find the data later when it is needed again.

Another advantage to logging information to the event log is that other administrators may use that as a starting point for their troubleshooting. If information from your PowerShell adventures is tracked there as well (with details and contact information), then the issues that may arise with scripts will be easy to locate and correct.

Even though PowerShell is capable of writing to the event log, like everything else, there is a place for doing so. If we write log information about a Windows process or application, we put it in the log; many times, this is a separate sublog of the application or item that we’re dealing with. If logging the action(s) of a PowerShell script, however, a simple folder of text files works. This does a few things:

  • Keeps the PowerShell script logs out of the way

  • Allows them to be cleaned up more frequently than flushing an event log

  • Keeps things simple

Could you put it in the event log? Sure, but if scripting against a dozen computers, there should be a central location for the logs that is easily remembered and shared with other staff members. It also ensures a central location for things related to scripting.

Note

Centralized event log storage is possible and it can be configured fairly quickly. See http://blogs.technet.com/b/wincat/archive/2008/08/11/quick-and-dirty-large-scale-eventing-for-windows.aspx for more information on this topic.

Keeping script logs out of the event logs feels cleaner, especially since script logs are only occasionally used for troubleshooting, and scripts are generally not always logged.

If your organization has a good grasp on centrally managed event logs (or they require such tracking), by all means, use the event log for script data storage.

With the use of Get-WinEvent, Get-EventLog, and Write-EventLog, the administrator has a decent arsenal of tools to help troubleshoot Windows Server or workstation issues that may come up. PowerShell’s strengths include its remoting capabilities and its willingness to manipulate information for use by other PowerShell scripts, functions, or modules, and by other applications or employees within the organization.

Summary

In this chapter, our focus was the event log. We looked at some of the ways that PowerShell helps access information in the logs. In addition, we touched on certain constructs like filter hash tables, which provide another way of using PowerShell’s features.

In the next chapter, we will look at gathering and reporting system information from a Windows system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.182.96