forked from oneoffdallas/check_ioc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
check_ioc.ps1
377 lines (333 loc) · 20.8 KB
/
check_ioc.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#
# check_ioc.ps1 - v1.4 - 6November2016 - by Dallas Haselhorst
# Look for the associated SANS Gold Paper to describe this work in greater detail as well if you'd like to learn more.
# https://www.sans.org/reading-room/whitepapers/critical/uncovering-indicators-compromise-ioc-powershell-event-logs-traditional-monitorin-36352
# The most up-to-date version of the Gold Paper may also be found on my blog post.
# http://linuxincluded.com/uncovering-indicators-of-compromise/
#
# This script attempts to locate indicators of compromise on Windows systems. Much of the legwork was performed by the
# National Security Agency (NSA) in the white paper, "Spotting the Adversary with Windows Event Log Monitoring" (16Dec2013) so a
# huge thank you to them. The various checks below are notated with the corresponding section from the white paper wherever valid.
# Example: (4.1) ties to section 4.1 Application Whitelisting in the NSA white paper
#
# Heavily modified from the script, watch-eventlogs.ps1, found on Nagios Exchange and originally written by Aaron Wurthmann.
# Nonetheless, thanks for the framework and various bits of code Aaron!
#
# If you are using this from a command line and not Nagios, simply type the script name followed by the amount of time from now
# to check. Running in this mode will likely be helpful in incident handling and incident response to track down what changed in
# the last 3 hours, 24 hours, or whatever timeframe you decide.
# Examples:
# .\check_ioc.ps1 30 -- this line would search for the "selected" indicators of compromise (below) in the last 30 minutes
# .\check_ioc.ps1 30 > output.txt -- this line would do the same the above but send the output to an output file
# .\check_ioc.ps1 (60*24) -- would search for the "selected" indicators of compromise (below) in the last 24 hours (too lazy for math)
#
# For Nagios XI NCPA usage, the following line should be copied to the $ARG1$ text box
# -t '<token>' -P <port number> -M 'agent/plugin/check_ioc.ps1/<ArgLastMinutes>'
# For testing from the Nagios command line, add './check_ncpa.py -H <IP address>' (minus quotes) to the above line
# Notes:
# ArgLastMinutes should be populated with the time to check in minutes, e.g. 30 (for 30 minutes), 120 (for 2 hours), etc.
# Levels: 0 for all logs (LogAlways), 1 for Critical, 2 for Error, 3 for Warning, 4 for Informational, 5 for Verbose
# Example:
# -t 'TokenPass' -P 5693 -M 'agent/plugin/check_ioc.ps1/120'
# -- above line would search for the "selected" indicators of compromise (below) in the last 2 hours
#
# If running the pass-the-hash (PtH) checks on a domain controller this will work without any modifications
# If running on a non-domain system, you will need to enable "Audit logon events" using the following steps
# 1) Click Start, click Run, type "gpedit.msc" and hit Enter 2) On the left hand side, navigate to Local Computer Policy >
# Computer Configuration > Windows Settings > Security Settings > Local Policies > Audit Policy 3) On the right hand side, double-click
# “Audit logon events” 4) Check the boxes for Success and Failure, click OK.
# If in doubt, check your event viewer for Event IDs 4624 or 4625. If they are not there, it's either not turned on or it's logging
# elsewhere. ScheduledTaskCheck, RegKeyModCheck, and FileFolderModCheck all require "Audit object access" to be modified. This can be
# accomplished in the same manner "Audit logon events" is enabled above.
#
# If you are still reading this, great! For Nagios users, it may not make sense to check multiple IoC in single check. Instead,
# I would strongly suggest putting several logical selections together. For example, enable all the account-related tests and put them
# in their own separate check, enable all the kernel driver signing checks and put them in their own check, etc. Also, if you worried
# about log integrity, I would *strongly* recommend forwarding the logs and possibly even monitoring the event log service itself to
# ensure it does not get disabled in order to thwart all the log monitoring goodness of this script.
#
# 1 if you are running command for Nagios, comment out or change to 0 if you are running it interactively
$Nagios = 0
# Prevent PowerShell from auto-wrapping at 80 characters (for Nagios), cause newline characters on write-output otherwise
if ($Nagios -eq 1) {
if( $Host -and $Host.UI -and $Host.UI.RawUI ) {
$rawUI = $Host.UI.RawUI
$oldSize = $rawUI.BufferSize
$typeName = $oldSize.GetType( ).FullName
$newSize = New-Object $typeName (500, $oldSize.Height)
$rawUI.BufferSize = $newSize
}
}
Function CreateEventsOutput # Should receive argument to reflect what it is working on. For example: SuccessfulPtH or FailedPtH
{
$EntryCount = 0
$LogCount = 0
If ($Events) {
$LogCount = $Events.Count
If ((($args -eq "FailedUserAcctLogin") -And ($LogCount -ge $FailedUserAcctThreshold)) -Or ($args -ne "FailedUserAcctLogin"))
{
# set global critical flag if events exist
$script:CriticalFlag = 1
# separate out each of the checks so they can be read more easily
$script:FullOutput+="
------------------$args Events------------------
"
# loop through the entries and format the output
ForEach ($LogEntry in $Events) {
$Level=$LogEntry.Level.ToString()
$Message=$LogEntry.Message.Substring(0,[System.Math]::Min($EventMessageLength, $LogEntry.Message.Length)).TrimEnd().ToString()+'...'
$ProviderName=$LogEntry.ProviderName.ToString()
$LogName=$LogEntry.LogName.ToString()
$TimeCreated=$LogEntry.TimeCreated.ToString()
$Id=$LogEntry.Id.ToString()
$EntryCount++
$script:EventResults=@"
$EntryCount - At: $TimeCreated
$EntryCount - LogName: $LogName
$EntryCount - Level: $Level
$EntryCount - Event ID: $Id
$EntryCount - Source: $ProviderName
$EntryCount - Message: $Message
$EventResults
"@
}
$script:FullOutput+=$EventResults
# empty the global eventresults
$script:EventResults = ""
}
}
#If ($CondensedOutput) { $script:CondensedOutput+="; " }
If (($args -eq "FailedUserAcctLogin") -And ($LogCount -lt $FailedUserAcctThreshold))
{ $script:CondensedOutput+="$args` below threshold:$LogCount " }
Else { $script:CondensedOutput+="$args`:$EntryCount " }
}
# Pull in time argument if given, otherwise, default to [last] 30 mins
$ArgLastMinutes = $args[0]
if (!$ArgLastMinutes) { $ArgLastMinutes = 30 }
$ArgTimeQuery = ($ArgLastMinutes*60*1000) # XML queries must be in micro seconds
$EventMessageLength = 800 # main event information is about 30; should be around 800 to get a majority of details including the message text
# Change the values to 0 for items you do not want to check
$SuccessfulPtHCheck = 1 #(4.15) detects pass the hash attempts; may include false indicators in cases where remote desktop or remoteapp is utilized; added KeyLength to improve reliability (Thanks Dave Kennedy)
$FailedPtHCheck = 1 #(4.15) detects failed pass the hash attempts; same false indicator warning as PtH above
$LogClearCheck = 1 # (4.6) checks for all types of event log clears
$FirewallRuleModCheck = 1 # (4.5) checks for firewall rule adds, changes and deletions, may cause false indicators
$ServiceAddCheck = 1 # (4.7) checks for new Windows services
$AppErrorCheck = 0 # (4.2) may cause false indicators as applications do crash on their own; very useful in well-known environments
$AppHangCheck = 0 # (4.2) may cause false indicators as applications do crash on their own; very useful in well-known environments
$BSODCheck = 0 # (4.2) may cause false indicators as applications do crash on their own; very useful in well-known environments
$WindowsErrorReportingCheck = 0 # (4.2) may cause false indicators
$ServiceFailCrashCheck = 0 # (4.3) may cause false indicators
$AppLockerBlockCheck = 0 # (4.1) AppLocker must be configured
$AppLockerWarningCheck = 0 # (4.1) AppLocker must be configured
$SRPBlockCheck = 0 # (4.1) software restriction polices must be configured
$EMETCheck = 0 # (4.2) EMET must be configured and it will cause errors if you don't have it installed
$NewKernelFilterDriverCheck = 0 # (4.7) causes quite a few false indicators so you would have to add exceptions
$AppInstallCheck = 0 # (4.7) may cause false indicators Note: does not work in Win8
$MSIInstallCheck = 0 # (4.7) may cause false indicators; very useful in well-known environments
$AccountLockoutCheck = 0 # (4.8) may cause false indicators if the # of invalid password attempts to lockout in group policy is low (recommend 25)
$UserAddPrivGroupCheck = 0 # (4.8) user added to privileged group
$SecEnabledGroupModCheck = 0 # (4.8) security-enabled group modification
$FailedUserAcctLoginCheck = 1 # (4.8) failed user account login, works with FailedUserAcctThreshold value below
# FailedUserAcctThreshold works in conjunction with the check above, FailedUserAcctLoginCheck
# Find out what a "standard" baseline number is for the period of time you are checking for and then add a bit more to avoid false indicators
$FailedUserAcctThreshold = 50 # threshold for the number of failed logins before 'critical' is triggered
$InvalidImageHashFileCheck = 1 # (4.9) kernel driver signing - detected an invalid image hash of a file
$InvalidPageHashFileCheck = 1 # (4.9) kernel driver signing - detected an invalid page hash of an image file
$CodeIntegrityCheck = 0 # (4.9) kernel driver signing - code integrity check
$FailedKernelDriverCheck = 1 # (4.9) kernel driver signing - failed kernel driver loading
$LSASAMPassChangesCheck = 0 # indicators code is loaded into LSA (Local Security Authority) or SAM (Security Account Manager) and watching for password changes (Thanks Jessica Payne)
$NewMassStorageInstallCheck = 0 # (4.13) new mass storage installation; this occurs every time the device is inserted (not just the first time)
# Recommend to disable all customer experience tasks to avoid false indicators with line below. Turn off in "Action Center" and then disable *ALL* jobs under
# "Microsoft/Windows/Application Experience" and "Customer Experience Improvement Program" (and "Server" jobs if it exists under the latter library)
$ScheduledTaskCheck = 0 # checks for various changes to the scheduled tasks (for persistent access)
# auditing must be enabled/configured for registry keys you want to monitor, the check below is looking for "CurrentVersion" in the message
$RegKeyModCheck = 1 # checks for changes to the various registry keys that might be used for persistent access
# auditing must be enabled/configured for the files or folders you want to monitor
#$FileFolderModCheck = 1 # checks for changes to high value files you specify. Note: Do not attempt to audit the entire c:\windows directory
# set default properties we will pull with each query
$Properties='Level','Message','ProviderName','TimeCreated','Id','LogName'
If ($SuccessfulPtHCheck -eq 1) {
$SuccessPtHQuery = @'
<QueryList>
<Query Id="0">
<Select Path="Security">
*[System[(EventID="4624")
and
(Level=4 or Level=0)
and
TimeCreated[timediff(@SystemTime) <=
'@
$SuccessPtHQuery += $ArgTimeQuery
$SuccessPtHQuery += @'
] ]]
and
*[EventData[Data[@Name="LogonType"] and (Data="3")]]
and
*[EventData[Data[@Name="AuthenticationPackageName"] = "NTLM"]]
and
*[EventData[Data[@Name="KeyLength"] = "0"]]
and
*[EventData[Data[@Name="TargetUserName"] != "ANONYMOUS LOGON"]]
</Select>
</Query>
</QueryList>
'@
$Events = Get-winevent -FilterXml $SuccessPtHQuery -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "SuccessfulPtH"
}
If ($FailedPtHCheck -eq 1) {
$FailedPtHQuery = @'
<QueryList>
<Query Id="0">
<Select Path="Security">
*[System[(EventID="4625")
and
(Level=4 or Level=0)
and
TimeCreated[timediff(@SystemTime) <=
'@
$FailedPtHQuery += $ArgTimeQuery
$FailedPtHQuery += @'
] ]]
and
*[EventData[Data[@Name="LogonType"] and (Data="3")]]
and
*[EventData[Data[@Name="AuthenticationPackageName"] = "NTLM"]]
and
*[EventData[Data[@Name="KeyLength"] = "0"]]
and
*[EventData[Data[@Name="TargetUserName"] != "ANONYMOUS LOGON"]]
</Select>
</Query>
</QueryList>
'@
$Events = Get-winevent -FilterXml $FailedPtHQuery -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "FailedPtH"
}
If ($LogClearCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security','System'; id=1102,104; Level=4; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "LogClear"
}
If ($FirewallRuleModCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-Windows Firewall With Advanced Security/Firewall'; id=2003,2004,2005,2006,2033; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "FirewallRuleMod"
}
If ($ServiceAddCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='System'; id=7045; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "ServiceAdd"
}
If ($AppErrorCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Application'; ProviderName='Application Error'; id=1000; Level = 2; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AppError"
}
If ($AppHangCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Application'; ProviderName='Application Hang'; id=1002; Level = 2; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AppHang"
}
If ($BSODCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='System'; id=1001; Level = 2; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "BSOD"
}
If ($WindowsErrorReportingCheck -eq 1 ) {
$Events = Get-winevent -FilterHashtable @{logname='Application'; id=1001; Level = 4; ProviderName='Windows Error Reporting'; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "WindowsErrorReporting"
}
If ($ServiceFailCrashCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='System'; id=7022,7023,7024,7026,7031,7032,7034; Level = 2; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "ServiceFailsCrash"
}
If ($AppLockerBlockCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-AppLocker/EXE and DLL'; id=8003,8004; Level = 2,3; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AppLockerBlock"
}
If ($AppLockerWarningCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-AppLocker/MSI and Script'; id=8006,8007; Level = 2,3; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AppLockerWarning"
}
If ($EMETCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Application'; ProviderName='EMET'; id=1,2; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "EMET"
}
If ($NewKernelFilterDriverCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='System'; id=6; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "NewKernelFilterDriver"
}
If ($AppInstallCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-Application-Experience/Program-Inventory'; id=903,904; ProviderName='Microsoft-Windows-Application-Experience'; Level=4; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AppInstall"
}
If ($MSIInstallCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Application'; id=1022,1033; ProviderName='MsiInstaller'; Level=4; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "MSIInstall"
}
If ($AccountLockoutCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4740; ProviderName='Microsoft-Windows-Security-Auditing'; Level=4; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "AccountLockout"
}
If ($UserAddPrivGroupCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4728,4732,4756; ProviderName='Microsoft-Windows-Security-Auditing'; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "UserAddPrivGroup"
}
If ($SecEnabledGroupModCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4735; ProviderName='Microsoft-Windows-Security-Auditing'; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "SecEnabledGroupMod"
}
If ($FailedUserAcctLoginCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4625; ProviderName='Microsoft-Windows-Security-Auditing'; Level=0; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "FailedUserAcctLogin"
}
If ($InvalidImageHashFileCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=5038; ProviderName='Microsoft-Windows-Security-Auditing'; Level=0; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "InvalidImageHashFile"
}
If ($InvalidPageHashFileCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=6281; ProviderName='Microsoft-Windows-Security-Auditing'; Level=0; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "InvalidPageHashFile"
}
If ($CodeIntegrityCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-CodeIntegrity/Operational'; id=3001,3002,3003,3004,3010,3023; ProviderName='Microsoft-Windows-CodeIntegrity'; Level=2,3; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "CodeIntegrity"
}
If ($FailedKernelDriverCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='System'; id=219; ProviderName='Microsoft-Windows-Kernel-PnP'; Level=3; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "FailedKernelDriver"
}
If ($LSASAMPassChangesCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4610,4611,4614,4622; Level=0; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "LSASAMPassChanges"
}
If ($NewMassStorageInstallCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Microsoft-Windows-Kernel-PnP/Configuration'; id=400,410; ProviderName='Microsoft-Windows-Kernel-PnP'; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "NewMassStorageInstall"
}
If ($ScheduledTaskCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4698,4699,4700,4701,4702; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | Select-Object -Property $Properties
CreateEventsOutput "ScheduledTask"
}
If ($RegKeyModCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4657; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | where-object {$_.Message -like "*CurrentVersion*" } | Select-Object -Property $Properties
CreateEventsOutput "RegKeyMod"
}
<#
If ($FileFolderModCheck -eq 1) {
$Events = Get-winevent -FilterHashtable @{logname='Security'; id=4656,4658; StartTime = (Get-Date).AddMinutes(-$ArgLastMinutes) } -ea SilentlyContinue | where-object {$_. -eq "" } | Select-Object -Property $Properties
CreateEventsOutput "FileFolderMod"
}
#>
If ($CriticalFlag -eq 1) {
# write the "summary" at the top and bottom so you don't have to hunt for it
# write-host is used first so it returns one line to Nagios without newline characters
# write-output allows us to easily re-direct the script from the command line to a separate file
$OutputString = "Critical: $CondensedOutput"
$OutputString += "in the last $ArgLastMinutes minutes"
write-output $OutputString
write-output $FullOutput
write-output $OutputString
exit 2 # the 2 returns to Nagios as a critical event
}
else {
$OutputString = "OK: $Status$CondensedOutput"
$OutputString += "in the last $ArgLastMinutes minutes"
write-output $OutputString
exit 0 # the 0 returns to Nagios as all is well
}