Skip to content

Instantly share code, notes, and snippets.

@michaelsanford
Created December 11, 2019 14:18
Show Gist options
  • Save michaelsanford/7ad32a3ddea2a6156967842d3b3f8574 to your computer and use it in GitHub Desktop.
Save michaelsanford/7ad32a3ddea2a6156967842d3b3f8574 to your computer and use it in GitHub Desktop.
PowerShell script to execute Docker maintenance, optionally non-interactively
<#
.Synopsis
Runs periodic maintenance on Docker for Windows.
It must be run as an Administrator!
.Description
Intended to be run interactively or as a periodoc service, this will execute configurable docker prune
within the VM and then stop and compact the virtual machine hard disk before restarting Docker.
When run as a service, logs are sent to the Windows Event Log. Otherwise, progress is logged to the console.
.Parameter VHDX
Required. The complete path to your DockerDesktop virtual hard disk file, i.e., 'F:\Docker\DockerDesktop.vhdx'
.Parameter FullSystem
Optional. By default docker will prune unused images with 'docker image prune'.
Add this flag to execute 'docker system prune -f'.
.Parameter Pull
Optional (but recommended). Pull rebuilt base images from the internal HQ-DOCKER registry.
.Example
periodic-maintenance.ps1 -VHDX "F:\Docker\DockerDesktop.vhdx" -FullSystem -Pull
# Interactively run a full system prune, pull the latest internal base images, compact the VHDX.
.Example
periodic-maintenance.ps1 -VHDX "F:\Docker\DockerDesktop.vhdx"
# Run a minimal image prune and compact the VHDX.
#>
#Requires -RunAsAdministrator
#Requires -Modules Hyper-V
param(
[Switch]$FullSystem,
[Switch]$Pull,
[String]$VHDX
)
if ([System.Diagnostics.EventLog]::SourceExists("DockerMaintenance") -eq $False) {
New-EventLog -LogName Application -Source DockerMaintenance
}
function Write-ErrorLog($Message) {
if (!$MyInvocation.scriptname) {
Write-EventLog -LogName Application `
-Source DockerMaintenance `
-EventID 3001 `
-Category 1 `
-EntryType Error `
-Message $Message
} else {
Write-Host -ForegroundColor Red $Message
}
}
function Write-InfoLog($Message) {
if (!$MyInvocation.scriptname) {
Write-EventLog -LogName Application `
-Source DockerMaintenance `
-EventID 3001 `
-Category 1 `
-EntryType Information `
-Message $Message
} else {
Write-Host $Message
}
}
if ($null -eq $VHDX) {
$err = "The -VHDX parameter is missing! Please add it."
Write-ErrorLog $err
Exit -1
} elseif ((![System.IO.File]::Exists("${VHDX}")) -or ($VHDX -notlike "*\DockerDesktop.vhdx")){
$err = "The path provided for -VHDX ""${VHDX}"" does not point to a 'DockerDesktop.vhdx'!"
Write-ErrorLog $err
Exit -2
}
function Invoke-Toast($Message, $Cancel) {
$AppId = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe'
$XmlString = @"
<toast>
<visual>
<binding template="ToastGeneric">
<text hint-maxLines="1">Docker Maintenance</text>
<text>$Message</text>
</binding>
</visual>
<audio src="ms-winsoundevent:Notification.Default" />
</toast>
"@
$ToastXml = [Windows.Data.Xml.Dom.XmlDocument]::new()
$ToastXml.LoadXml($XmlString)
$Toast = [Windows.UI.Notifications.ToastNotification]::new($ToastXml)
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($AppId).Show($Toast)
}
function Invoke-ImagePrune() {
Write-InfoLog "Pruning unused and dangling images"
docker image prune -f
}
function Invoke-SystemPrune() {
Write-InfoLog "Fully pruning docker system"
docker system prune -f
}
function Invoke-DockerPull() {
Write-InfoLog "Pulling HQ docker images"
docker images --format "{{.Repository}}:{{.Tag}}" | Where-Object { $_ -like "hq-docker-*" } | ForEach-Object { docker pull $_ }
}
function Invoke-CompactDocker() {
Write-InfoLog "Compacting ${VHDX}"
Mount-VHD $VHDX -ReadOnly
Optimize-VHD $VHDX -Mode Full
Dismount-VHD $VHDX
}
function Stop-Docker() {
$docker = Get-VM | Where-Object { $_.Name -eq 'DockerDesktopVM' }
if ($docker.State -ne "Off") {
Write-InfoLog "Docker is still running. Stopping..."
Get-VM | Where-Object { $_.Name -eq 'DockerDesktopVM' } | Stop-VM
Get-Process -Name "*Docker*" | Stop-Process -Force
}
}
function Start-Docker() {
Write-InfoLog "Restarting docker"
Net Start "com.docker.service"
& "C:\Program Files\Docker\Docker\Docker Desktop.exe"
if ($MyInvocation.scriptname) {
Write-Host "Docker for Windows is now starting up. Watch for the usual Toast notification."
}
}
if ($MyInvocation.scriptname) {
Invoke-Toast "Your Docker for Windows will be temporarily shut down for maintenance in 5 MINUTES. `
This process should take about 3 minutes."
Start-Sleep -Seconds (60*5)
} else {
Write-Host -ForegroundColor Green "Beginning maintenance in 5 seconds. Abort with [CTRL-C]."
Start-Sleep -Seconds 5
}
if ($True -eq $Pull) {
Invoke-DockerPull
}
if ($True -eq $FullSystem) {
Invoke-SystemPrune
} else {
Invoke-ImagePrune
}
Stop-Docker
Invoke-CompactDocker
Write-InfoLog "Maintenance Complete, restarting Docker..."
Start-Docker
@michaelsanford
Copy link
Author

This is also (currently) awaiting review on Code Review.SE, please feel free to contribute comments there https://codereview.stackexchange.com/questions/233370/powershell-script-to-execute-docker-maintenance-optionally-non-interactively

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment