├── .gitattributes
├── .gitignore
├── check_ms_win_disk_load.php
├── check_ms_win_disk_load.ps1
└── readme.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # =========================
18 | # Operating System Files
19 | # =========================
20 |
21 | # OSX
22 | # =========================
23 |
24 | .DS_Store
25 | .AppleDouble
26 | .LSOverride
27 |
28 | # Icon must end with two \r
29 | Icon
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear on external disk
35 | .Spotlight-V100
36 | .Trashes
37 |
38 | # Directories potentially created on remote AFP share
39 | .AppleDB
40 | .AppleDesktop
41 | Network Trash Folder
42 | Temporary Items
43 | .apdisk
44 |
--------------------------------------------------------------------------------
/check_ms_win_disk_load.php:
--------------------------------------------------------------------------------
1 | MACRO['DISP_HOSTNAME'] . " / " . $this->MACRO['DISP_SERVICEDESC'] . " \" ";
29 | $def[1] = '';
30 |
31 | foreach ($DS as $i) {
32 | $def[1] .= rrd::def("var$i", $RRDFILE[1], $DS[$i], 'AVERAGE');
33 | $def[1] .= rrd::line2("var$i", $colors[$i], "$NAME[$i]");
34 | $def[1] .= rrd::gprint("var$i" ,'LAST' ,"Last\:%5.0lf%s$UNIT[1]");
35 | $def[1] .= rrd::gprint("var$i" ,'MIN' ,"min\:%5.0lf%s$UNIT[1]");
36 | $def[1] .= rrd::gprint("var$i" ,'MAX' ,"max\:%5.0lf%s$UNIT[1]");
37 | $def[1] .= rrd::gprint("var$i" ,'AVERAGE' ,"avg\:%5.0lf%s$UNIT[1] \\r");
38 |
39 | };
40 |
41 | $def[1] .= rrd::comment("\\r");
42 | $def[1] .= rrd::comment("Disk Load Monitoring on Windows\\r");
43 | $def[1] .= rrd::comment("Command " . $TEMPLATE[1] . "\\r");
44 |
45 | ?>
46 |
--------------------------------------------------------------------------------
/check_ms_win_disk_load.ps1:
--------------------------------------------------------------------------------
1 | # Script name: check_ms_windows_disk_load.ps1
2 | # Version: v2.04.160115
3 | # Created on: 10/10/2014
4 | # Author: D'Haese Willem
5 | # Purpose: Check MS Windows disk load by using Powershell to get all disk load related counters from Windows
6 | # Performance Manager, computing averages for all gathered samples and calculating read / write rate,
7 | # number of reads / writes, read / write latency and read / write queue length.
8 | # On Github: https://github.com/OutsideIT/check_ms_win_disk_load
9 | # Copyright:
10 | # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published
11 | # by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed
12 | # in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 | # PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public
14 | # License along with this program. If not, see .
15 |
16 | #Requires –Version 2.0
17 |
18 | $DebugPreference = 'SilentlyContinue'
19 | $VerbosePreference = 'SilentlyContinue'
20 | [Int]$DefaultInt = -99
21 |
22 | $DiskStruct = New-object PSObject -Property @{
23 | Hostname = ([System.Net.Dns]::GetHostByName((hostname.exe)).HostName).tolower();
24 | DiskLetter = 'C';
25 | Exitcode = 3;
26 | MaxSamples = 2;
27 | LogicalDiskId = 236;
28 | AvgDiskSecReadId = 208;
29 | AvgDiskSecReadValue = 0;
30 | AvgDiskSecWriteId = 210;
31 | AvgDiskSecWriteValue = 0;
32 | AvgDiskReadQueueId = 1402;
33 | AvgDiskReadQueueValue = 0;
34 | AvgDiskWriteQueueId = 1404;
35 | AvgDiskWriteQueueValue = 0;
36 | DiskReadsSecId = 214;
37 | DiskReadsSecValue = 0;
38 | DiskWritesSecId = 216;
39 | DiskWritesSecValue = 0;
40 | DiskReadBytesSecId = 220;
41 | DiskReadBytesSecValue = 0;
42 | DiskWriteBytesSecId = 222;
43 | DiskWriteBytesSecValue = 0;
44 | AvgDiskReadQueueWarn = $DefaultInt;
45 | AvgDiskReadQueueCrit = $DefaultInt;
46 | AvgDiskWriteQueueWarn = $DefaultInt;
47 | AvgDiskWriteQueueCrit = $DefaultInt;
48 | ReturnString = 'UNKNOWN: Please debug the script...'
49 | }
50 |
51 | #region Functions
52 |
53 | function Write-Log {
54 | [CmdletBinding()]
55 | param (
56 | [parameter(Mandatory=$true)]
57 | [string]$Log,
58 | [parameter(Mandatory=$true)]
59 | [ValidateSet('Debug', 'Info', 'Warning', 'Error')]
60 | [string]$Severity,
61 | [parameter(Mandatory=$true)]
62 | [string]$Message
63 | )
64 | $Now = Get-Date -Format 'yyyy-MM-dd HH:mm:ss,fff'
65 | if ($Log -eq 'Verbose') {
66 | Write-Verbose "${Now}: ${Severity}: $Message"
67 | }
68 | elseif ($Log -eq 'Debug') {
69 | Write-Debug "${Now}: ${Severity}: $Message"
70 | }
71 | elseif ($Log -eq 'Output') {
72 | Write-Host "${Now}: ${Severity}: $Message"
73 | }
74 | elseif ($Log -match '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(?::(?\d+))$' -or $Log -match "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$") {
75 | $IpOrHost = $log.Split(':')[0]
76 | $Port = $log.Split(':')[1]
77 | if ($IpOrHost -match '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$') {
78 | $Ip = $IpOrHost
79 | }
80 | else {
81 | $Ip = ([System.Net.Dns]::GetHostAddresses($IpOrHost)).IPAddressToString
82 | }
83 | Try {
84 | $JsonObject = (New-Object PSObject | Add-Member -PassThru NoteProperty logdestination $Log | Add-Member -PassThru NoteProperty logtime $Now| Add-Member -PassThru NoteProperty severity $Severity | Add-Member -PassThru NoteProperty message $Message ) | ConvertTo-Json
85 | $JsonString = $JsonObject -replace "`n",' ' -replace "`r",' ' -replace ' ',''
86 | $Socket = New-Object System.Net.Sockets.TCPClient($Ap,$Port)
87 | $Stream = $Socket.GetStream()
88 | $Writer = New-Object System.IO.StreamWriter($Stream)
89 | $Writer.WriteLine($JsonString)
90 | $Writer.Flush()
91 | $Stream.Close()
92 | $Socket.Close()
93 | }
94 | catch {
95 | Write-Host "${Now}: Error: Something went wrong while trying to send message to Logstash server `"$Log`"."
96 | }
97 | Write-Host "${Now}: ${Severity}: Ip: $Ip Port: $Port JsonString: $JsonString"
98 | }
99 | elseif ($Log -match '^((([a-zA-Z]:)|(\\{2}\w+)|(\\{2}(?:(?:25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)(?(?=\.?\d)\.)){4}))(\\(\w[\w ]*))*)') {
100 | if (Test-Path -Path $Log -pathType container){
101 | Write-Host "${Now}: Error: Passed Path is a directory. Please provide a file."
102 | exit 1
103 | }
104 | elseif (!(Test-Path -Path $Log)) {
105 | try {
106 | New-Item -Path $Log -Type file -Force | Out-null
107 | }
108 | catch {
109 | $Now = Get-Date -Format 'yyyy-MM-dd HH:mm:ss,fff'
110 | Write-Host "${Now}: Error: Write-Log was unable to find or create the path `"$Log`". Please debug.."
111 | exit 1
112 | }
113 | }
114 | try {
115 | "${Now}: ${Severity}: $Message" | Out-File -filepath $Log -Append
116 | }
117 | catch {
118 | Write-Host "${Now}: Error: Something went wrong while writing to file `"$Log`". It might be locked."
119 | }
120 | }
121 | }
122 |
123 | Function Initialize-Args {
124 | Param (
125 | [Parameter(Mandatory=$True)]$Args
126 | )
127 |
128 | try {
129 | For ( $i = 0; $i -lt $Args.count; $i++ ) {
130 | $CurrentArg = $Args[$i].ToString()
131 | if ($i -lt $Args.Count-1) {
132 | $Value = $Args[$i+1];
133 | If ($Value.Count -ge 2) {
134 | foreach ($Item in $Value) {
135 | Test-Strings $Item | Out-Null
136 | }
137 | }
138 | else {
139 | $Value = $Args[$i+1];
140 | Test-Strings $Value | Out-Null
141 | }
142 | } else {
143 | $Value = ''
144 | };
145 |
146 | switch -regex -casesensitive ($CurrentArg) {
147 | "^(-H|--Hostname)$" {
148 | if ($value -match "^[a-zA-Z0-9._-]+$") {
149 | $DiskStruct.Hostname = $value
150 | } else {
151 | throw "Hostname does not meet regex requirements (`"^[a-zA-Z0-9._-]+$`"). Value given is `"$value`"."
152 | }
153 | $i++
154 | }
155 | "^(-dl|--DiskLetter)$" {
156 | if ($value -match "^[a-zA-Z]$") {
157 | $DiskStruct.DiskLetter = $value
158 | } else {
159 | throw "Diskletter does not meet regex requirements (`"^[a-zA-Z]$`"). Value given is `"$value`"."
160 | }
161 | $i++
162 | }
163 | "^(-rqw|--ReadQueueWarn)$" {
164 | if (($value -match "^[\d]+$") -and ([int]$value -lt 999999)) {
165 | $DiskStruct.AvgDiskReadQueueWarn = $value
166 | } else {
167 | throw "Read queue warning does not meet regex requirements (`"^[\d]+$`"). Value given is `"$value`"."
168 | }
169 | $i++
170 | }
171 | "^(-rqc|--ReadQueueCrit)$" {
172 | if (($value -match "^[\d]+$") -and ([int]$value -lt 999999)) {
173 | $DiskStruct.AvgDiskReadQueueCrit = $value
174 | } else {
175 | throw "Read queue critical does not meet regex requirements (`"^[\d]+$`"). Value given is `"$value`"."
176 | }
177 | $i++
178 | }
179 | "^(-wqw|--WriteQueueWarn)$" {
180 | if (($value -match "^[\d]+$") -and ([int]$value -lt 999999)) {
181 | $DiskStruct.AvgDiskWriteQueueWarn = $value
182 | } else {
183 | throw "Write queue warning does not meet regex requirements (`"^[\d]+$`"). Value given is `"$value`"."
184 | }
185 | $i++
186 | }
187 | "^(-wqc|--WriteQueueCrit)$" {
188 | if (($value -match "^[\d]+$") -and ([int]$value -lt 999999)) {
189 | $DiskStruct.AvgDiskWriteQueueCrit = $value
190 | } else {
191 | throw "Write queue critical does not meet regex requirements (`"^[\d]+$`"). Value given is `"$value`"."
192 | }
193 | $i++
194 | }
195 | "^(-ms|--MaxSamples)$" {
196 | if (($value -match "^[\d]+$") -and ([int]$value -lt 100)) {
197 | $DiskStruct.MaxSamples = $value
198 | } else {
199 | throw "Write queue critical does not meet regex requirements (`"^[\d]+$`"). Value given is `"$value`"."
200 | }
201 | $i++
202 | }
203 | "^(-h|--Help)$" {
204 | Write-Help
205 | }
206 | default {
207 | throw "Illegal arguments detected: $_"
208 | }
209 | }
210 | }
211 | }
212 | catch {
213 | Write-Host "Error: $_"
214 | Exit 2
215 | }
216 | }
217 |
218 | Function Test-Strings {
219 | Param ( [Parameter(Mandatory=$True)][string]$String )
220 | $BadChars=@("``", '|', ';', "`n")
221 | $BadChars | ForEach-Object {
222 | If ( $String.Contains("$_") ) {
223 | Write-Host "Error: String `"$String`" contains illegal characters."
224 | Exit $DiskStruct.ExitCode
225 | }
226 | }
227 | Return $true
228 | }
229 |
230 | Function Write-Help {
231 | Write-Host @"
232 | check_ms_windows_disk_load.ps1:
233 | This script is designed to monitor Microsoft Windows disk load.
234 | Arguments:
235 | -H | --Hostname => Optional hostname of remote system, default is localhost, not yet tested on remote host.
236 | -dl | --DiskLetter => Diskletter to get data from.
237 | -rqw | --ReadQueueWarn => Warning threshold for read queue length.
238 | -rqc | --ReadQueueCrit => Critical threshold for read queue length.
239 | -wqw | --WriteQueueWarn => Warning threshold for write queue length.
240 | -wqc | --WriteQueueCrit => Critical threshold for write queue length.
241 | -ms | --MaxSamples => Amount of samples to take.
242 | -h | --Help => Print this help output.
243 | "@
244 | Exit $DiskStruct.ExitCode;
245 | }
246 |
247 | function Get-PerformanceCounterID
248 | {
249 | param (
250 | [Parameter(Mandatory=$true)] $Name
251 | )
252 | if ($script:perfHash -eq $null) {
253 | Write-Progress -Activity 'Retrieving PerfIDs' -Status 'Working'
254 | $key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage'
255 | $counters = (Get-ItemProperty -Path $key -Name Counter).Counter
256 | $script:perfHash = @{}
257 | $all = $counters.Count
258 | for($i = 0; $i -lt $all; $i+=2) {
259 | Write-Progress -Activity 'Retrieving PerfIDs' -Status 'Working' -PercentComplete ($i*100/$all)
260 | $script:perfHash.$($counters[$i+1]) = $counters[$i]
261 | }
262 | }
263 | $script:perfHash.$Name
264 | }
265 |
266 | Function Get-PerformanceCounterLocalName
267 | {
268 | param (
269 | [UInt32]$ID,
270 | $ComputerName = $env:COMPUTERNAME
271 | )
272 | $code = '[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)] public static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, System.Text.StringBuilder szNameBuffer, ref uint pcchNameBufferSize);'
273 | $Buffer = New-Object System.Text.StringBuilder(1024)
274 | [UInt32]$BufferSize = $Buffer.Capacity
275 | $t = Add-Type -MemberDefinition $code -PassThru -Name PerfCounter -Namespace Utility
276 | $rv = $t::PdhLookupPerfNameByIndex($ComputerName, $id, $Buffer, [Ref]$BufferSize)
277 | if ($rv -eq 0) {
278 | $Buffer.ToString().Substring(0, $BufferSize-1)
279 | }
280 | else {
281 | Throw 'Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.'
282 | }
283 | }
284 |
285 | function Get-DiskLoadCounters
286 | {
287 | $PerfCounterArray = @()
288 |
289 | $LogicalDisk = Get-PerformanceCounterLocalName $DiskStruct.LogicalDiskId
290 | $AvgDiskSecRead = Get-PerformanceCounterLocalName $DiskStruct.AvgDiskSecReadId
291 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskSecRead"
292 | $AvgDiskSecWrite = Get-PerformanceCounterLocalName $DiskStruct.AvgDiskSecWriteId
293 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskSecWrite"
294 | $AvgDiskReadQueue = Get-PerformanceCounterLocalName $DiskStruct.AvgDiskReadQueueId
295 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskReadQueue"
296 | $AvgDiskWriteQueue = Get-PerformanceCounterLocalName $DiskStruct.AvgDiskWriteQueueId
297 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskWriteQueue"
298 | $AvgDiskReadsSec = Get-PerformanceCounterLocalName $DiskStruct.DiskReadsSecId
299 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskReadsSec"
300 | $AvgDiskWritesSec = Get-PerformanceCounterLocalName $DiskStruct.DiskWritesSecId
301 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskWritesSec"
302 | $AvgDiskReadBytesSec = Get-PerformanceCounterLocalName $DiskStruct.DiskReadBytesSecId
303 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskReadBytesSec"
304 | $AvgDiskWriteBytesSec = Get-PerformanceCounterLocalName $DiskStruct.DiskWriteBytesSecId
305 | $PerfCounterArray += "\$LogicalDisk($($DiskStruct.DiskLetter):)\$AvgDiskWriteBytesSec"
306 | $PfcValues = (Get-Counter $PerfCounterArray -MaxSamples $DiskStruct.MaxSamples)
307 | $AvgDiskSecReadValues = @()
308 | $AvgDiskSecWriteValues = @()
309 | $AvgDiskReadQueueValues = @()
310 | $AvgDiskWriteQueueValues = @()
311 | $AvgDiskReadsSecValues = @()
312 | $AvgDiskWritesSecValues = @()
313 | $AvgDiskReadBytesSecValues = @()
314 | $AvgDiskWriteBytesSecValues = @()
315 | for ($y=0; $y -lt $DiskStruct.MaxSamples; $y++) {
316 | $AvgDiskSecReadValues += $PfcValues[$y].CounterSamples[0].CookedValue
317 | $AvgDiskSecWriteValues += $PfcValues[$y].CounterSamples[1].CookedValue
318 | $AvgDiskReadQueueValues += $PfcValues[$y].CounterSamples[2].CookedValue
319 | $AvgDiskWriteQueueValues += $PfcValues[$y].CounterSamples[3].CookedValue
320 | $AvgDiskReadsSecValues += $PfcValues[$y].CounterSamples[4].CookedValue
321 | $AvgDiskWritesSecValues += $PfcValues[$y].CounterSamples[5].CookedValue
322 | $AvgDiskReadBytesSecValues += $PfcValues[$y].CounterSamples[6].CookedValue
323 | $AvgDiskWriteBytesSecValues += $PfcValues[$y].CounterSamples[7].CookedValue
324 | }
325 | $AvgObjDiskSecReadValues = $AvgDiskSecReadValues | Measure-Object -Average
326 | $AvgObjDiskSecWriteValues = $AvgDiskSecWriteValues | Measure-Object -Average
327 | $AvgObjDiskReadQueueValues = $AvgDiskReadQueueValues | Measure-Object -Average
328 | $AvgObjDiskWriteQueueValues = $AvgDiskWriteQueueValues | Measure-Object -Average
329 | $AvgObjDiskReadsSecValues = $AvgDiskReadsSecValues | Measure-Object -Average
330 | $AvgObjDiskWritesSecValues = $AvgDiskWritesSecValues | Measure-Object -Average
331 | $AvgObjDiskReadBytesSecValues = $AvgDiskReadBytesSecValues | Measure-Object -Average
332 | $AvgObjDiskWriteBytesSecValues = $AvgDiskWriteBytesSecValues | Measure-Object -Average
333 | $OldCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
334 | [System.Threading.Thread]::CurrentThread.CurrentCulture = 'en-US'
335 | $DiskStruct.AvgDiskSecReadValue = [decimal]('{0:N5}' -f ($AvgObjDiskSecReadValues.average * 1000))
336 | $DiskStruct.AvgDiskSecWriteValue = [decimal]('{0:N5}' -f ($AvgObjDiskSecWriteValues.average * 1000))
337 | $DiskStruct.AvgDiskReadQueueValue = [decimal]('{0:N5}' -f ($AvgObjDiskReadQueueValues.average))
338 | $DiskStruct.AvgDiskWriteQueueValue = [decimal]('{0:N5}' -f ($AvgObjDiskWriteQueueValues.average))
339 | $DiskStruct.DiskReadsSecValue = [decimal]('{0:N5}' -f ($AvgObjDiskReadsSecValues.average))
340 | $DiskStruct.DiskWritesSecValue = [decimal]('{0:N5}' -f ($AvgObjDiskWritesSecValues.average))
341 | $DiskStruct.DiskReadBytesSecValue = [decimal]('{0:N5}' -f ($AvgObjDiskReadBytesSecValues.average / 1024 / 1024))
342 | $DiskStruct.DiskWriteBytesSecValue = [decimal]('{0:N5}' -f ($AvgObjDiskWriteBytesSecValues.average / 1024 / 1024))
343 | [System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
344 | $ReadQueueCritThreshReached = $false
345 | $ReadQueueWarnThreshReached = $false
346 | $WriteQueueCritThreshReached = $false
347 | $WriteQueueWarnThreshReached = $false
348 | if ($DiskStruct.AvgDiskReadQueueCrit -ne $DefaultInt -and $DiskStruct.AvgDiskReadQueueValue -gt $DiskStruct.AvgDiskReadQueueCrit) {
349 | $DiskStruct.ExitCode = 2
350 | $ReadQueueCritThreshReached = $true
351 | $OutputReadQueue = "CRITICAL: Read Queue Threshold ($($DiskStruct.AvgDiskReadQueueCrit)) Passed!"
352 | }
353 | elseif ($DiskStruct.AvgDiskReadQueueWarn -ne $DefaultInt -and $DiskStruct.AvgDiskReadQueueValue -gt $DiskStruct.AvgDiskReadQueueWarn) {
354 | $DiskStruct.ExitCode = 1
355 | $ReadQueueWarnThreshReached = $true
356 | $OutputReadQueue = "WARNING: Read Queue Threshold ($($DiskStruct.AvgDiskReadQueueWarn)) Passed!"
357 | }
358 | if ($DiskStruct.AvgDiskWriteQueueCrit -ne $DefaultInt -and $DiskStruct.AvgDiskWriteQueueValue -gt $DiskStruct.AvgDiskWriteQueueCrit) {
359 | $DiskStruct.ExitCode = 2
360 | $WriteQueueCritThreshReached = $true
361 | $OutputWriteQueue = "CRITICAL: Write Queue Threshold ($($DiskStruct.AvgDiskWriteQueueCrit)) Passed!"
362 | }
363 | elseif ($DiskStruct.AvgDiskWriteQueueWarn -ne $DefaultInt -and $DiskStruct.AvgDiskWriteQueueValue -gt $DiskStruct.AvgDiskWriteQueueWarn) {
364 | $DiskStruct.ExitCode = 1
365 | $WriteQueueWarnThreshReached = $true
366 | $OutputWriteQueue = "WARNING: Write Queue Threshold ($($DiskStruct.AvgDiskWriteQueueWarn)) Passed!"
367 | }
368 |
369 | if ($ReadQueueCritThreshReached -eq $false -and $ReadQueueWarnThreshReached -eq $false -and $WriteQueueCritThreshReached -eq $false -and $WriteQueueWarnThreshReached -eq $false) {
370 | $DiskStruct.ReturnString = "OK: Drive $($DiskStruct.DiskLetter): Avg of $($DiskStruct.MaxSamples) samples: {Rate (Read: $($DiskStruct.DiskReadBytesSecValue)MB/s)(Write: $($DiskStruct.DiskWriteBytesSecValue)MB/s)} {Avg Nr of (Reads: $($DiskStruct.DiskReadsSecValue)r/s)(Writes: $($DiskStruct.DiskWritesSecValue)w/s)} {Latency (Read: $($DiskStruct.AvgDiskSecReadValue)ms)(Write: $($DiskStruct.AvgDiskSecWriteValue)ms)} {Queue Length (Read: $($DiskStruct.AvgDiskReadQueueValue)ql)(Write: $($DiskStruct.AvgDiskWriteQueueValue)ql)} | "
371 | $DiskStruct.ExitCode = 0
372 | }
373 | else {
374 | $DiskStruct.ReturnString = "$OutputReadQueue $OutputWriteQueue : Drive $($DiskStruct.DiskLetter): Avg of $($DiskStruct.MaxSamples) samples: {Rate (Read: $($DiskStruct.AvgDiskReadBytesSecValue)MB/s)(Write: $($DiskStruct.AvgDiskWriteBytesSecValue)MB/s)} {Avg Nr of (Reads: $($DiskStruct.DiskReadsSecValue)r/s)(Writes: $($DiskStruct.DiskWritesSecValue)w/s)} {Latency (Read: $($DiskStruct.AvgDiskSecReadValue)ms)(Write: $($DiskStruct.AvgDiskSecWriteValue)ms)} {Queue Length (Read: $($DiskStruct.AvgDiskReadQueueValue)ql)(Write: $($DiskStruct.AvgDiskWriteQueueValue)ql)} | "
375 | }
376 |
377 | $DiskStruct.ReturnString += "'Read_Latency'=$($DiskStruct.AvgDiskSecReadValue)ms "
378 | $DiskStruct.ReturnString += "'Write_Latency'=$($DiskStruct.AvgDiskSecWriteValue)ms "
379 | $DiskStruct.ReturnString += "'Read_Queue'=$($DiskStruct.AvgDiskReadQueueValue)ql "
380 | $DiskStruct.ReturnString += "'Write_Queue'=$($DiskStruct.AvgDiskWriteQueueValue)ql "
381 | $DiskStruct.ReturnString += "'Number_of_Reads'=$($DiskStruct.DiskReadsSecValue)r/s "
382 | $DiskStruct.ReturnString += "'Number_of_Writes'=$($DiskStruct.DiskWritesSecValue)w/s "
383 | $DiskStruct.ReturnString += "'Read_Rate'=$($DiskStruct.DiskReadBytesSecValue)MB/s "
384 | $DiskStruct.ReturnString += "'Write_Rate'=$($DiskStruct.DiskWriteBytesSecValue)MB/s "
385 | }
386 |
387 | #endregion Functions
388 |
389 | # Main function
390 |
391 | if ($Args) {
392 | if($Args[0].ToString() -ne "$ARG1$"){
393 | if($Args.count -ge 1){Initialize-Args $Args}
394 | }
395 | }
396 | Get-DiskLoadCounters
397 | Write-Host $DiskStruct.ReturnString
398 | Exit $DiskStruct.ExitCode
399 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Nagios plugin to check disk load on a Microsoft Windows host.
2 |
3 | ### Idea
4 |
5 | Check MS Windows disk load by using this Powershell script to get all disk load related counters from Windows Performance
6 | Manager, computing averages for all gathered samples and calculating read / write rate, number of reads / writes, read /
7 | write latency and read / write queue length.
8 |
9 | ### Screenshot
10 |
11 | 
12 |
13 | ### Status
14 |
15 | Production ready.
16 |
17 | ### How To
18 |
19 | Please visit https://outsideit.net/check-ms-win-disk-load for more information on how to use this plugin.
20 |
21 | ### Help
22 |
23 | In case you find a bug or have a feature request, please make an issue on GitHub.
24 |
25 | ### On Nagios Exchange
26 |
27 | https://exchange.nagios.org/directory/Plugins/Operating-Systems/Windows-NRPE/Check-Microsoft-Windows-Disk-Load/details
28 |
29 | ### Copyright
30 |
31 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
32 | License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
33 | version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
34 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
35 | details at .
--------------------------------------------------------------------------------