The immediate fix is to create your own array representation, by enumerating the elements and separating them with ,
, enclosing string values in '...'
:
# Sample input hashtable. [ordered] preserves the entry order.
$resumeParms = [ordered] @{ foo = 42; bar = 'baz'; arr = (Get-ChildItem *.txt) }
$resumeParms.GetEnumerator() |
ForEach-Object {
"{0}={1}" -f $_.Name, (
$_.Value.ForEach({
(("'{0}'" -f ($_ -replace "'", "''")), $_)[$_.GetType().IsPrimitive]
}) -join ','
)
}
Not that this represents all non-primitive .NET types as strings, by their .ToString()
representation, which may or may not be good enough.
The above outputs something like:
foo=42
bar='baz'
arr='C:\Users\jdoe\file1.txt','C:\Users\jdoe\file2.txt','C:\Users\jdoe\file3.txt'
See the bottom section for a variation that creates a *.psd1
file that can later be read back into a hashtable instance with Import-PowerShellDataFile
.
Alternatives for saving settings / configuration data in text files:
If you don't mind taking on a dependency on a third-party module:
Consider using the PSIni
module, which uses the Windows initialization file (*.ini
) file format; see this answer for a usage example.
- Adding support for initialization files to PowerShell itself (not present as of 7.0) is being proposed in GitHub issue #9035.
Consider using YAML as the file format; e.g., via the FXPSYaml
module.
- Adding support for YAML files to PowerShell itself (not present as of 7.0) is being proposed in GitHub issue #3607.
The Configuration
module provides commands to write to and read from *.psd1
files, based on persisted PowerShell hashtable literals, as you would declare them in source code.
Alternatively, you could modify the output format in the code at the top to produce such files yourself, which allows you to read them back in via
Import-PowerShellDataFile
, as shown in the bottom section.
As of PowerShell 7.0 there's no built-in support for writing such as representation; that is, there is no complementary Export-PowerShellDataFile
cmdlet.
However, adding this ability is being proposed in GitHub issue #11300.
If creating a (mostly) plain-text file is not a must:
The solution that provides the most flexibility with respect to the data types it supports is the XML-based CLIXML format that Export-Clixml
creates, as Lee Dailey suggests, whose output can later be read with Import-Clixml
.
However, this format too has limitations with respect to type fidelity, as explained in this answer.
Saving a JSON representation of the data, as Lee also suggests, via ConvertTo-Json
/ ConvertFrom-Json
, is another option, which makes for human-friendlier output than XML, but is still not as friendly as a plain-text representation; notably, all \
chars. in file paths must be escaped as \\
in JSON.
Writing a *.psd1
file that can be read with Import-PowerShellDataFile
Within the stated constraints regarding data types - in essence, anything that isn't a number or a string becomes a string - it is fairly easy to modify the code at the top to write a PowerShell hashtable-literal representation to a *.psd1
file so that it can be read back in as a [hashtable]
instance via Import-PowerShellDataFile
:
As noted, if you don't mind installing a module, consider the Configuration
module, which has this functionality built int.
# Sample input hashtable.
$resumeParms = [ordered] @{ foo = 42; bar = 'baz'; arr = (Get-ChildItem *.txt) }
# Create a hashtable-literal representation and save it to file settings.psd1
@"
@{
$(
($resumeParms.GetEnumerator() |
ForEach-Object {
" {0}={1}" -f $_.Name, (
$_.Value.ForEach({
(("'{0}'" -f ($_ -replace "'", "''")), $_)[$_.GetType().IsPrimitive]
}) -join ','
)
}
) -join "`n"
)
}
"@ > settings.psd1
If you read settings.psd1
with Import-PowerShellDataFile settings.psd1
later, you'll get a [hashtable]
instance whose entries you an access as usual and which produces the following display output:
Name Value
---- -----
bar baz
arr {C:\Users\jdoe\file1.txt, C:\Users\jdoe\file1.txt, C:\Users\jdoe\file1.txt}
foo 42
Note how the order of entries (keys) was not preserved, because hashtable entries are inherently unordered.
On writing the *.psd1
file you can preserve the key(-creation) order by declaring the input hashtable (System.Collections.Hashtable
) as [ordered]
, as shown above (which creates a System.Collections.Specialized.OrderedDictionary
instance), but the order is, unfortunately, lost on reading the *.psd1
file.
As of PowerShell 7.0, even if you place [ordered]
before the opening @{
in the *.psd1
file, Import-PowerShellDataFile
quietly ignores it and creates an unordered hashtable nonetheless.