(view source code of gethddstatusgui.ps as plain text)
<#
.SYNOPSIS
Display the SMART status for all local harddisks in a popup window and in Windows' Notification Area (a.k.a. System Tray)
.DESCRIPTION
This script uses WMI to query the status of all local physical harddisk drives, and displays the results in a popup window and in Windows' Notification Area (a.k.a. System Tray).
In the status display, each physical harddisk is associated with the drive letter of one of its volumes.
Since Windows 10 limits the number of lines in desktop notifications, any errors will be placed at the top of the displayed status list, otherwise the list is sorted by drive letter.
If all disks report OK, the script returns True and return code ("ErrorLevel") 0, otherwise False and return code 1.
Since this script uses WMI and drive letters, it will not work in Linux.
.PARAMETER Modal
Make the popup window always stay on top
.PARAMETER Hide
Hide the console window when the script is started, restore it (but minimized) afterwards
.PARAMETER Version
Show this script's version number; if combined with -Verbose show full script path, version number and last modified or release date
.PARAMETER Debug
Display intermediate results for each disk drive in console; if combined with -Verbose show intermediate results for each associated volume too
.PARAMETER Help
Show this script's help screen
.OUTPUTS
True and return code 0 if all disks report OK, otherwise False and return code 1
.EXAMPLE
. ./GetHDDStatusGUI.ps1
Will display a popup window with the drive letters in use and the SMART status of the associated physical harddisk drive.
.EXAMPLE
. ./GetHDDStatusGUI.ps1 -Debug -Verbose
Will list details for all physical harddisk drives and volumes in the console, and display a popup window with the drive letters in use and the SMART status of the associated physical harddisk drive.
.EXAMPLE
. ./GetHDDStatusGUI.ps1 -Version -Verbose
Will display this script's full path, version number and last modified or release date.
.LINK
Script written by Rob van der Woude:
https://www.robvanderwoude.com/
.LINK
Disk check based on code by Geoff:
http://www.uvm.edu/~gcd/2013/01/which-disk-is-that-volume-on
.LINK
System Tray ToolTip Balloon code by Don Jones:
http://blog.sapien.com/current/2007/4/27/creating-a-balloon-tip-notification-in-powershell.html
.LINK
Extract icons from Shell32.dll by Thomas Levesque:
http://stackoverflow.com/questions/6873026
.LINK
Hide and restore console by Anthony:
http://stackoverflow.com/a/15079092
.LINK
Capture common parameters by mklement0:
https://stackoverflow.com/a/48643616
#>
param (
[parameter( ValueFromRemainingArguments = $true )]
[string[]]$Args, # Leave all argument validation to the script, not to PowerShell
[switch]$Modal,
[switch]$Hide,
[switch]$Version,
[switch]$Help
)
$progver = "1.04"
[bool]$Debug = ( $PSBoundParameters.ContainsKey( 'Debug' ) )
[bool]$Verbose = ( $PSBoundParameters.ContainsKey( 'Verbose' ) )
# Show help if any unnamed argument is given
$Help = $Help -or ( $Args.Length -gt 0 )
# Show help if running in Linux
$Help = $Help -or ( $HOME[0] -eq '/' )
# Help disables Hide parameter
$Hide = $Hide -and -not $Help
# Debug disables Hide parameter
$Hide = $Hide -and -not $Debug
if ( $Help ) {
Get-Help "$PSCommandPath" -Full
exit 1
}
if ( $Version ) {
if ( $Verbose ) {
$lastmod = ( [System.IO.File]::GetLastWriteTime( $PSCommandPath ) )
if ( $lastmod.ToString( "h.mm" ) -eq $progver ) {
"`"{0}`", Version {1}, release date {2}" -f $PSCommandPath, $progver, $lastmod.ToString( "yyyy-MM-dd" )
} else {
# if last modified time is not equal to program version, the script has been tampered with
"`"{0}`", Version {1}, last modified date {2}" -f $PSCommandPath, $progver, $lastmod.ToString( "yyyy-MM-dd" )
}
} else {
$progver
}
exit 0
}
#######################################
# Hide console window #
# by Anthony on StackOverflow.com #
# http://stackoverflow.com/a/15079092 #
#######################################
$signature1 = @'
public static void ShowConsoleWindow( int state )
{
var handle = GetConsoleWindow( );
ShowWindow( handle, state );
}
[System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
static extern IntPtr GetConsoleWindow( );
[System.Runtime.InteropServices.DllImport( "user32.dll" )]
static extern bool ShowWindow( IntPtr hWnd, int nCmdShow );
'@
$hideconsole = Add-Type -MemberDefinition $signature1 -Name Hide -Namespace HideConsole -ReferencedAssemblies System.Runtime.InteropServices -PassThru
# Hide console
if ( $Hide ) {
$hideconsole::ShowConsoleWindow( 0 )
}
##################
# Disk inventory #
##################
[System.Collections.SortedList]$volumedetails = New-Object System.Collections.SortedList
[System.Collections.SortedList]$volumestatus = New-Object System.Collections.SortedList
if ( $Debug ) {
Write-Host "Disk#`tStatus`tSize (GB)`tModel"
Write-Host "=====`t======`t=========`t====="
}
$diskdrives = Get-WmiObject -Namespace "root/CIMV2" -Class Win32_DiskDrive
$warnings = $false
foreach ( $disk in $diskdrives ) {
$diskindex = $disk.Index
$diskmodel = $disk.Model -replace "Disk Device","Disk"
$disksize = "{0,5:F0} GB" -f ( $disk.Size / 1GB )
$diskstatus = $disk.Status
if ( $Debug ) {
if ( $Verbose ) {
Write-Host
}
Write-Host ( "{0}`t{1}`t{2}`t{3}" -f $diskindex, $diskstatus, $disksize, $diskmodel )
}
$part_query = 'ASSOCIATORS OF {Win32_DiskDrive.DeviceID="' + $disk.DeviceID.replace('\','\\') + '"} WHERE AssocClass=Win32_DiskDriveToDiskPartition'
$partitions = @( Get-WmiObject -Query $part_query | Sort-Object StartingOffset )
foreach ( $partition in $partitions ) {
$vol_query = 'ASSOCIATORS OF {Win32_DiskPartition.DeviceID="' + $partition.DeviceID + '"} WHERE AssocClass=Win32_LogicalDiskToPartition'
$volumes = @( Get-WmiObject -Query $vol_query )
foreach ( $volume in $volumes ) {
# 0 = Unknown; 1 = No Root Directory; 2 = Removable Disk; 3 = Local Disk; 4 = Network Drive; 5 = Compact Disc; 6 = RAM Disk
# DriveType 3 means harddisks only
if ( $volume.DriveType -eq 3 ) {
if ( $Debug -and $Verbose ) {
Write-Host ( "{0}`t{1,2}`t{2}`t{3}" -f $diskindex, $volume.Name, $disksize, $diskmodel )
}
if ( -not $volumedetails.Contains( $volume.Name ) ) {
$volumedetails.Add( $volume.Name, "[Disk {0,2}] {1} {2}" -f ( $diskindex, $disksize, $diskmodel ) )
$volumestatus.Add( $volume.Name, $diskstatus )
}
}
}
}
}
#################
# Dialog window #
#################
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles( )
$form = New-Object System.Windows.Forms.Form
$form.Width = 640
$form.Height = 25 * $volumedetails.Count + 120
$form.Font = 'Courier New, 10'
$form.BackColor = 'White'
$form.MaximizeBox = $false;
$form.FormBorderStyle = 'FixedSingle'
$form.TopMost = $Modal
$y = 0
$even = $false
$volumedetails.Keys | ForEach-Object {
$label = New-Object System.Windows.Forms.Label
$label.Size = '35, 20'
$label.Location = New-Object System.Drawing.Point( 10, ( 15 + $y ) )
$label.Text = "$_"
if ( $even ) { $label.BackColor = 'ButtonFace' }
$form.Controls.Add( $label )
$status = ( $volumestatus[$_] )
$label = New-Object System.Windows.Forms.Label
$label.Size = '40, 20 '
$label.Location = New-Object System.Drawing.Point( 45, ( 15 + $y ) )
$label.Text = $status
if ( $status -eq "OK" ) {
$label.ForeColor = 'Green'
} else {
$label.ForeColor = 'Red'
$warnings = $true
}
if ( $even ) { $label.BackColor = 'ButtonFace' }
$form.Controls.Add( $label )
$label = New-Object System.Windows.Forms.Label
$label.Size = '490, 20'
$label.Location = New-Object System.Drawing.Point( 85, ( 15 + $y ) )
$label.Text = $volumedetails[$_]
if ( $even ) { $label.BackColor = 'ButtonFace' }
$form.Controls.Add( $label )
$y = $y + 25
$even = -not $even
}
if ( $warnings ) {
$form.Text = "HDD Status Warning"
} else {
$form.Text = "HDD Status OK"
}
$buttonOK = New-Object System.Windows.Forms.Button
$buttonOK.BackColor = 'ButtonFace'
$buttonOK.Text = "OK"
$buttonOK.Size = '60,24'
$buttonOK.Location = New-Object System.Drawing.Point( 85, ( 30 + $y ) )
$form.Controls.Add( $buttonOK )
$form.AcceptButton = $buttonOK # Pressing Enter closes the dialog
$form.CancelButton = $buttonOK # Pressing Escape closes the dialog
########################################
# System tray balloon tip notification #
########################################
[System.Windows.Forms.ToolTipIcon]$icon = [System.Windows.Forms.ToolTipIcon]::Info
$title = "HDD Status OK"
$systraymessage = ""
$volumedetails.Keys | ForEach-Object {
$status = ( $volumestatus[$_] )
if ( $status -eq "OK" ) {
$systraymessage = $systraymessage + "$_`t$status`n" # list in alphabetical sort order
} else {
$systraymessage = "$_`t$status`n$systraymessage" # errors at top of list
$icon = [System.Windows.Forms.ToolTipIcon]::Error
$title = "Warning: HDD Errors"
}
}
################################################################
# Extract system tray icon from Shell32.dll #
# C# code to extract icons from Shell32.dll by Thomas Levesque #
# http://stackoverflow.com/questions/6873026 #
################################################################
$signature2 = @'
[DllImport( "Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall )]
private static extern int ExtractIconEx( string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons );
public static Icon Extract( string file, int number, bool largeIcon )
{
IntPtr large;
IntPtr small;
ExtractIconEx( file, number, out large, out small, 1 );
try
{
return Icon.FromHandle( largeIcon ? large : small );
}
catch
{
return null;
}
}
'@
$iconextractor = Add-Type -MemberDefinition $signature2 -Name IconExtract -Namespace IconExtractor -ReferencedAssemblies System.Windows.Forms,System.Drawing -UsingNamespace System.Windows.Forms,System.Drawing -PassThru
# System tray icon depends on status
if( $title -eq "HDD Status OK" ) {
$systrayicon = $iconextractor::Extract( "C:\Windows\System32\shell32.dll", 223, $true )
} else {
$systrayicon = $iconextractor::Extract( "C:\Windows\System32\shell32.dll", 53, $true )
}
# Show system tray icon and balloon tip
$notify = New-Object System.windows.Forms.NotifyIcon
$notify.BalloonTipText = $systraymessage
$notify.BalloonTipTitle = $title
$notify.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]$icon
$notify.Icon = $systrayicon
$notify.Visible = $true
$notify.ShowBalloonTip( 30000 )
# Show dialog
[void] $form.ShowDialog( )
##########################################
# Restore console minimized (2) #
# Change to 1 to restore to normal state #
##########################################
if ( $Hide ) {
$hideconsole::ShowConsoleWindow( 2 )
}
#################################
# Exit code 1 in case of errors #
#################################
if ( $warnings ) {
$false
exit 1
} else {
$true
exit 0
}
page last modified: 2024-04-16; loaded in 0.0148 seconds