Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

PowerShell: Monitoring and Notifications

DZone's Guide to

PowerShell: Monitoring and Notifications

This article walks us through using PowerShell to set up a simple email notification system to alert when a server is running low on disk space.

· DevOps Zone
Free Resource

The Nexus Suite is uniquely architected for a DevOps native world and creates value early in the development pipeline, provides precise contextual controls at every phase, and accelerates DevOps innovation with automation you can trust. Read how in this ebook.

Monitoring disk space utilization of servers is a critical and important job for any administrator. Keeping things organized improves application availability and server availability. This article takes us through the detailed steps to read each drive and notify every drive details based on threshold values and output data. You’ll basically feed a list of servers to watch over and it will report back on these for you, meaning you could also use it as a more general daily server disk space report. A DBA doesn’t want to run out of space on their servers, even in their labs! To avoid this happening, they wrote a PowerShell script to provide some alerts by email.

The credentials can be used to query external servers that have a trust relationship between the domains, and also list various methods to secure the password. The process iterates through a list of servers and drives that you have listed in a CSV file. Checking for the disk space status of every listed drive and its status may fall under one of the four statuses, defined as critical, warning, low and good. If the disk in question is below the threshold, then the corresponding status is updated and notification sent to the respective teams.

Highlights

  • The CSV input: this file contains server, disk information, and threshold values.
  • The WMI class: Win32_LogicalDisk, querying with credentials and without credentials.
  • Activity logging in a log file.
  • The output has status columns that give a clear indication of the status of each drive.
  • Email notification.

We query win32_logicaldisks using credentials, and without using credentials.

Using Credentials

Get-Credential always pops up with a dialog box for entering a password. However, you can save your securestring password to a file or directly feed the password. The problem with this is that the password will be exposed to anyone with access to the file.

Using Get-Credential Cmdlet: Pop Dialog Box

The Get-Credential displays a window to enter credential details. This will appear every time when you run the script. The $credential variable stores the username and password. It’s then fed to the respective queries for further processing.

clear
$credential = Get-Credential
foreach ( $args in get-Content c:\server.txt ) {
get-WmiObject win32_logicaldisk -Credential $credential -ComputerName $args -Filter "Drivetype=3"  |
ft SystemName,DeviceID,VolumeName,@{Label="Total SIze";Expression={$_.Size / 1gb -as [int] }},@{Label="Free Size";Expression={$_.freespace / 1gb -as [int] }} -autosize
}

Hard-Code the Credentials

The password can be hard-coded in the script. Of course, the problem with this is that your password will be exposed to anyone with access to the script file.

$User = 'hqnt\abcd'
 $Pass = ConvertTo-SecureString 'abcd@2015' -AsPlainText -Force
 $Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
 foreach ( $args in get-Content c:\server.txt ) {
get-WmiObject win32_logicaldisk -ComputerName $args -Credential $Credentials -Filter "Drivetype=3"  |
ft SystemName,DeviceID,VolumeName,@{Label="Total SIze";Expression={$_.Size / 1gb -as [int] }},@{Label="Free Size";Expression={$_.freespace / 1gb -as [int] }} -autosize
}

Using a Secured File

First, the password has to be written to a file.

ps:\>read-host -AsSecureString |ConvertFrom-SecureString |Out-File C:\SecurePassword.txt

Second, the credentials are read from the file using the PSCredential class. You don’t need to re-enter the password over and over again.

clear
$User = 'hqnt\abcdv'
$pass= cat C:\passwordstring.txt |ConvertTo-SecureString
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
foreach ( $args in get-Content c:\server.txt ) {
get-WmiObject win32_logicaldisk -ComputerName $args -Credentials $cred -Filter "Drivetype=3"  |

ft SystemName,DeviceID,VolumeName,@{Label="Total SIze";Expression={$_.Size / 1gb -as [int] }},@{Label="Free Size";Expression={$_.freespace / 1gb -as [int] }} -autosize

}

Without Using Credentials

You don’t need to use the credential parameter in any of the cmdlet execution.

clear
foreach ( $args in get-Content c:\server.txt ) {
get-WmiObject win32_logicaldisk -ComputerName $args -Filter "Drivetype=3"  |
ft SystemName,DeviceID,VolumeName,@{Label="Total SIze";Expression={$_.Size / 1gb -as [int] }},@{Label="Free Size";Expression={$_.freespace / 1gb -as [int] }} -autosize
}

Code in Detail

The source code can be downloaded from the TechNet Gallery. This section describes the coding and other details of the PoSH script – diskSpace.ps1.

Input File

The template of Inputserver.csv is given below. Change the content as per your requirement/environment.

import-csv C:\InputServer_1.csv |Format-Table -AutoSize

The comma-delimited text file (.csv) file InputServer_1.csv file is parsed below. You’ll notice that, at the top, there are headings for each column: ServerName, Drive, LowTh, WarnTh, CritTh, Email, LowPri, WarnPri, CritPri, and EscInst. The PowerShell import-csv cmdlet understands this default format and expects to see the column headers before parsing the main data.

  • ServerName: the name of the server; acts as a source for cmdlet execution.
  • Drive: the drive letter is an input for querying Win32_LogicalDisk class library.
  • LowTh: the low limit for sending the alert notification to intended recipients.
  • WarnTh: the middle limit for the drive.
  • CritTh: the higher limit for the drive; it requires urgent attention from the technician
  • Email: the list where the notification is sent.
  • LowPri: the priority decides the attention and importance. In this case, the technician will have enough time to respond to this issue.
  • WarnPri: the priority decides the attention and importance. In this case, the technician will fix the turn around time to react to any such issues.
  • CritPri: requires urgent and immediate action.
  • EscInst: defines the escalation team.

The above columns are defined just to illustrate how the process works. This can vary for every environment by considering the underlying infrastructure.

Write-Log

Write-Log writes a message to a specified log file along with the current time stamp, and also writes state of the message (information, warning, or error).

In the first example writes a simple message with a default state to a log file abc.log. In the second example, a message along with “error” state details are entered into the log file.

1.EXAMPLE 1
2.PS:\> Write-Log  -Message "Server is reachable and starting the process " -Logfile c:\PowerSQL\abc.log
3.EXAMPLE 2
4.PS:\> Write-Log  -level Error -Message "Server is not reachable " -Logfile c:\PowerSQL\abc.log

The below function can be reused in any of the PoSH code. Also, the output file will be used for troubleshooting and activity progress tracking.

Function Write-Log {
    [CmdletBinding()]
    Param(
    [Parameter(Mandatory=$False)]
    [ValidateSet("INFO","WARN","ERROR")]
    [String]
    $Level = "INFO",

    [Parameter(Mandatory=$True)]
    [string]
    $Message,

    [Parameter(Mandatory=$False)]
    [string]
    $logfile
    )

    $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
    $Line = "$Stamp $Level $Message"
    If($logfile) {
    Add-Content $logfile -Value $Line
    }
    Else {
        Write-Output $Line
    }
}

Password

This portion of code decides whether to pass credentials or not. The Get-credential always pops-up a dialog box for entering a password; however, you can save your securestring password to a file, or directly feed the password. The problem with this is that the password will be exposed to anyone with access to the file. If you want to use the default login credentials, then you don’t need to mention anything in the code. You can comment the line of code.

$User = 'abcd'
$Pass = ConvertTo-SecureString ''abcd@#2016' -AsPlainText -Force
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass

This part of the code reads values from the CSV file. The CSV file has well-defined disk space threshold values for each drive that needs monitoring and alerting. The code imports the server name and reads the server header value and loops through each and every server. After reading, the values are assigned to a local variable, and then it’s used to query WMI query by filtering on -computername and -DeviceID, which is marked green in color. The credentials parameter would be really helpful when you are querying different domains which have trust relationships between them. If you are querying the servers under the same domain and want to use the default login credentials, then you can ignore the credential parameter.

The next part is to calculate the “free %”. The status column is populated based on input threshold values. The $percentageFree will be used to identify the status of the drive. The four statuses of each drive are Critical, Warning, Low and Good. The three input parameters $clowth, $cwarnth, and $ccritth are compared with the $percentageFree variable to yield a result for the status columns.

Output

This section describes various options available in the script to validate the disk space data.

Log Filename

This code defines the output log file location and directory to save the output. The $date variable holds the date formatting part. It’s then appended to the $logfilename to generate a more meaningful filename. For example, DiskSpaceLog_2016-10-10.

$date=Get-Date -format
"yyyy-MM-d"#Prepare log file and output CSV file$LogFileName="DiskSpaceLog_$($date)"


Email

This section defines the body of an email, the content prepared using here-string. The email gives detailed information about the severity of the space and notifies the technician to act to remediate the issue. Here-Strings are a great technique to use if you want to have a lot of text that covers several lines. The below is one example created for the body of the email auto-notification.

$body = @"Notification that a disk drive is reporting an alert for low
disk space!$cserver $cdrivelt has $percentFree % free space. Please assign an $priority priority ticket to the $cescinst team.-This is an automated email being generated by the script DiskMonCheck.ps1, as a scheduled task on HQMONP09."@Send-MailMessage -to $cemail -from "HQMONP09@appvion.com"
-Subject "Disk Alert - $cserver $cdrivelt out of disk space!"
-body $body -smtpserver $SMTPServer


Console

The output is customized and written to the console. This option validates the data with the email. In the console output, the columns might not be displayed in the order in which we construct the script. The output of an object is displayed in a certain order because PoSH rearranges the output as per available metadata, hence the below code describes one way of showing the customization.

$mydisk +=New-Object PSObject -Property @{Server=$_.ServerDeviceID= $disk.DeviceIDVolumeName= $disk.VolumeNameSize= [math]::Round(($disk.Size /1GB),2)Usedspace= [math]::Round((($disk.Size - $disk.FreeSpace)/1GB),2)Percentage= ("{0:P}"
-f ($disk.FreeSpace / $disk.Size))status=$status}}}}$mydisk |Select-Object @{Name="Server";Expression={$_.Server}},@{Name="DeviceID";Expression={$_.DeviceID}},@{Name="VolumeName";Expression={$_.VolumeName}},@{Name="Size";Expression={$_.Size}},@{Name="Used Space";Expression={$_.Usedspace}},@{Name="% Free";Expression={$_.Percentage}},@{Name="Status";Expression={$_.status}}|Format-Table -AutoSize

Code

<#.SynopsisThe objective of the script is to make use of.csv files as sources for various parts of the script..DescriptionFunction to log manipulate the date based on the input file and display it to console. Log entries in the log file are time stamped. By default
the message are logged under INFO category. It can be changed to other category such as "WARN"
and"Error"
using -level
parameter.Parameter InoutFilePath to the file where the input details are saved.Example: c:\InputServer.csv.Parameter SMTPServerThe SMTP server name to send email to respective intendenciesExample: ancd.gmail.com.ExampleWrite-Log -Message "$($_.Server) is reachable and starting the process "
-Logfile $Logfile.ExampleWrite-Log -Message "$($_.Server) Critical alert logged for the drive $cdrivelt "
-Logfile $Logfile.Linkhttps://powershellsql.wordpress.com/ .NotesThe CSV file is going to hold all
the metadata for each drive that you intend to monitor and send out notification#>[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Low')]Param([Parameter(Mandatory=$true,Position=0)][String]$InputServer,[Parameter(Mandatory=$true,Position=1)][String]$DirectorytoSave,[Parameter(Mandatory=$true,Position=2)][String]$SMTPServer)# formatting the date$date=Get-Date -format
"yyyy-MM-d"#Prepare log file and output CSV file$LogFileName="DiskSpaceLog_$($date)"# before we do anything else, are we likely to be able to save the file?# if the directory doesn't exist, then create itif (!(Test-Path -path "$DirectoryToSaveTo")) #create it if not existing{New-Item "$DirectoryToSaveTo"
-type directory | out-null}#log File creation $logfile = "$DirectoryToSave$LogFileName.log"if (!(Test-Path -path "$logfile")) #create it if not existing{New-Item -ItemType file $logfile -Force}# Prepare headers for the log file for each execution of scriptAdd-Content $logfile"#################################################################"Add-Content $logfile "Disk Space Details"Add-Content $logfile "Generated $(get-date)"Add-Content $logfile "Generated from $(gc env:computername)"Add-Content $logfile"#################################################################"Function Write-Log {[CmdletBinding()]Param([Parameter(Mandatory=$False)][ValidateSet("INFO","WARN","ERROR")][String]$Level = "INFO",[Parameter(Mandatory=$True)][string]$Message,[Parameter(Mandatory=$False)][string]$logfile)$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")$Line = "$Stamp $Level $Message"If($logfile) {Add-Content $logfile -Value $Line}Else {Write-Output $Line}}#Creating PowerShell custom objects$Mydisk=@() #Import the file to get the drives status and other usage details#The Import-Csv cmdlet provides a way for you to read in data from a comma-separated values file (CSV)Import-Csv $InputServer|%{$cserver = $_.Server$cdrivelt = $_.Drive$clowth = $_.LowTh$cwarnth = $_.WarnTh$ccritth = $_.CritTh$cemail = $_.Email$clowpri = $_.LowPri$cwarnpri = $_.WarnPri$ccritpri = $_.CritPri$cescinst = $_.EscInstIf (!(Test-Connection $_.Server -count 1
-quiet)) {#Write the message to the log fileWrite-Log -level
ERROR -Message "$($_.Server) is not reachable"
-Logfile $Logfile}else{#Write the Progress to log fileWrite-Log -Message "$($_.Server) is reachable and starting the process "
-Logfile $Logfile$diskinfo= Get-WmiObject -Class Win32_LogicalDisk -ComputerName $cserver -Filter"DeviceID='$cdrivelt'"ForEach ($disk in $diskinfo){#Calculate the % free. This parameter will be compared with various thresholds to derive the status of the driveIf ($diskinfo.Size -gt 0) {$percentFree = [Math]::round((($diskinfo.freespace/$diskinfo.size) * 100))}Else {$percentFree = 0}#Determine if disk needs to be flagged for warning or critical alertIf ($diskinfo.Size -gt 0) {$percentFree = [Math]::round((($diskinfo.freespace/$diskinfo.size) * 100))}Else {$percentFree = 0}If ($percentFree -le $ccritth) {$status = "Critical"$priority = $ccritpri$body = @"Notification that a disk drive is reporting an alert for low
disk space!$cserver $cdrivelt has $percentFree % free space. Please assign an $priority priority ticket to the $cescinst team.-This is an automated email being generated by the script DiskMonCheck.ps1, as a scheduled task on HQMONP09."@Send-MailMessage -to $cemail -from "HQMONP09@appvion.com"
-Subject "Disk Alert - $cserver $cdrivelt out of disk space!"
-body $body -smtpserver $SMTPServerWrite-Log -Message "$($_.Server) Critical alert logged for the drive $cdrivelt "-Logfile $Logfile}ElseIf ($percentFree -gt $ccritth -AND $percentFree -le $cwarnth) {$status = "Warning"$priority = $cwarnpri$body = @"Notification that a disk drive is reporting an alert for low
disk space!$cserver $cdrivelt has $percentFree % free space. Please assign a $priority priority ticket to the $cescinst team.-This is an automated email being generated by the script DiskMonCheck.ps1, as a scheduled task on HQMONP09."@Send-MailMessage -to $cemail -from "HQMONP09@appvion.com"
-Subject "Disk Alert - $cserver $cdrivelt disk space warning!"
-body $body -smtpserver $SMTPServerWrite-Log -Message "$($_.Server) Warning alert logged for the drive $cdrivelt "
-Logfile $Logfile}ElseIf ($percentFree -ge $cwarnth -AND $percentFree -lt $clowth) { $status = "Low"$priority = $clowpri$body = @"Notification that a disk drive is reporting an alert for low
disk space!$cserver $cdrivelt has $percentFree % free space. Please assign a $priority priority ticket to the $cescinst team.-This is an automated email being generated by the script DiskMonCheck.ps1, as a scheduled task on HQMONP09."@Send-MailMessage -to $cemail -from "HQMONP09@appvion.com"
-Subject "Disk Alert - $cserver $cdrivelt disk space warning!"
-body $body -smtpserver $SMTPServerWrite-Log -Message "$($_.Server) low alert logged for the drive $cdrivelt "
-Logfile $Logfile}Else { $status = "Good"
}$mydisk +=New-Object PSObject -Property @{Server=$_.ServerDeviceID= $disk.DeviceIDVolumeName= $disk.VolumeNameSize= [math]::Round(($disk.Size /1GB),2)Usedspace= [math]::Round((($disk.Size - $disk.FreeSpace)/1GB),2)Percentage= ("{0:P}"
-f ($disk.FreeSpace / $disk.Size))status=$status}}}}$mydisk |Select-Object @{Name="Server";Expression={$_.Server}},@{Name="DeviceID";Expression={$_.DeviceID}},@{Name="VolumeName";Expression={$_.VolumeName}},@{Name="Size";Expression={$_.Size}},@{Name="Used Space";Expression={$_.Usedspace}},@{Name="% Free";Expression={$_.Percentage}},@{Name="Status";Expression={$_.status}}|Format-Table -AutoSize

Output

Compare Mail Inbox View With Posh Output

Log File Details Are Shown Below

Running Diskspace.ps1 File With Parameters

  • InputServer – The source for the entire script.
  • DirectoryToSave – To save activity and progress of the script file into a file.
  • SMTPServer – Email notification.

Conclusion

This article has illustrated how to set up and configure email notification when Server is running out of Hard Disk Space. Setting up a simple alerting system like this (i.e. via a schedule SQL Server agent job or via Task Scheduler) is a great way to help ensure that you don’t run into any surprises.

As usual, any feedback is welcome, and I hope that this article was helpful to you!

References

Technet

  1. PoSH : CSV-DiskSpace- CSV
  2. PoSH : Disk Space Utilization Report
  3. PoSH : CSV – Disk Space Report – HTML
  4. PoSH : CSV – Disk Space Report – Excel
  5. PoSH : DiskSpace GUI Tool
  6. PoSH : MultiServer(s) Disk Space GUI Tool
  7. PoSH & SQL : Monitoring Disk Space with SQL Server and PowerShell via SQL Agent

See Also

The DevOps Zone is brought to you in partnership with Sonatype Nexus.  See how the Nexus platform infuses precise open source component intelligence into the DevOps pipeline early, everywhere, and at scale. Read how in this ebook

Topics:
powershell ,devops ,security

Published at DZone with permission of Prashanth Jayaram, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}