Quick and dirty PowerPath/VE output parser

Here is a quick and dirty PowerShell script to parse the output of the rpowermt command used to manage PowerPath/VE on ESX (for EMC arrays). I wrote the code quickly to solve a particular problem, but if I get requests I could extend it to parse the rest of the output and do so in a little more robust fashion.

Why do this? I am in the middle of migrations between frames and I needed an easy way to determine what needed moved when the storage admin said move all LUNs from CLARiiON XXXX to the new LUNs on YYYY – and make sure to move LUN 41 to LUN 88.

By parsing the output of rpowermt I could more easily determine the ID of the LUNs they indicated and map that to the extent properties of my datastores to determine what needed to move.

Two step usage:

  1. rpowermt host=esx001 display dev=all > esx001_lundata.txt
  2. $lunInfo = .\SimplePowerVeParse esx001_lundata.txt

Alternate ways of accomplishing the same thing:

  1. The Storage Viewer plugin from EMC would be helpful in determining this from the GUI, but due to political reasons this is not yet deployed in production.
  2. I originally wanted to try and talk to the CIM provider for PowerPath, but quickly found that the Get-WSManInstance cmdlet’s authentication assumptions were very Windows centric.

The script

# Naive parsing of the output of rpowermt for PowerPath/VE against CLARiiON and Symmetrix devices
 
param (
    $fileName = "esx001_luninfo.txt"
)
 
# Easily re-usable data object
Function LunInfo {
    "" | Select-Object "PseudoName", "ArrayType", "ArrayID", "LunID", "LunLabel"
}
 
# Generic dispatcher to more detailed parsers
Function Parse-LunInfo {
 
    param (
        [String[]]$info
    )
 
    if ($info.Length -lt 2) {
        throw "Insufficient rpowermt input to determine device type."
    }
 
    switch -regex ($info[1]) {
        '^CLARiiON' {Parse-CLARiiONInfo $info}
        '^Symmetrix' {Parse-SymmetrixInfo $info}
        default {throw "Unhandled device type."}
    }
}
 
# Parse CLARiiON lun information
Function Parse-CLARiiONInfo {
    param (
        [String[]]$info
    )
 
    if ($info.Length -lt 3) {
        throw "Insufficient data for the CLARiiON data block."
    }
 
    $lunInfo = LunInfo
    $lunInfo.ArrayType = "CLARiiON"
 
    # Parse the first line
    if ($info[0] -match 'Pseudo name=(?<Name>\w+\d+)') {
        $lunInfo.PseudoName = $Matches["Name"]
    }
    else {
        throw "Invalid pseudo name data for CLARiiON."
    }
 
    # Parse the second line
    if ($info[1] -match 'CLARiiON ID=(?<ArrayId>[\w\d]+)') {
        $lunInfo.ArrayID = $Matches["ArrayId"]
    }
    else {
        throw "Invalid CLARiiON ID line."
    }
 
    # Third line
    if ($info[2] -match 'Standard UID=(?<LunID>.+)\s\[(?<LunLabel>.*)\]') {
        $lunInfo.LunID = $Matches["LunID"]
        $lunInfo.LunLabel = $Matches["LunLabel"]
    }
    else {
        throw "Invalid CLARiiON Standard UID line."
    }
 
    $lunInfo
}
 
# Parse Symmetrix LUN information
Function Parse-SymmetrixInfo {
        param (
        [String[]]$info
    )
 
    if ($info.Length -lt 4) {
        throw "Insufficient data for the CLARiiON data block."
    }
 
    $lunInfo = LunInfo
    $lunInfo.ArrayType = "Symmetrix"
 
    # Parse the first line
    if ($info[0] -match 'Pseudo name=(?<Name>\w+\d+)') {
        $lunInfo.PseudoName = $Matches["Name"]
    }
    else {
        throw "Invalid pseudo name data for Symmetrix."
    }
 
    # Parse the second line
    if ($info[1] -match 'Symmetrix ID=(?<ArrayId>\d+)') {
        $lunInfo.ArrayID = $Matches["ArrayId"]
    }
    else {
        throw "Invalid Symmetrix ID line."
    }
 
    # Third line
    if ($info[2] -match 'Logical device ID=(?<LunLabel>[\w\d]+)') {
        $lunInfo.LunLabel = $Matches["LunLabel"]
    }
    else {
        throw "Invalid Symmetrix logical device ID line."
    }
 
    # Fourth line
    if ($info[3] -match 'Standard UID=(?<LunID>naa\.\d+)') {
        $lunInfo.LunID = $Matches["LunID"]
    }
    else {
        throw "Invalid CLARiiON Standard UID line."
    }
 
    $lunInfo
}
 
 
$fileData = Get-Content $fileName
$elementData = @()
 
# Assuming information blocks are data are separated by a blank line.
foreach ($line in $fileData) {
 
    if ($line -eq "") {
        if ($elementData.Length -gt 0) {
            Parse-LunInfo $elementData
            $elementData = @()
        }
    }
    else {
        $elementData += $line
    }
}
 
# Catch anything leftover at the end.
if ($elementData.Length -gt 0) {
    Parse-LunInfo $elementData
}

Leave a Comment

Your email address will not be published.