From 076219c6a8447cb1eb2df45bbe30aede7f18c5ea Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 13:50:37 +0000 Subject: [PATCH 01/16] Removed unused variable --- scripts_wip/Win_Disk_Space_Check.ps1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts_wip/Win_Disk_Space_Check.ps1 b/scripts_wip/Win_Disk_Space_Check.ps1 index 99a08eb6..798a481a 100644 --- a/scripts_wip/Win_Disk_Space_Check.ps1 +++ b/scripts_wip/Win_Disk_Space_Check.ps1 @@ -22,9 +22,6 @@ Param( [switch]$Percent ) -#Script Version -$sScriptVersion = "1.0" - function Win_Disk_Space_Check { [CmdletBinding()] Param( From d8468043a33dedbcbaddf25b7b596248e8b7e562 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 13:50:51 +0000 Subject: [PATCH 02/16] Renamed with approved verbs --- scripts_wip/Win_Disk_Space_Check.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts_wip/Win_Disk_Space_Check.ps1 b/scripts_wip/Win_Disk_Space_Check.ps1 index 798a481a..f2daece9 100644 --- a/scripts_wip/Win_Disk_Space_Check.ps1 +++ b/scripts_wip/Win_Disk_Space_Check.ps1 @@ -22,7 +22,7 @@ Param( [switch]$Percent ) -function Win_Disk_Space_Check { +function Confirm-DiskSpaceAvailable { [CmdletBinding()] Param( [Parameter(Mandatory)] @@ -39,11 +39,12 @@ function Win_Disk_Space_Check { $errors = 0 $drives = Get-PSDrive | Where-Object { $_.Provider.Name -eq "FileSystem" -and $_.Used -gt 0 } foreach ($drive in $drives) { + $name = $drive.Name if ($Percent) { #Percent flag is set #Calculate percent of space left on drive $remainingPercent = [math]::Round($drive.Used / ($drive.Free + $drive.Used)) - $name = $drive.Name + if ($Size -gt $remainingPercent) { Write-Output "$remainingPercent% space remaining on $name." $errors += 1 @@ -76,7 +77,7 @@ function Win_Disk_Space_Check { } } -if (-not(Get-Command 'Win_Disk_Space_Check' -errorAction SilentlyContinue)) { +if (-not(Get-Command 'Confirm-DiskSpaceAvailable' -errorAction SilentlyContinue)) { . $MyInvocation.MyCommand.Path } @@ -85,4 +86,4 @@ $scriptArgs = @{ Percent = $Percent } -Win_Disk_Space_Check @scriptArgs \ No newline at end of file +Confirm-DiskSpaceAvailable @scriptArgs \ No newline at end of file From b276122f8c2c4235aebe0bfe259361702da7f501 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 14:03:45 +0000 Subject: [PATCH 03/16] Refactored to condense logic, and correct issue with Percent reporting the percentage of FREE space available (was reporting the percentage of USED space) --- scripts_wip/Win_Disk_Space_Check.ps1 | 33 +++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/scripts_wip/Win_Disk_Space_Check.ps1 b/scripts_wip/Win_Disk_Space_Check.ps1 index f2daece9..9b9d654e 100644 --- a/scripts_wip/Win_Disk_Space_Check.ps1 +++ b/scripts_wip/Win_Disk_Space_Check.ps1 @@ -5,9 +5,9 @@ Long description Checks all FileSystem drives for an amount of space specified (amount is converted to Gigabytes). .EXAMPLE - Win_Disk_Space_Check -Size 10 + Confirm-DiskSpaceAvailable -Size 10 .EXAMPLE - Win_Disk_Space_Check -Size 10 -Percent + Confirm-DiskSpaceAvailable -Size 10 -Percent .NOTES Version: 1.0 Author: redanthrax @@ -37,26 +37,23 @@ function Confirm-DiskSpaceAvailable { Process { Try { $errors = 0 - $drives = Get-PSDrive | Where-Object { $_.Provider.Name -eq "FileSystem" -and $_.Used -gt 0 } + $drives = Get-PSDrive | Where-Object { $_.Provider.Name -eq "FileSystem" -and $_.Used -gt 0 -and $_.Name.ToLower() -ne "temp" } foreach ($drive in $drives) { - $name = $drive.Name + [string]$label = "GB" + [double]$available = 0 if ($Percent) { #Percent flag is set - #Calculate percent of space left on drive - $remainingPercent = [math]::Round($drive.Used / ($drive.Free + $drive.Used)) - - if ($Size -gt $remainingPercent) { - Write-Output "$remainingPercent% space remaining on $name." - $errors += 1 - } + #Calculate percent of free space left on drive + $available = [math]::Round(($drive.Free / ($drive.Free + $drive.Used)) * 100,2) + $label = "%" } else { - $free = [math]::Round($drive.Free / 1Gb, 2) - $name = $drive.Name - if ($Size -gt $free) { - Write-Output "${free}GB of space on $name." - $errors += 1 - } + $available = [math]::Round($drive.Free / 1Gb, 2) + } + + if ($Size -gt $available) { + Write-Output "$available $label space remaining on $($drive.Name)." + $errors += 1 } } } @@ -72,7 +69,7 @@ function Confirm-DiskSpaceAvailable { Exit 1 } - Write-Output "All disk space checked and clear." + Write-Output "All disks have been checked and have more than or equal to $size $label space available." Exit 0 } } From 68fa0ac80b7899cd353d4d8a731bc504cf6d61a5 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 14:28:16 +0000 Subject: [PATCH 04/16] Updated output messages and added an option to log successes as well as errors --- scripts_wip/Win_Disk_Space_Check.ps1 | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts_wip/Win_Disk_Space_Check.ps1 b/scripts_wip/Win_Disk_Space_Check.ps1 index 9b9d654e..89e7b8d4 100644 --- a/scripts_wip/Win_Disk_Space_Check.ps1 +++ b/scripts_wip/Win_Disk_Space_Check.ps1 @@ -12,6 +12,7 @@ Version: 1.0 Author: redanthrax Creation Date: 2022-04-05 + Updated: Owen Conti 2025-12-12 #> Param( @@ -26,10 +27,16 @@ function Confirm-DiskSpaceAvailable { [CmdletBinding()] Param( [Parameter(Mandatory)] - [int]$Size, + [int]#The minimum amount of GB that should be available + $Size, [Parameter(Mandatory = $false)] - [switch]$Percent + [switch]#Switches the Size to be a percentage instead of GB + $Percent, + + [Parameter(Mandatory = $false)] + [switch]#Writes a message out even when the drive has more than the minimum available amount. In other words, logs *every* time. + $outputSuccess ) Begin {} @@ -51,8 +58,12 @@ function Confirm-DiskSpaceAvailable { $available = [math]::Round($drive.Free / 1Gb, 2) } - if ($Size -gt $available) { + If($outputSuccess){ Write-Output "$available $label space remaining on $($drive.Name)." + } + + if ($Size -gt $available) { + Write-Output "ERROR: $($drive.Name) is below the threshold of $size $label ($available available)." $errors += 1 } } From 5e45df7b0560ece11db68941323bf9036f29f214 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 14:36:16 +0000 Subject: [PATCH 05/16] Connected outputSuccess to the actual execution of the function. --- scripts_wip/Win_Disk_Space_Check.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts_wip/Win_Disk_Space_Check.ps1 b/scripts_wip/Win_Disk_Space_Check.ps1 index 89e7b8d4..17242a1a 100644 --- a/scripts_wip/Win_Disk_Space_Check.ps1 +++ b/scripts_wip/Win_Disk_Space_Check.ps1 @@ -17,10 +17,16 @@ Param( [Parameter(Mandatory)] - [int]$Size, + [int]#The minimum amount of GB that should be available + $Size, [Parameter(Mandatory = $false)] - [switch]$Percent + [switch]#Switches the Size to be a percentage instead of GB + $Percent, + + [Parameter(Mandatory = $false)] + [switch]#Writes a message out even when the drive has more than the minimum available amount. In other words, logs *every* time. + $outputSuccess ) function Confirm-DiskSpaceAvailable { @@ -92,6 +98,7 @@ if (-not(Get-Command 'Confirm-DiskSpaceAvailable' -errorAction SilentlyContinue) $scriptArgs = @{ Size = $Size Percent = $Percent + outputSuccess = $outputSuccess } Confirm-DiskSpaceAvailable @scriptArgs \ No newline at end of file From 86c761db95530c313832b2052316a13dc3d746a7 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 10:10:10 +0000 Subject: [PATCH 06/16] Removed duplicate/predecessor file --- scripts_wip/Win_Disk_SMART.ps1 | 327 ++++++++++++++++++++------------ scripts_wip/Win_Disk_SMART2.ps1 | 215 --------------------- 2 files changed, 208 insertions(+), 334 deletions(-) delete mode 100644 scripts_wip/Win_Disk_SMART2.ps1 diff --git a/scripts_wip/Win_Disk_SMART.ps1 b/scripts_wip/Win_Disk_SMART.ps1 index fa5ea446..c255e5a3 100644 --- a/scripts_wip/Win_Disk_SMART.ps1 +++ b/scripts_wip/Win_Disk_SMART.ps1 @@ -1,126 +1,215 @@ -# From nullzilla - -# Requires -Version 3.0 +# Requires -Version 4.0 # Requires -RunAsAdministrator - -# If this is a virtual machine, we don't need to continue -$Computer = Get-CimInstance -ClassName 'Win32_ComputerSystem' -if ($Computer.Model -like 'Virtual*') { - exit -} - -$disks = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | Select-Object 'InstanceName') - -$Warnings = @() - -foreach ($disk in $disks.InstanceName) { - # Retrieve SMART data - $SmartData = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_ATAPISMartData' | Where-Object 'InstanceName' -eq $disk) - - [Byte[]]$RawSmartData = $SmartData | Select-Object -ExpandProperty 'VendorSpecific' - - # Starting at the third number (first two are irrelevant) - # get the relevant data by iterating over every 12th number - # and saving the values from an offset of the SMART attribute ID - [PSCustomObject[]]$Output = for ($i = 2; $i -lt $RawSmartData.Count; $i++) { - if (0 -eq ($i - 2) % 12 -and $RawSmartData[$i] -ne 0) { - # Construct the raw attribute value by combining the two bytes that make it up - [Decimal]$RawValue = ($RawSmartData[$i + 6] * [Math]::Pow(2, 8) + $RawSmartData[$i + 5]) - - $InnerOutput = [PSCustomObject]@{ - DiskID = $disk - ID = $RawSmartData[$i] - #Flags = $RawSmartData[$i + 1] - #Value = $RawSmartData[$i + 3] - Worst = $RawSmartData[$i + 4] - RawValue = $RawValue + +<# +.Synopsis + Outputs SMART data +.DESCRIPTION + Checks the system for a comprehensive list of SMART data. + Will exit on finding a virtual machine. + Use the -Warning flag to only get warnings instead of all data. + Use the -Pretty flag to make the output pretty. +.EXAMPLE + Win_Hardware_Disk_SMART +.EXAMPLE + Win_Hardware_Disk_SMART -Warning +.EXAMPLE + Win_Hardware_Disk_SMART -Warning -Pretty +.NOTES + Version: 1.0 + Author: nullzilla + Modified by: redanthrax +#> + +Param( + [Parameter(Mandatory = $false)] + [switch]$Warning, + + [Parameter(Mandatory = $false)] + [switch]$Pretty +) + +function Win_Hardware_Disk_SMART { + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false)] + [switch]$Warning, + + [Parameter(Mandatory = $false)] + [switch]$Pretty + ) + + Begin { + # If this is a virtual machine, we don't need to continue + $Computer = Get-CimInstance -ClassName 'Win32_ComputerSystem' + if ($Computer.Model -like 'Virtual*') { + exit + } + } + + Process { + Try { + $data = @{} + $disks = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | Select-Object 'InstanceName') + foreach ($disk in $disks.InstanceName) { + $SmartData = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_ATAPISMartData' | Where-Object 'InstanceName' -eq $disk) + [Byte[]]$RawSmartData = $SmartData | Select-Object -ExpandProperty 'VendorSpecific' + # Starting at the third number (first two are irrelevant) + # get the relevant data by iterating over every 12th number + # and saving the values from an offset of the SMART attribute ID + [PSCustomObject[]]$Output = for ($i = 2; $i -lt $RawSmartData.Count; $i++) { + if (0 -eq ($i - 2) % 12 -and $RawSmartData[$i] -ne 0) { + # Construct the raw attribute value by combining the two bytes that make it up + [Decimal]$RawValue = ($RawSmartData[$i + 6] * [Math]::Pow(2, 8) + $RawSmartData[$i + 5]) + + $InnerOutput = [PSCustomObject]@{ + ID = $RawSmartData[$i] + #Flags = $RawSmartData[$i + 1] + #Value = $RawSmartData[$i + 3] + Worst = $RawSmartData[$i + 4] + RawValue = $RawValue + } + + $InnerOutput + + } + } + + # View full table with + #$Output + + $diskData = [PSCustomObject]@{ + "Reallocated Sector Count" = ($Output | Where-Object ID -eq 5 | Select-Object -ExpandProperty RawValue) + "Spin Retry Count" = ($Output | Where-Object ID -eq 10 | Select-Object -ExpandProperty RawValue) + "Recalibration Retries" = ($Output | Where-Object ID -eq 11 | Select-Object -ExpandProperty RawValue) + "Used Reserved Block Count Total" = ($Output | Where-Object ID -eq 179 | Select-Object -ExpandProperty RawValue) + "Erase Failure Count" = ($Output | Where-Object ID -eq 182 | Select-Object -ExpandProperty RawValue) + "SATA Downshift Error Countor Runtime Bad Block" = ($Output | Where-Object ID -eq 183 | Select-Object -ExpandProperty RawValue) + "End-to-End error / IOEDC" = ($Output | Where-Object ID -eq 184 | Select-Object -ExpandProperty RawValue) + "Reported Uncorrectable Errors" = ($Output | Where-Object ID -eq 187 | Select-Object -ExpandProperty RawValue) + "Command Timeout" = ($Output | Where-Object ID -eq 188 | Select-Object -ExpandProperty RawValue) + "High Fly Writes" = ($Output | Where-Object ID -eq 189 | Select-Object -ExpandProperty RawValue) + "Temperature Celcius" = ($Output | Where-Object ID -eq 194 | Select-Object -ExpandProperty RawValue) + "Reallocation Event Count" = ($Output | Where-Object ID -eq 196 | Select-Object -ExpandProperty RawValue) + "Current Pending Sector Count" = ($Output | Where-Object ID -eq 197 | Select-Object -ExpandProperty RawValue) + "Uncorrectable Sector Count" = ($Output | Where-Object ID -eq 198 | Select-Object -ExpandProperty RawValue) + "UltraDMA CRC Error Count" = ($Output | Where-Object ID -eq 199 | Select-Object -ExpandProperty RawValue) + "Soft Read Error Rate" = ($Output | Where-Object ID -eq 201 | Select-Object -ExpandProperty RawValue) + "SSD Life Left" = ($Output | Where-Object ID -eq 231 | Select-Object -ExpandProperty RawValue) + "SSD Media Wear Out Indicator" = ($Output | Where-Object ID -eq 233 | Select-Object -ExpandProperty RawValue) + "Power On Hours" = ($Output | Where-Object ID -eq 9 | Select-Object -ExpandProperty RawValue) + "FailurePredictStatus" = ( + Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | + Select-Object PredictFailure, Reason + ) + "DiskDriveOkay" = ( + Get-CimInstance -ClassName 'Win32_DiskDrive' | + Select-Object -ExpandProperty Status + ) + "PhysicalDiskOkayAndHealthy" = ( + Get-PhysicalDisk | + Select-Object OperationalStatus, HealthStatus + ) + } + + $data.Add($disk, $diskData) + } + + #Only output warnings + if ($Warning) { + $warnings = @{} + $data.GetEnumerator() | Foreach-Object { + $diskWarnings = @{} + $_.Value.psobject.Members | ForEach-Object { + $item = $_ + switch ($_.Name) { + #Anything in this section will cause the script to return warning. + "Power On Hours" { if ($null -ne $item.Value -and $item.Value -gt 50000) { $diskWarnings.Add($item.Name, $item.Value) } } #Remove line or adjust 50000 number if you don't want Old drives to start returning Warnings + "Reallocated Sector Count" { if ($null -ne $item.Value -and $item.Value -gt 1) { $diskWarnings.Add($item.Name, $item.Value) } } + "Recalibration Retries" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Used Reserved Block Count Total" { if ($null -ne $item.Value -and $item.Value -gt 1) { $diskWarnings.Add($item.Name, $item.Value) } } + "Erase Failure Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "SATA Downshift Error Countor Runtime Bad Block" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "End-to-End error / IOEDC" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Reported Uncorrectable Errors" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Command Timeout" { if ($null -ne $item.Value -and $item.Value -gt 2) { $diskWarnings.Add($item.Name, $item.Value) } } + "High Fly Writes" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Temperature Celcius" { if ($null -ne $item.Value -and $item.Value -gt 50) { $diskWarnings.Add($item.Name, $item.Value) } } + "Reallocation Event Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Current Pending Sector Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Uncorrectable Sector Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "UltraDMA CRC Error Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } + "Soft Read Error Rate" { if ($null -ne $item.Value -and $item.Value -lt 95) { $diskWarnings.Add($item.Name, $item.Value) } } + "SSD Life Left" { if ($null -ne $item.Value -and $item.Value -lt 50) { $diskWarnings.Add($item.Name, $item.Value) } } + "SSD Media Wear Out Indicator" { if ($null -ne $item.Value -and $item.Value -lt 50) { $diskWarnings.Add($item.Name, $item.Value) } } + "FailurePredictStatus" { if ($item.Value | Where-Object PredictFailure -ne $False) { $diskWarnings.Add($item.Name, $item.Value) } } + "DiskDriveOkay" { if ($null -ne $item.Value -and $item.Value -ne 'OK') { $diskWarnings.Add($item.Name, $item.Value) } } + "PhysicalDiskOkayAndHealthy" { if ($item.Value | Where-Object { ($_.OperationalStatus -ne 'OK') -or ($_.HealthStatus -ne 'Healthy') }) { $diskWarnings.Add($item.Name, $item.Value) } } + } + } + + if ($diskWarnings.Count -gt 0) { + $warnings.Add($_.Key, $diskWarnings) + } + } + + if ($warnings.Count -gt 0) { + if ($Pretty) { + foreach ($key in $warnings.Keys) { + Write-Output "Disk: $key" + Write-Output $warnings[$key] + } + } + else { + $warnings + } + Write-Output "Done" + Exit 1 + } + } + else { + if ($Pretty) { + foreach ($key in $data.Keys) { + Write-Output "Disk: $key" + Write-Output $data[$key] + } + } + else { + $data + } } - - $InnerOutput + } + + Catch { + $exception = $_.Exception + Write-Output "Error: $exception" + Write-Output "Done" + Exit 1 } } - - # Reallocated Sectors Count - $Warnings += $Output | Where-Object ID -eq 5 | Where-Object RawValue -gt 1 | Format-Table - - # Spin Retry Count - $Warnings += $Output | Where-Object ID -eq 10 | Where-Object RawValue -ne 0 | Format-Table - - # Recalibration Retries - $Warnings += $Output | Where-Object ID -eq 11 | Where-Object RawValue -ne 0 | Format-Table - - # Used Reserved Block Count Total - $Warnings += $Output | Where-Object ID -eq 179 | Where-Object RawValue -gt 1 | Format-Table - - # Erase Failure Count - $Warnings += $Output | Where-Object ID -eq 182 | Where-Object RawValue -ne 0 | Format-Table - - # SATA Downshift Error Count or Runtime Bad Block - $Warnings += $Output | Where-Object ID -eq 183 | Where-Object RawValue -ne 0 | Format-Table - - # End-to-End error / IOEDC - $Warnings += $Output | Where-Object ID -eq 184 | Where-Object RawValue -ne 0 | Format-Table - - # Reported Uncorrectable Errors - $Warnings += $Output | Where-Object ID -eq 187 | Where-Object RawValue -ne 0 | Format-Table - - # Command Timeout - $Warnings += $Output | Where-Object ID -eq 188 | Where-Object RawValue -gt 2 | Format-Table - - # High Fly Writes - $Warnings += $Output | Where-Object ID -eq 189 | Where-Object RawValue -ne 0 | Format-Table - - # Temperature Celcius - $Warnings += $Output | Where-Object ID -eq 194 | Where-Object RawValue -gt 50 | Format-Table - - # Reallocation Event Count - $Warnings += $Output | Where-Object ID -eq 196 | Where-Object RawValue -ne 0 | Format-Table - - # Current Pending Sector Count - $Warnings += $Output | Where-Object ID -eq 197 | Where-Object RawValue -ne 0 | Format-Table - - # Uncorrectable Sector Count - $Warnings += $Output | Where-Object ID -eq 198 | Where-Object RawValue -ne 0 | Format-Table - - # UltraDMA CRC Error Count - $Warnings += $Output | Where-Object ID -eq 199 | Where-Object RawValue -ne 0 | Format-Table - - # Soft Read Error Rate - $Warnings += $Output | Where-Object ID -eq 201 | Where-Object Worst -lt 95 | Format-Table - - # SSD Life Left - $Warnings += $Output | Where-Object ID -eq 231 | Where-Object Worst -lt 50 | Format-Table - - # SSD Media Wear Out Indicator - $Warnings += $Output | Where-Object ID -eq 233 | Where-Object Worst -lt 50 | Format-Table - + + End { + if ($Error) { + if ($Error -match "Not supported") { + Write-Output "You may need to switch from ACHI to RAID/RST mode, see the link for how to do this non-destructively: https://www.top-password.com/blog/switch-from-raid-to-ahci-without-reinstalling-windows/" + } + + Write-Output $Error + Write-Output "Done" + exit 1 + } + Write-Output "Done" + Exit 0 + } } - -$Warnings += Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | -Select-Object InstanceName, PredictFailure, Reason | -Where-Object { $_.PredictFailure -ne $False } | Format-Table - -$Warnings += Get-CimInstance -ClassName 'Win32_DiskDrive' | -Select-Object Model, SerialNumber, Name, Size, Status | -Where-Object { $_.status -ne 'OK' } | Format-Table - -$Warnings += Get-PhysicalDisk | -Select-Object FriendlyName, Size, MediaType, OperationalStatus, HealthStatus | -Where-Object { $_.OperationalStatus -ne 'OK' -or $_.HealthStatus -ne 'Healthy' } | Format-Table - -if ($Warnings) { - $Warnings = $warnings | Out-String - $Warnings - Write-Host "$Warnings" - Exit 1 + +if (-not(Get-Command 'Win_Hardware_Disk_SMART' -errorAction SilentlyContinue)) { + . $MyInvocation.MyCommand.Path } - -if ($Error) { - if ($Error -match "Not supported") { - $notsup = "You may need to switch from ACHI to RAID/RST mode, see the link for how to do this non-destructively: https://www.top-password.com/blog/switch-from-raid-to-ahci-without-reinstalling-windows/" - $notsup - } - Write-Host "$Error $notsup" - exit 1 + +$scriptArgs = @{ + Warning = $Warning + Pretty = $Pretty } - + +Win_Hardware_Disk_SMART @scriptArgs \ No newline at end of file diff --git a/scripts_wip/Win_Disk_SMART2.ps1 b/scripts_wip/Win_Disk_SMART2.ps1 deleted file mode 100644 index c255e5a3..00000000 --- a/scripts_wip/Win_Disk_SMART2.ps1 +++ /dev/null @@ -1,215 +0,0 @@ -# Requires -Version 4.0 -# Requires -RunAsAdministrator - -<# -.Synopsis - Outputs SMART data -.DESCRIPTION - Checks the system for a comprehensive list of SMART data. - Will exit on finding a virtual machine. - Use the -Warning flag to only get warnings instead of all data. - Use the -Pretty flag to make the output pretty. -.EXAMPLE - Win_Hardware_Disk_SMART -.EXAMPLE - Win_Hardware_Disk_SMART -Warning -.EXAMPLE - Win_Hardware_Disk_SMART -Warning -Pretty -.NOTES - Version: 1.0 - Author: nullzilla - Modified by: redanthrax -#> - -Param( - [Parameter(Mandatory = $false)] - [switch]$Warning, - - [Parameter(Mandatory = $false)] - [switch]$Pretty -) - -function Win_Hardware_Disk_SMART { - [CmdletBinding()] - Param( - [Parameter(Mandatory = $false)] - [switch]$Warning, - - [Parameter(Mandatory = $false)] - [switch]$Pretty - ) - - Begin { - # If this is a virtual machine, we don't need to continue - $Computer = Get-CimInstance -ClassName 'Win32_ComputerSystem' - if ($Computer.Model -like 'Virtual*') { - exit - } - } - - Process { - Try { - $data = @{} - $disks = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | Select-Object 'InstanceName') - foreach ($disk in $disks.InstanceName) { - $SmartData = (Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_ATAPISMartData' | Where-Object 'InstanceName' -eq $disk) - [Byte[]]$RawSmartData = $SmartData | Select-Object -ExpandProperty 'VendorSpecific' - # Starting at the third number (first two are irrelevant) - # get the relevant data by iterating over every 12th number - # and saving the values from an offset of the SMART attribute ID - [PSCustomObject[]]$Output = for ($i = 2; $i -lt $RawSmartData.Count; $i++) { - if (0 -eq ($i - 2) % 12 -and $RawSmartData[$i] -ne 0) { - # Construct the raw attribute value by combining the two bytes that make it up - [Decimal]$RawValue = ($RawSmartData[$i + 6] * [Math]::Pow(2, 8) + $RawSmartData[$i + 5]) - - $InnerOutput = [PSCustomObject]@{ - ID = $RawSmartData[$i] - #Flags = $RawSmartData[$i + 1] - #Value = $RawSmartData[$i + 3] - Worst = $RawSmartData[$i + 4] - RawValue = $RawValue - } - - $InnerOutput - - } - } - - # View full table with - #$Output - - $diskData = [PSCustomObject]@{ - "Reallocated Sector Count" = ($Output | Where-Object ID -eq 5 | Select-Object -ExpandProperty RawValue) - "Spin Retry Count" = ($Output | Where-Object ID -eq 10 | Select-Object -ExpandProperty RawValue) - "Recalibration Retries" = ($Output | Where-Object ID -eq 11 | Select-Object -ExpandProperty RawValue) - "Used Reserved Block Count Total" = ($Output | Where-Object ID -eq 179 | Select-Object -ExpandProperty RawValue) - "Erase Failure Count" = ($Output | Where-Object ID -eq 182 | Select-Object -ExpandProperty RawValue) - "SATA Downshift Error Countor Runtime Bad Block" = ($Output | Where-Object ID -eq 183 | Select-Object -ExpandProperty RawValue) - "End-to-End error / IOEDC" = ($Output | Where-Object ID -eq 184 | Select-Object -ExpandProperty RawValue) - "Reported Uncorrectable Errors" = ($Output | Where-Object ID -eq 187 | Select-Object -ExpandProperty RawValue) - "Command Timeout" = ($Output | Where-Object ID -eq 188 | Select-Object -ExpandProperty RawValue) - "High Fly Writes" = ($Output | Where-Object ID -eq 189 | Select-Object -ExpandProperty RawValue) - "Temperature Celcius" = ($Output | Where-Object ID -eq 194 | Select-Object -ExpandProperty RawValue) - "Reallocation Event Count" = ($Output | Where-Object ID -eq 196 | Select-Object -ExpandProperty RawValue) - "Current Pending Sector Count" = ($Output | Where-Object ID -eq 197 | Select-Object -ExpandProperty RawValue) - "Uncorrectable Sector Count" = ($Output | Where-Object ID -eq 198 | Select-Object -ExpandProperty RawValue) - "UltraDMA CRC Error Count" = ($Output | Where-Object ID -eq 199 | Select-Object -ExpandProperty RawValue) - "Soft Read Error Rate" = ($Output | Where-Object ID -eq 201 | Select-Object -ExpandProperty RawValue) - "SSD Life Left" = ($Output | Where-Object ID -eq 231 | Select-Object -ExpandProperty RawValue) - "SSD Media Wear Out Indicator" = ($Output | Where-Object ID -eq 233 | Select-Object -ExpandProperty RawValue) - "Power On Hours" = ($Output | Where-Object ID -eq 9 | Select-Object -ExpandProperty RawValue) - "FailurePredictStatus" = ( - Get-CimInstance -Namespace 'Root\WMI' -ClassName 'MSStorageDriver_FailurePredictStatus' | - Select-Object PredictFailure, Reason - ) - "DiskDriveOkay" = ( - Get-CimInstance -ClassName 'Win32_DiskDrive' | - Select-Object -ExpandProperty Status - ) - "PhysicalDiskOkayAndHealthy" = ( - Get-PhysicalDisk | - Select-Object OperationalStatus, HealthStatus - ) - } - - $data.Add($disk, $diskData) - } - - #Only output warnings - if ($Warning) { - $warnings = @{} - $data.GetEnumerator() | Foreach-Object { - $diskWarnings = @{} - $_.Value.psobject.Members | ForEach-Object { - $item = $_ - switch ($_.Name) { - #Anything in this section will cause the script to return warning. - "Power On Hours" { if ($null -ne $item.Value -and $item.Value -gt 50000) { $diskWarnings.Add($item.Name, $item.Value) } } #Remove line or adjust 50000 number if you don't want Old drives to start returning Warnings - "Reallocated Sector Count" { if ($null -ne $item.Value -and $item.Value -gt 1) { $diskWarnings.Add($item.Name, $item.Value) } } - "Recalibration Retries" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Used Reserved Block Count Total" { if ($null -ne $item.Value -and $item.Value -gt 1) { $diskWarnings.Add($item.Name, $item.Value) } } - "Erase Failure Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "SATA Downshift Error Countor Runtime Bad Block" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "End-to-End error / IOEDC" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Reported Uncorrectable Errors" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Command Timeout" { if ($null -ne $item.Value -and $item.Value -gt 2) { $diskWarnings.Add($item.Name, $item.Value) } } - "High Fly Writes" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Temperature Celcius" { if ($null -ne $item.Value -and $item.Value -gt 50) { $diskWarnings.Add($item.Name, $item.Value) } } - "Reallocation Event Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Current Pending Sector Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Uncorrectable Sector Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "UltraDMA CRC Error Count" { if ($null -ne $item.Value -and $item.Value -ne 0) { $diskWarnings.Add($item.Name, $item.Value) } } - "Soft Read Error Rate" { if ($null -ne $item.Value -and $item.Value -lt 95) { $diskWarnings.Add($item.Name, $item.Value) } } - "SSD Life Left" { if ($null -ne $item.Value -and $item.Value -lt 50) { $diskWarnings.Add($item.Name, $item.Value) } } - "SSD Media Wear Out Indicator" { if ($null -ne $item.Value -and $item.Value -lt 50) { $diskWarnings.Add($item.Name, $item.Value) } } - "FailurePredictStatus" { if ($item.Value | Where-Object PredictFailure -ne $False) { $diskWarnings.Add($item.Name, $item.Value) } } - "DiskDriveOkay" { if ($null -ne $item.Value -and $item.Value -ne 'OK') { $diskWarnings.Add($item.Name, $item.Value) } } - "PhysicalDiskOkayAndHealthy" { if ($item.Value | Where-Object { ($_.OperationalStatus -ne 'OK') -or ($_.HealthStatus -ne 'Healthy') }) { $diskWarnings.Add($item.Name, $item.Value) } } - } - } - - if ($diskWarnings.Count -gt 0) { - $warnings.Add($_.Key, $diskWarnings) - } - } - - if ($warnings.Count -gt 0) { - if ($Pretty) { - foreach ($key in $warnings.Keys) { - Write-Output "Disk: $key" - Write-Output $warnings[$key] - } - } - else { - $warnings - } - Write-Output "Done" - Exit 1 - } - } - else { - if ($Pretty) { - foreach ($key in $data.Keys) { - Write-Output "Disk: $key" - Write-Output $data[$key] - } - } - else { - $data - } - } - } - - Catch { - $exception = $_.Exception - Write-Output "Error: $exception" - Write-Output "Done" - Exit 1 - } - } - - End { - if ($Error) { - if ($Error -match "Not supported") { - Write-Output "You may need to switch from ACHI to RAID/RST mode, see the link for how to do this non-destructively: https://www.top-password.com/blog/switch-from-raid-to-ahci-without-reinstalling-windows/" - } - - Write-Output $Error - Write-Output "Done" - exit 1 - } - Write-Output "Done" - Exit 0 - } -} - -if (-not(Get-Command 'Win_Hardware_Disk_SMART' -errorAction SilentlyContinue)) { - . $MyInvocation.MyCommand.Path -} - -$scriptArgs = @{ - Warning = $Warning - Pretty = $Pretty -} - -Win_Hardware_Disk_SMART @scriptArgs \ No newline at end of file From d8809ca2b7eabb576cae40050cb37f16d8421799 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 11:39:56 +0000 Subject: [PATCH 07/16] Added a disk health check based on Windows Storage Reliability Counters. --- scripts_wip/Win_Disk_HealthCheck.ps1 | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 scripts_wip/Win_Disk_HealthCheck.ps1 diff --git a/scripts_wip/Win_Disk_HealthCheck.ps1 b/scripts_wip/Win_Disk_HealthCheck.ps1 new file mode 100644 index 00000000..351fc1d7 --- /dev/null +++ b/scripts_wip/Win_Disk_HealthCheck.ps1 @@ -0,0 +1,92 @@ +<# +.Synopsis + Outputs Drive Health +.DESCRIPTION + This was written specifically for use as a "Script Check" in mind, where it the output is deliberaly light unless a warning or error condition is found that needs more investigation. + + Uses the Windows Storage Reliabilty Counters first (the information behind Settings - Storage - Disks & Volumes - %DiskID% - Drive health) to report on drive health. + + Will exit if running on a virtual machine. + +.NOTES + Learing taken from "Win_Disk_SMART2.ps1" by nullzilla, and modified by: redanthrax +#> + +# Requires -Version 5.0 +# Requires -RunAsAdministrator +[cmdletbinding()] +Param( + [Parameter(Mandatory = $false)] + [int]#Warn if the temperature (in degrees C) is over this limit + $TemperatureWarningLimit = 45, + + [Parameter(Mandatory = $false)] + [int]#Warn if the "wear" of the drive (as a percentage) is above this + $maximumWearAllowance = 20, + + [Parameter(Mandatory = $false)] + [switch]#Outputs a full report, instead of warnings only + $fullReport +) + +BEGIN { + # If this is a virtual machine, we don't need to continue + $Computer = Get-CimInstance -ClassName 'Win32_ComputerSystem' + if ($Computer.Model -like 'Virtual*') { + exit + } + } + +PROCESS { + Try{ + #Using Windows Storage Reliabilty Counters first (the information behind Settings - Storage - Disks & Volumes - %DiskID% - Drive health) + $physicalDisks = Get-PhysicalDisk -ErrorAction Stop + $storageResults = @() + foreach ($disk in $physicalDisks) { + $reliabilityCounter = $null + try { + $reliabilityCounter = $disk | Get-StorageReliabilityCounter -ErrorAction Stop + } + catch { + Write-Error "No Storage Reliability Counter for '$($disk.FriendlyName)'. This usually means the driver/controller isn't exposing it." + } + + $storageResults += [pscustomobject]@{ + FriendlyName = $disk.FriendlyName + SerialNumber = $disk.SerialNumber + BusType = $disk.BusType + HealthStatus = $disk.HealthStatus + OperationalStatus = ($disk.OperationalStatus -join ", ") + Temperature = $reliabilityCounter.Temperature + Wear = $reliabilityCounter.Wear + ReadErrorsTotal = $reliabilityCounter.ReadErrorsTotal + WriteErrorsTotal = $reliabilityCounter.WriteErrorsTotal + ReallocatedSectors = $reliabilityCounter.ReallocatedSectors + PowerOnHours = $reliabilityCounter.PowerOnHours + } + + If( + $disk.HealthStatus.ToLower() -ne "healthy" -or + ($disk.OperationalStatus | Where-Object -FilterScript { $_.ToLower() -ne "ok" }) -or + $reliabilityCounter.Wear -ge $maximumWearAllowance -or + $reliabilityCounter.Temperature -ge $TemperatureWarningLimit + ){ + Write-Error -Message "$($disk.FriendlyName) has conditions that require investigation. $storageResults" + } + } + + If($fullReport) { $storageResults } + + } catch { + Write-Error -Message "Get-PhysicalDisk failed. This can happen on older OS builds or restricted environments." + } +} + +END{ + if ($error) { + Write-Output $error + exit 1 + } + Write-Output "All drives report as healthy" + Exit 0 +} \ No newline at end of file From 626fbe0add0b6b0b8f7572b2bb9253cdf70919b2 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 11:54:41 +0000 Subject: [PATCH 08/16] Added a check for excessive uptime (defaults for workstations) --- scripts_wip/Win_CPU_Uptime_Check.ps1 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 scripts_wip/Win_CPU_Uptime_Check.ps1 diff --git a/scripts_wip/Win_CPU_Uptime_Check.ps1 b/scripts_wip/Win_CPU_Uptime_Check.ps1 new file mode 100644 index 00000000..34ae2ad7 --- /dev/null +++ b/scripts_wip/Win_CPU_Uptime_Check.ps1 @@ -0,0 +1,24 @@ +<# +.Synopsis + Checks Uptime of the computer +.DESCRIPTION + This was written specifically for use as a "Script Check" in mind, where it the output is deliberaly light unless a warning or error condition is found that needs more investigation. + + If the totalhours of uptime of the computer is greater than or equal to the warning limit, an error is returned. + +.NOTES + Learing taken from "Win_Disk_SMART2.ps1" by nullzilla, and modified by: redanthrax +#> +[cmdletbinding()] +Param( + [Parameter(Mandatory = $false)] + [int]#Warn if the uptime total hours is over this limit. Defaults to 2.5 days. + $maximumUptimeHoursWarningLimit = 60 +) + +If((Get-Uptime).TotalHours -ge $maximumUptimeHoursWarningLimit){ + return 1 + exit +} + +return 0 \ No newline at end of file From 51a6dae6a9b1cabf0154ea032e02a21350620b6d Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 12:00:36 +0000 Subject: [PATCH 09/16] Updated to be backwards compatable with PS v5 --- scripts_wip/Win_CPU_Uptime_Check.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts_wip/Win_CPU_Uptime_Check.ps1 b/scripts_wip/Win_CPU_Uptime_Check.ps1 index 34ae2ad7..7615930d 100644 --- a/scripts_wip/Win_CPU_Uptime_Check.ps1 +++ b/scripts_wip/Win_CPU_Uptime_Check.ps1 @@ -9,6 +9,7 @@ .NOTES Learing taken from "Win_Disk_SMART2.ps1" by nullzilla, and modified by: redanthrax #> + [cmdletbinding()] Param( [Parameter(Mandatory = $false)] @@ -16,7 +17,10 @@ Param( $maximumUptimeHoursWarningLimit = 60 ) -If((Get-Uptime).TotalHours -ge $maximumUptimeHoursWarningLimit){ +$uptime = (get-Date) - (Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime) + #v7 introduces Get-Uptime, but using WMI is backwards compatiable with v5 + +If($uptime.TotalHours -ge $maximumUptimeHoursWarningLimit){ return 1 exit } From 47c5a25d1338178af4419663107c9e15c8911933 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 12:06:28 +0000 Subject: [PATCH 10/16] Changed return for Exit code so Tactical RMM picks it up correctly. --- scripts_wip/Win_CPU_Uptime_Check.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts_wip/Win_CPU_Uptime_Check.ps1 b/scripts_wip/Win_CPU_Uptime_Check.ps1 index 7615930d..05f243a3 100644 --- a/scripts_wip/Win_CPU_Uptime_Check.ps1 +++ b/scripts_wip/Win_CPU_Uptime_Check.ps1 @@ -21,8 +21,9 @@ $uptime = (get-Date) - (Get-CimInstance -ClassName Win32_OperatingSystem | Selec #v7 introduces Get-Uptime, but using WMI is backwards compatiable with v5 If($uptime.TotalHours -ge $maximumUptimeHoursWarningLimit){ - return 1 - exit + "Uptime is over threshold ($($uptime.TotalHours)/$maximumUptimeHoursWarningLimit)" + Exit 1 } -return 0 \ No newline at end of file +"Uptime is below threshold ($($uptime.TotalHours)/$maximumUptimeHoursWarningLimit)" +Exit 0 \ No newline at end of file From bee5c320d8544822dfdfd3223b2c05e1b0f263ae Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 12:32:46 +0000 Subject: [PATCH 11/16] Updated comment help --- scripts_wip/Win_CPU_Uptime_Check.ps1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts_wip/Win_CPU_Uptime_Check.ps1 b/scripts_wip/Win_CPU_Uptime_Check.ps1 index 05f243a3..1fb55d11 100644 --- a/scripts_wip/Win_CPU_Uptime_Check.ps1 +++ b/scripts_wip/Win_CPU_Uptime_Check.ps1 @@ -5,9 +5,6 @@ This was written specifically for use as a "Script Check" in mind, where it the output is deliberaly light unless a warning or error condition is found that needs more investigation. If the totalhours of uptime of the computer is greater than or equal to the warning limit, an error is returned. - -.NOTES - Learing taken from "Win_Disk_SMART2.ps1" by nullzilla, and modified by: redanthrax #> [cmdletbinding()] From 0fef93c918308b273fea98e19d1141a48556397d Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 12:54:09 +0000 Subject: [PATCH 12/16] Added RAM Check --- scripts_wip/Win_RAM_Available_Check.ps1 | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 scripts_wip/Win_RAM_Available_Check.ps1 diff --git a/scripts_wip/Win_RAM_Available_Check.ps1 b/scripts_wip/Win_RAM_Available_Check.ps1 new file mode 100644 index 00000000..09d04e7b --- /dev/null +++ b/scripts_wip/Win_RAM_Available_Check.ps1 @@ -0,0 +1,39 @@ +<# +.Synopsis + Checks the available amount of RAM on a computer +.DESCRIPTION + This was written specifically for use as a "Script Check" in mind, where it the output is deliberaly light unless a warning or error condition is found that needs more investigation. + + If the total available (free) amount of RAM is less than the warning limit, an error is returned. + +#> + +[cmdletbinding()] +Param( + [Parameter(Mandatory = $false)] + [double]#Warn if the amount of available RAM (defaults to GB) is below this limit. Defaults to 1 GB. + $minimumAvailableRAM = 1, + + [Parameter(Mandatory = $false)] + [switch]#Use percentage instead of absolute GB values + $percent +) + +$os = Get-CimInstance -ClassName Win32_OperatingSystem + +$available = [math]::Round(($os.FreePhysicalMemory * 1KB) / 1GB, 2) +$label = "GB" +if ($Percent) { + #Percent flag is set + #Calculate percent of free space left on drive + $available = [math]::Round(($os.FreePhysicalMemory / $os.TotalVisibleMemorySize) * 100, 1) + $label = "%" +} + +If($minimumAvailableRAM -gt $available){ + Write-Output "Avalable RAM is below the threshold of $minimumAvailableRAM $label ($available $label available)." + Exit 1 +} else { + Write-Output "Avalable RAM is above the threshold of $minimumAvailableRAM $label ($available $label available)." + Exit 0 +} \ No newline at end of file From d303d9b32bc8098c3c3096a03a40e3798f6529cb Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 13:14:22 +0000 Subject: [PATCH 13/16] updating comments from copy/paste --- scripts_wip/Win_RAM_Available_Check.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts_wip/Win_RAM_Available_Check.ps1 b/scripts_wip/Win_RAM_Available_Check.ps1 index 09d04e7b..503f2c82 100644 --- a/scripts_wip/Win_RAM_Available_Check.ps1 +++ b/scripts_wip/Win_RAM_Available_Check.ps1 @@ -25,7 +25,7 @@ $available = [math]::Round(($os.FreePhysicalMemory * 1KB) / 1GB, 2) $label = "GB" if ($Percent) { #Percent flag is set - #Calculate percent of free space left on drive + #Calculate percent of free available RAM $available = [math]::Round(($os.FreePhysicalMemory / $os.TotalVisibleMemorySize) * 100, 1) $label = "%" } From 2a8cd906911c698b8c9dc119d7f0a2b6debacf21 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 13:23:05 +0000 Subject: [PATCH 14/16] Added a battery full charge vs design capacity check --- scripts_wip/Win_Battery_Capacity_Check.ps1 | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 scripts_wip/Win_Battery_Capacity_Check.ps1 diff --git a/scripts_wip/Win_Battery_Capacity_Check.ps1 b/scripts_wip/Win_Battery_Capacity_Check.ps1 new file mode 100644 index 00000000..55eaee7c --- /dev/null +++ b/scripts_wip/Win_Battery_Capacity_Check.ps1 @@ -0,0 +1,53 @@ +<# +.Synopsis + Checks the battery full charge capacity VS the design capacity +.DESCRIPTION + This was written specifically for use as a "Script Check" in mind, where it the output is deliberaly light unless a warning or error condition is found that needs more investigation. + + If the total full charge capacity is less than the minimum capacity amount, an error is returned. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory = $false)] + [int]#The minimum battery full charge capacity (as a percentage of design capacity by default). Defaults to 70 percent. + $minimumBatteryCapacity = 70, + + [Parameter(Mandatory = $false)] + [switch]#Set the check condition to absolute mWh values instead of a percentage + $absoluteValues +) + +try{ + $searcher = New-Object System.Management.ManagementObjectSearcher("root\wmi","SELECT * FROM BatteryStaticData") + $batteryStatic = $searcher.Get() + #CIM approach threw errors when Get-WMIObject did not - WMI approach is not available in PSv7, so took .NET approach + $batteryCharge = Get-CimInstance -Namespace "root\wmi" -ClassName "BatteryFullChargedCapacity" -ErrorAction Stop +} catch { + Write-Output "No battery detected" + exit 0 +} + +if (-not $batteryStatic -or -not $batteryCharge) { + Write-Output "No battery detected" + exit 0 +} + +$chargeCapacity = $batteryCharge.FullChargedCapacity +$designCapacity = $batteryStatic.DesignedCapacity + +$available = [math]::Round(($chargeCapacity / $designCapacity) * 100,2) +$label = "%" +if ($absoluteValues) { + $available = $chargeCapacity + $label = "mWh" +} + +If($available -le $minimumBatteryCapacity) +{ + Write-Output "The battery needs investigating. Full charge capacity is below the threshold of $minimumBatteryCapacity $label ($available $label available of design capacity $designCapacity mWh." + Exit 1 +} else { + Write-Output "The battery is reporting ok. Full charge capacity is above the threshold of $minimumBatteryCapacity $label ($available $label available of design capacity $designCapacity mWh." + Exit 0 +} \ No newline at end of file From 32551984cec3f5d703aaf02f5a125501b87e2d3f Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 13:25:31 +0000 Subject: [PATCH 15/16] Changed default value to 85% --- scripts_wip/Win_Battery_Capacity_Check.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts_wip/Win_Battery_Capacity_Check.ps1 b/scripts_wip/Win_Battery_Capacity_Check.ps1 index 55eaee7c..f1cb0baf 100644 --- a/scripts_wip/Win_Battery_Capacity_Check.ps1 +++ b/scripts_wip/Win_Battery_Capacity_Check.ps1 @@ -10,8 +10,8 @@ [CmdletBinding()] param( [Parameter(Mandatory = $false)] - [int]#The minimum battery full charge capacity (as a percentage of design capacity by default). Defaults to 70 percent. - $minimumBatteryCapacity = 70, + [int]#The minimum battery full charge capacity (as a percentage of design capacity by default). Defaults to 85 percent. + $minimumBatteryCapacity = 85, [Parameter(Mandatory = $false)] [switch]#Set the check condition to absolute mWh values instead of a percentage From 90758bb12300d76e2b4490c787435012664c31d3 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Tue, 16 Dec 2025 13:55:29 +0000 Subject: [PATCH 16/16] Increased default --- scripts_wip/Win_Disk_HealthCheck.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts_wip/Win_Disk_HealthCheck.ps1 b/scripts_wip/Win_Disk_HealthCheck.ps1 index 351fc1d7..24993dc4 100644 --- a/scripts_wip/Win_Disk_HealthCheck.ps1 +++ b/scripts_wip/Win_Disk_HealthCheck.ps1 @@ -18,7 +18,7 @@ Param( [Parameter(Mandatory = $false)] [int]#Warn if the temperature (in degrees C) is over this limit - $TemperatureWarningLimit = 45, + $TemperatureWarningLimit = 55, [Parameter(Mandatory = $false)] [int]#Warn if the "wear" of the drive (as a percentage) is above this