PowerShell for Storage and File System Management (Part 6)

If you would like to read the other parts in this article series please go to:

In my previous article in this series, I showed you how to build a PowerShell function that I called Get-Smart. This function was designed to retrieve SMART information for the disks in each of our servers. When I created this function, I built a small script (which included the function). The script’s job was to pass the server names to the function. For the sake of reference, here is that script once again:

Function Get-Smart

{

(Get-WmiObject -namespace root\wmi –class MSStorageDriver_FailurePredictStatus -ComputerName $Input | Select-Object PSComputerName, InstanceName, PredictFailure, Reason)

}

 

$Servers = @(“Prod1”, “Prod2”)

ForEach ($Server in $Servers) {

$Server | Get-Smart

}

Now that we have a function for retrieving SMART information, the next thing that we need to do is to build onto the function to acquire basic disk health information. This is actually easier than it sounds because we have already built a script that can pass the server names one at a time to a function. We can use exactly the same technique to call a second function that lists disk health information. Even so, we do have to be a little bit creative in order to achieve the desired result. I will show you how as we go along.

When I write an article like this one, I try not to introduce too much complexity all at once because I want to make sure that my readers understand the basics before I build on those techniques. That being the case, I want to forget all about functions for the time being. Rather than focusing on functions, I want to show you a raw block of code that we can use to retrieve the disk health information. Once I show you how this block of code works, I will put it into function form, which will require an extra layer or two of complexity. So with that said, here is the code:

$Pdisk= Get-PhysicalDisk

ForEach ( $LDisk in $PDisk )

                {

                $LDisk.FriendlyName

                $LDisk.HealthStatus

                $LDisk | Get-StorageReliabilityCounter | Select-Object ReadErrorsTotal, WriteErrorsTotal, Temperature | FL

                Write-Host ==================

                }

There is a lot going on in this block of code, so I want to step you through it one line at a time. The first line sets up a variable called Pdisk. You can use any variable name you want. I used Pdisk because it reminds me of PhysicalDisk. The variable’s contents are equal to the full output of the Get-PhysicalDisk cmdlet.

The second line of code uses the ForEach cmdlet. This time I am setting up a second variable called Ldisk. Again, you can use any variable name that you want. In my mind, Ldisk stands for local disk. So what this line is doing is setting up a loop that takes the output from the Get-PhysicalDisk cmdlet and acts on it, one disk at a time. You will notice that the third line is the brace symbol ( { ). Everything between the { symbol and the } symbol is a part of the loop. The instructions that fall between the { and the } are acted on for each individual disk.

The next line is $Ldisk.FriendlyName. Remember, $Ldisk represents one specific disk. For example, the $Ldisk variable could potentially represent the following:

Get-PhysicalDisk PhysicalDisk0

As such, this line of code causes the contents of one of the disk’s attributes (in this case, the friendly name) to be displayed.

The next line of code works in exactly the same way as the previous line. This time instead of displaying the disk’s friendly name, we are displaying the disk’s health status.

The following line is the longest of the entire script. This line is:

$LDisk | Get-StorageReliabilityCounter | Select-Object ReadErrorsTotal, WriteErrorsTotal, Temperature | FL

In order to understand what this line does, you must remember that at any given moment the $Ldisk variable represents the Get-PhysicalDisk cmdlet and a specific disk within the system. As such, we are essentially running the Get-PhysicalDisk cmdlet against a specific disk and then redirecting the output to the Get-StorageReliabilityCounter cmdlet. The Select-Object cmdlet allows us to control which attributes are displayed. In this case, we are looking at the total read and write errors as well as the disk’s temperature.

The next line is:

Write-Host ==================

I don’t think that I have talked about Write-Host yet in this article series. The Write-Host cmdlet allows a value to be displayed on the screen. In this case, I am displaying a series of equal signs. This line of code only serves to act as a seperator to separate one disk’s statistics from that of the next disk.

Finally, the last line of code is the } symbol that closes the loop.

When executed, this code block will inventory all of the disks on a server and then display each disk’s friendly name, its health status, the total number of read errors, the total number of write errors, and the disk temperature. This information is displayed for all of the server’s disks. You can see a sample of the output in Figure A.

Image
Figure A: Our script displays various health statistics for each of the system’s disks.

As you look at the output that is shown above, you can see that it works really well. Even so, there are a couple of issues that need to be addressed. For starters, we aren’t looking at the disk SMART information in this code block. We can obviously fix that problem by combining the two scripts, but the other issue is a bit more complicated to deal with.

As you look at the code above, you will notice that it is designed to run on the local computer. When we retrieved the SMART information, we were able to redirect the command by using the ComputerName parameter. Unfortunately, that technique isn’t really an option for using the Get-PhysicalDisk cmdlet to retrieve disk health information from a remote system. Fortunately, there is a way around this issue.

I have created a script that retrieves both SMART information and disk health information for a list of remote servers. Here is the code that I used in my script:

Function Get-Smart

#Function to get disk SMART information

{

(Get-WmiObject -namespace root\wmi –class MSStorageDriver_FailurePredictStatus -ComputerName $Input | Select-Object PSComputerName, InstanceName, PredictFailure, Reason)

}

 

Function Get-Health

#Function to get disk health information

{

$Pdisk= Get-PhysicalDisk

ForEach ( $LDisk in $PDisk )

                {

                $LDisk.FriendlyName

                $LDisk.HealthStatus

                $LDisk | Get-StorageReliabilityCounter | Select-Object ReadErrorsTotal, WriteErrorsTotal, Temperature | FL

                Write-Host ==================

                }

}

 

#Script Body

$Servers = @(“Hyper-V-1”, “Hyper-V-2”)

                ForEach ($Server in $Servers) {

                $Server | Get-Smart

                Enter-PSSession -ComputerName $Server

                Get-Health

                Exit-PSSession

                }

You can see the script’s output in Figure B.

Image
Figure B: This is the partial output from the script shown above.

The figure above only displays a single server’s results because the output was too long for a single screen capture to be used. Even so, you can see that the script displays health information and a series of vital statistics for each of a system’s disks.

Conclusion

In the next article in this series, I want to step you though this script so that you can see how it works. After that, I want to talk about how you might filter the output to avoid creating a script that spews irrelevant output.

If you would like to read the other parts in this article series please go to:

About The Author

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top