spuder
spuder

Reputation: 18447

powershell prevent duplicate object keys

This is a follow up to this question

If I have 2 json files

file1.json

{
  "foo": {
    "honk": 42
  }
}

file2.json

{
  "foo": {
    "honk": 9000,
    "toot": 9000
  }
}

And I create an object using ConvertFrom-Json

$bar = @(Get-ChildItem . -Filter *.json -Recurse | Get-Content -Raw |ConvertFrom-Json)

Powershell will happily take both, and overwrite foo.

foo

---
@{honk=42}
@{honk=9000; toot=9000}

The contents of $bar.foo are merged

$bar.foo

honk
----
  42
9000

How can I error if importing duplicate objects?

Upvotes: 1

Views: 1113

Answers (2)

spuder
spuder

Reputation: 18447

When importing to an array, every object is unique. In this example it isn't ideal to leave the objects in an array, since there is no way to predictably iterate over them, since some objects might contain multiple keys.

{
  "foo": 42
}

vs

{
  "bar": 9000,
  "buzz": 9000
}

This will cause heartache when trying to loop through all objects.

Instead, I took all array items and combined them into 1 powershell object. Since powershell objects are basically hashes, and hashes by design must have all keys unique, powershell will automatically error if overwriting a key.

function Load-Servers {

    $allObjects = @(
        Get-ChildItem '.\servers' -Filter *.json -Recurse | Get-Content -Raw | ConvertFrom-Json
    )
    $object = New-Object PSObject
    Foreach ($o in $allObjects) {
        $o.psobject.members | ? {$_.Membertype -eq "noteproperty" } | %{$object | add-member $_.Name $_.Value }
    }

    return $object
}

Upvotes: 1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200313

Each JSON file is imported as a separate object, so there's nothing overwritten really. You just get a list of objects.

To throw an error when you get multiple objects with the same top-level property you can group the objects by property name and throw an error if you get a count >1.

$bar | Group-Object { $_.PSObject.Properties.Name } |
  Where-Object { $_.Count -gt 1 } |
  ForEach-Object { throw "Duplicate object $($_.Name)" }

Upvotes: 3

Related Questions