DockerHelpers.psm1
Write-Verbose 'Importing from [C:\MyProjects\DockerHelpers\DockerHelpers\private]' # .\DockerHelpers\private\ConvertFrom-Docker.ps1 <# .SYNOPSIS Converts from docker output to objects .DESCRIPTION Converts from docker tabular output to objects that can be worked with in a familiar way in PowerShell .EXAMPLE Get the running containers and docker ps -a --no-trunc | ConvertFrom-Docker | ft .NOTES Original source: https://github.com/samneirinck/posh-docker/blob/3f8645196209ff7fd7090bcf1176307315b1ab30/posh-docker/posh-docker.psm1#L259-L284 Copywrite/licence: https://github.com/samneirinck/posh-docker/blob/master/LICENSE #> function ConvertFrom-Docker{ [CmdletBinding()] Param( [Parameter(Mandatory=$True, ValueFromPipeline=$True)] [object[]]$items ) begin{ $positions = $null; } process { foreach ($item in $items) { if($null -eq $positions) { # header row => determine column positions $positions = GetColumnInfo -headerRow $item } else { # data row => output! ParseRow -row $item -columnInfo $positions } } } end { } } # .\DockerHelpers\private\GetColumnInfo.ps1 function GetColumnInfo($headerRow){ $lastIndex = 0 $i = 0 while ($i -lt $headerRow.Length){ $i = GetHeaderBreak $headerRow $lastIndex if ($i -lt 0){ $name = $headerRow.Substring($lastIndex) New-Object PSObject -Property @{ HeaderName = $name; Name = PascalName $name; Start=$lastIndex; End=-1} break } else { $name = $headerRow.Substring($lastIndex, $i-$lastIndex) $temp = $lastIndex $lastIndex = GetHeaderNonBreak $headerRow $i New-Object PSObject -Property @{ HeaderName = $name; Name = PascalName $name; Start=$temp; End=$lastIndex} } } } # .\DockerHelpers\private\GetHeaderBreak.ps1 function GetHeaderBreak($headerRow, $startPoint=0){ $i = $startPoint while( $i + 1 -lt $headerRow.Length) { if ($headerRow[$i] -eq ' ' -and $headerRow[$i+1] -eq ' '){ return $i break } $i += 1 } return -1 } # .\DockerHelpers\private\GetHeaderNonBreak.ps1 function GetHeaderNonBreak($headerRow, $startPoint=0){ $i = $startPoint while( $i + 1 -lt $headerRow.Length) { if ($headerRow[$i] -ne ' '){ return $i break } $i += 1 } return -1 } # .\DockerHelpers\private\ParseRow.ps1 function ParseRow($row, $columnInfo) { $values = @{} $columnInfo | ForEach-Object { if ($_.End -lt 0) { $len = $row.Length - $_.Start } else { $len = $_.End - $_.Start } $values[$_.Name] = $row.SubString($_.Start, $len).Trim() } New-Object PSObject -Property $values } # .\DockerHelpers\private\PascalName.ps1 function PascalName($name){ $parts = $name.Split(" ") for($i = 0 ; $i -lt $parts.Length ; $i++){ $parts[$i] = [char]::ToUpper($parts[$i][0]) + $parts[$i].SubString(1).ToLower(); } $parts -join "" } Write-Verbose 'Importing from [C:\MyProjects\DockerHelpers\DockerHelpers\public]' # .\DockerHelpers\public\Get-DockerContainer.ps1 function Get-DockerContainer { <# .SYNOPSIS Return powershell objects describing container(s) on the docker host .DESCRIPTION Return powershell objects describing container(s) on the docker host .PARAMETER Name Filter container to return based on name .PARAMETER All Include stopped containers? .PARAMETER Inspect Return information about the container using `docker inspect`? .EXAMPLE Get-DockerContainer Description ----------- Return running containers; see `docker container ls` .EXAMPLE Get-DockerContainer -All -Inspect Description ----------- Return verbose information for both running and stopped containers; see `docker container ls` and `docker container inspect` .EXAMPLE Get-DockerContainer my-container, my-container2 Description ----------- Return multiple containers by exact name match .EXAMPLE Get-DockerContainer 'my-*' -Inspect Description ----------- Return verbose information for containers whose name matches a wildcard search .EXAMPLE Get-DockerContainer 'web*' -Inspect | select -PV container | ForEach-Object { $_.Mounts.Source } | ForEach-Object { [PsCustomObject]@{ Name = $container.Name; MountPath = $_ } } Name MountPath ---- --------- web-spa C:\ProgramData\Docker\volumes\web-spa-iis-logs\_data web-spa C:\ProgramData\Docker\volumes\web-spa-app-logs\_data web-tokensvr C:\ProgramData\Docker\volumes\web-tokensvr-app-logs\_data Description ----------- Return the local path(s) for volumes mounted into the containers whose name matches the wildcard search 'web*' .NOTES Alias 'gdc' #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [string[]]$Name, [Parameter(ParameterSetName = 'List')] [switch] $All, [switch] $Inspect ) process { $candidateNames = if ($All -or $PSCmdlet.ParameterSetName -eq 'Name') { docker container ls -a --format '{{.Names}}' } else { docker container ls --format '{{.Names}}' } $matchedNames = switch ($PSCmdlet.ParameterSetName) { 'List' { $candidateNames } 'Name' { $Name | ForEach-Object { $currentName = $_ $criteria = if ($currentName -match '\*') { { $_ -like $currentName } } else { { $_ -eq $currentName } } $candidateNames | Where-Object $criteria } | Select-Object -Unique } Default { throw "ParameterSet '$PSCmdlet.ParameterSetName' not implemented" } } $containers = if ($Inspect) { $matchedNames | ForEach-Object { [PsCustomObject](docker container inspect $_ | ConvertFrom-Json) } | Select-Object -ExcludeProperty Name -Property @{n = 'Name'; e = { $_.Name.TrimStart('/')}}, * } else { docker container ls -a | ConvertFrom-Docker | Where-Object { $_.Names -in $matchedNames } | Select-Object -ExcludeProperty Names, Command -Property @{n = 'Name'; e = { $_.Names}}, * } $containers } } Set-Alias -Name gdc -Value Get-DockerContainer Export-ModuleMember -Alias gdc # .\DockerHelpers\public\Get-DockerContainerIP.ps1 function Get-DockerContainerIP { <# .SYNOPSIS Return the IP address assigned to a container .DESCRIPTION Return the IP address assigned to a container .PARAMETER Name Filter container based on name .PARAMETER All Include stopped containers? .PARAMETER InputObject The container object whose IP address to return .EXAMPLE Get-DockerContainerIP Name IPAddress ---- --------- web-spa 172.24.221.65 web-tokensvr 172.24.221.66 Description ----------- Return IP address of all running containers; see `docker container ls` and `docker container inspect -f` .EXAMPLE Show-DockerContainerGridView -PassThru | Get-DockerContainerIP # or sdc -PassThru | gdip Description ----------- Return IP address for container(s) selected interactively from a grid .NOTES Alias 'gdip' #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [string[]]$Name, [Parameter(ParameterSetName = 'List')] [switch] $All, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Container')] [PSCustomObject]$InputObject ) process { $containers = switch ($PSCmdlet.ParameterSetName) { 'Name' { Get-DockerContainer -Name $Name -Inspect } 'List' { Get-DockerContainer -Inspect } 'Container' { if ($InputObject.PsObject.Properties.Name -notcontains 'NetworkSettings') { Get-DockerContainer -Name ($InputObject.Name) -Inspect } else { $InputObject } } Default { throw "ParameterSet '$PSCmdlet.ParameterSetName' not implemented"} } $containers | Select-Object -PV container | Select-Object -Exp NetworkSettings | Select-Object -Exp Networks | Select-Object -Exp * | Select-Object @{n = 'Name'; e = {$container.Name}}, IPAddress } } Set-Alias -Name gdip -Value Get-DockerContainerIP Export-ModuleMember -Alias gdip # .\DockerHelpers\public\Get-DockerContainerStatus.ps1 function Get-DockerContainerStatus { <# .SYNOPSIS Return the status of a container .DESCRIPTION Return the status of a container .PARAMETER Name Filter container based on name .PARAMETER All Include stopped containers? .PARAMETER InputObject The container object whose status to return .EXAMPLE Get-DockerContainerStatus Name Status Health ---- --------- --------- web-spa running healthy web-tokensvr running healthy Description ----------- Return status of all running containers .EXAMPLE Show-DockerContainerGridView -PassThru | Get-DockerContainerStatus # or sdc -PassThru | gdip Description ----------- Return status for container(s) selected interactively from a grid .NOTES Alias 'gdcs' #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [string[]]$Name, [Parameter(ParameterSetName = 'List')] [switch] $All, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Container')] [PSCustomObject]$InputObject ) process { $containers = switch ($PSCmdlet.ParameterSetName) { 'Name' { Get-DockerContainer -Name $Name -Inspect } 'List' { Get-DockerContainer -Inspect } 'Container' { if ($InputObject.PsObject.Properties.Name -notcontains 'NetworkSettings') { Get-DockerContainer -Name ($InputObject.Name) -Inspect } else { $InputObject } } Default { throw "ParameterSet '$PSCmdlet.ParameterSetName' not implemented"} } $containers | Select-Object ` @{n = 'Name'; e = {$_.Name}}, @{n = 'Status'; e = { $_.State.Status }}, @{n = 'Health'; e = { if ($_.State.Health) { $_.State.Health.Status } else { '' } }} } } Set-Alias -Name gdcs -Value Get-DockerContainerIP Export-ModuleMember -Alias gdcs # .\DockerHelpers\public\Get-DockerVolume.ps1 function Get-DockerVolume { <# .SYNOPSIS Return powershell object describing docker volume(s) .DESCRIPTION Return powershell object describing docker volume(s) .PARAMETER Name Filter volume to return based on name .PARAMETER ContainerName Filter volume to those associated with the supplied container .PARAMETER Container Filter volume to those associated with the supplied container .EXAMPLE Get-DockerVolume Description ----------- Return all volumes; see `docker volume ls` and `docker volume inspect` .EXAMPLE Get-DockerVolume my-vol1, my-vol2 Description ----------- Return multiple volumes by exact name match .EXAMPLE Get-DockerVolume 'my-*' Description ----------- Return volumes whose name matches a wildcard search .EXAMPLE Show-DockerContainerGridView -PassThru | Get-DockerVolume Description ----------- Return volumes associated by container(s) selected interactively from a grid .NOTES Alias 'gdv' #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [string[]]$Name, [Parameter(Mandatory, ParameterSetName = 'ContainerName')] [SupportsWildcards()] [string]$ContainerName, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Container')] [PSCustomObject]$Container ) process { $selectVolumeName = { $_ | Select-Object -Exp Mounts | Select-Object -Exp Name } $getAllVolumeNames = { docker volume ls --format '{{.Name}}' } $volumes = switch ($PSCmdlet.ParameterSetName) { 'List' { & $getAllVolumeNames } 'Name' { $allNames = & $getAllVolumeNames $Name | ForEach-Object { $currentName = $_ $criteria = if ($currentName -match '\*') { { $_ -like $currentName } } else { { $_ -eq $currentName } } $allNames | Where-Object $criteria } | Select-Object -Unique } 'ContainerName' { Get-DockerContainer -Name $ContainerName -Inspect | ForEach-Object $selectVolumeName } 'Container' { $Container = if ($Container.PsObject.Properties.Name -notcontains 'Mounts') { Get-DockerContainer -Name ($Container.Name) -Inspect } else { $Container } $Container | ForEach-Object $selectVolumeName } Default { throw "ParameterSet '$PSCmdlet.ParameterSetName' not implemented" } } $volumes | ForEach-Object { [PsCustomObject](docker volume inspect $_ | ConvertFrom-Json) } } } Set-Alias -Name gdv -Value Get-DockerVolume Export-ModuleMember -Alias gdv # .\DockerHelpers\public\Show-DockerContainerGridView.ps1 function Show-DockerContainerGridView { <# .SYNOPSIS Show docker containers in a grid; optionally allow items in grid to be selected for input to other commands .DESCRIPTION Show docker containers in a grid; optionally allow items in grid to be selected for input to other commands .PARAMETER InputObject The docker containers to show in grid .PARAMETER All Include stopped containers? .PARAMETER Inspect Return information about the container using `docker inspect`? Only relevant when -PassThru supplied .PARAMETER Force Show grid even when there is only one container? Only relevant when -PassThru supplied .PARAMETER PassThru Pass items selected in grid down the pipeline as input to other commands? .EXAMPLE Show-DockerContainerGridView -All Description ----------- Include both running and stopped containers; see `docker container ls` .EXAMPLE Show-DockerContainerGridView -PassThru -Force | ForEach-Object { docker container rm $_.Name } # or sdc -PassThrus -Force | % { docker rm $_.Name } Description ----------- Show running containers for selection, even if there is only one; run the native docker remove command on any container selected from grid .EXAMPLE Get-DockerContainer 'mycompose_*' | Show-DockerContainerGridView -PassThru | % { docker rm $_.Name } Description ----------- Show containers whose name matches the wildcard search to allow user to select which ones to remove .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Input')] [PSCustomObject[]] $InputObject, [Parameter(ParameterSetName = 'List')] [switch] $All, [switch] $Inspect, [switch] $Force, [switch] $PassThru ) begin { $items = @() } process { $items += if ($InputObject) { $InputObject } else { Get-DockerContainer -All:$All } } end { $title = 'docker container(s)' if (!$All) { $title = "RUNNING $title" } if ($PassThru) { $title = "Select $title; tip: hold down CTRL button for multi-select" } $outputMode = if ($PassThru) { 'Multiple' } else { 'None' } $selected = if ($PassThru -and !$Force -and $items.Count -eq 1) { $items } else { $items | Sort-Object Name -Unique | Sort-Object Image, Name | Out-GridView -Title $title -OutputMode $outputMode } if ($PassThru) { $selected | Select-Object -Exp Name | Get-DockerContainer -Inspect:$Inspect } } } Set-Alias -Name sdc -Value Show-DockerContainerGridView Export-ModuleMember -Alias sdc # .\DockerHelpers\public\Show-DockerContainerVolumeGridView.ps1 function Show-DockerContainerVolumeGridView { <# .SYNOPSIS Select docker containers whose associated volumn are shown in a grid; optionally allow volumes in grid to be selected for input to other commands .DESCRIPTION Select docker containers whose associated volumn are shown in a grid; optionally allow volumes in grid to be selected for input to other commands .PARAMETER InputObject The docker containers to show in grid .PARAMETER All Include stopped containers? .PARAMETER Force Show grid even when there is only one volume? Only relevant when -PassThru supplied .PARAMETER PassThru Pass volumes selected in grid down the pipeline as input to other commands? .EXAMPLE Show-DockerContainerVolumeGridView -All Description ----------- Select from both running and stopped containers whose volumes are to be shown; see `docker container ls` and `docker volume ls` .EXAMPLE Get-DockerContainer 'mycompose_*' | Show-DockerContainerVolumeGridView Description ----------- Select from containers whose name matches the wildcard search; show volumes associated with only these containers .EXAMPLE Show-DockerContainerVolumeGridView -PassThru | Show-DockerVolumeDirectory Description ----------- Select from both running containers, then select from volumes associated with these containers; show the filesystem contents of the host directory for the selected volumes .NOTES Alias sdcv #> [CmdletBinding(DefaultParameterSetName = 'List')] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Input')] [PSCustomObject[]] $InputObject, [Parameter(ParameterSetName = 'List')] [switch] $All, [switch] $Force, [switch] $PassThru ) begin { $items = @() } process { $items += if ($InputObject) { $InputObject } else { Get-DockerContainer -All:$All } } end { $items | Show-DockerContainerGridView -Force -PassThru | Get-DockerVolume | Show-DockerVolumeGridView -Force:$Force -PassThru:$PassThru } } Set-Alias -Name sdcv -Value Show-DockerContainerVolumeGridView Export-ModuleMember -Alias sdcv # .\DockerHelpers\public\Show-DockerVolumeDirectory.ps1 function Show-DockerVolumeDirectory { <# .SYNOPSIS Show the filesystem content of docker volumes .DESCRIPTION Show the filesystem content of docker volumess .PARAMETER Name Filter volume to return based on name .PARAMETER InputObject The docker volumes to show in grid .PARAMETER Interactive Show the directory contents in windows explorer? Defaults to true Where Windows explorer is not available, falls back to listing the content in the console .EXAMPLE Show-DockerVolumeDirectory Description ----------- Show directory content of all volume .EXAMPLE Show-DockerVolumeDirectory 'my-vol*' -Interactive:$false Description ----------- Show directory content of those volumes whose name matches the wildcard search; use the console to display this content .EXAMPLE Show-DockerVolumeGridView -PassThru | Show-DockerVolumeDirectory Description ----------- Show directory content for the selected volumes .NOTES Alias 'sdvd' #> [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [string[]]$Name, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Volume', Position = 0)] [PSCustomObject[]]$InputObject, [switch] $Interactive ) begin { if (!$PSBoundParameters.ContainsKey('Interactive')) { $Interactive = $true } if (-not(Test-Path 'C:\Windows\explorer.exe')) { $Interactive = $false } $volumes = @() $showDirectory = if ($Interactive) { { Start-Process explorer $_.Mountpoint } } else { { "Volume '$($_.Name)'" | Out-Host $directoryContent = Get-ChildItem $_.Mountpoint if ($directoryContent) { $directoryContent | Out-Host } else { "$([Environment]::NewLine)" | Out-Host " Directory: None" | Out-Host } "$([Environment]::NewLine)" | Out-Host } } } process { $volumes += switch ($PSCmdlet.ParameterSetName) { 'Name' { Get-DockerVolume -Name $Name } 'Volume' { $InputObject } 'List' { Get-DockerVolume } Default { throw "ParameterSet '$PSCmdlet.ParameterSetName' not implemented" } } } end { $volumes | Sort-Object Mountpoint -Unique | ForEach-Object $showDirectory } } Set-Alias -Name sdvd -Value Show-DockerVolumeDirectory Export-ModuleMember -Alias sdvd # .\DockerHelpers\public\Show-DockerVolumeGridView.ps1 function Show-DockerVolumeGridView { <# .SYNOPSIS Show docker volumes in a grid; optionally allow items in grid to be selected for input to other commands .DESCRIPTION Show docker volumes in a grid; optionally allow items in grid to be selected for input to other commands .PARAMETER InputObject The docker volumes to show in grid .PARAMETER Force Show grid even when there is only one volume? Only relevant when -PassThru supplied .PARAMETER PassThru Pass items selected in grid down the pipeline as input to other commands? .EXAMPLE Show-DockerVolumeGridView Description ----------- Show all volumes; see `docker volume ls` and `docker volume inspect` .EXAMPLE Show-DockerVolumeGridView -PassThru | Show-DockerVolumeDirectory Description ----------- Show directories for the selected volumes .NOTES Alias 'sdv' #> [CmdletBinding()] [OutputType('System.Management.Automation.PSCustomObject')] param ( [Parameter(ValueFromPipeline)] [PSCustomObject[]] $InputObject, [switch]$Force, [switch] $PassThru ) begin { $items = @() } process { $items += if ($InputObject) { $InputObject } else { Get-DockerVolume } } end { $title = 'docker volume(s)' if ($PassThru) { $title = "Select $title; tip: hold down CTRL button for multi-select" } $outputMode = if ($PassThru) { 'Multiple' } else { 'None' } $selected = if ($PassThru -and !$Force -and $items.Count -eq 1) { $items } else { $items | Sort-Object Name -Unique | Select-Object Name, Driver, MountPoint | Out-GridView -Title $title -OutputMode $outputMode } if ($PassThru) { $selected | ForEach-Object { Get-DockerVolume ($_.Name) } } } } Set-Alias -Name sdv -Value Show-DockerVolumeGridView Export-ModuleMember -Alias sdv # .\DockerHelpers\public\Wait-DockerContainerStatus.ps1 function Wait-DockerContainerStatus { <# .SYNOPSIS Waits for the container status supplied .DESCRIPTION Waits for the container status supplied .PARAMETER Name The container to inspect .PARAMETER Status The status to wait for .PARAMETER Timeout The time (in seconds) to wait until giving up and throwing .PARAMETER Interval The polling interval to check for container status .EXAMPLE Wait-DockerContainerStatus 'some-container' running Description ----------- Wait for the container named 'some-container' to have a status of running .NOTES Alias 'wdcs' #> [CmdletBinding()] param ( [Parameter(Mandatory)] [SupportsWildcards()] [string[]]$Name, [Parameter(Mandatory)] [ValidateSet('created', 'running', 'paused', 'exited', 'dead', 'healthy', 'unhealthy')] [string[]] $Status, [int] $Timeout = 90, [int] $Interval = 3 ) begin { # todo: support wildcards; will need careful thought: # * wait for any container with the required status or all containers whose # name matches at the start of the wait? # * should created status be treated differently from other status? # IMPORTANT: we are NOT correctly supporting wildcards just be commenting out the code below! # The wait will likely fail when a wildcard matches more than one container # if ($Name -match '\*') { # throw "Name parameter does not support wildcards" # } $timeToWait = if ($Timeout -eq 0) { # ie never timeout! (Get-Date).AddYears(99) } else { (Get-Date).AddSeconds($Timeout) } $healthStates = 'healthy', 'unhealthy' $healthStatus = $Status | Where-Object { $healthStates -contains $_ } $getContainerStatusString = { $result = "{0}:{1}" -f $_.Name, $_.Status if ($_.Health) { $result = '{0} ({1})' -f $result, $_.Health } $result } } process { $names = @() $names += $Name | Select-Object -Unique while ($true) { $container = @(Get-DockerContainerStatus $Name) $container | ForEach-Object $getContainerStatusString | Write-Verbose $matching = @($container | Where-Object { $_.Status -in $Status -or $_.Health -in $healthStatus } ) if ($names.Count -eq $matching.Count) { break } elseif ((Get-Date) -ge $timeToWait) { throw "Timeout exceeded waiting on container (desired status: $Status)" } elseif ('healthy' -eq $Status -and ($container | Where-Object Health -eq unhealthy)) { throw "Waited status not achievable (desired 'healthy')" } Start-Sleep -Seconds $Interval } } } Set-Alias -Name wdcs -Value Wait-DockerContainerStatus Export-ModuleMember -Alias wdcs Write-Verbose 'Importing from [C:\MyProjects\DockerHelpers\DockerHelpers\classes]' |