I made another post about Powershell and YAML some months ago with more code where I explain the different ways to write YAML and how it behaves in powershell, comparing PSYaml and powershell-yaml modules.
After the experience of being working in a module that's compatible with both modules to read YAML files, I decided to write this new post to make it shorter, clearer and more concise.
No official YAML support in Powershell
YAML is not supported by default in powershell like JSON and XML, although some people are already asking for it in github and Windows user voice (give your voice, too!). YAML is more comfortable for human reading than JSON.
Currently there're two maintained modules to work with YAML:
- PSYaml from Phil Factor. More info in this post. Requires minimum powershell 2.0.
- powershell-yaml from Cloudbase. Requires powershell 3.0 although it is only tested in 4.0 and 5.0.
YAML
YAML is composed on:
- Sequences: starts with a dash '
-
': it's an array that can have repeated items. - Mappings: are dictionaries, where items cannot be repeated.
Here is an easy example how to convert a YAML to native Powershell objects:
$yaml = "
name: Johan
surname: McGuinness
emails:
- personal: johnanmg@hotmmail.com
- professional: johan@gmmail.com
- personal: johnan_mguinness@yahooo.com
"
$person = ConvertFrom-YAML $yaml
Representing YAML with Powershell native objects
The same structure could be created with native Powershell objects (Array @()
and Hashtable @{}
). I find it useful when creating objects for unit testing:
$person = @{ name="Johan"; surname="McGuinness"; emails=@(
@{ "personal"="johnanmg@hotmmail.com" },
@{ "professional"="johan@gmmail.com" },
@{ "personal"="johnan_mguinness@yahooo.com" }
)
}
HashTable @{}
does not preserve insertion order. If it is important, it can be changed for an OrderedDictionary .NET class:
$orderedPerson = New-Object ([System.Collections.specialized.OrderedDictionary])
$orderedPerson.Add("name", "Johan");
$orderedPerson.Add("surname", "McGuinness");
$orderedPerson.Add("emails", @(
@{ "personal"="johnanmg@hotmmail.com" },
@{ "professional"="johan@gmmail.com" },
@{ "personal"="johnan_mguinness@yahooo.com" }
));
To access the items is the same:
powershell
$orderedPerson['emails'][0]['personal']
How YAML files are mapped in Powershell objects
module | mappings | sequences |
---|---|---|
PSYaml | OrderedDictionary | Array |
powershell-yaml | Hastable | List |
powershell-yaml with -Ordered | OrderedDictionary | List |
powershell native objects | Hastable | Array |
Powershell-yaml by default uses Hashtable
and , as we've seen with Powershell native @{}
the insertion order is not maintained! But powershell-yaml has the option to use -Ordered
switch parameter to force ordered mappings using OrderedDictionary
as PSYaml does.
When counting the number of elements in a sequence use Count
property that works equaly with Array
and List
. It exists Length
that works with Array
but with List
doesn't return the desired result.
Read a YAML file
To read a YAML file using Get-Content
and then convert with ConvertFrom-YAML
:
[string[]]$fileContent = Get-Content "C:\temp\learnxinyminutes.yaml"
$content = ''
foreach ($line in $fileContent) { $content = $content + "`n" + $line }
$yaml = ConvertFrom-YAML $content