0

I have a really weird json file and I am trying to extract data from it via powershell.

The issue is that the creator of this file is using json in a way I have never seen before:

(Cities are not in the Array, Continents are not in the array etc)

Shortened JSON File:

{
"zscloud.net": {
    "continent : EMEA": {
        "city : Abu Dhabi I": [
            {
                "range": "147.161.174.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "24.453884",
                "longitude": "54.3773438"
            }
        ],
        "city : Amsterdam II": [
            {
                "range": "185.46.212.0/23",
                "vpn": "amsterdam2-vpn.zscloud.net",
                "gre": "185.46.212.36",
                "hostname": "ams2.sme.zscloud.net",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.228.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "165.225.240.0/23",
                "vpn": "ams2-2-vpn.zscloud.net",
                "gre": "165.225.240.42",
                "hostname": "ams2-2.sme.zscloud.net",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.172.0/23",
                "vpn": "",
                "gre": "165.225.240.42",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.230.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.232.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.234.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.224.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            },
            {
                "range": "147.161.226.0/23",
                "vpn": "",
                "gre": "",
                "hostname": "",
                "latitude": "52",
                "longitude": "5"
            }
        ]
    }
}

}

I am trying to get the name of the city + the nested hostname.

My Options:

  1. I can either use Convertfrom-JSON and then somehow iterate over several unknown Keys and Properties.

  2. Or I can use select-string and basically grep only the matching regex. Then put them into array etc.

Previously, I went with select-string against beautified JSON as it was easier.

Today, I have found out that not only Hostname but Hostname + City name may be required. Any idea how to extract them from the json?

I am on PS5.

Many Thanks, Aster

aster007
  • 335
  • 2
  • 13

1 Answers1

1

I can either use ConvertFrom-JSON and then somehow iterate over several unknown Keys and Properties.

Let me show you how!

PowerShell allows you to programmatically discover the properties of any object via the psobject hidden memberset:

PS ~> $someObject = [pscustomobject]@{ A = 123; B = "a string value" }
PS ~> $someObject.psobject.Properties


MemberType      : NoteProperty
IsSettable      : True
IsGettable      : True
Value           : 123
TypeNameOfValue : System.Int32
Name            : A
IsInstance      : True

MemberType      : NoteProperty
IsSettable      : True
IsGettable      : True
Value           : a string value
TypeNameOfValue : System.String
Name            : B
IsInstance      : True

Applied to your JSON input, we could do something like this:

# The following assumes you've loaded the JSON into a string like below
$json = @'
{
    "zscloud.net": {
        "continent : EMEA": {
            "city : Abu Dhabi I": [
                {
                    "range": "147.161.174.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "24.453884",
                    "longitude": "54.3773438"
                }
            ],
            "city : Amsterdam II": [
                {
                    "range": "185.46.212.0/23",
                    "vpn": "amsterdam2-vpn.zscloud.net",
                    "gre": "185.46.212.36",
                    "hostname": "ams2.sme.zscloud.net",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.228.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "165.225.240.0/23",
                    "vpn": "ams2-2-vpn.zscloud.net",
                    "gre": "165.225.240.42",
                    "hostname": "ams2-2.sme.zscloud.net",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.172.0/23",
                    "vpn": "",
                    "gre": "165.225.240.42",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.230.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.232.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.234.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.224.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                },
                {
                    "range": "147.161.226.0/23",
                    "vpn": "",
                    "gre": "",
                    "hostname": "",
                    "latitude": "52",
                    "longitude": "5"
                }
            ]
        }
    }
}
'@

Now for the actual code:

# Convert json to an object
$data = $json |ConvertFrom-Json

# Iterate over each property (cloud provider?) on the root object
foreach($provider in $data.psobject.Properties){
  # save the provider name for later
  $providerName = $provider.Name
  # Iterate over each property (geographic region?) on the provider object
  foreach($region in $provider.Value.psobject.Properties){
    # save the region name for later, remove the `continent : ` prefix
    $regionName = $region.Name -replace '^.*?:\s*'
    # Iterate over each property (datacenter location?) on the region object
    foreach($location in $region.Value.psobject.Properties){
      # save the location name for later, remove the `city : ` prefix
      $locationName = $location.Name -replace '^.*?:\s*'

      # Extract the network information, attach the parent details
      $location.Value |Select-Object *,@{Name='provider';Expression={$providerName}},@{Name='region';Expression={$regionName}},@{Name='location';Expression={$locationName}},
    }
  }
}

For which you'll get output like this, much easier to work with:

range     : 147.161.174.0/23
vpn       :
gre       :
hostname  :
latitude  : 24.453884
longitude : 54.3773438
provider  : zscloud.net
region    : EMEA
location  : Abu Dhabi I

range     : 185.46.212.0/23
vpn       : amsterdam2-vpn.zscloud.net
gre       : 185.46.212.36
hostname  : ams2.sme.zscloud.net
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.228.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 165.225.240.0/23
vpn       : ams2-2-vpn.zscloud.net
gre       : 165.225.240.42
hostname  : ams2-2.sme.zscloud.net
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.172.0/23
vpn       :
gre       : 165.225.240.42
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.230.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.232.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.234.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.224.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II

range     : 147.161.226.0/23
vpn       :
gre       :
hostname  :
latitude  : 52
longitude : 5
provider  : zscloud.net
region    : EMEA
location  : Amsterdam II
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206