-
Notifications
You must be signed in to change notification settings - Fork 29
/
Get-AspNetEvents.ps1
129 lines (124 loc) · 8.15 KB
/
Get-AspNetEvents.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<#
.SYNOPSIS
Parses ASP.NET errors from the event log on the given server.
.OUTPUTS
System.Management.Automation.PSObject containing the fields stored in the event.
.LINK
Get-WinEvent
.EXAMPLE
Get-AspNetEvents.ps1 WebServer
Returns any ASP.NET-related events from the WebServer Application event log that occurred today.
#>
#Requires -Version 3
[CmdletBinding()][OutputType([psobject])] Param(
# The name of the server on which the error occurred.
[Parameter(Position=0)][Alias('CN','Server')][string[]]$ComputerName = $env:COMPUTERNAME,
<#
Skip events older than this datetime.
Defaults to 00:00 today.
#>
[Parameter(Position=1)][DateTime]$After = ([DateTime]::Today),
<#
Skip events newer than this datetime.
Defaults to now.
#>
[Parameter(Position=2)][DateTime]$Before = ([DateTime]::Now),
# Include all event fields as properties.
[switch]$AllProperties
)
$IdFields = @{
# 5, 9, 21 (1) Classic ASP errors, no fields
# 1020 (0) IIS config failure, no fields
# 1309 (30) late runtime issues
1309 = @('EventCode','EventMessage','EventTime','EventTimeUtc','EventId','EventSequence','EventOccurrence',
'EventDetailCode','AppDomain','TrustLevel','AppPath','AppLocalPath','MachineName','_','ProcessId','ProcessName',
'AccountName','ExceptionType','ExceptionMessage','RequestUrl','RequestPath','UserHostAddress','User','IsAuthenticated',
'AuthenticationType','ReqThreadAccountName','ThreadId','ThreadAccountName','IsImpersonating','StackTrace','CustomEventDetails')
# 1310 (30) early configuration-type issues
1310 = @('EventCode','EventMessage','EventTime','EventTimeUtc','EventId','EventSequence','EventOccurrence',
'EventDetailCode','AppDomain','TrustLevel','AppPath','AppLocalPath','MachineName','_','ProcessId','ProcessName',
'AccountName','ExceptionType','ExceptionMessage','RequestUrl','RequestPath','UserHostAddress','User','IsAuthenticated',
'AuthenticationType','ReqThreadAccountName','ThreadId','ThreadAccountName','IsImpersonating','StackTrace','CustomEventDetails')
# 1314 (24) access issues
1314 = @('EventCode','EventMessage','EventTime','EventTimeUtc','EventId','EventSequence','EventOccurrence',
'EventDetailCode','AppDomain','TrustLevel','AppPath','AppLocalPath','MachineName','_','ProcessId','ProcessName',
'AccountName','RequestUrl','RequestPath','UserHostAddress','User','IsAuthenticated','AuthenticationType',
'ThreadAccountName','CustomEventDetails')
# 1315 (25) forms authentication failure
1315 = @('EventCode','EventMessage','EventTime','EventTimeUtc','EventId','EventSequence','EventOccurrence',
'EventDetailCode','AppDomain','TrustLevel','AppPath','AppLocalPath','MachineName','_','ProcessId','ProcessName',
'AccountName','RequestUrl','RequestPath','UserHostAddress','User','IsAuthenticated','AuthenticationType',
'ThreadAccountName','CustomEventDetails')
# 1316 (31) session state failure
1316 = @('EventCode','EventMessage','EventTime','EventTimeUtc','EventId','EventSequence','EventOccurrence',
'EventDetailCode','AppDomain','TrustLevel','AppPath','AppLocalPath','MachineName','_','ProcessId','ProcessName',
'AccountName','ExceptionType','ExceptionMessage','RequestUrl','RequestPath','UserHostAddress','User','IsAuthenticated',
'AuthenticationType','ReqThreadAccountName','ThreadId','ThreadAccountName','IsImpersonating','StackTrace','CustomEventDetails')
# 1325 (1) serious low-level stuff, no fields
}
$order =
if($AllProperties) { @('MachineName','EventTime','EventTimeUtc','LogTime','EntryType','AppPath','ExceptionType',
'ExceptionMessage','AccountName','UserHostAddress','IsImpersonating','IsAuthenticated','AuthenticationType','User','TrustLevel',
'CustomEventDetails','AppLocalPath','RequestUrl','RequestPath','AppDomain','Source','EventCode','EventDetailCode','EventMessage',
'EventOccurrence','EventSequence','EventId','ProcessName','ProcessId','ThreadId','ThreadAccountName','ReqThreadAccountName',
'StackTrace') }
else { @('MachineName','EventTime','EventTimeUtc','LogTime','EntryType','AppPath','ExceptionType','ExceptionMessage','AccountName',
'UserHostAddress','IsImpersonating','IsAuthenticated','CustomEventDetails') }
$RemoveFields= '_','ThreadAccountName','ReqThreadAccountName' # blank or redundant fields
$BoolFields= 'IsAuthenticated','IsImpersonating'
$IntFields= 'EventOccurrence','EventSequence','EventCode','EventDetailCode','ProcessId','ThreadId'
$query = [xml]@"
<QueryList>
<Query Id="0" Path="Application">
<Select Path="Application">*[System[Provider[@Name='Active Server Pages'
or @Name='ASP.NET 2.0.50727.0'
or @Name='ASP.NET 4.0.30319.0']
and TimeCreated[@SystemTime >= '$(Get-Date $After.ToUniversalTime() -Format yyyy-MM-ddTHH:mm:ss.000Z)'
and @SystemTime <= '$(Get-Date $Before.ToUniversalTime() -Format yyyy-MM-ddTHH:mm:ss.999Z)']]]</Select>
<Suppress Path="Application">*[System[EventID=1017
or EventID=1019
or EventID=1023
or EventID=1025
or EventID=1076
or EventID=1077]]</Suppress>
</Query>
</QueryList>
"@
Write-Verbose $query.OuterXml
$ComputerName |
ForEach-Object {Get-WinEvent $query -CN $_} |
ForEach-Object {
$fields = @{EntryType=$_.LevelDisplayName;Source=$_.ProviderName}
if($_.Properties.Count -lt 2 -or !$IdFields.Contains($_.Id))
{ # not structured nicely
Write-Verbose "Unstructured:`n$($_.Message)"
if($_.Message -match '(?m)^Application ID: (?<AppId>.+)$'){$fields.AppId=$Matches.AppId.TrimEnd()}
if($_.Message -match '(?m)^Process ID: (?<ProcessId>.+)$'){$fields.ProcessId=[int]$Matches.ProcessId.TrimEnd()}
if($_.Message -match '(?m)^Exception: (\w+\.)*(?<ExceptionType>\w+)\s*$'){$fields.ExceptionType=$Matches.ExceptionType}
if($_.Message -match '(?m)^Message: (?<ExceptionMessage>.+)$'){$fields.ExceptionMessage=$Matches.ExceptionMessage.TrimEnd()}
if($_.Message -match '(?ms)^StackTrace: (?<StackTrace>.+)$'){$fields.StackTrace=$Matches.StackTrace.TrimEnd()}
}
else
{
$values = $_.Properties |Select-Object -ExpandProperty Value
$names = $IdFields[$_.Id]
if($values.Length -gt $names.Length) { Write-Warning ('Unexpected field values: {0} > {1}' -f $values.Length,$names.Length) }
0..($values.Length-1) |ForEach-Object {[void]$fields.Add($names[$_],$values[$_].TrimEnd())}
$RemoveFields |ForEach-Object {$fields.Remove($_)}
$BoolFields |ForEach-Object {$fields[$_]=[bool]$fields[$_]}
$IntFields |ForEach-Object {$fields[$_]=[int]$fields[$_]}
$fields.RequestUrl= [uri]$fields.RequestUrl
$fields.EventTime= [datetime]::Parse($fields.EventTime,$null,[Globalization.DateTimeStyles]::AssumeLocal)
if($AllProperties -or $fields.EventTime -ne $_.TimeCreated) {$fields.LogTime = $_.TimeCreated}
$fields.EventTimeUtc= [datetime]::Parse($fields.EventTimeUtc,$null,[Globalization.DateTimeStyles]::AssumeUniversal)
if(!$AllProperties -and $fields.EventTime -eq $fields.EventTimeUtc) {$fields.Remove('EventTimeUtc')}
if($fields.ExceptionMessage -and $fields.StackTrace)
{ $fields.ExceptionMessage= $fields.ExceptionMessage.Replace($fields.StackTrace,'').TrimEnd() } # don't need stack trace twice
}
if($fields.Count -eq 2) {return}
$ordered = [ordered]@{}
$order |Where-Object {$fields.ContainsKey($_)} |ForEach-Object {[void]$ordered.Add($_,$fields.$_)}
$value = New-Object PSObject -Property $ordered
$value.PSObject.TypeNames.Insert(0,'AspNetApplicationEventLogEntry')
$value
}