A few days ago I shared some experiences of working with Docker containers and PowerShell. As I continue to learn Docker, I am also learning how to manage it with PowerShell. The Docker command line tools are fine but I think they are even better when drizzled with a nice PowerShell glaze. Here's a bit more of what I have been working on.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Container ID
In my previous work, I needed the full container ID so I could use it with the PowerShell PSSession cmdlets. Thanks to people like Tim Pringle, who provided tips on better using the Docker CLI, specifically the filter option.
docker container ls -f Name=srv4
The -f could also be written as --filter.
Be careful. Container names are case-sensitive.
With this, I can combine it with a few other parameters to get the full configuration ID.
docker container ls --no-trunc -qf Name=srv4
Formatting Containers
It gets better. After a bit of research and experimentation, I figured out how to take advantage of the --format parameter in the Docker CLI. This is meant to show you what formatting options are available to you using the JSON format.
docker container ls --no-trunc --format "{{json .}}"
You can format using any heading preceded by a colon. In other words, you can tell Docker what properties to return from the JSON output.
docker container ls -a --no-trunc --format "{{json .Names}},{{json .ID}},{{json .Image}},{{json .Networks}},{{json .Mounts}},{{json .CreatedAt}}"
Hey! That is a CSV output. I can use PowerShell to turn that into objects.
docker container ls -a --no-trunc --format "{{json .Names}},{{json .ID}},{{json .Image}},{{json .Networks}},{{json .Mounts}},{{json .CreatedAt}}" |
ConvertFrom-CSV -Header "Name","ID","Image","Network","Mounts","Created"
That is very useful, so why not take everything? I know Docker will provide JSON output which means I can convert it and then tweak a few properties to be the of the proper type.
docker container ls -a --no-trunc --format "{{json .}}" | convertfrom-json |
Select-Object ID,@{Name="Name";Expression = {$_.names}},Image,
@{Name="Created";Expression = {($_.createdat -split "\s[-+]\d{4}.*")[0] -as [datetime]}},
Networks,Mounts
In case you're wondering I'm using a regular expression pattern to parse the CreatedAt value to that I can convert it to a proper DateTime object.
Digging Deeper
You know me. I always want to discover how far I can go. The Docker CLI has an option to inspect a container. This allows you to get all the information about a given container. The default output is a JSON document. This means I can get all container names and then inspect each one, converting the JSON output to objects in PowerShell.
$c = docker container ls -a --no-trunc --format "{{json .Names}}" |
foreach-object { docker container inspect $_ | ConvertFrom-Json }
I get output like this:
With a bit of scripting, I can turn this into something a bit more manageable.
foreach ($item in $c) {
$item | Select-object Id,
@{Name="Name";Expression = {$_.Name.substring(1)}},
@{Name="State";Expression = {$_.state.status}},
@{Name="IsRunning";Expression = {$_.state.Running}},
@{Name="Started";Expression = {$_.state.startedat -as [datetime]}},
@{Name="Finished";Expression = {
#this value shows the last time it finished which won't be accurate if
#the container is running
if ($_.state.running) {
$null
}
else {
$_.state.finishedat -as [datetime]
}
}},
@{Name="Runtime";Expression = {
if ($_.state.running) {
(Get-Date) - ($_.state.startedat -as [datetime])
}
else {
($_.state.finishedat -as [datetime]) - ($_.state.startedat -as [datetime])
}
}},
Platform,Mounts,
@{Name="Image";Expression = { (docker image inspect ($_.image -split ":")[1] --format "{{json .RepoTags}}") -replace '\[|\]|"',"" }},
@{Name="Created";Expression ={$_.Created -as [datetime]}}
}
I can even add my own properties.
Toolmaking Time
Obviously, nobody wants to type that all the time. So I turned the code into a proper PowerShell function.
The function is using a nested PowerShell class to define my custom object.
I'm glad I have all of this information available, but part of PowerShell toolmaking is to take how it will be used into account. I wanted a different default view of the objects. This meant I needed a custom format ps1xml file. Fortunately, that is is easy now using the New-PSFormatXML command in my PSScriptTools module.
Get-DockerContainer | Select -first 1 | New-PSFormatXML -Properties ID,Name,Image,State,IsRunning,Created,Started,Finished,Runtime -Path c:\scripts\mydockercontainer.format.ps1xml
I edited the file to get the desired output.
<?xml version="1.0" encoding="UTF-8"?>
<!--
format type data generated 03/27/2019 17:01:10
by BOVINE320\Jeff
-->
<Configuration>
<ViewDefinitions>
<View>
<!--Created 03/27/2019 17:01:10 by BOVINE320\Jeff-->
<Name>default</Name>
<ViewSelectedBy>
<TypeName>Get-DockerContainer.myDockerContainer</TypeName>
</ViewSelectedBy>
<GroupBy>
<ScriptBlock>@"
$($_.ID)
Image Tag : $($_.image)
"@</ScriptBlock>
<Label>Container ID</Label>
</GroupBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Name</Label>
<Width>7</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Created</Label>
<Width>22</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>State</Label>
<Width>8</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>IsRunning</Label>
<Width>10</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Started</Label>
<Width>21</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Finished</Label>
<Width>21</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Runtime</Label>
<Width>20</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Created</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>State</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>IsRunning</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Started</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Finished</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Runtime</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
Before it can be used, it needs to be imported into the PowerShell session.
Update-FormatData C:\scripts\mydockercontainer.format.ps1xml
Now I get a formatted output that is easier to digest.
The other properties are still available if I need them.
I can already think of more that I want to do with this. Hopefully, you have some ideas as well. And now that I know how to get data from Docker using JSON, there is much, much more that I can do.

The possibilities… just replace docker cli with az cli 🙂 Never would have thought to put a class in begin {}. Thanks!