Archive for the ‘Powershell’ Category.

Powershell List KB Articles

During the course of my work today, troubleshooting a particularly sluggish application, I was investigating whether some DCOM errors in the Event Log had any impact on things.  One thing I have always found frustrating when doing this research, is that Microsoft will sometimes refer to their MS-05-051 Security Bulletin nomenclature, instead of the KB article that gets referred to when that bulletin in applied.

Moaning aside, I give a script below that will display if a particular KB is installed on a machine.

Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* |
 where-object {$_.DisplayName -like “*KB963707*”} |
   Format-Table DisplayName, Publisher

The above will display an entry if the string matches, so you could get more than one result, or none at all.  If you want to pull back all KB’s installed, just modify the query like so:

HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* |
 where-object {$_.DisplayName -like “*KB*”} |
   Format-Table DisplayName, Publisher

Proactive Monitoring on the Cheap II

Sometimes it just is not convenient to pull back for particular events.  In the previous post I find I would much prefer the approach to have been having an exclusion list, rather than inclusion list of eventIDs to monitor.

While I work on that, I want to share the script I use to do this job, for a quick sneak peak at event logs across the network.  You can easily glean from the other scripts to have this read in a list of computers if you want, but I tend to use this while troubleshooting a single machine.  Then I’ll run multiple tabs in the powershell GUI for each computer.

## http://blog.getbusinessconfident.com
## PowerShell script to list the eventlogs on another computer
##
##The below is useful mostly for ad-hoc diagnostics or reviewing for a particular problem and whether it has recurred

$Log = “Application”
$Computer =”computerHostName”
$ID = “12345
$Type = “Error”

##The above are your standard Event Viewer attributes, to choose the system log, replace the word Application
##To view Warnings or Information, replace the word Error
$Objlog = New-Object system.diagnostics.eventLog($Log, $Computer)
#$Objlog = $Objlog | Where-object { $_.EntryType -like $Type }
#$Objlog.entries | select -last 5000

$result = $Objlog.entries | where { $_.EntryType -like “[$Type]*” } | select -last 20 | out-string
## On the above, you can amend the ‘select -last 20 to whichever number of entries you would like to pull back

write-host $result

Proactive Monitoring on the Cheap

–update, I have included a way that differentiates between XP and newer OS versions.  This was causing some problems with some events getting missed.

Today I have started to share out some of my powershell scripts I’ve had knocking around for a while, on Microsoft’s Script Repository.  While I’m an enthusiast, it’s not the bread and butter of my daily work, so I appreciate my code comments and such can be on the scruffy side.

During this, I discovered a nifty script by  mck74 & mjolinor that monitors MS Windows event logs for particular events across a network of computers.  Even better, you can set the script to run every x minutes, and streamline that with Task Scheduler so when you login to your workstation, your alert monitoring is going.

Unfortunately the script they provide in the repository wasn’t pulling back ALL events I was seeking out.  This was because the filter on the events was not filtering on the actual EventId, but another value called InstanceID.

InstanceID usually matches up to EventIDs but not always (as is the case with SceCli events).  That said, I suggest to monitor the script at line 74.

## Powershell Log Monitor Script ##
## Contributing authors – mck74,mjolinor,

param([switch]$ShowEvents = $false,[switch]$NoEmail = $false)
$log = “Security”
$hist_file = $log + “_loghist.xml”
$seed_depth = 200

#run interval in minutes – set to zero for runonce, “C” for 0 delay continuous loop.
$run_interval = 0

$EmailFrom = “<youremail@domain.tls>”
$EmailTo = “<youremail@domain.tls>”
$EmailSubject = “Server event notification” 
 
$SMTPServer = “smtpServer”
$SMTPAuthUsername = “username”
$SMTPAuthPassword = “password”

$computers = @(gc monitored_computers.txt)
$event_list = @{}
Import-Csv alert_events.csv |% {$event_list[$_.source + '#' + $_.id] = 1}
#see if we have a history file to use, if not create an empty $histlog
if (Test-Path $hist_file){$loghist = Import-Clixml $hist_file}
 else {$loghist = @{}}
$timer = [System.Diagnostics.Stopwatch]::StartNew()

function send_email {
$mailmessage = New-Object system.net.mail.mailmessage
$mailmessage.from = ($emailfrom)
$mailmessage.To.add($emailto)
$mailmessage.Subject = $emailsubject
$mailmessage.Body = $emailbody
$mailmessage.IsBodyHTML = $true
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25) 
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential(“$SMTPAuthUsername”, “$SMTPAuthPassword”)
$SMTPClient.Send($mailmessage)
}
#START OF RUN PASS
$run_pass = {

$EmailBody = “Log monitor found monitored events. `n”

$computers |%{
$timer.reset()
$timer.start()

Write-Host “Started processing $($_)”

## Get the OS version number below.  If it is older than Vista process the EventID.  If it is Vista or Newer (version 6) process
## the InstanceID

$os = gwmi win32_operatingsystem -computer $server | % {$_.version}
if ($ver -lt 6){
    $useID = ‘EventID’
}
else {
    $useID = ‘InstanceID’
}

#Get the index number of the last log entry
$index = (Get-EventLog -ComputerName $_ -LogName $log -newest 1).index

#if we have a history entry calculate number of events to retrieve
#   if we don’t have an event history, use the $seed_depth to do initial seeding
if ($loghist[$_]){$n = $index – $loghist[$_]}
 else {$n = $seed_depth}
 
if ($n -lt 0){
 Write-Host “Log index changed since last run. The log may have been cleared. Re-seeding index.”
 $events_found = $true
 $EmailBody += “`n Possible Log Reset $($_)`nEvent Index reset detected by Log Monitor`n” | ConvertTo-Html
 $n = $seed_depth
 }
 
Write-Host “Processing $($n) events.”

#get the log entries

$log_hits = Get-EventLog -ComputerName $_ -LogName $log -Newest $n |
? {$event_list[$_.source + "#" + $_.$useID]}

#save the current index to $loghist for the next pass
$loghist[$_] = $index

#report number of alert events found and how long it took to do it
if ($log_hits){
 $events_found = $true
 $hits = $log_hits.count
 $EmailBody += “`n Alert Events on server $($_)`n”
 $log_hits |%{
  $emailbody += “<br><br>”
  $emailbody += $_ | select MachineName,EventID,Message | ConvertTo-Html
 $emailbody += “<br><br>”
 }
 }
 else {$hits = 0}
$duration = ($timer.elapsed).totalseconds
write-host “Found $($hits) alert events in $($duration) seconds.”
“-”*60
” ”
if ($ShowEvents){$log_hits | fl | Out-String |? {$_}}
}

#save the history file to disk for next script run
$loghist | export-clixml $hist_file

#Send email if there were any monitored events found
if ($events_found -and -not $NoEmail){send_email}

}
#END OF RUN PASS

Write-Host “`n$(“*”*60)”
Write-Host “Log monitor started at $(get-date)”
Write-Host “$(“*”*60)`n”

#run the first pass
$start_pass = Get-Date
&$run_pass

#if $run_interval is set, calculate how long to sleep before the next pass
while ($run_interval -gt 0){
if ($run_interval -eq “C”){&$run_pass}
 else{
 $last_run = (Get-Date) – $start_pass
 $sleep_time = ([TimeSpan]::FromMinutes($run_interval) – $last_run).totalseconds
 Write-Host “`n$(“*”*10) Sleeping for $($sleep_time) seconds `n”
 
#sleep, and then start the next pass
 Start-Sleep -seconds $sleep_time
 $start_pass = Get-Date
 &$run_pass
 }
 }

Search them flatfile logs with ease on Powershell

This guy has a nice post on what I am getting at:

http://www.winblogs.net/index.php/2009/09/30/a-few-powershell-useful-tricks/

Where I take mine a little further, is that I’ll run this command either on a temp drive or a UNC path for interrogating logs on remote servers:

cat “\\servername\c$\Program Files\iis\w3xxxx.log” | findstr interestingString

Show Me Users!

I watched a request go through a service desk setup recently asking for all users who use a particular application.  While at first this sounds trivial, the application is a heavily used flat-file system which has security enforced via Group Policy permissions.  This means that nested groups among all the various security groups makes this a tedious task going through active directory.

Enter the 2003 active directory commands complete with pipeline example of my end result.

dsquery group -name *funky* “dc=mystery,dc=localzoo” | dsget group -members | dsget user -display

That’ll bring back the nice display name, of all users, who belong to any group that has ‘funky’ in its name.

There is probably a smooth way to list out each group, then list out each user in each of those groups (to include the duplicate names), but that hasn’t been asked for..  i suppose that could be done by taking the first part of the pipe, then running the second and third piped commands against each group that is returned… that’d be the way to do it for say less than 10 groups… any more than that though, I’m sure powershell can come to the rescue.