简体   繁体   中英

Foreach loop vs if/elseif in nested hashtable using Powershell

My goal is to create a PowerShell script that monitors host hardware health and alerts (via exit codes) if a component status is not "GREEN". The following information is pulled from the software API as a hashtable by default.

For readability purposes, this is the information in JSON format, which I converted using the convertto-json cmdlet:

"host":  {
             "serial_number":  "55555",
             "status":  "GREEN",
             "name":  "hostname",
             "raid_card":  {
                               "serial_number":  "55555",
                               "status":  "GREEN",
                               "product_name":  "PRODUCT",
                           },
             "battery":  {
                             "percent_charged":  100,
                             "health":  "HEALTHY",
                             "status":  "GREEN"
                         },
             "accelerator":  {
                                      "temperature":  36,
                                      "status":  "GREEN"
                                  },
             "logical_drives":  [
                                    "@{serial_number=55555555555; health=HEALTHY}",
                                    "@{serial_number=55555555556; health=HEALTHY}"
                                ]
         }
}

If any of the components (battery, raid_card, accelerator or logical_drives) is not green, then the top host.status value would change to "RED."

The logic I envision is to do an initial if statement in which if host.value is "GREEN" then exit 0 (meaning it is up) and just output a message.

Else, do a foreach loop to search and identify which component is not "GREEN." This is where I am stuck with the logic.

The first problem I have is not knowing if a foreach loop is most appropriate for this problem. If it is, how could you structure the foreach loop since one of the components, logical drives, has a nested hashtable inside.

The second problem I have is how could you retrieve the component name if the status is not "GREEN"?

I didn't get far but this is the structure I was initially going with:

if (host.value -eq "GREEN"){
Write-Host "Message: host hardware is healthy"
Exit 0;
}

else{
    foreach ($components in $response.host){
       if ($_.status -ne "GREEN){
       Write-Host "Message: host.??? is not healthy"
       Exit 1;
       }
}

One alternative structure is to just do if/elseif statements instead of the foreach loop. The problem with this is that it is not very elegant and its repetitiveness suggests there is a better way.

if (host.value -eq "GREEN"){
Write-Host "Message: host hardware is healthy"
Exit 0;
}

else{
    if (host.raid_card.status -ne "GREEN"){
    Write-Host "Message: host.raid_card.product_name is not healthy"
    Exit 1;
    }

    elseif (host.battery.status -ne "GREEN"){
    Write-Host "Message: host battery is host.battery.status"
    Exit 1;
    }

    elseif (host.accelerator.status -ne "GREEN"{
    Write-Host "Message: accelerator temperature is host.accelerator.temperature"
    Exit 1;
    }
}

Any recommendations on how to better structure this would be appreciated!

I would suggest putting the components you would like to iterate one step deeper in the structure and also make sure every component has similar 'status' properties to check (which isn't the case in your json example) like so:

{
    "host": {
        "serial_number": "55555",
        "status": "GREEN",
        "name": "hostname",
        "components": {
            "raid_card": {
                "serial_number": "55555",
                "status": "GREEN",
                "product_name": "PRODUCT"
            },
            "battery": {
                "percent_charged": 100,
                "health": "HEALTHY",
                "status": "GREEN"
            },
            "accelerator": {
                "temperature": 36,
                "status": "GREEN"
            },
            "logical_drives": {
                "serial_number": "55555555555",
                "health": "HEALTHY",
                "status": "GREEN"
            }
        }
    }
}

When you have that in place, you can use code like this to check the status of each component:

# Set up an return variable (exit code)
[int]$exitCode = 0

# $machine is the variable name i used to import the json above
if ($machine.host.status -eq "GREEN") {
    Write-Host "Message: Machine $($machine.host.name) - hardware is healthy"
}
else {
    foreach ($component in $machine.host.components.PSObject.Properties) { 
        if ($component.Value.status -ne "GREEN") {
            Write-Host "Message: Machine $($machine.host.name) - $($component.Name) is not healthy"
            $exitCode = 1
        }
    }
}

Exit $exitCode

Of course you have different items in there and for now i can see the array of logical drives may be a problem. If you want to have the script tell you which logical drive is causing the status to be "not GREEN" you need to provide an if statement inside the foreach loop to iterate over every drive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM