Blog Response: Using PowerShell To Get Physical Disk Info On A Dell Server

This is a response to: http://itcloudpro.net/2017/01/05/using-powershell-to-get-drive-info-on-a-dell-server/

If you want to go straight for the loot, click here

While perambulating the web for ways to get Dell server's physical and virtual disk health status via PowerShell, I stumbled across Liam Kemp's blog entry. As Liam mentions, you can get pretty much everything you need in regards to Dell hardware monitoring with WMI/CIM, except for the disk info. Thanks to Liam's contribution I figured out another approach, this alternative works from remote servers without using Invoke-Command (WinRM) and with the help of a little "regex-fu" we can turn the plain text results into precious custom objects we can tinker with.

Getting omremote.exe

There is a tool named omreport.exe in every Dell Server that has Server Manager installed, however it can get you info from the host server only, in order to query remote hosts we need omremote.exe.

The challenge: omremote.exe is not offered stand-alone (wishlist!), this component and its dll's are bundled within a free application from Dell named OpenManage Essentials (OME from now on), but even if you unzip the files from the installer and navigate the components you won't be able to find omremote's compiled executable, what this means is that you need to install OME over a compatible Windows Server Version .  Unless you have it installed somewhere already or you have a lab setup, the easiest approach would be to install a Windows Server Trial in a virtual machine using something like VirtualBox  and run the OME Installer over it. After the installation, the files needed are found in:
"C:\Program Files (x86)\Dell\SysMgt\Essentials\bin"

If OME is installed in a server within your infrastructure, you may of course just use omremote.exe  directly from the server where it's installed, but if you want to use it anywhere else you need to copy the "bin" folder to the machine where you want to run the queries from.

…You may also skip all of the above since for your convenience you may find omremote.exe here along with it's dll's: 

DISCLAMER: It's everyone's responsibility to scan any files downloaded from the internet with your AV of choice.

Click for download


Using omremote.exe

The commands are pretty similar to what you use with omreport.exe only, we just need to add omremote's parameters, for example:

omreport.exe storage pdisk controller=0


Would then be:

omremote.exe -user="domain\user" -pswd="YourPassword" -com=wmi "TheRemoteHostorIPAddress" omreport storage pdisk controller=0

omremote.exe -user=Contoso\Maverick1 -pswd=MyP@22w0rd -com=wmi 192.168.77.1 omreport storage pdisk controller=0


To continue, unzip the download and reference its location whenever you run it. In the following examples I'll leave it in C:\temp (you may choose another location, just remember to adjust your path in the examples ahead). From PowerShell remember to add "&" at the beginning so it knows it's not a PowerShell command, I'll also wrap omremote's path in quotes.

&  "C:\temp\omremote\omremote.exe" -user=Contoso\Maverick1 -pswd=MyP@22w0rd -com=wmi HostOrIPHere omreport storage pdisk controller=0


In action:

Click to "embiggen"

In case you don't have access to Dell hardware and would like to try out the exercise below, you may grab a dummy sample of the output here: OMremote Report Dummy

Parsing the output with PowerShell and Regex

I guess I am obliged to say something about regex (regular expressions), the subject is a bit too…regexy to go too deep into in this post, but the community sums it up like this:

Having said that, let's get going!

Take the command above and trap its output in a variable:

$User = 'Contoso\Maverick1' # Your user goes here
$Password = 'MyP@22w0rd' # Your password goes here
$Hostname = '192.168.77.1' # The remote Dell server you'll like to query goes here

$OMremoteResults = &  "C:\temp\omremote\omremote.exe" -user="$User" -pswd="$Password" -com=wmi "$Hostname" omreport storage pdisk controller=0


Now we have the results stored in the $OMremoteResults variable, as it is, it's just a bunch of text with steady words and other things that vary such as the actual ID, Status, Serial number etc. Next, we need to create a regex pattern to match and give us only what we need. Luckily the format follows a steady pattern, this is where our "Regex-fu" kicks in. To be more specific, we need to use .NET regex.

Regular expressions match patterns based on numbers, letters, spaces, literal words or characters etc, there's more than one way to do this, but the way I like to go is to "wrap" patterns inside groups and then turn those into objects.

My favorite tools for the job are both free and amazing:
RegexHero– This is the .NET Regex tool of choice
Regex101 – The Regex web tool of choice (it doesn't have a .NET flavor, however with the "common" expressions, you can get by with PCRE 
)

Here are some pointers to get a grasp about what's going on within the full regex pattern we'll use in our script:

(?<Groupname>) – This creates a capture group that will encapsulate just the patterns we want, you can name it as you wish e.g. (?<Status>), (?<ID>)
\s – Matches a character of whitespace (space, tab, carriage return, line feed)
\d – Matches a decimal character (0-9)
\w – Matches an alpha-numeric character (a-z, A-Z, 0-9, and underscore)

* or + are quantifiers, if added to any of the last 3 examples above, specifies that there's 0, 1 or more of the same character, e.g.

\d*
– Matches a decimal character (0-9), 0 or more times),
\d+ – Matches a decimal character (0-9), 1 or more times), .

The following example will show a bit of how it works and start creating matches, I'll match and create a group for ID and Status from the omremote output dummy shared above, in this case I have the following:

ID                              : 0:1:0
Status                          : Ok

We know the "0:1:0" ID digits could vary and also the "Ok" word for the Status could be something other than "Ok".

So (very) roughly this is what we'll tell regex:

To capture the ID numbers – After " Literal Word ID, 0 or more blankspaces, colon, single blankspace", find and capture within a group named ID "digits, colon, digits, colon, digits". 

ID\s*:\s(?<ID>\d+:\d+:\d+)

To capture the Status – After "0 or more blankspaces, Literal Word Status, 0 or more blankspaces, colon, single blankspace", find and capture within a group named Status "1 or more word characters"

\s*Status\s*:\s(?<Status>\w+)


The full regex pattern for ID and Status:

ID\s*:\s(?<ID>\d+:\d+:\d+)\s*Status\s*:\s(?<Status>\w+)


Watch it in action:

Click to "embiggen"

You can hover over the expressions to see what they do and play around with them here: https://regex101.com/r/bA47kr/1

Phew! That will be it for regex-fu today, if you would like to know more there's plenty of great resources out there, but I suggest taking a look at Kevin Marquette's blogpost, he did a fantastic job:  Powershell: The many ways to use regex

Here is the full regex code we'll use to get the Name, ID, Status, Failure Predicted and Serial Number, see it in action and play around with it here: https://regex101.com/r/VRR3Hq/3:

ID\s*:\s(?<ID>\d+:\d+:\d+)\s*Status\s*:\s(?<Status>\w+)\s*Name\s*:\s(?<Name>\w+\s\w+\s\d+:\d+:\d+)([\s\S]*?)(?=Failure)Failure\sPredicted\s*:\s(?<FailurePredicted>\w+)([\s\S]*?)(?=Serial)Serial\sNo\.\s*:\s(?<SerialNumber>\w+)


Now we need to add this regex noodle soup in PowerShell, we'll store it in $RegexCode, remember the single quotes!

[regex]$RegexCode = 'ID\s*:\s(?<ID>\d+:\d+:\d+)\s*Status\s*:\s(?<Status>\w+)\s*Name\s*:\s(?<Name>\w+\s\w+\s\d+:\d+:\d+)([\s\S]*?)(?=Failure)Failure\sPredicted\s*:\s(?<FailurePredicted>\w+)([\s\S]*?)(?=Serial)Serial\sNo\.\s*:\s(?<SerialNumber>\w+)'


And then we'll take advantage of PowerShell's .NET nature goodness and match the content against the omremote.exe results, we'll store the matches in $RegexParsing:

$RegexParsing = ([regex]::Matches($OMremoteResults,$RegexCode))


Script so far:

# omremote parameter content
$User = 'Contoso\Maverick1' # User variable, your user goes here
$Password = 'MyP@22w0rd' # Password variable, your password goes here
$Hostname = '192.168.77.1' # Hostname variable, the remote Dell server you'll like to query goes here

# Run omremote, collect the disk info loot and store it in a variable
$OMremoteResults = &  "C:\temp\omremote\omremote.exe" -user="$User" -pswd="$Password" -com=wmi "$Hostname" omreport storage pdisk controller=0

# Rejoice on raw regex rampage magical mistery macaroni madness 
[regex]$RegexCode = 'ID\s*:\s(?<ID>\d+:\d+:\d+)\s*Status\s*:\s(?<Status>\w+)\s*Name\s*:\s(?<Name>\w+\s\w+\s\d+:\d+:\d+)([\s\S]*?)(?=Failure)Failure\sPredicted\s*:\s(?<FailurePredicted>\w+)([\s\S]*?)(?=Serial)Serial\sNo\.\s*:\s(?<SerialNumber>\w+)'
$RegexParsing = ([regex]::Matches($OMremoteResults,$RegexCode)) # Invoking Regex .NET class


If you run the script above and then the $RegexParsing variable, you should get something like this:

Click to "embiggen"

Looks a bit messy huh? No fear! The hard part is over. We can easily turn the regex groups into orderly awesome objects, just add the following line to the script:

$RegexParsing | foreach {new-object PSObject -Property @{ID=($_.Groups["ID"].value); Status=($_.Groups["Status"].value);Name=($_.Groups["Name"].value);FailurePredicted=($_.Groups["FailurePredicted"].value);SerialNumber=($_.Groups["SerialNumber"].value)}}
Click to "embiggen"

Much better! But we can make it even neater, let's wrap the above line inside a $Variable and then export it to a table, now that we have it parsed into objects, we could export it to a csv file, gridview or bunch of other cool stuff!

Let's replace the line above with the following 2 lines:

$RPtoObjects = $RegexParsing | foreach {new-object PSObject -Property @{ID=($_.Groups["ID"].value); Status=($_.Groups["Status"].value);Name=($_.Groups["Name"].value);FailurePredicted=($_.Groups["FailurePredicted"].value);SerialNumber=($_.Groups["SerialNumber"].value)}}
$RPtoObjects | Format-Table Name,ID,Status,FailurePredicted,SerialNumber -AutoSize -Wrap


…et voila!

That's it!!! Congrats for making it this far. One nice thing about omremote is that you are not limited to the disk info, you can do everything omreport.exe can do and perhaps even run other om commands such as omconfig, but I haven't tested this.

Here is the full script, I took the liberty to add the hostname you are querying too as an object, should come in handy:

$User = 'Contoso\Maverick1' # User variable, your user goes here
$Password = 'MyP@22w0rd' # Password variable, your password goes here
$Hostname = '192.168.77.1' # Hostname variable, the remote Dell server you'll like to query goes here

# Run omremote, collect the disk info loot and store it in a variable
$OMremoteResults = &  "C:\temp\omremote\omremote.exe" -user="$User" -pswd="$Password" -com=wmi "$Hostname" omreport storage pdisk controller=0

# Rejoice on raw regex rampage magical mistery macaroni madness 
[regex]$RegexCode = 'ID\s*:\s(?<ID>\d+:\d+:\d+)\s*Status\s*:\s(?<Status>\w+)\s*Name\s*:\s(?<Name>\w+\s\w+\s\d+:\d+:\d+)([\s\S]*?)(?=Failure)Failure\sPredicted\s*:\s(?<FailurePredicted>\w+)([\s\S]*?)(?=Serial)Serial\sNo\.\s*:\s(?<SerialNumber>\w+)'
$RegexParsing = ([regex]::Matches($OMremoteResults,$RegexCode)) # Invoking Regex .NET class

# Parse values as per regex group names and turn them into precious Objects
$RPtoObjects = $RegexParsing | foreach {new-object PSObject -Property @{Hostname=($Hostname);ID=($_.Groups["ID"].value); Status=($_.Groups["Status"].value);Name=($_.Groups["Name"].value);FailurePredicted=($_.Groups["FailurePredicted"].value);SerialNumber=($_.Groups["SerialNumber"].value)}}
# Make it look purty $RPtoObjects | Format-Table Hostname,Name,ID,Status,FailurePredicted,SerialNumber -AutoSize -Wrap

Summary:

  1. Download the omremote folder, and unzip it in "C:\temp"
  2. Copy the script in PowerShell ISE, and make sure you edit the $User, $Password and $Hostname values to your needs
  3. Save it as "Posh-OMRemote.ps1" in "C:\temp"
  4. From PowerShell as admin, run: C:\temp\Posh-OMRemote.ps1
  5. Rejoice in disk monitoring sweetness

Thank you for visiting my blog!

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.