How to: Load multiple lines into array

Hello,

I need to build a simple script to automate reporting in storage. I have the following:

$lunlist = @(2..4) 
$spa = '10.00.00.00'

ForEach ($lunid in $lunlist) {
    write-host LUN_id= $lunid
    naviseccli -h $spa storagepool -list -id $lunid -availablecap -consumedcap
}

This works, but the naviseccli command returns multiple lines. For example:

LUN_id= 2
Pool Name: MyPool
Pool ID: 2
Consumed Capacity (Blocks): 176033627136
Consumed Capacity (GBs): 83939.375
Available Capacity (Blocks): 58651610112
Available Capacity (GBs): 27967.267

I need to format the Consumed GBs and Available GBs into an .csv file.

Any suggestions greatly appreciated.

Search for “Powershell naviseccli”. Command line output needs to be parsed into PSObject to use Export-CSV. Below is a report (HTML) and the second is a wrapper function that does some parsing:

https://storagewind.wordpress.com/2016/11/24/automating-health-check-on-emc-vnxunity/
http://blog.superautomation.co.uk/2016/03/simple-wrapper-function-for-naviseccli.html

Hello Rob,

First of all, thank you for your suggestion. I was able to get it working on my array and expanded on it by calculating TB’s and exporting to .csv.

One thing that still eludes me is adding a subtotal line for each column on the .csv.

Below is what I have so far. Any help greatly appreciated.

Function Get-PoolDetails { 
    Param($VNX, [Parameter(Mandatory=$true)]$StorageProc) 

    $PoolInfo = naviseccli -h $StorageProc storagepool -list 

    $poolLine1TAG = "Pool Name" 
    $poolLine2TAG = "Raw Capacity \(GBs\)" 
    $poolLine3TAG = "User Capacity \(GBs\)" 
    $poolLine4TAG = "Consumed Capacity \(GBs\)" 
    $poolLine5TAG = "Available Capacity \(GBs\)"
    $poolLine6TAG = "Percent Full:" 
    $OutTable = @()

    ForEach ($Line in $PoolInfo) { 
        #Iterate through each pool returned and create a PS object for it 
        if ($Line -match $poolLine1TAG) { 
            #Start of new pool, Create new object 
            $OutObject = "" | Select PoolName, RawTB, UseableTB, AllocatedTB, FreeTB, PctFull 
            $OutObject.PoolName = $VNX + $Line.Split(":",2)[1].Trim()
        } elseif ($Line -match $poolLine2TAG) {
            $OutObject.RawTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)
            $RawTB += [System.Convert]::ToDecimal($OutObject.RawTB)
        } elseif ($Line -match $poolLine3TAG) { 
            $OutObject.UseableTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)
            $UseableTB += [System.Convert]::ToDecimal($OutObject.UseableTB)
        } elseif ($Line -match $poolLine4TAG) {
            $OutObject.AllocatedTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2) 
            $AllocatedTB += [System.Convert]::ToDecimal($OutObject.AllocatedTB) 
        } elseif ($Line -match $poolLine5TAG) {
            $OutObject.FreeTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)
            $FreeTB += [System.Convert]::ToDecimal($OutObject.FreeTB)
        } elseif ($Line -match $poolLine6TAG) { 
            $OutObject.PctFull = [math]::round($Line.Split(":",2)[1].Trim(),2)

        #End of pool info line, add object to table as it's about to be overwritten 
        $OutTable += $OutObject
        }
    } 
    Return $OutTable 
}

$OutTable = Get-PoolDetails "VNX5800 " 10.10.10.10
$OutTable | Export-Csv c:\temp\vnx5800.csv -Notypeinfo

Cannot test, but this is a little cleaner way to use the last item rather than the first item to create the object and use switch rather than If\Else, but if the current function is working, you can ignore the update:

function Get-PoolDetails { 
    Param($VNX, [Parameter(Mandatory=$true)]$StorageProc) 

    $PoolInfo = naviseccli -h $StorageProc storagepool -list 

    $results = foreach ($Line in $PoolInfo) { 

        switch -Regex ($Line) {
            "Pool Name"                 {$poolName = $VNX + $Line.Split(":",2)[1].Trim()}
            "Raw Capacity \(GBs\)"      {$rawTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)}
            "User Capacity \(GBs\)"     {$UseableTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)}
            "Consumed Capacity \(GBs\)" {$AllocatedTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)}
            "Available Capacity \(GBs\)"{$FreeTB = [math]::round(($Line.Split(":",2)[1].Trim()/1000),2)}
            "Percent Full:"             {
                $PctFull = [math]::round($Line.Split(":",2)[1].Trim(),2)
                
                [pscustomobject]@{
                    PoolName    = $poolName
                    RawTB       = $rawTB
                    UseableTB   = $UseableTB
                    AllocatedTB = $AllocatedTB
                    FreeTB      = $FreeTB
                    PctFull     = $PctFull
                }
            }
        }
    }

    $results
}

$pools = Get-PoolDetails "VNX5800 " 10.10.10.10

There isn’t really a subtotal line per se, but a separate property. Get the data and then use Calculated Properties to do the rounding and calculations. Here is a WMI query to get the memory which is returned in bytes and then using an expression we get MB and GB:

PS C:\WINDOWS\system32> 

$pools = Get-CimInstance -ClassName Win32_ComputerSystem | 
         Select TotalPhysicalMemory,
                @{Name='TotalPhysicalMemoryMB';Expression={$_.TotalPhysicalMemory / 1mb}},
                @{Name='TotalPhysicalMemoryGB';Expression={[math]::Round($_.TotalPhysicalMemory / 1gb, 2)}}

$pools


TotalPhysicalMemory TotalPhysicalMemoryMB TotalPhysicalMemoryGB
------------------- --------------------- ---------------------
        17014935552        16226.70703125                 15.85

After I posted I realized the server where naviseccli is installed has is Windows Server 2008 with PowerShell 2.0. I then launched the script from a different server that has PS v5.0 and it is now working.

To get the subtotals, I’m thinking to import the csv, calculate the subtotals then export to a second .csv using something like:

$total = Import-Csv “c:\temp\test1.csv” | Measure-Object ‘RawTB’ -Sum
‘Total {0:n2}’ -f $total.Sum

 

 

 

 

I like this format much better. However, when I export to csv

$results = Get-PoolDetails "VNX5800 " 10.10.10.10
$results | Export-Csv 'c:\temp\test1.csv' -NoTypeInfo

I’m getting the following in c:\temp\test1.csv:

IsReadOnly","IsFixedSize","IsSynchronized","Keys","Values","SyncRoot","Count"
"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","6"
"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","6"
"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","6"
"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","6"
"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","6"

Are you using PowerShell version 2 ? Because type casting hastable to PSCsutomObject to create a custom object doesn’t work in v2, your csv looks like a hashtable exported to csv format. Modify the object creation part in the above code like below.

$Hash =        [pscustomobject]@{
                    PoolName    = $poolName
                    RawTB       = $rawTB
                    UseableTB   = $UseableTB
                    AllocatedTB = $AllocatedTB
                    FreeTB      = $FreeTB
                    PctFull     = $PctFull
                }

New-Object -TypeName PSObject -Property $hash

That was exactly my problem. Works in 5.0,

Thanks.