Life of a techno-guru
New Blog
Hello! I know I don't have any readers, but if any of you are interested, I have a new blog:
http://trevorsullivan.wordpress.comCheers!
Parsing Windows 2003 Print Logs
Here is a Powershell script that parses event log ID 10 on a Windows 2003 print server. Normally, you'll have a message that looks something like this:
Document 172, C:\Documents and Settings\Trevor\W5QZ4XUR\MyFinanceReport.pdf owned by Trevor was printed on 4thFloorHpPrinter via port IP_10.1.1.50. Size in bytes: 168123; pages printed: 2
Now, how do you get that information into a usable format? The answer lies below:
#################################################################################
# #
# Author: Trevor Sullivan #
# #
# Date: February 10th, 2009 #
# #
# Purpose: This script is meant for running against a Windows 2003 event log. #
# The verbage for the print log entries has changed for Windows Vista. #
# #
#################################################################################
Function GetPrintEntriesFromTextFile($tFileName)
{
Get-Content $tFileName
}
Function GetPrintEntriesFromServer()
{
$PrintEntries = Get-EventLog -LogName System | Where-Object { $_.EventId -eq 10 -and $_.Source -eq "Print" }
return $PrintEntries
}
# Parses username from a Windows 2003 Print log message
Function GetUserName($PrintEntry)
{
If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null }
$rxUserName = [regex]"owned by ([0-9a-zA-Z]{7})"
$rxUserName = [regex]"owned by ([0-9a-zA-Z]{1,}) was"
$rxMatches = $rxUserName.Match($PrintEntry)
return $rxMatches.Groups[1].Value
}
Function GetPrinterName($PrintEntry)
{
If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null }
#Write-Host "Parsing printer name"
$rxPrinterName = [regex]"printed on ([0-9a-zA-Z-_\s]{5,}) via"
$rxMatches = $rxPrinterName.Match($PrintEntry)
return $rxMatches.Groups[1].Value
}
Function GetPrintSize($PrintEntry)
{
If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null }
#Write-Host "Getting print size"
$rxPrintSize = [regex]"Size in bytes: ([0-9]+);"
$rxMatches = $rxPrintSize.Match($PrintEntry)
return $rxMatches.Groups[1].Value
}
Function GetPageCount($PrintEntry)
{
If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null }
#Write-Host "Getting page count"
$rxPageCount = [regex]"pages printed\: ([0-9]+)"
$rxMatches = $rxPageCount.Match($PrintEntry)
return $rxMatches.Groups[1].Value
}
Function GetDocumentName($PrintEntry)
{
If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null }
#Write-Host "Getting print size"
$rxDocumentName = [regex]", ([a-zA-Z-_:/\[#\]\?\\\=\d\.\s\(\)&-,]{1,}) owned by"
$rxMatches = $rxDocumentName.Match($PrintEntry)
return $rxMatches.Groups[1].Value
}
# Retrieves user's full name from AD
Function GetUserFullName($UserId)
{
if ($UserId -gt "")
{
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$LdapFilter = "(&(objectClass=user)(samAccountName=${UserId}))"
#Write-Host "Filter is: ${LdapFilter}"
$DirectorySearcher.Filter = $LdapFilter
$UserEntry = [adsi]"$($DirectorySearcher.FindOne().Path)"
#Write-Host $UserEntry.displayName
return $UserEntry.displayName
}
return
}
Function CreatePrintJob()
{
$PrintJob = New-Object PsObject
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name PageCount -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name UserName -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name DocumentName -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Size -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Printer -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Time -Value $null
Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name UserFullName -Value $null
return $PrintJob
}
Function ParsePrintEntry($PrintEntry)
{
$NewPrintJob = CreatePrintJob
if ($PrintEntry.GetType() -eq [System.String])
{
$NewPrintJob.PageCount = GetPageCount $PrintEntry
$NewPrintJob.UserName = GetUserName $PrintEntry
$NewPrintJob.DocumentName = GetDocumentName $PrintEntry
$NewPrintJob.Size = GetPrintSize $PrintEntry
$NewPrintJob.Printer = GetPrinterName $PrintEntry
$NewPrintJob.UserFullName = GetUserFullName $NewPrintJob.UserName
}
elseif ($PrintEntry.GetType() -eq [System.Diagnostics.EventLogEntry])
{
$NewPrintJob.PageCount = GetPageCount $PrintEntry.Message
$NewPrintJob.UserName = GetUserName $PrintEntry.Message
$NewPrintJob.DocumentName = GetDocumentName $PrintEntry.Message
$NewPrintJob.Size = GetPrintSize $PrintEntry.Message
$NewPrintJob.Printer = GetPrinterName $PrintEntry.Message
$NewPrintJob.Time = $PrintEntry.Time
$NewPrintJob.UserFullName = GetUserFullName $NewPrintJob.UserName
}
return $NewPrintJob
}
Function Main()
{
#$PrintEntries = GetPrintEntriesFromServer
$PrintEntries = GetPrintEntriesFromTextFile "c:\Users\i081225\Desktop\Powershell Scripts\Print Log Parser\PrintLog.txt"
$Global:ParsedEntries = @{}; $i = 0
ForEach ($PrintEntry in $PrintEntries)
{
$ParsedEntries.Add($i, $(ParsePrintEntry $PrintEntry))
#$ParsedEntries += (ParsePrintEntry $PrintEntry)
$i++
if ($i % 100 -eq 0)
{ Write-Host "Processed $i records" }
}
WriteToExcel $ParsedEntries
}
Function WriteToExcel($tEntries)
{
# Load Excel interop assembly
[Void] [Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel")
# Create Excel application, workbook, and worksheet objects
$Excel = New-Object Microsoft.Office.Interop.Excel.ApplicationClass
$Workbook = $Excel.Workbooks.Add()
$Worksheet = $Workbook.Worksheets.Add()
# Write Excel worksheet headers
$Worksheet.Cells.Item(1, 1).Value2 = "Username"
$Worksheet.Cells.Item(1, 2).Value2 = "Full Name"
$Worksheet.Cells.Item(1, 3).Value2 = "Time"
$Worksheet.Cells.Item(1, 4).Value2 = "Page Count"
$Worksheet.Cells.Item(1, 5).Value2 = "Printer"
$Worksheet.Cells.Item(1, 6).Value2 = "Size (bytes)"
$Worksheet.Cells.Item(1, 7).Value2 = "Document Name"
# End writing Excel worksheet headers
# Iterate over each print entry
$row = 2
ForEach ($key in $tEntries.Keys)
{
$Worksheet.Cells.Item($row, 1).Value2 = $tEntries[$key].UserName
$Worksheet.Cells.Item($row, 2).Value2 = $tEntries[$key].UserFullName
$Worksheet.Cells.Item($row, 3).Value2 = $tEntries[$key].Time
$Worksheet.Cells.Item($row, 4).Value2 = $tEntries[$key].PageCount
$Worksheet.Cells.Item($row, 5).Value2 = $tEntries[$key].Printer
$Worksheet.Cells.Item($row, 6).Value2 = $tEntries[$key].Size
$Worksheet.Cells.Item($row, 7).Value2 = $tEntries[$key].DocumentName
$row++
}
# Do some formatting
# AutoFit the columns
[Void] $Excel.ActiveCell.CurrentRegion.Columns.AutoFit()
# Add table styling and auto-filtering
[Void] $Excel.ActiveCell.CurrentRegion.Select()
$ListObject = $Excel.ActiveSheet.ListObjects.Add([Microsoft.Office.Interop.Excel.XlListObjectSourceType]::xlSrcRange, $Excel.ActiveCell.CurrentRegion, $null ,[Microsoft.Office.Interop.Excel.XlYesNoGuess]::xlYes)
$ListObject.Name = "TableData"
$ListObject.TableStyle = "TableStyleLight9"
# Show the Excel window after writing data to spreadsheet
$Excel.Visible = $true
}
MainI hope this helps someone out there :)
-Trevor Sullivan
Enable AutoProvision Policy with Powershell
Hello,
Are you working with Out of Band Management (OOB) in ConfigMgr / SCCM? Instead of waiting for SCCM policy to apply to a client, would you like to force the auto-provisioning policy to apply on-demand? If so, then you've come to the right place. Here is some Powershell code that will enable auto-provisioning on an SCCM client.
$OobSettings = [wmiclass]”root\ccm\policy\machine\actualconfig:CCM_OutOfBandManagementSettings”
$OobSettingsInstance = $OobSettings.CreateInstance()
$OobSettingsInstance.AutoProvision = $True
$OobSettingsInstance.SiteSettingsKey = 1
$OobSettingsInstance.Put()-Trevor Sullivan
Powershell - Compare Active Directory Groups
Here is a Powershell script that compares two Active Directory groups, and determines the differences between the account membership of them.
$DN1 = "CN=Group1,OU=Groups,OU=Accounts,DC=subdomain,DC=mydomain,DC=local"
$DN2 = "CN=Group2,OU=Groups,OU=Accounts,DC=subdomain,DC=mydomain,DC=local"
$Group1 = [adsi]"LDAP://$DN1"
$Group2 = [adsi]"LDAP://$DN2"
ForEach ($User in $Group1.member)
{
if ($Group2.member -contains $User)
{
Write-Host "$User belongs to $($Group2.cn)"
}
else
{
Write-Host "$User does not belong to $($Group2.cn)"
}
}-Trevor Sullivan
Powershell - Domain Distinguished Name
Hello,
The two lines below allow you to use the LDAP "RootDSE" object to dynamically access the root of an Active Directory (AD) domain, from a domain member. The
defaultNamingContext attribute on the RootDSE object contains the full distinguished name of the AD domain.
$RootDSE = [adsi]"LDAP://RootDSE"
$DomainRoot = [adsi]"$($RootDSE.DefaultNamingContext)"Now that you have a reference to the domain root in the $DomainRoot variable, you can perform any operations you need to from that point. For example, to enumerate the children of the domain root, simply type the following at your interactive Powershell command prompt:
$DomainRoot.psbase.Children-Trevor Sullivan
Office 2007, OpenXML and Powershell
Here are some tools to work with Office 2007 documents from Windows Powershell:
http://www.codeplex.com/PowerTools
An open letter to Criterion Games
I e-mailed this brief letter to Criterion Games today. If you have a PS3, and/or Xbox 360, and/or gaming PC (being released in February 2009), you should definitely purchase Burnout Paradise. It's one of the best games I have ever played, and enjoy many aspects of the game's design. I hope that everyone else, that has already bought and played this game, has gotten as much enjoyment from it as I have.
------------------
Hello Criterion,
I just wanted to thank you guys for making a fabulous game. These days, it’s hard to find games that provide a real return on investment, like Burnout Paradise (BP) does. BP achieves outstanding success in pretty much every area of game design. It has breathtaking graphics (despite being only 720p), it has an incredible soundtrack (I love the classical music, and the electronic remixes of other songs), it has phenomenal multiplayer integration (the seamlessness makes it quite appealing), it has awesome-looking slow-motion crashes, and the continual support of new, free content has blown me away. Keep all of this up in future games, and you will continue to be exceedingly successful and respected.
---
You know, of all the great things I have to say about Burnout Paradise, it’s really only lacking one major thing … instant replays. I can’t really think of anything else that’s missing, but having the ability to save instant replays of crashes, and races, would make the game all that much better.
---
Thanks for listening, and for making one of the best games I’ve seen on the PS3. Your hard work, focus on the customer, and excellent designers and developers, have made Burnout Paradise a shining star amongst a heaping pile of failed attempts. Keep up the good work, Criterion.
Sincerely,
Trevor Sullivan
My life of learning various things about technology including network administration, development, and 3D design