Public/HpAruba/Get-HpArubaInventory.ps1

function Get-HpArubaInventory {
    [CmdletBinding(DefaultParametersetName = "path")]

    Param (
        [Parameter(Mandatory = $True, Position = 0, ParameterSetName = 'path')]
        [string]$ConfigPath,

        [Parameter(Mandatory = $True, Position = 0, ParameterSetName = 'array')]
        [array]$ConfigArray
    )

    # It's nice to be able to see what cmdlet is throwing output isn't it?
    $VerbosePrefix = "Get-HpArubaInventory:"

    # Check for path and import
    if ($ConfigPath) {
        if (Test-Path $ConfigPath -PathType Leaf) {
            Write-Verbose "$VerbosePrefix ConfigPath is file"
            $LoopArray = Get-Content $ConfigPath
        }
    } else {
        $LoopArray = $ConfigArray
    }

    # Setup return Array
    $ReturnObject = "" | Select-Object Hostname, StackMember, ChassisMember, `
        CopperPortTotal, OneGigCopperPortCount, OneGigFiberCount, `
        FiberPortTotal, TenGigFiberCount, FortyGigFiberCount, `
        PowerSupply, Transceiver
    $ReturnObject.StackMember = @()
    $ReturnObject.ChassisMember = @()
    $ReturnObject.CopperPortTotal = 0
    $ReturnObject.FiberPortTotal = 0
    $ReturnObject.OneGigCopperPortCount = 0
    $ReturnObject.OneGigFiberCount = 0
    $ReturnObject.TenGigFiberCount = 0
    $ReturnObject.FortyGigFiberCount = 0
    $ReturnObject.PowerSupply = @()
    $ReturnObject.Transceiver = @()

    #region moduleMap
    ###########################################################################################
    # was originally doing this with regex, but was afraid of missing something

    $ModuleMap = @{ }

    # J9150D
    $ModuleMap.'J9150D' = @{
        ProductType      = 'Transceiver'
        Description      = 'Aruba 10G SFP+ LC SR 300m MMF XCVR'
        SpeedInMbps      = 10000
        SubType          = 'SR'
        DistanceInMeters = 300
        CableType        = 'Multimode Fiber'
    }

    # J9151E
    $ModuleMap.'J9151E' = @{
        ProductType      = 'Transceiver'
        Description      = 'Aruba 10G SFP+ LC LR 10km SMF XCVR'
        SpeedInMbps      = 10000
        SubType          = 'LR'
        DistanceInMeters = 10000
        CableType        = 'Singlemode Fiber'
    }

    # J9281D
    $ModuleMap.'J9281D' = @{
        ProductType      = 'Transceiver'
        Description      = 'Aruba 10G SFP+ to SFP+ 1m DAC Cable'
        SpeedInMbps      = 10000
        SubType          = 'DAC'
        DistanceInMeters = 1
        CableType        = 'Direct Attach'
    }

    # JH234A
    $ModuleMap.'JH234A' = @{
        ProductType      = 'DAC'
        Description      = 'HPE X242 40G QSFP+ to QSFP+ 1m DAC Cable'
        SpeedInMbps      = 40000
        PortType         = 'QSFP-Plus'
        DistanceInMeters = 1
    }

    # J9734A
    $ModuleMap.'J9734A' = @{
        ProductType      = 'StackCable'
        Description      = 'Aruba 2920/2930M 0.5m Stacking Cable'
        DistanceInMeters = .5
    }

    # J9735A
    $ModuleMap.'J9735A' = @{
        ProductType      = 'StackCable'
        Description      = 'Aruba 2920/2930M 1m Stacking Cable'
        DistanceInMeters = 1
    }

    # J9736A
    $ModuleMap.'J9736A' = @{
        ProductType      = 'StackCable'
        Description      = 'Aruba 2920/2930M 3m Stacking Cable'
        DistanceInMeters = 3
    }

    # JL083A
    $ModuleMap.'JL083A' = @{
        BladeType   = 'Module'
        Description = 'Aruba 3810M/2930M 4SFP+ MACsec Module'
        Port        = @(
            @{
                SpeedInMbps = 10000
                PortType    = 'fiber'
                PortCount   = 4
                PortPoe     = $false
            }
        )
    }

    # JL086A
    $ModuleMap.'JL086A' = @{
        ProductType = 'PowerSupply'
        Description = 'Aruba X372 54VDC 680W Power Supply'
        Wattage     = 680
    }

    # JL322A
    $ModuleMap.'JL322A' = @{
        ProductType = 'Switch'
        Description = 'Aruba 2930M 48G PoE+ 1-slot Switch'
        Port        = @(
            @{
                SpeedInMbps = 1000
                PortType    = 'copper'
                PortCount   = 48
                PortPoe     = $true
            }
            @{
                SpeedInMbps = 1000
                PortType    = 'fiber'
                PortCount   = 4
                PortPoe     = $false
            }
        )
    }

    # JL325A
    $ModuleMap.'JL325A' = @{
        BladeType   = 'Module'
        Description = 'Aruba 2930 2-port Stacking Module'
        Port        = @(
            @{
                SpeedInMbps = 0
                PortType    = 'stack'
                PortCount   = 2
                PortPoe     = $false
            }
        )
    }

    # JL479A
    $ModuleMap.'JL479A' = @{
        ProductType = 'Switch'
        Description = 'Aruba 8320 48 10/6 40 X472 5 2 Bundle'
        Port        = @(
            @{
                SpeedInMbps = 10000
                PortType    = 'fiber'
                PortCount   = 48
                PortPoe     = $false
            }
            @{
                SpeedInMbps = 40000
                PortType    = 'fiber'
                PortCount   = 6
                PortPoe     = $false
            }
        )
    }

    ###########################################################################################
    #endregion moduleMap


    $IpRx = [regex] "(\d+)\.(\d+)\.(\d+)\.(\d+)"

    $TotalLines = $LoopArray.Count
    $i = 0
    $StopWatch = [System.Diagnostics.Stopwatch]::StartNew() # used by Write-Progress so it doesn't slow the whole function down

    :fileloop foreach ($entry in $LoopArray) {
        $i++

        # Write progress bar, we're only updating every 1000ms, if we do it every line it takes forever

        if ($StopWatch.Elapsed.TotalMilliseconds -ge 1000) {
            $PercentComplete = [math]::truncate($i / $TotalLines * 100)
            Write-Progress -Activity "Reading Support Output" -Status "$PercentComplete% $i/$TotalLines" -PercentComplete $PercentComplete
            $StopWatch.Reset()
            $StopWatch.Start()
        }

        if ($entry -eq "") { continue }

        ###########################################################################################
        # Check for the Section
        $EvalParams = @{ }
        $EvalParams.StringToEval = $entry


        $EvalParams.Regex = [regex] "^\s+(?<stackmember>\d+)\s+(?<psnumber>\d+)\s+(?<model>J[^\ ]+?)\s+(?<serial>[^\ ]+?)\s+(?<state>(Not\ )?Powered)\s+(?<powertype>AC|DC)\s(?<acvoltage>\d+)V\/(?<dcvoltage>\d+)V\s+(?<wattage>\d+)\s+(?<maxwattage>\d+)"
        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            Write-Verbose "$VerbosePrefix $i`: psu: psu found"
            $NewPsu = [PowerSupply]::new()

            $Model = $Eval.Groups['model'].Value

            $NewPsu.Model = $Model
            $NewPsu.StackMember = $Eval.Groups['stackmember'].Value
            $NewPsu.PsuNumber = $Eval.Groups['psnumber'].Value
            $NewPsu.SerialNumber = $Eval.Groups['serial'].Value
            $NewPsu.PowerType = $Eval.Groups['powertype'].Value
            $NewPsu.AcVoltage = $Eval.Groups['acvoltage'].Value
            $NewPsu.DcVoltage = $Eval.Groups['dcvoltage'].Value
            $NewPsu.CurrentWattage = $Eval.Groups['wattage'].Value
            $NewPsu.MaxWattage = $Eval.Groups['maxwattage'].Value

            if ($Eval.Groups['state'].Value -eq 'Not Powered') {
                $NewPsu.IsPowered = $false
            } else {
                $NewPsu.IsPowered = $true
            }

            $NewPsu.Description = $ModuleMap.$Model.Description

            $ReturnObject.PowerSupply += $NewPsu
            continue
        }

        #region transceiverinfo
        #######################################################################################

        # section start
        $EvalParams.Regex = [regex] "^Transceiver\ Technical\ Information"
        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $InTransceiverSection = $true
            Write-Verbose "$VerbosePrefix $i`: transceiver: section start"
            continue
        }

        if ($InTransceiverSection) {

            # section end
            $EvalParams.Regex = [regex] "#"
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {
                $InTransceiverSection = $false
                Write-Verbose "$VerbosePrefix $i`: transceiver: section end"
                continue
            }

            # transceiver
            $EvalParams.Regex = [regex] "^\s+(?<port>[^\ ]+?)\s+(?<type>[^\ ]+?)\s+(?<model>J[^\ ]+?)\s+(?<serial>[^\ ]+?)\s+"
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {

                $NewTransceiver = [Transceiver]::new()

                $Model = $Eval.Groups['model'].Value
                Write-Verbose "$VerbosePrefix $i`: transceiver: adding $Model"

                $NewTransceiver.Model = $Model
                $NewTransceiver.Description = $ModuleMap.$Model.Description
                $NewTransceiver.CableType = $ModuleMap.$Model.CableType
                $NewTransceiver.SpeedInMbps = $ModuleMap.$Model.SpeedInMbps
                $NewTransceiver.DistanceInMeters = $ModuleMap.$Model.DistanceInMeters

                # Parse Type/SubType
                $Type = $Eval.Groups['type'].Value
                Write-Verbose "$VerbosePrefix $i`: transceiver: parsing type: $Type"
                switch -Regex ($Type) {
                    'SFP+' {
                        $ThisEvalParams = @{ }
                        $ThisEvalParams.StringToEval = $Type
                        $ThisEvalParams.Regex = [regex] "(SFP\+)(.+)"
                        $ThisEval = Get-RegexMatch @ThisEvalParams
                        $Type = $ThisEval.Groups[1].Value
                        $SubType = $ThisEval.Groups[2].Value
                    }
                }

                $NewTransceiver.Type = $Type
                $NewTransceiver.SubType = $SubType

                $ReturnObject.Transceiver += $NewTransceiver
                continue
            }
        }

        #######################################################################################
        #endregion transceiverinfo

        #region stacking
        #######################################################################################

        # section start
        $EvalParams.Regex = [regex] "^stacking$"
        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $InStackingSection = $true
            Write-Verbose "$VerbosePrefix $i`: stacking: section start"
            continue
        }

        if ($InStackingSection) {

            # section end
            $EvalParams.Regex = [regex] "^exit"
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {
                $InStackingSection = $false
                Write-Verbose "$VerbosePrefix $i`: stacking: section end"
                continue
            }

            # stacking config
            $EvalParams.Regex = [regex] '^\s+member\s(?<number>\d+)\stype\s"(?<model>.+?)"\smac-address\s(?<mac>[^\ ]+?)'
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {
                Write-Verbose "$VerbosePrefix looking up StackMember: $($Eval.Groups['number'].Value)"
                $StackLookup = $ReturnObject.StackMember | Where-Object { ($_.Number -eq $Eval.Groups['number'].Value) -and ($_.Slot -eq 0) }

                if ($StackLookup) {
                    $Model = $Eval.Groups['model'].Value
                    $StackLookup.Model = $Model
                    $StackLookup.Description = $ModuleMap.$Model.Description

                    $ModuleLookup = $ModuleMap.$Model

                    foreach ($p in $ModuleLookup.Port) {
                        switch ($p.PortType) {
                            'copper' {
                                $ReturnObject.CopperPortTotal += $p.PortCount
                                switch ($p.SpeedInMbps) {
                                    1000 {
                                        $ReturnObject.OneGigCopperPortCount += $p.PortCount
                                        break
                                    }
                                    default {
                                        Write-Warning "$VerbosePrefix unhandled port speed $($p.PortType) $($p.SpeedInMbps)"
                                        break
                                    }
                                }
                                break
                            }
                            'fiber' {
                                $ReturnObject.FiberPortTotal += $p.PortCount
                                switch ($p.SpeedInMbps) {
                                    1000 {
                                        $ReturnObject.OneGigFiberCount += $p.PortCount
                                        break
                                    }
                                    default {
                                        Write-Warning "$VerbosePrefix unhandled port speed $($p.PortType) $($p.SpeedInMbps)"
                                        break
                                    }
                                }
                                break
                            }
                            default {
                                Write-Warning "$VerbosePrefix unhandled port type $($p.PortType)"
                            }
                        }
                    }
                } else {
                    Write-Warning "$VerbosePrefix no lookup found "
                }

                continue
            }
        }

        #######################################################################################
        #endregion stacking

        #region systeminfo
        #######################################################################################

        # section start
        $EvalParams.Regex = [regex] "^\s+Member\s+:(\d+)"
        $Eval = Get-RegexMatch @EvalParams -ReturnGroupNumber 1
        if ($Eval) {
            Write-Verbose "$VerbosePrefix $i`: switch: adding member $Eval"
            $InSwitch = $true
            $NewSwitch = [SwitchModule]::new()
            $NewSwitch.Number = $Eval
            $NewSwitch.Slot = 0

            $ReturnObject.StackMember += $NewSwitch
            continue
        }

        if ($InSwitch) {

            # mac address
            $EvalParams.Regex = [regex] "^\s+MAC\sAddr\s+:\s([^\ ]+)"
            $Eval = Get-RegexMatch @EvalParams -ReturnGroupNumber 1
            if ($Eval) {
                Write-Verbose "$VerbosePrefix $i`: switch: $($NewSwitch.Member): adding mac address"
                $NewSwitch.MacAddress = $Eval
                continue
            }

            # serial number
            $EvalParams.Regex = [regex] "^\s+Serial\sNumber\s+:\s([^\ ]+)"
            $Eval = Get-RegexMatch @EvalParams -ReturnGroupNumber 1
            if ($Eval) {
                Write-Verbose "$VerbosePrefix $i`: switch: $($NewSwitch.Member): adding serial number"
                $NewSwitch.SerialNumber = $Eval

                $InSwitch = $false
                continue
            }
        }

        #######################################################################################
        #endregion systeminfo

        #region module
        #######################################################################################

        # section start
        $EvalParams.Regex = [regex] "ID\s+Slot\s+Module\sDescription"
        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $InModuleSection = $true
            Write-Verbose "$VerbosePrefix $i`: module: section start"
            continue
        }

        if ($InModuleSection) {

            # section end
            $EvalParams.Regex = [regex] "^[^\s]+"
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {
                $InModuleSection = $false
                Write-Verbose "$VerbosePrefix $i`: module: section end"
                continue
            }

            # module
            $EvalParams.Regex = [regex] '^\s+(?<member>\d+)\s+(?<slot>[^\ ]+)\s+(?<description>.+?)\s{2,}(?<serial>[^\ ]+?)\s+(?<state>.+)'
            $Eval = Get-RegexMatch @EvalParams
            if ($Eval) {
                $Global:TestEval = $Eval
                Write-Verbose "$VerbosePrefix $i`: module: module found"
                $NewModule = [SwitchModule]::new()
                $NewModule.Number = $Eval.Groups['member'].Value
                $NewModule.Slot = $Eval.Groups['slot'].Value
                $NewModule.SerialNumber = $Eval.Groups['serial'].Value

                $ModelRx = [regex] 'J[0-9A-Z]+(?=\s)'
                $Model = $ModelRx.Match($Eval.Groups['description'].Value).Value
                $NewModule.Model = $Model
                $ModuleLookup = $ModuleMap.$Model
                $NewModule.Description = $ModuleLookup.Description

                $ReturnObject.StackMember += $NewModule

                foreach ($p in $ModuleLookup.Port) {
                    switch ($p.PortType) {
                        'copper' {
                            $ReturnObject.CopperPortTotal += $p.PortCount
                            switch ($p.SpeedInMbps) {
                                1000 {
                                    $ReturnObject.OneGigCopperPortCount += $p.PortCount
                                    break
                                }
                                default {
                                    Write-Warning "$VerbosePrefix unhandled port speed $($p.PortType) $($p.SpeedInMbps)"
                                    break
                                }
                            }
                            break
                        }
                        'fiber' {
                            $ReturnObject.FiberPortTotal += $p.PortCount
                            switch ($p.SpeedInMbps) {
                                1000 {
                                    $ReturnObject.OneGigFiberCount += $p.PortCount
                                    break
                                }
                                10000 {
                                    $ReturnObject.TenGigFiberCount += $p.PortCount
                                    break
                                }
                                40000 {
                                    $ReturnObject.FortyGigFiberCount += $p.PortCount
                                    break
                                }
                                default {
                                    Write-Warning "$VerbosePrefix unhandled port speed $($p.PortType) $($p.SpeedInMbps)"
                                    break
                                }
                            }
                            break
                        }
                        'stack' {
                            # don't need to do anything with this.
                        }
                        default {
                            Write-Warning "$VerbosePrefix unhandled port type $($p.PortType)"
                        }
                    }
                }

                continue
            }
        }

        #######################################################################################
        #endregion module

        <# # check for stacking
        $EvalParams.Regex = [regex] "^stack\ unit\ (\d+)"
        $Eval = Get-RegexMatch @EvalParams -ReturnGroupNumber 1
        if ($Eval) {
            $StackNumber = $Eval
            Write-Verbose "$VerbosePrefix $i`: stack: $StackNumber config started"
            continue
        }

        $EvalParams.Regex = [regex] "^\s*module\ (?<num>\d+)\ (?<model>.+)"
        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $Model = ($Eval.Groups['model'].Value).Trim()
            $Number = $Eval.Groups['num'].Value
            $ModuleMapEntry = $BrocadeModuleMap.$Model

            if ($ModuleMapEntry) {
                $NewBlade = "" | Select-Object Number, Module, Model, MacAddress
                $NewBlade.Model = $Model
                if ($StackNumber) {
                    $NewBlade.Number = $StackNumber
                    $NewBlade.Module = $Number
                    $ReturnObject.StackMember += $NewBlade
                } else {
                    #$NewBlade.Number = $Eval.Groups['num'].Value
                    $NewBlade.Number = $Number
                    $ReturnObject.ChassisMember += $NewBlade
                }
                Write-Verbose "$VerbosePrefix $i`: module: config started"
                Write-Verbose "$VerbosePrefix $i`: module: decoding blade: $BladeNumber"

                $BladeType = $ModuleMapEntry.BladeType
                $PortSpeed = $ModuleMapEntry.PortSpeed
                $PortType = $ModuleMapEntry.PortType
                $PortCount = $ModuleMapEntry.PortCount
                $PortPoe = $ModuleMapEntry.PortPoe

                Write-Verbose "$VerbosePrefix $i`: module: decoding blade: BladeType: $BladeType"
                Write-Verbose "$VerbosePrefix $i`: module: decoding blade: PortSpeed: $PortSpeed"
                Write-Verbose "$VerbosePrefix $i`: module: decoding blade: PortType: $PortType"

                if (($PortType -eq 'qsfp') -and ($PortSpeed -eq '160g')) {
                    Write-Verbose "$VerbosePrefix $i`: module: decoding blade: adjusting for 4x40gig"
                    $PortCount = 4
                    $PortSpeed = '40gig'
                }

                if ($PortType -eq 'sfp-plus') {
                    $PortSpeed = '10gig'
                    $PortType = 'fiber'
                }

                if ($PortSpeed -eq 'management') {
                    $PortSpeed = '1gig'
                }

                if ($PortSpeed -eq '10g') {
                    $PortSpeed = '10gig'
                    $PortType = 'fiber'
                }

                if (('' -eq $PortType) -and ($PortSpeed -eq '1gig')) {
                    $PortType = 'copper'
                }


                switch -Regex ($PortType) {
                    '^(copper-poe|p|copper)$' {
                        switch -Regex ($PortSpeed) {
                            '^(1gig|gig)$' {
                                Write-Verbose "$VerbosePrefix Current OneGigCopperCount: $($ReturnObject.OneGigCopperPortCount); Current CopperPortTotal: $($ReturnObject.CopperPortTotal)"
                                $ReturnObject.OneGigCopperPortCount += $PortCount
                                $ReturnObject.CopperPortTotal += $PortCount
                                Write-Verbose "$VerbosePrefix Adding $PortCount ports with speed $PortSpeed of type $PortType"
                            }
                            default {
                                Write-Verbose "$VerbosePrefix Adding $PortCount ports with speed $PortSpeed of type $PortType"
                            }
                        }
                    }
                    '^(fiber|qsfp)$' {
                        switch ($PortSpeed) {
                            '1gig' {
                                $ReturnObject.OneGigFiberCount += $PortCount
                                $ReturnObject.FiberPortTotal += $PortCount
                                Write-Verbose "$VerbosePrefix Adding $PortCount ports with speed $PortSpeed of type $PortType"
                            }
                            '10gig' {
                                $ReturnObject.TenGigFiberCount += $PortCount
                                $ReturnObject.FiberPortTotal += $PortCount
                                Write-Verbose "$VerbosePrefix Adding $PortCount ports with speed $PortSpeed of type $PortType"
                            }
                            '40gig' {
                                $ReturnObject.FortyGigFiberCount += $PortCount
                                $ReturnObject.FiberPortTotal += $PortCount
                                Write-Verbose "$VerbosePrefix Adding $PortCount ports with speed $PortSpeed of type $PortType"
                            }
                            default {
                                Write-Warning "$VerbosePrefix unhandled PortSpeed/PortType combination: $PortSpeed/$PortType"
                            }
                        }
                    }
                    'management' {
                        if ($PortCount -eq 0) {
                            Write-Verbose "$VerbosePrefix skipping management blade with $PortCount ports"
                        } else {
                            Write-Warning "$VerbosePrefix unhandled PortType: $PortType with count: $PortCount"
                        }
                    }
                    default {
                        Write-Warning "$VerbosePrefix unhandled PortType: $PortType"
                    }
                }
                continue
            } else {
                Write-Warning "$VerbosePrefix unmatched module detected on line $i`: |$Model|"
            }
        } #>


        $EvalParams.Regex = [regex] '^hostname\ "?([^"]+)'
        $Eval = Get-RegexMatch @EvalParams -ReturnGroupNumber 1
        if ($Eval) {
            $ReturnObject.Hostname = $Eval
            continue
        }
    }

    $ReturnObject
}