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
636 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
8 Comments
 
LVL 18

Expert Comment

by:BSonPosh
ID: 21770014
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
ID: 21770307
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
ID: 21770329
- 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Author Comment

by:Number5ix
ID: 21777121
Great reply, thanks.  I'll have to wait until Monday before I can try it though so I'll update the question then.
0
 
LVL 18

Expert Comment

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

Author Comment

by:Number5ix
ID: 21790397
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
ID: 21793779
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
ID: 21797936
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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
When you upgrade from Windows 8 to 8.1 or to Windows 10 or if you are like me you are on the Insider Program you may find yourself with many 450MB recovery partitions.  With a traditional disk that may not be a problem but with relatively smaller SS…
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…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

733 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