I'm doing a script in powershell where i'm modifying the Chrome Bookmarks file. This is what i want to do.
- Read the file and parse the Json (Done)
- Check if a certain folder is added, if it isn't, add it.
- Parse again the object to Json, and save a new bookmark file. (i know how to do it)
This is how i convert it to Object:
$BkmrkJson = Get-Content $GoogleBkmrk | ConvertFrom-Json
And this is how i'm adding a new Object to the current "Childrens(Urls or bookmarks)".
$BkmrkJson.roots.bookmark_bar.children = New-Object -TypeName psobject -Property @{children=@();date_added="";date_modified="";guid="";id="";name="HV2";type="folder"}
My main problem, it's that when i add it, it isn't respecting the order of the properties. The usual order it's "children, date_added, date_modified, guid, id, name, type".
I add some values in blank, because Chrome adds new values automatically, after i add that value, or children, i parse again the psobject to Json.
$MyFinalJson = ConvertTo-Json $BkmrkJson -Depth 9
But when i create the file, it wasn't made correctly. So my principal question it's, how i can add correctly a new object to the parsed one, so when i parse it again, can recognize correctly the new ones.
CodePudding user response:
hashtables (@{ ... }
) are inherently unordered in PowerShell / .NET, i.e the order in which their entries are later enumerated isn't guaranteed, which means that by the time your New-Object
call receives its -Property
argument, the definition order of the entries in the hashtable is already lost.
However, PowerShell v3 offers syntactic sugar for constructing custom objects ([pscustomobject]
(aka [psobject]
)), in which case the order of entries, i.e. the order of the resulting properties is guaranteed to reflect the definition order, namely if you cast a hashtable to [pscustomobject]
:
$BkmrkJson.roots.bookmark_bar.children =
[pscustomobject] @{
children=@(); # Note: ";" only strictly needed in *single-line* defs.
date_added="";
date_modified="";
guid="";
id="";
name="Humach V2";
type="folder"
}
Note that in cases where you do want to stick with a hashtable (dictionary), you can "cast" a hashtable literal to [ordered]
, which also guarantees preserving the input order; specifically, this syntactic sugar creates an ordered hashtable, i.e. a System.Collections.Specialized.OrderedDictionary
instance, which also implements the IDictionary
interface, but (a) enumerates its entries in definition order and (b) allows accessing entries by positional index, as an alternative to using a key as the index; e.g.:
$orderedHashTable = [ordered] @{ zebra = 26; quebec = 17; alpha = 1}
$orderedHashTable.Keys # -> 'zebra', 'quebec', 'alpha'
# Access by key.
$orderedHashTable['quebec'] # -> 17
# Access by positional index
$orderedHashTable[0] # -> 26 (key 'zebra')