Hey, Scripting Guy! Question

Hey, Scripting Guy! I love the Windows Firewall. I think it is really cool. The fact that it is a low-maintenance tool is sweet, but every once in a while, I would like to look over the log files and see what is going on. In particularly, I want to know about what packets are being dropped by the firewall. Can you help me?

- DC

SpacerHey, Scripting Guy! Answer

Hi DC,

Did you ever have someone try to help you out, and in the end they caused you more work than if they hadn’t “helped”? Windows Firewall is kind of like that helpful friend. It tries to hide some of the details. Luckily, all you need to do is remember that you first need to enable Windows Firewall logging. This is seen in the image just below.

This week we are focusing on regular expressions. There are some VBScript examples in the Script Center. Here is a good introduction from the 2008 Winter Scripting Games (by the way, in the 2009 Summer Scripting Games, I can pretty much guarantee you will need to be able to do something with regular expressions for one of the events). The Regex .NET Framework class from the System.Text.RegularExpressions namespace is documented on MSDN. This is one of the main classes we use in Windows PowerShell when working with regular expressions. You also will find some information about regular expressions in the Microsoft Press book, Windows PowerShell Scripting Guide. Here is a very good article about regular expression use in VBScript. In this week's articles, we are using Windows PowerShell for our samples. Please refer to the Windows PowerShell Scripting Hub for more information about this exciting new technology.

Image of enabling Windows Firewall logging

 

As soon as logging is turned on, you can use a script such as SearchFirewallLogForDroppedPackets.ps1 to search the Windows Firewall log. One thing you will need to do is make sure the path of the Windows Firewall log points to the correct location. The location for Windows 7, Windows Vista, and Windows XP are listed here:

Windows 7: "C:\Windows\System32\LogFiles\Firewall\pfirewall.log"

Windows Vista: "C:\Windows\System32\Logfiles\Firewall\Firewall.log"

Windows XP: "C:\Windows\pfirewall.log"

You can, of course, customize this and move the logs to another location (however, we do not recommend this because of the importance of maintaining proper security settings to protect the log files). After you set the correct path for your particular firewall you run the script. The regular expression pattern is set up to display propped UDP packets. The SearchFirewallLogForDroppedPackets.ps1 script is shown here:

SearchFirewallLogForDroppedPackets.ps1

Function New-TempFile
{
  [io.path]::GetTempFileName()
} #end Get-TempFile

Function Search-Logfile 
{
 Param(
       $logFIle,
       $pattern
      )
 Get-Content -path $logFile |
 Select-String  -pattern $pattern
} #end Search-LogFile

Function Show-Output 
{ 
 Notepad $TempFile | Out-Null 
 Remove-Item -path $TempFile
} #end Show-Output

# *** Entry to script ***

$log = "C:\Windows\pfirewall.log"
$pattern = "DROP\sUDP\s\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

Search-LogFile -log $log -pattern $pattern |
Out-File -filepath (New-TempFile | Tee-Object -variable TempFile) | 
Show-Output

You do not have to write your script in the way we have done here. You could write it like a lot of people who write VBScripts do and just have one line of code after another. There are several reasons for writing the script by using functions. For one thing, the code is much easier to read because the function names are self explanatory, and therefore we know the New-TempFile creates a temporary file. Also, the three functions are reusable, which means we can easily use them in creating other scripts. In Windows PowerShell 2.0, these functions can go into a module that you import into your current script session, making them immediately available. The names are important because in Windows PowerShell 2.0 the verbs will be checked against an allowed list of verbs, and a message will be displayed if they do not comply with standards.

The first thing we want to do is to create a function named Get-TempFile. This function is used to create a temporary file with a temporary name. The advantage of using a temporary file with a temporary name in a temporary location is that we do not need to worry about making up a file name or worrying about file locations. All computers have a temporary file directory. To create the Get-TempFile function, we use the Function keyword, as shown here.

Function Get-TempFile
{

Inside the function, we have a single command. This command uses the static method Get-TempFileName from the system.io.path .NET Framework class. A static method is one that is always available to us. We can find static methods in any .NET Framework class by using the Get-Member cmdlet as seen here:

PS C:\> [io.path] | Get-Member -membertype method -static


   TypeName: System.IO.Path

Name                        MemberType Definition
----                        ---------- ----------
ChangeExtension             Method     static System.String ChangeExtension(...
Combine                     Method     static System.String Combine(String p...
Equals                      Method     static System.Boolean Equals(Object o...
GetDirectoryName            Method     static System.String GetDirectoryName...
GetExtension                Method     static System.String GetExtension(Str...
GetFileName                 Method     static System.String GetFileName(Stri...
GetFileNameWithoutExtension Method     static System.String GetFileNameWitho...
GetFullPath                 Method     static System.String GetFullPath(Stri...
GetInvalidFileNameChars     Method     static System.Char[] GetInvalidFileNa...
GetInvalidPathChars         Method     static System.Char[] GetInvalidPathCh...
GetPathRoot                 Method     static System.String GetPathRoot(Stri...
GetRandomFileName           Method     static System.String GetRandomFileName()
GetTempFileName             Method     static System.String GetTempFileName()
GetTempPath                 Method     static System.String GetTempPath()
HasExtension                Method     static System.Boolean HasExtension(St...
IsPathRooted                Method     static System.Boolean IsPathRooted(St...
ReferenceEquals             Method     static System.Boolean ReferenceEquals...

If you do not want to do so much typing, you can use a shorter command by using the gm alias for Get-Member and only typing the first letter of each parameter. You can also use a wild card for the membertype method. This is seen here:

PS C:\> [io.path] | gm -m m* –s

You can see from the listing of static methods that the path .NET Framework class can do quite a bit for us. The cool thing about the GetTempFileName method is that in addition to creating a temporary file name in the temporary directory, it also creates the temporary file for us to use. To do the same thing in VBScript would require several lines of code, which is seen here in a script from the Microsoft Press book, Microsoft VBScript Step By Step:

FunTempFile.vbs

'==========================================================================
'
' NAME: FunTempFile.vbs
'
' AUTHOR: ed wilson , mred
' DATE  : 4/6/2006
'
' COMMENT: <FunTempFile function.>
'1.Uses two methods from File system object: getSpecialFolder, and getTempName
'2.Builds up a path to the temporary folder  and temporary file. You can use
'3.this directly as as seen here, or can use the path THEN create as seen In
'4.CreateTempFileNameAndOpenInNotepad.vbs MSPRess VBScript Step by Step ch 6 
'==========================================================================
Option Explicit 
'On Error Resume Next
Dim objFSO 'the fileSystemObject
Dim objFile 'File object


Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.createTextFIle(funTempFile(objFSO))


' *** function below *****
Function FunTempFile(objFSO)'Creates temp folder, and temp file name
Dim objfolder 'temporary folder object
Dim  strName'Temporary file name

Const TemporaryFolder = 2'File system object constant value

Set objfolder = objfso.GetSpecialFolder(TemporaryFolder)
   strName = objfso.GetTempName
   strName = objfolder & "\" & strName   
  FunTempFile = strName  
End Function

On the other hand, the Windows PowerShell command that creates a temporary file name in the temporary directory, and then creates the file is seen here:

  [io.path]::GetTempFileName()
} #end Get-TempFile

After we are done with the Get-TempFile function, we create another function named Search-LogFile:

Function Search-LogFile 
{

Inside the function, we define two parameters. Using the Param statement inside the code block of the function is a good way to create input parameters because in Windows PowerShell 2.0, there are additional parameter modifiers we can use to do things such as make the parameter mandatory. The two parameters we create are the –logfile and the –pattern parameters. The –logfile parameter is used to hold the path of the Windows Firewall log, and the –pattern parameter is used to hold the regular expression pattern we wish to use to parse the log. This is shown  here:

 Param(
       $logFile,
       $pattern
      )

We now use the Get-Content cmdlet to read the content of the log file. In Monday’s “Hey, Scripting Guy!” article we talked about using the Select-String cmdlet to read and parse a text file all in one step. The Windows Firewall log file is always in use, so Select-String was not able to open and read the file. However, on my computer, Get-Content was able to perform this bit of magic. So we use Get-Content to read the content of the file, and stream it across the pipeline to the Select-String cmdlet. This is seen here:

 Get-Content -path $logFile |
 Select-String -pattern $pattern
} #end Search-LogFile

The Show-Output function uses Notepad to open the temporary file and display the results. An example of this is seen here:

Image of using Notepad to display the temporary file

 

We use the Function keyword to create the Show-Output  function:

Function Show-Output 
{ 

The first thing we do is feed the path of the temporary file stored in the $TempFile variable to Notepad. We then use a trick to halt execution of the script by pipelining the command to the Out-Null cmdlet. When we close Notepad, the script continues and calls the Remote-Item cmdlet to delete the temporary file. This is shown here:

 Notepad $TempFile | Out-Null 
 Remove-Item -path $TempFile
} #end Show-Output

Now we get to the entry point of the script. The first thing we do is assign a path to the $log variable that points to the Windows Firewall log file. This is seen here.

$log = "C:\Windows\pfirewall.log"

The pattern we use specifies the word DROP followed by any white space and the word UDP, followed by one to three numbers separated by a period and more numbers and periods. This is seen here:

$pattern = "DROP\sUDP\s\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

We first call the Search-LogFile function and pass in the path of the Windows Firewall log that we have held in the $log variable. We then pass in our dropped packet regular expression pattern that we have stored in the $pattern variable. We then pipeline the results from the Search-LogFile function to the next command. This is shown here:

Search-LogFile -log $log -pattern $pattern |

The next command is pretty cool. The first thing we do is call the Out-File cmdlet. The Out-File needs the path of the temporary file. But at this point, the temporary file has not been created. It gets created by calling the New-TempFile function. It is common in situations such as this to store the pointer to the temporary file in a variable and give that variable to the Out-File cmdlet. We do not want to use an intermediate variable, however, so we pipeline the returned fileinfo object to the Tee-Object cmdlet. The cool thing is that the Tee-Object lets us split the output. On the one hand, we are passing my temporary file to the Out-File cmdlet. On the other hand, we need to be able to pass the temporary file with its contents to the Show-Output function. This is the beauty of the Tee-Output cmdlet—it lets us do two things at once. We pipeline the results to the Show-Output function:

Out-File -filepath (New-TempFile | Tee-Object -variable TempFile) | 
Show-Output

Well, DC, that is it for parsing the Windows Firewall log. Obviously, we can use the same technique to parse any of the hundreds of other text log files in Windows. The functions we created today can be employed for other uses in other scripts because they are pretty much self-contained. Take care, and we will see you tomorrow as we continue regular expression week. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys