Edit: It turns out that I did in fact go over nesting a hash table inside a hash table in Part II of my Splunk series. There’s still some likable and solid content in this post though.
It’s how it works. A single topic, or idea, or even a real live project, can lead to additional writing and posting. As many might recognize, I use my blog for at least two things. One, it’s a place for you and others to come and potentially learn something new. Or maybe it’s just to reinforce a concept. I do my best to make things quick and clear. Two, it’s. for. me. Sometimes I share something simply because I need a place to store it for my own reference. Every post I’ve written — and I’m getting close to 350 of them — serves both purposes. This one certainly does, too.
If you’ve been paying attention, you know I’m currently working with my function template (which I write as FunctionTemplate at work), gathering telemetry data, and posting that to Splunk via a REST endpoint. It’s been fascinating. I had wanted an opportunity to work with Splunk and lucky for me a colleague mentioned it, even though I was preparing to work with AWS. I’m grateful they did!
A part of working with Splunk and REST and HEC requires that a payload be sent in as JSON. Luckily, PowerShell includes a command to convert a hash table to JSON. As a part of this project, I’ve converted numerous strings and even an array to JSON. Take a look.
I got to thinking that I want my telemetry code to acquire the city, state, and country via the public IP address and a geolocation API. Although it started this way, I decided I didn’t want single strings in my JSON for each of the properties.
Therefore, I needed to create a hash table of the data (within the parent hash table), and then convert that to JSON. Yes, you heard that correctly, we’re going to nest a hash table inside of another hash table and convert that to JSON. You may remember something about this in the Splunk series. Well, we cover it all again, and all because I want my Location data inside a hash table and not as three single strings. In the end, the below explanations — most of it anyway — will get us to this image.
Let’s pretend my public IP address is 8.8.8.8. Much of the hey-sign-up text in the below response won’t be there if you’re using your own public IP address, as opposed to one of Google’s. I’d still recommend you take a look at the ipapi.co website and do your own due diligence regarding the API.
Once I knew how to obtain my geolocation data via ipapi.co, I could use the below code. In the code I create three hash tables:
- TelemetryHash
- TelemetryHashStandard
- TelemetryHashLocation
The TelemetryHashStandard hash table holds two key-value pairs: DateTime and Directory (as in our location within the operating system). These aren’t vital for more than the inclusion of a couple of standard entries in the parent hash table. The TelemetryHashLocation hash table holds three key-value pairs: City, Region, and Country.
Once the values are obtained and stored in one of the two hash tables, we store TelemetryHashStandard in TelemetryHash. Then we add our TelemetryHashLocation hash table as a single key-value pair to the TelemetryHash hash table. Now that you’ve gotten through that reading, be sure to review the below code.
Remove-Variable -Name TelemetryHash,TelemetryHashStandard,TelemetryHashLocation -ErrorAction SilentlyContinue New-Variable -Name TelemetryHash -Value @{} New-Variable -Name TelemetryHashStandard -Value @{} New-Variable -Name TelemetryHashLocation -Value @{} $TelemetryHashStandard.Add('DateTime',"$(Get-Date)") $TelemetryHashStandard.Add('Directory',"$((Get-Location).Path)") $Location = Invoke-RestMethod -Uri "https://ipapi.co/8.8.8.8/json" $TelemetryHashLocation.Add('City',$Location.city) $TelemetryHashLocation.Add('Region',$Location.region) $TelemetryHashLocation.Add('Country',$Location.country_name) $TelemetryHash = $TelemetryHashStandard $TelemetryHash.Add('Location',$TelemetryHashLocation) $TelemetryHash | ConvertTo-Json { "Location": { "Region": "California", "Country": "United States", "City": "Mountain View" }, "Directory": "C:\\", "DateTime": "01/13/2021 19:33:14" }
See that; just above? There are the two single strings — DateTime and Directory — as well as the single Location hash table and its nested keys and values. And, just for fun, here’s another example. Here we create two hash tables: one for parents and one for children. Once they’re both populated, we add the children to the parents’ hash table. Like we did above, we could’ve gotten everything into a single hash table that was neither the parent’s or children’s hash table. All this to say, there’s no requirement for a third and final hash table needed prior to the JSON export.
[PS7.1.0] C:\> $Parent = @{}; $Child = @{} [PS7.1.0] C:\> $Child.Add('Son','CM') [PS7.1.0] C:\> $Child.Add('Daughter','AM') [PS7.1.0] C:\> $Child Name Value ---- ----- Son CM Daughter AM [PS7.1.0] C:\> $Parent.Add('Father','Tommy') [PS7.1.0] C:\> $Parent.Add('Mother','JM') [PS7.1.0] C:\> $Parent Name Value ---- ----- Mother JM Father Tommy [PS7.1.0] C:\> $Parent.Add('Children',$Child) [PS7.1.0] C:\> $Parent Name Value ---- ----- Children {Son, Daughter} Father Tommy Mother JM [PS7.1.0] C:\> $Parent.Children Name Value ---- ----- Son CM Daughter AM [PS7.1.0] C:\> $Parent | ConvertTo-Json { "Children": { "Son": "CM", "Daughter": "AM" }, "Father": "Tommy", "Mother": "JM" }
By nesting a hash table inside of another hash table, we can convert to JSON and maintain the data’s original structure. Add arrays and hash tables to the hash table you intend to convert/export to JSON, and they’ll be there just as you expect them to be.