Solved

How can I write a Windows Powershell script to search the Windows event logs for occurrences of a certain string?

Posted on 2008-06-11
8
616 Views
Last Modified: 2012-08-14
Hi all,

I'm currently converting some old VB scripts to Windows Powershell.  The one I'm working on now looks at the event logs for a remote computer and searches the logs for all occurrences of a certain string then grabs information from the events when it finds a match.  My script's syntax looks ok but I keep getting an error saying "Quota violation" when I run the script.  Here's the script I'm using.  Can someone take a look at it and see if it looks ok?  The script is intended to be used to give back information regarding the time people connected to our Cisco VPN.  The server being searched is the IAS server for the Cisco VPN hence why I'm searching the Windows event logs for this stuff.

I'm totally open to the script being completely hacked to pieces if I'm doing this wrong.  The end result is that I want to look in the application log for a remote server for occurrences of a certain string then grab information from the events when a match is found (yes I know I'm repeating myself!).  The current script searches ALL the event logs - can it be restricted to the application log only?

*** script start ***

$strComputer = "server01.mydomain.local"

$colItems = get-wmiobject -class "Win32_NTLogEvent" -namespace "root\CIMV2" -computername $strComputer -credential "mydomain.local\myaccount"

foreach ($objItem in $colItems)
{
      if ($objItem.LogFile = "System")
      {
            if ($objItem.Message -ne $null)
            {
                  if ($objItem.Message.Contains("cisco_router_name"))
                  {
                        $userLocationStart = $objItem.Message.IndexOf("User") + 5
                        $userLocationFinish = $objItem.Message.IndexOf("was granted") - 1
                        $userStr = $objItem.Message.SubString($userLocationStart, $userLocationFinish - $userLocationStart)
                        $strVPNAccess = "$strVPNAccess $userStr - objItem.TimeWritten`r`n"
                  }
            }
      }            
}

*** script end ***

Thanks in advance!
0
Comment
Question by:Number5ix
  • 5
  • 3
8 Comments
 
LVL 18

Expert Comment

by:BSonPosh
Comment Utility
I can definately tweak your code, but I think the "Quota violation" is entirely different issue. Your code is a tad bloated, but it looks functional.

Some thoughts:
1) Use Get-Credential and store it in a variable to pass to Get-WMIOBject
$creds = Get-Credential
2) $objItem.LogFile = "System" : "=" is an assignment operator not a comparison. Use "-eq"
($objItem.LogFile -eq "System")
3) This "if ($objItem.Message -ne $null)" can be changed to "if ($objItem.Message)"
4) The biggest benefit to Powershell is the pipeline... live it, love it, use it.

I will post some more in a moment
0
 
LVL 18

Accepted Solution

by:
BSonPosh earned 500 total points
Comment Utility
Try this.. it should be quiet a bit faster.


$strComputer = "server01.mydomain.local"

$creds = Get-Credential

$strVPNAccess = @()
 

# Use a WMI filter to allow the Server to reduce the data sent back. Only return entries with Message you want

$Log = Get-WMIObject "Win32_NTLogEvent" -computername $strComputer -filter "LogFile='System'" -cred $creds | ?{$_.Message -match "cisco_router_name"}
 

foreach ($entry in $Log)

{

    $userLocationStart = $objItem.Message.IndexOf("User") + 5

    $userLocationFinish = $objItem.Message.IndexOf("was granted") - 1

    $userStr = $objItem.Message.SubString($userLocationStart, $userLocationFinish - $userLocationStart)

    $strVPNAccess += "{0} - {1}" -f $userStr,$entry.TimeWritten

}

Open in new window

0
 
LVL 18

Expert Comment

by:BSonPosh
Comment Utility
- Notice the use of the WMI Filter: This reduces what the Server sends back instead of client side parsing.
- Notice the use of the pipe to filter out the Type of messages we want.
0
 
LVL 3

Author Comment

by:Number5ix
Comment Utility
Great reply, thanks.  I'll have to wait until Monday before I can try it though so I'll update the question then.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 18

Expert Comment

by:BSonPosh
Comment Utility
cool.. also if you post the "string" your parsing. Perhaps I can help with that.
0
 
LVL 3

Author Comment

by:Number5ix
Comment Utility
Hi there BSonPosh,

I've had a hack at your answers above and, with a couple of modifications, it works beautifully, e.g. foreach ($entry in $Log) should be foreach ($objItem in $Log) because $objItem is referred to later, not $entry.  I also couldn't find a way of converting $objItem.TimeWritten to a nice human-readable format - that's why I ended up using all the SubString stuff below - is there a way of doing this quickly that you're aware of?  I've done heaps of .NET development outside of PS so feel free to throw in .NET stuff if you want.

However, the complete script as it stands now, with internal server names changed, is:

$strComputer = "myserver.mydomain.local"
$creds = Get-Credential
$strVPNAccess = @()
 
# Use a WMI filter to allow the Server to reduce the data sent back. Only return entries with Message you want
$Log = Get-WMIObject "Win32_NTLogEvent" -computername $strComputer -filter "LogFile='System'" -cred $creds | ?{$_.Message -match "cisco_router_name"}
 
foreach ($objItem in $Log)
{
      if ($objItem.Message)
      {
            $userLocationStart = $objItem.Message.IndexOf("User") + 5
            $userLocationFinish = $objItem.Message.IndexOf("was granted") - 1
            if ($userLocationFinish -ge 5)
            {
            
                  $timeWritten = $objItem.TimeWritten.SubString(6,2) + "/" `
                  + $objItem.TimeWritten.SubString(4,2) + "/" `
                  + $objItem.TimeWritten.SubString(0,4) + " " `
                  + $objItem.TimeWritten.SubString(8,2) + ":" `
                  + $objItem.TimeWritten.SubString(10,2) + ":" `
                  + $objItem.TimeWritten.SubString(12,2)
            
                  $userStr = $objItem.Message.SubString($userLocationStart, $userLocationFinish - $userLocationStart)
                  $userStr = $userStr.Trim()
                  $strVPNAccess += "<p class='content'>{0} - {1}</p>`r`n" -f $userStr,$timeWritten
                  
            }
    }
}

$strVPNAccessEmail += "<html>`r`n`r`n<head>`r`n<style type='text/css'>.title { font-family: 'Verdana'; font-size: 14px; } .content { font-family: 'Verdana'; font-size: 11px; }</style>`r`n</head>`r`n`r`n<body><p class='title'>VPN Access Summary</p>`r`n" + $strVPNAccess + "</body>`r`n`r`n</html>"

$mailer = new-object Net.Mail.SMTPclient("smtp.mydomain.local")
$mailer.port = 25
$msg = new-object Net.Mail.MailMessage("me@me.com","me@me.com","VPN Access Summary",$strVPNAccessEmail)
$msg.IsBodyHTML = $true
$mailer.send($msg)

THANKS!  :)
0
 
LVL 18

Expert Comment

by:BSonPosh
Comment Utility
The $entry thing was intential.. I am trying to get you away from vbscript syntaxed Powershell :)

For the time string... I am not sure this is easier, but it definately more useful

This will return a datetime object instead
[System.DateTime]::ParseExact($objItem.TimeWritten,Split(".")[0],"yyyyMMddHHmmss",$null)
0
 
LVL 3

Author Comment

by:Number5ix
Comment Utility
LOL yes I can see your point now re the $entry thing being intentional!  Thank you very much for your help though, it solved my PowerShell problem and is worth the 500 points & A grade rating.  :)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
This video Micro Tutorial explains how to clone a hard drive using a commercial software product for Windows systems called Casper from Future Systems Solutions (FSS). Cloning makes an exact, complete copy of one hard disk drive (HDD) onto another d…
Windows 8 came with a dramatically different user interface known as Metro. Notably missing from that interface was a Start button and Start Menu. Microsoft responded to negative user feedback of the Metro interface, bringing back the Start button a…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now