Created
October 4, 2025 15:57
-
-
Save PanosGreg/739d6501b10f2ada10eee030d27e33c7 to your computer and use it in GitHub Desktop.
Find the docker image from Docker Hub, for the current Windows Server OS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-ImageFromHub { | |
<# | |
.SYNOPSIS | |
Find the docker image for the current Windows Server OS from Docker Hub. | |
Additionally it can also inspect the image and get its size (from all of its layers) | |
NOTE: This function does not download the docker image, just its metadata. | |
The -ShowSize switch requires the docker tool. | |
.EXAMPLE | |
Get-ImageFromHub -ShowSize | |
Find the image from Docker Hub along with its layers. | |
.EXAMPLE | |
$img = Get-ImageFromHub | |
docker pull $img | |
Find the image for the current OS and then pull it from docker hub | |
#> | |
[OutputType([string],[psobject])] # <-- default is [string], and [psobject] with ShowSize switch | |
[cmdletbinding()] | |
param ( | |
[ValidateSet('Release','Insider')] | |
[string]$Channel = 'Release', | |
[ValidateSet('Base','Core','Nano')] | |
[string]$Type = 'Core', | |
[switch]$ShowSize | |
) | |
$list = @( | |
[pscustomobject] @{ | |
Type = 'Base' | |
Chan = 'Release' | |
Img = 'mcr.microsoft.com/windows' | |
Tag = 'https://mcr.microsoft.com/v2/windows/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-windows' | |
} | |
[pscustomobject] @{ | |
Type = 'Base' | |
Chan = 'Insider' | |
Img = 'mcr.microsoft.com/windows/insider' | |
Tag = 'https://mcr.microsoft.com/v2/windows/insider/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-windows-insider' | |
} | |
[pscustomobject] @{ | |
Type = 'Core' | |
Chan = 'Release' | |
Img = 'mcr.microsoft.com/windows/servercore' | |
Tag = 'https://mcr.microsoft.com/v2/windows/servercore/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-windows-servercore' | |
} | |
[pscustomobject] @{ | |
Type = 'Core' | |
Chan = 'Insider' | |
Img = 'mcr.microsoft.com/windows/servercore/insider' | |
Tag = 'https://mcr.microsoft.com/v2/windows/servercore/insider/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-windows-servercore-insider' | |
} | |
[pscustomobject] @{ | |
Type = 'Nano' | |
Chan = 'Release' | |
Img = 'mcr.microsoft.com/windows/nanoserver' | |
Tag = 'https://mcr.microsoft.com/v2/windows/nanoserver/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-windows-nanoserver' | |
} | |
[pscustomobject] @{ | |
Type = 'Nano' | |
Chan = 'Insider' | |
Img = 'mcr.microsoft.com/windows/nanoserver/insider' | |
Tag = 'https://mcr.microsoft.com/v2/windows/nanoserver/insider/tags/list' | |
Url = 'https://hub.docker.com/r/microsoft-nanoserver-insider' | |
} | |
) | |
$obj = $list | where {$_.Type -eq $Type -and $_.Chan -eq $Channel} | |
$ProgressPreference = 'SilentlyContinue' # <-- makes Invoke-RestMethod faster | |
# find appropriate version for your OS | |
try { | |
Write-Verbose "Find docker image from: $($obj.Url)" | |
$all = (Invoke-RestMethod $obj.Tag -Verbose:$false).tags | |
$ver = [System.Environment]::OSVersion.Version.ToString(3) # <-- ex. 10.0.20348 | |
$reg = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' | |
$rev = (Get-ItemProperty $reg -Name 'UBR').UBR # <-- ex. 4106 | |
$tag = '{0}.{1}' -f $ver,$rev | |
$t2 = $all | where {$_ -like "$tag*"} | select -First 1 | |
$t3a = $all | where {$_ -match "^$ver\.\d+$"} | foreach {[version]$_} | Sort-Object | |
$less= $t3a | where {$_.Revision -lt $rev} | select -Last 1 | |
$more= $t3a | where {$_.Revision -gt $rev} | select -First 1 | |
$Blu = '{0}[38;2;{1};{2};{3}m' -f [char]27, 61, 148, 243 # Blue | |
$Ita = '{0}[3m' -f [char]27 # Italic | |
$Def = '{0}[0m' -f [char]27 # Default | |
if ([bool]$t2) { | |
$img = '{0}:{1}' -f $obj.img,$t2 | |
} | |
elseif ([bool]$less -or [bool]$more){ | |
$msg = $Blu + $Ita + "Could not find the exact tag $tag. Will fetch closest tags as fallback" + $Def | |
Write-Information $msg -InformationAction Continue | |
$img = @( | |
'{0}:{1}' -f $obj.img,$less.ToString() | |
'{0}:{1}' -f $obj.img,$more.ToString() | |
) | |
} | |
else { | |
$msg1 = "Could not find tag $tag in URL $($obj.Tag)" | |
$msg2 = "Make sure the Channel ($Channel) param aligns with your OS" | |
$msg3 = "Or that your OS version ($tag) actually has a docker image of $Type type" | |
$msg1,$msg2,$msg3 | foreach {Write-Warning $_} | |
return | |
} | |
} | |
catch {throw $_} | |
if ($ShowSize.IsPresent) { | |
try { | |
docker.exe -v *>$null | |
$HasDocker = $true | |
} | |
catch { | |
$HasDocker = $false | |
} | |
} | |
# helper function that shows human-readable sizes (which returns a string not a number) | |
function Get-PrettyCapacity ([uint64]$Size) { | |
$SzId = ('b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') | |
$Ord = [Math]::Floor( [Math]::Log($Size, 1000) ) | |
$Num = $Size/([Math]::Pow(1000,$Ord)) | |
$Flo = if ($Num -ge 100) {0} elseif ($Num -ge 10) {1} else {2} | |
$Rnd = [Math]::Round($Num,$Flo) | |
[String]($Rnd) + $SzId[$Ord] | |
} | |
if (-not $ShowSize.IsPresent) { | |
$out = $img | |
} | |
elseif ($ShowSize.IsPresent -and -not $HasDocker) { | |
$msg = $Blu + $Ita + 'Docker tool was not found, could not fetch the image size.' + $Def | |
Write-Information $msg -InformationAction Continue | |
$out = $img | |
} | |
elseif ($ShowSize -and $HasDocker) { | |
try { | |
$out = foreach ($image in $img) { | |
$man = docker manifest inspect --verbose $image 2>&1 # <-- the manifest from docker hub | |
if ($man -is [System.Management.Automation.ErrorRecord]) {throw $man} | |
$json = $man | ConvertFrom-Json -ErrorAction Stop | |
$Size = ($json.SchemaV2Manifest.layers | Measure-Object size -Sum).Sum | |
$i = 1 ; $Layers = [ordered]@{} | |
$json.SchemaV2Manifest.layers | foreach {$Layers.Add($i++,$_.size)} | |
[PSCustomObject] @{ | |
Image = $image | |
Size = Get-PrettyCapacity $Size | |
SizeByte = $Size -as [uint64] | |
Layers = $Layers | |
} | |
} #foreach image | |
} | |
catch {throw $_} | |
} #elseif showsize | |
# return the results | |
Write-Output $out | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment