Number5ix
asked on
How can I write a Windows Powershell script to search the Windows event logs for occurrences of a certain string?
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_ro uter_name" ))
{
$userLocationStart = $objItem.Message.IndexOf(" User") + 5
$userLocationFinish = $objItem.Message.IndexOf(" was granted") - 1
$userStr = $objItem.Message.SubString ($userLoca tionStart, $userLocationFinish - $userLocationStart)
$strVPNAccess = "$strVPNAccess $userStr - objItem.TimeWritten`r`n"
}
}
}
}
*** script end ***
Thanks in advance!
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
{
$userLocationStart = $objItem.Message.IndexOf("
$userLocationFinish = $objItem.Message.IndexOf("
$userStr = $objItem.Message.SubString
$strVPNAccess = "$strVPNAccess $userStr - objItem.TimeWritten`r`n"
}
}
}
}
*** script end ***
Thanks in advance!
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
- 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.
- Notice the use of the pipe to filter out the Type of messages we want.
ASKER
Great reply, thanks. I'll have to wait until Monday before I can try it though so I'll update the question then.
cool.. also if you post the "string" your parsing. Perhaps I can help with that.
ASKER
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.SubSt ring(6,2) + "/" `
+ $objItem.TimeWritten.SubSt ring(4,2) + "/" `
+ $objItem.TimeWritten.SubSt ring(0,4) + " " `
+ $objItem.TimeWritten.SubSt ring(8,2) + ":" `
+ $objItem.TimeWritten.SubSt ring(10,2) + ":" `
+ $objItem.TimeWritten.SubSt ring(12,2)
$userStr = $objItem.Message.SubString ($userLoca tionStart, $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.l ocal")
$mailer.port = 25
$msg = new-object Net.Mail.MailMessage("me@m e.com","me @me.com"," VPN Access Summary",$strVPNAccessEmai l)
$msg.IsBodyHTML = $true
$mailer.send($msg)
THANKS! :)
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("
$userLocationFinish = $objItem.Message.IndexOf("
if ($userLocationFinish -ge 5)
{
$timeWritten = $objItem.TimeWritten.SubSt
+ $objItem.TimeWritten.SubSt
+ $objItem.TimeWritten.SubSt
+ $objItem.TimeWritten.SubSt
+ $objItem.TimeWritten.SubSt
+ $objItem.TimeWritten.SubSt
$userStr = $objItem.Message.SubString
$userStr = $userStr.Trim()
$strVPNAccess += "<p class='content'>{0} - {1}</p>`r`n" -f $userStr,$timeWritten
}
}
}
$strVPNAccessEmail += "<html>`r`n`r`n<head>`r`n<
$mailer = new-object Net.Mail.SMTPclient("smtp.
$mailer.port = 25
$msg = new-object Net.Mail.MailMessage("me@m
$msg.IsBodyHTML = $true
$mailer.send($msg)
THANKS! :)
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]::ParseEx act($objIt em.TimeWri tten,Split (".")[0]," yyyyMMddHH mmss",$nul l)
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]::ParseEx
ASKER
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. :)
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