I load some config from a JSON file and I want to be able to check what I've just loaded and potentially set some default values.
for now, I create a hash table containing info then load and check this way
$config_info=@{
foo=@{default='' ;type=[string]}
bar=@{default=@();type=[array] }
}
$config = Get-Content $configPath -Raw | ConvertFrom-Json
if(-not [Bool]$config.PSObject.Properties['foo']) {
$config | Add-Member -MemberType NoteProperty -Name 'foo' -Value $config_info.foo.default
}
if($config.foo -isnot $config_info.foo.type) { ... }
but I'm wondering how safe is the notation type=[string]
and if I should rather use type=''.getType()
witch looks less natural.
Update 1
in the past I used Export-Clixml
/Import-Clixml
for my config files but the resulting files are hardly human readable/ editable.
I also sometimes used dot-sourcing PS1 files but for the current project, config has to be maintain by non-powershell people.
What I'm wondering is, is type=[string]
a safe/ lasting syntax to store ''.getType()
in a variable, or not.
CodePudding user response:
What I'm wondering is, is
type=[string]
a safe/ lasting syntax to store''.getType()
in a variable, or not.
Yes, assuming that the .NET
[string]
type (System.String
) isn't being shadowed by a customclass
definition of the same name (which would be unwise to do).[string]
is a PowerShell type literal, and referring to a .NET type this way works predictably, assuming the type has been loaded into the session, which is by definition true for built-in types such asSystem.String
. You can refer to a .NET type:by its accelerator name, if defined; such as
[string]
or[regex]
; use the.FullName
property to see the type's full name; e.g.[regex].FullName
by its full name, though note that you're free to omit the
System.
part of the namespace, e.g., you can refer toSystem.Text.Encoding
as[System.Text.Encoding]
or[Text.Encoding]
by its assembly-qualified name; e.g. (obtained with
[string].AssemblyQualifiedName
):[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]`
However:
This doesn't work across PowerShell editions, at least not for built-in types.
It is rarely necessary and can give the false impression that a given assembly version is being referenced (.NET seemingly loads whatever version is available)
However, in .NET (Core) / PowerShell (Core) only, you may omit the
Version
field; similarly,Culture
andPublicKeyToken
are optional.While I doubt the need will arise, especially with respect to built-in types, at least hypothetically you can then disambiguate types with the same full name by their hosting assembly; e.g.:
# PS Core (v7 ) only; the PublicKeyToken field may be omitted. [System.String, System.Private.CoreLib, PublicKeyToken=7cec85d7bea7798e]
A simpler PowerShell (Core) 7 solution:
In PowerShell (Core) 7 ,
ConvertFrom-Json
has an-AsHashtable
switch returns the parsing results as hashtables rather than as[pscustomobject]
instances.Given that you can cast from a hashtable to a custom
class
type literal, you can use strongly typed properties with default values that correspond to the properties in the input JSON data.
# Custom class that describes the structure of the config data,
# with strongly typed properties and default values.
class Config {
[string] $foo = '(none)'
[int[]] $bar = @()
}
# Sample JSON input; parse it into a hashtable.
$ht = @'
{
"bar": [1, 2]
}
'@ | ConvertFrom-Json -AsHashtable
# Construct a [Config] instance from the values in the hashtable,
# enforcing data types, with on-demand conversion.
[Config] $ht
Output (note how foo
has its default value):
foo bar
--- ---
(none) {1, 2}
Note:
PowerShell's flexible automatic type conversions are used when constructing the
Config
instance, and given that PowerShell's allows any data type to be converted to[string]
, non-string input for[string]
-typed properties is still accepted (resulting in stringification).When a value is of the wrong type and cannot be converted (e.g., a value of
"abc"
for an[int]
-typed property), the[Config]
cast results in a statement-terminating error.If you need more stringent type-checking, consider using validation by a JSON schema, which
Test-Json
supports via the-Schema
and-SchemaFile
parameters, in PowerShell (Core) only, as zett42 suggests.