sdwheeler.ReleaseInfo.psm1
|
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. #------------------------------------------------------- #region Private functions #------------------------------------------------------- function GetGraphQLQuery { param( [string]$org, [string]$repo, [string]$after ) $GraphQLQuery = @" query { repository(name: "$repo", owner: "$org") { releases(first: 100, after: $after, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { publishedAt name tagName url } pageInfo { hasNextPage endCursor } } } } "@ return $GraphQLQuery } #------------------------------------------------------- $eolCategories = (Invoke-RestMethod https://endoflife.date/api/v1/categories).result #------------------------------------------------------- #endregion module variables #------------------------------------------------------- #region Public functions #------------------------------------------------------- function Find-PmcPackage { <# .SYNOPSIS Gets information about PowerShell packages from the Microsoft Package Cache (PMC). .DESCRIPTION Gets information about PowerShell packages that are published to https://packages.microsoft.com. By default, packages for all supported distributions are returned, but you can filter by specific distribution(s) using the -Distribution parameter. .PARAMETER Distribution The distribution(s) to filter by. Valid values are 'debian', 'ubuntu', 'rhel', 'azurelinux'. You can specify multiple values for this parameter. If not specified, packages for all supported distributions are returned. #> param( [ValidateSet('debian', 'ubuntu', 'rhel', 'azurelinux')] [string[]]$Distribution ) if ($IsWindows) { $gitcmd = Get-Command git -ErrorAction SilentlyContinue $gitroot = $gitcmd.Path -replace 'cmd\\git.exe', '' $toolpath = Join-Path $gitroot 'usr\bin\gzip.exe' $gzipcmd = Get-Command $toolpath -ErrorAction SilentlyContinue } else { $gzipcmd = Get-Command gzip -ErrorAction SilentlyContinue } if ($null -eq $gzipcmd) { Write-Error 'gzip command not found' return } if (Test-Path "$env:temp\repodata") { $null = Remove-Item -Path "$env:temp\repodata" -Recurse -Force $null = New-Item -ItemType Directory -Path "$env:temp\repodata" } else { $null = New-Item -ItemType Directory -Path "$env:temp\repodata" } $pmcVersionInfo = Get-Content -Path "$PSScriptRoot\PmcVersionInfo.jsonc" | ConvertFrom-Json $versions = $pmcVersionInfo.versions $debrepos = $pmcVersionInfo.debrepos $rpmrepos = $pmcVersionInfo.rpmrepos if ($null -ne $Distribution) { $repolist = foreach ($distro in $Distribution) { $debrepos | Where-Object { $_.distro -like "$distro*" } } } else { $repolist = $debrepos } # Download and parse DEB package information foreach ($repo in $repolist) { # Get package metadata $lines = (Invoke-RestMethod -Uri $repo.packages) -split '\n' | Select-String -Pattern '^Package:|^Version:|^Filename:' | Select-Object -ExpandProperty Line # Filter and select package information $packages = @() for ($i = 0; $i -lt $lines.Count; $i += 3) { $pkg = [pscustomobject]($lines[$i..($i + 2)] | ConvertFrom-Yaml) if ($pkg.Package -match '^powershell' -and $pkg.Version -match '^7\.\d+') { $packages += $pkg } } # Normalize version strings $packages | ForEach-Object { $_.Version = $_.Version -replace '-1.ubuntu.\d\d.\d\d|-1.deb', '' } # Enumerate stable packages foreach ($ver in $versions.stable) { $package = $packages | Where-Object { $_.Version -like $ver -and $_.Package -eq 'powershell'} | Sort-Object {[semver]($_.Version)} -Descending | Select-Object -First 1 if ($package) { [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]$package.Version channel = 'stable' processor = $repo.processor package = ($package.Filename -split '/')[-1] } } } # Enumerate lts packages foreach ($ver in $versions.lts) { $package = $packages | Where-Object { $_.Version -like $ver -and $_.Package -eq 'powershell-lts'} | Sort-Object {[semver]($_.Version)} -Descending | Select-Object -First 1 if ($package) { [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]$package.Version channel = 'lts' processor = $repo.processor package = ($package.Filename -split '/')[-1] } } } # Enumerate preview packages foreach ($ver in $versions.preview) { $package = $packages | Where-Object { $_.Version -like $ver -and $_.Package -eq 'powershell-preview'} | Sort-Object {[semver]($_.Version)} -Descending | Select-Object -First 1 if ($package) { [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]$package.Version channel = 'preview' processor = $repo.processor package = ($package.Filename -split '/')[-1] } } } } # RPM-based packages have XML metadata if ($null -ne $Distribution) { $repolist = foreach ($distro in $Distribution) { $rpmrepos | Where-Object { $_.distro -like "$distro*" } } } else { $repolist = $rpmrepos } # Download and parse RPM package information foreach ($repo in $repolist) { # Get repo metadata $xml = [xml](Invoke-WebRequest -Uri $repo.mdxml).Content $primarypath = ($xml.repomd.data | Where-Object type -eq primary).location.href # Get package metadata $primaryurl = $repo.mdxml -replace 'repodata/repomd.xml', $primarypath Invoke-WebRequest -Uri $primaryurl -OutFile "$env:temp\$primarypath" $primary = [xml](& $gzipcmd -d -c "$env:temp\$primarypath") # Filter and select package information $packages = $primary.metadata.package | Where-Object { $_.name -match '^powershell' -and $_.version.ver -match '^7\.\d+' } $results = @() # Enumerate stable packages foreach ($ver in $versions.stable) { $package = $packages | Where-Object { $_.version.ver -like $ver -and $_.name -eq 'powershell'} | Sort-Object {[semver]($_.version.ver -replace '_','-')} -Descending | Select-Object -First 1 if ($package) { $results += [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]$package.version.ver channel = 'stable' processor = $repo.processor package = ($package.location.href -split '/')[-1] } } } # Enumerate lts packages foreach ($ver in $versions.lts) { $package = $packages | Where-Object { $_.version.ver -like $ver -and $_.name -eq 'powershell-lts'} | Sort-Object {[semver]($_.version.ver -replace '_','-')} -Descending | Select-Object -First 1 if ($package) { $results += [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]$package.version.ver channel = 'lts' processor = $repo.processor package = ($package.location.href -split '/')[-1] } } } # Enumerate preview packages foreach ($ver in $versions.preview) { $package = $packages | Where-Object { $_.version.ver -like $ver -and $_.name -eq 'powershell-preview'} | Sort-Object {[semver]($_.version.ver -replace '_','-')} -Descending | Select-Object -First 1 if ($package) { $results += [pscustomobject]@{ PSTypeName = 'PmcData' distro = $repo.distro version = [semver]($package.version.ver -replace '_','-') channel = 'preview' processor = $repo.processor package = ($package.location.href -split '/')[-1] } } } $results | Sort-Object distro, version, channel, processor } } Set-Alias Find-PmcPackages Find-PmcPackage #------------------------------------------------------- function Find-DotnetDockerInfo { <# .SYNOPSIS Gets information about .NET SDK Docker images that have PowerShell installed from the dotnet/dotnet-docker repository. .DESCRIPTION Gets information about .NET SDK Docker images that have PowerShell installed from the dotnet/dotnet-docker repository. You must have a local clone of the repository to use this command, and you must specify the path to the repository with the -Path parameter. The command extracts the information from the Dockerfile images in the src/sdk directory. .PARAMETER Path The path to the local clone of the dotnet/dotnet-docker repository. #> param( [string]$Path = 'D:\Git\PS-Src\dotnet-docker\src\sdk' ) $images = Get-ChildItem -Path $Path -Include dockerfile -Recurse | Select-String 'powershell_version[\n\s]*=|POWERSHELL_DISTRIBUTION_CHANNEL' | Select-Object Path, Line | Group-Object Path | Where-Object Count -ge 2 $results = foreach ($image in $images) { $psver = $os = '' $imagePath = $image.Group.Path[0] -replace [regex]::Escape($Path), '' foreach ($line in $image.Group.Line) { $value = if ($line -match '.+=([^\s]+)') { $Matches[1] } if ($line -like '*powershell_version*') { $psver = $value } else { $os = $value -replace 'PSDocker-DotnetSDK-','' } } if ($psver -ge '7.4') { $parts = $imagePath -split [regex]::Escape([System.IO.Path]::DirectorySeparatorChar) [pscustomobject]@{ PSTypeName = 'DockerInfo' family = switch -wildcard ($parts[2]) { '*mariner*' { 'Mariner' } '*azure*' { 'AzureLinux' } '*nano*' { 'Windows' } '*windows*' { 'Windows' } '*jammy*' { 'Ubuntu' } '*noble*' { 'Ubuntu' } '*resolute*' { 'Ubuntu' } '*alpine*' { 'Alpine' } '*bookworm*' { 'Debian' } '*trixie*' { 'Debian' } } os = if ($os -ne '') { $os } else { $parts[2] } dotnetver = [version]$parts[1] arch = $parts[3] psver = $psver } } } $results | Sort-Object family, os, dotnetver, arch } #------------------------------------------------------- function Find-DockerImage { <# .SYNOPSIS Gets information about PowerShell-based Docker images from the Microsoft Container Registry (MAR). .DESCRIPTION Gets information about PowerShell-based Docker images from MAR. By default, images for all supported distributions are returned, but you can filter by specific distribution(s) using the -Distribution parameter. .PARAMETER Distribution The distribution(s) to filter by. Valid values are 'debian', 'ubuntu', 'rhel', 'azurelinux', 'alpine', 'windows'. You can specify multiple values for this parameter. If not specified, images for all supported distributions are returned. .NOTES These Docker images are no longer maintained. Use the .NET SDK Docker images instead. #> param( [ValidateSet('debian', 'ubuntu', 'rhel', 'azurelinux', 'alpine', 'windows')] [string[]]$Distribution = ( 'debian', 'ubuntu', 'rhel', 'azurelinux', 'alpine', 'windows' ) ) $baseUrl = 'https://mcr.microsoft.com/api/v1/catalog/powershell' $supportedTags = Invoke-RestMethod "$baseUrl/details?reg=mar" | Select-Object -ExpandProperty supportedTags $allTags = Invoke-RestMethod "$baseUrl/tags?reg=mar" $images = $allTags | Where-Object name -in $supportedTags foreach ($i in $images) { if ($i.operatingSystem -eq 'linux') { switch -Regex ($i.name) { 'alpine' { $i.operatingSystem = 'alpine' } 'debian' { $i.operatingSystem = 'debian' } 'ubuntu' { $i.operatingSystem = 'ubuntu' } 'azurelinux' { $i.operatingSystem = 'azurelinux' } 'ubi' { $i.operatingSystem = 'rhel' } } } } $images | Where-Object operatingSystem -in $Distribution | Sort-Object -Property operatingSystem, name | Select-Object -Property name, operatingSystem, architecture, @{n='modifiedDate';e={'{0:yyyy-MM-dd}' -f $_.lastModifiedDate}} } Set-Alias Find-DockerImages Find-DockerImage #------------------------------------------------------- function Get-OSEndOfLife { <# .SYNOPSIS Gets end of life information for operating systems supported by PowerShell from https://endoflife.date. .DESCRIPTION Gets end of life information for operating systems supported by PowerShell.By default, all supported operating systems are included, but you can filter by specific operating system. The command only shows the supported versions. If you want the whole release history, use the Get-EndOfLife command. .PARAMETER OS The operating system to query. You can use tab completion with the parameter to see available operating systems. .EXAMPLE Get-OSEndOfLife ubuntu os cycle latest codename endOfSupport endOfLife endOfExtSupport lts -- ----- ------ -------- ------------ --------- --------------- --- ubuntu 25.10 25.10 Questing Quokka 2026-07-01 2026-07-01 False ubuntu 24.04 24.04.4 Noble Numbat 2029-05-31 2029-05-31 2036-05-31 True ubuntu 22.04 22.04.5 Jammy Jellyfish 2024-09-30 2027-04-01 2032-04-09 True #> param ( [Parameter(Position = 0)] [ValidateSet('alpine-linux', 'debian', 'macos', 'rhel', 'ubuntu', 'windows', 'windows-server')] [string[]]$OS = ('alpine-linux', 'debian', 'macos', 'rhel', 'ubuntu', 'windows', 'windows-server') ) $links = [ordered]@{ 'alpine-linux' = 'https://endoflife.date/api/v1/products/alpine' debian = 'https://endoflife.date/api/v1/products/debian' macos = 'https://endoflife.date/api/v1/products/macos' rhel = 'https://endoflife.date/api/v1/products/rhel' ubuntu = 'https://endoflife.date/api/v1/products/ubuntu' windows = 'https://endoflife.date/api/v1/products/windows' 'windows-server' = 'https://endoflife.date/api/v1/products/windows-server' } $results = $links.GetEnumerator().Where({$_.Name -in $OS}) | ForEach-Object { $item = (Invoke-RestMethod $_.Value).result foreach ($release in $item.releases) { if ($release.isEol -eq $false) { [pscustomobject]@{ PSTypeName = 'EolData' product = $item.name cycle = $release.name latest = $release.latest.name codename = $release.codename releaseDate = $release.releaseDate latestReleaseDate = $release.latest.date endOfSupport = $release.eoasFrom endOfLife = $release.eolFrom endOfExtSupport = $release.eoesFrom isEol = $release.isEol isLts = $release.isLts link = $release.latest.link } } } } $results | Sort-Object product,@{Expr={[version]($_.latest)}; Desc=$true} } #------------------------------------------------------- function Get-EndOfLife { <# .SYNOPSIS Gets end of life information for products from https://endoflife.date. .DESCRIPTION Gets end of life information for products from https://endoflife.date. When you specify a Category, the command return a list of products in that category. Use that information to find the product name. When you specify a product name, the command returns all of its releases for that product. .PARAMETER Name The name of the product to query. The command uses regular expression matching for that value. .PARAMETER Category The category to query. The parameter supports wildcards. You can use tab completion with the parameter to see available categories. .EXAMPLE Get-EndOfLife -Category standard name category product uri ---- -------- ------- --- pci-dss standard PCI-DSS https://endoflife.date/api/v1/products/pci-dss tls standard TLS https://endoflife.date/api/v1/products/tls .EXAMPLE Get-EndOfLife debian product cycle latest codename endOfSupport endOfLife endOfExtSupport isEol isLts ------- ----- ------ -------- ------------ --------- --------------- ----- ----- debian 13 13.4 Trixie 2028-08-09 2030-06-30 False False debian 12 12.13 Bookworm 2026-06-10 2028-06-30 False False debian 11 11.11 Bullseye 2024-08-14 2026-08-31 True False debian 10 10.13 Buster 2022-09-10 2024-06-30 True False debian 9 9.13 Stretch 2020-07-18 2022-07-01 True False debian 8 8.11 Jessie 2018-06-17 2020-06-30 True False debian 7 7.11 Wheezy 2016-04-25 2018-05-31 True False debian 6 6.0.10 Squeeze 2014-05-31 2016-02-29 True False debian 5 5.0.10 Lenny 2012-02-06 2012-02-06 True False debian 4 4.0r9 Etch 2010-02-15 2010-02-15 True False debian 3.1 3.1r8 Sarge 2008-03-31 2008-03-31 True False debian 3.0 3.0r6 Woody 2006-06-30 2006-06-30 True False debian 2.2 2.2r7 Potato 2003-06-30 2003-06-30 True False debian 2.1 2.1r5 Slink 2000-09-30 2000-10-30 True False debian 2.0 2.0r5 Hamm 1999-02-15 1999-02-15 True False debian 1.3 1.3.1 r.6 Bo 1998-12-08 1998-12-08 True False debian 1.2 1.2 Rex 1997-10-23 1997-10-23 True False debian 1.1 1.1 Buzz 1996-12-12 1996-12-12 True False #> [CmdletBinding(DefaultParameterSetName='ByName')] param ( [Parameter(Position = 0, ParameterSetName='ByName')] [string[]]$Name, [Parameter(ParameterSetName='ListCategories')] [SupportsWildcards()] [string[]]$Category ) if ($Category.Count -ne 0) { $categories = foreach ($cat in $Category) { ($eolCategories | Where-Object name -like $cat).uri } if ($Category -ne '') { foreach ($cat in $categories) { (Invoke-RestMethod $cat).result | Sort-Object -Property label, category | Select-Object -Property name, category, @{n='product'; e={$_.label}}, uri } return } } if ($Name.Count -ne 0) { $products = (Invoke-RestMethod https://endoflife.date/api/v1/products).result foreach ($n in $Name) { $plist = $products | Where-Object name -match $n if ($plist.Count -lt 1) { Write-Warning "Product '$n' not found." continue } foreach ($p in $plist) { $item = (Invoke-RestMethod $p.uri).result foreach ($release in $item.releases) { [pscustomobject]@{ PSTypeName = 'EolData' product = $item.name cycle = $release.name latest = $release.latest.name codename = $release.codename releaseDate = $release.releaseDate latestReleaseDate = $release.latest.date endOfSupport = $release.eoasFrom endOfLife = $release.eolFrom endOfExtSupport = $release.eoesFrom isEol = $release.isEol isLts = $release.isLts link = $release.latest.link } } } } } } #------------------------------------------------------- function Get-DSCReleaseHistory { <# .SYNOPSIS Gets release history for DSC releases. .DESCRIPTION Gets release history for DSC v3 releases. By default, only the latest release for each major.minor version is returned, but this can be modified with the available parameters. This command uses the GitHub GraphQL API to query release information. To use this command, a GitHub personal access token is required. The token should be stored in an environment variable named GITHUB_TOKEN. .PARAMETER AllVersions If specified, all releases are returned. Otherwise, only the latest release for each major.minor version is returned. #> param( [switch]$AllVersions ) $query = GetGraphQLQuery -org 'PowerShell' -repo 'DSC' -after 'null' $irmSplat = @{ Headers = @{ Authorization = "bearer $env:GITHUB_TOKEN" Accept = 'application/vnd.github.v4.json' } Uri = 'https://api.github.com/graphql' Body = @{ query = $query } | ConvertTo-Json -Compress Method = 'POST' } $hasNextPage = $true $history = while ($hasNextPage) { $result = Invoke-RestMethod @irmSplat $result.data.repository.releases.nodes | Select-Object @{n = 'Version'; e = { $_.tagName.Substring(0, 4) } }, @{n = 'Tag'; e = { $_.tagName } }, @{n = 'Date'; e = { '{0:yyyy-MM-dd}' -f $_.publishedAt } } $hasNextPage = $result.data.repository.releases.pageInfo.hasNextPage $after = '"',$result.data.repository.releases.pageInfo.endCursor,'"' -join '' $query = GetGraphQLQuery -org 'PowerShell' -repo 'PowerShell' -after $after $irmSplat.Body = @{ query = $query} | ConvertTo-Json -Compress } if ($AllVersions) { $history } else { $history | Group-Object Version | Sort-Object Name -Descending | ForEach-Object { $_.Group | Select-Object -First 1 } } } #------------------------------------------------------- function Get-PSReleaseHistory { <# .SYNOPSIS Gets release history for PowerShell releases. .DESCRIPTION Gets release history for PowerShell releases. By default, only the latest release for each major.minor version is returned, but this can be modified with the available parameters. This command uses the GitHub GraphQL API to query release information. To use this command, a GitHub personal access token is required. The token should be stored in an environment variable named GITHUB_TOKEN. .PARAMETER Version The major.minor version to filter by (e.g. '7.5'). If not specified, the latest release for each major.minor version are returned. .PARAMETER Current If specified, only releases for the currently running version ofPowerShell are returned. .PARAMETER GeneralAvailability If specified, only GA releases (i.e. tags that end with '.0') are returned. .PARAMETER All If specified, all releases are returned. .EXAMPLE Get-PSReleaseHistory Version Tag ReleaseDate DotnetVersion SupportType EndOfSupport ------- --- ----------- ------------- ----------- ------------ v7.6 v7.6.0-rc.1 2026-02-20 .NET 10.0 Preview v7.5 v7.5.4 2025-10-20 .NET 9.0 STS 2026-05-12 v7.4 v7.4.13 2025-10-20 .NET 8.0 LTS 2026-11-10 v7.3 v7.3.12 2024-04-11 .NET 7.0 STS 2024-05-08 v7.2 v7.2.24 2024-10-22 .NET 6.0 LTS 2024-11-08 v7.1 v7.1.7 2022-04-26 .NET 5.0 STS 2022-05-08 v7.0 v7.0.13 2022-10-20 .NET Core 3.1 LTS 2022-12-03 v6.2 v6.2.7 2020-07-16 .NET Core 2.1 STS 2020-09-04 v6.1 v6.1.6 2019-09-12 .NET Core 2.1 STS 2019-09-28 v6.0 v6.0.5 2018-11-13 .NET Core 2.0 STS 2019-02-13 #> [CmdletBinding(DefaultParameterSetName = 'ByVersion')] param( [Parameter(ParameterSetName = 'ByVersion', Position = 0)] [string]$Version, [Parameter(ParameterSetName = 'Current')] [switch]$Current, [Parameter(ParameterSetName = 'ByVersion')] [Parameter(ParameterSetName = 'Current')] [Alias('GA')] [switch]$GeneralAvailability, [Parameter(ParameterSetName = 'ShowAll')] [switch]$All ) $history = @() $lifecycle = Get-Content -Path $PSScriptRoot\PowerShellLifecycle.jsonc -Raw | ConvertFrom-Json -AsHashtable $query = GetGraphQLQuery -org 'PowerShell' -repo 'PowerShell' -after 'null' $irmSplat = @{ Headers = @{ Authorization = "bearer $env:GITHUB_TOKEN" Accept = 'application/vnd.github.v4.json' } Uri = 'https://api.github.com/graphql' Body = @{ query = $query} | ConvertTo-Json -Compress Method = 'POST' } $hasNextPage = $true while ($hasNextPage) { $irmSplat.Body = @{ query = $query} | ConvertTo-Json -Compress $result = Invoke-RestMethod @irmSplat $result.data.repository.releases.nodes | Where-Object tagName -gt 'v5.1' | ForEach-Object { $history += [pscustomobject]@{ PSTypeName = 'ReleaseInfoData' Version = $_.tagName.Substring(0, 4) Tag = $_.tagName ReleaseDate = '{0:yyyy-MM-dd}' -f $_.publishedAt DotnetVersion = $lifecycle[$_.tagName.Substring(0, 4)].Dotnet SupportType = if ($_.tagName -like '*-*') { 'Preview' } else { $lifecycle[$_.tagName.Substring(0, 4)].Support } EndOfSupport = $lifecycle[$_.tagName.Substring(0, 4)].EndOfSupport ReleaseUrl = $_.url } } $hasNextPage = $result.data.repository.releases.pageInfo.hasNextPage $after = '"',$result.data.repository.releases.pageInfo.endCursor,'"' -join '' $query = GetGraphQLQuery -org 'PowerShell' -repo 'PowerShell' -after $after } switch ($PSCmdlet.ParameterSetName) { 'ByVersion' { if ($Version -eq '') { $groupedByVersion = $history | Group-Object Version | Sort-Object Name -Descending if ($GeneralAvailability) { $groupedByVersion | ForEach-Object { $_.Group | Where-Object Tag -Like '*.0' } } else { $groupedByVersion | ForEach-Object { $_.Group | Select-Object -First 1 } } } else { if ($GeneralAvailability) { $history | Where-Object Version -EQ $Version | Where-Object Tag -Like '*.0' } else { $history | Where-Object Version -EQ $Version } } break } 'Current' { $Version = ('v{0}' -f $PSVersionTable.PSVersion.ToString().SubString(0, 3)) if ($GeneralAvailability) { $history | Where-Object Version -EQ $Version | Where-Object Tag -Like '*.0' } else { $history | Where-Object Version -EQ $Version } break } 'ShowAll' { $history } } } #------------------------------------------------------- function Get-PSReleasePackage { <# .SYNOPSIS Gets release assets for a given PowerShell release tag. .DESCRIPTION Gets release assets for a given PowerShell release tag. If a file name is specified, only the asset with that name is downloaded. Otherwise, all assets are listed. This command uses the GitHub REST API to query release information. To use this command, a GitHub personal access token is required. The token should be stored in an environment variable named GITHUB_TOKEN. .PARAMETER Tag The release tag to query. .PARAMETER FileName The name of the asset to download. If not specified, the command lists the available assets. .PARAMETER OutputPath The directory to which assets will be downloaded. Defaults to the current directory. .EXAMPLE Get-PSReleasePackage v7.5.4 PowerShell-7.5.4-win-x64.msi This example downloads PowerShell-7.5.4-win-x64.msi to the current directory. #> param( [Parameter(Mandatory, Position = 0)] [ValidatePattern('^v\d\.\d+\.\d+(-\p{L}+\.?\d*)?$')] [string]$Tag, [Parameter(Position = 1)] [string[]]$FileName, [Parameter(Position = 2)] [string]$OutputPath = '.' ) try { $irmSplat = @{ Headers = @{ Accept = 'application/vnd.github.v4.json' Authorization = "bearer $env:GITHUB_TOKEN" } Uri = "https://api.github.com/repos/PowerShell/PowerShell/releases/tags/$tag" ErrorAction = 'Stop' } $release = Invoke-RestMethod @irmSplat if ($release.assets.Count -eq 0) { Write-Warning "No assets found for release '$Tag'." return } } catch { Write-Error ("Error fetching release tag '$Tag'." + [Environment]::NewLine + $_.Exception.Message) } if ($FileName.Count -eq 0) { $release.assets | Select-Object name, size, browser_download_url } else { $release.assets | Where-Object name -in $FileName | ForEach-Object { $outputFile = Join-Path $OutputPath $_.name Invoke-WebRequest -Uri $_.browser_download_url -OutFile $outputFile Get-Item $outputFile } } } #------------------------------------------------------- function Get-PSModuleVersion { <# .SYNOPSIS Gets version information for PowerShell modules in a specified path. .DESCRIPTION The Get-PSModuleVersion function scans a directory for PowerShell modules and retrieves version information from their module manifests (.psd1 files). The manifest file is parsed using Import-PowerShellDataFile. The module isn't imported into the session, so any executable code in the manifest won't be executed. If a manifest file can't be parsed, the error type is returned in the ParseStatus property. .PARAMETER ModulePath The path to the directory containing PowerShell modules. Defaults to the PowerShell modules directory ($PSHOME/modules). The command recursively searches for module manifests in the specified directory tree. .EXAMPLE Get-PSModuleVersion Name Version Prerelease ParseStatus ---- ------- ---------- ----------- CimCmdlets 7.0.0.0 OK Microsoft.PowerShell.Archive 1.2.5 OK Microsoft.PowerShell.Diagnostics 7.0.0.0 OK Microsoft.PowerShell.Host 7.0.0.0 OK Microsoft.PowerShell.Management 7.0.0.0 OK Microsoft.PowerShell.PSResourceGet 1.2.0 OK Microsoft.PowerShell.Security 7.0.0.0 OK Microsoft.PowerShell.ThreadJob 2.2.0 OK Microsoft.PowerShell.Utility 7.0.0.0 OK Microsoft.WSMan.Management 7.0.0.0 OK PackageManagement 1.4.8.1 OK PowerShellGet 2.2.5 OK PSDiagnostics 7.0.0.0 OK PSReadLine 2.4.5 OK Gets version information for all modules in the default PowerShell installation directory. .EXAMPLE Get-PSModuleVersion -ModulePath "C:\Users\Username\Documents\PowerShell\Modules" Gets version information for all modules in the user's PowerShell modules directory. .OUTPUTS PSModuleVersionInfo #> [CmdletBinding()] param( [Parameter(Position = 0)] [string]$ModulePath = "$PSHOME/modules" ) $modPaths = Get-ChildItem -Path $ModulePath -Directory foreach ($modPath in $modPaths) { $result = [pscustomobject]@{ PSTypeName = 'PSModuleVersionInfo' Name = $modPath.Name Version = '' Prerelease = '' ParseStatus = '' } $path = Get-ChildItem -Path $modPath.FullName -Include "$($modPath.Name).psd1" -Recurse foreach ($p in $path) { try { $paramSplat = @{ Path = $p.FullName SkipLimitCheck = $true ErrorAction = 'Stop' } $moduleInfo = Import-PowerShellDataFile @paramSplat $result.Version = $moduleInfo.ModuleVersion $result.Prerelease = $moduleInfo.PrivateData.PSData.Prerelease $result.ParseStatus = 'OK' $result } catch { $fullyQualifiedErrorId = $_.FullyQualifiedErrorId.Split(',')[0] # Skip non-module manifest files if ($fullyQualifiedErrorId -ne 'CouldNotParseAsPowerShellDataFileNoHashtableRoot') { # Manifest files with executable code throw System.InvalidOperationException # Executable code is allowed by Import-Module but not Import-PowerShellDataFile $result.ParseStatus = $fullyQualifiedErrorId $result } } } } } #------------------------------------------------------- function Get-DotnetRelease { <# .SYNOPSIS Gets release information for .NET releases from the dotnet/core repository. .DESCRIPTION Gets release information for .NET releases from the dotnet/core repository. The command extracts the information from the releases-index.json file in the repository, which contains information about all .NET releases, including the latest release for each channel and the latest SDK version for each release. .EXAMPLE Get-DotnetRelease product channel type support eolDate version sdkVersion ------- ------- ---- ------- ------- ------- ---------- .NET 11.0 sts preview 11.0.0-preview.2 11.0.100-preview.2.26159.112 .NET 10.0 lts active 2028-11-14 10.0.5 10.0.201 .NET 9.0 sts active 2026-11-10 9.0.14 9.0.312 .NET 8.0 lts active 2026-11-10 8.0.25 8.0.419 .NET 7.0 sts eol 2024-05-14 7.0.20 7.0.410 .NET 6.0 lts eol 2024-11-12 6.0.36 6.0.428 .NET 5.0 sts eol 2022-05-10 5.0.17 5.0.408 .NET Core 3.1 lts eol 2022-12-13 3.1.32 3.1.426 .NET Core 3.0 sts eol 2020-03-03 3.0.3 3.0.103 .NET Core 2.1 lts eol 2021-08-21 2.1.30 2.1.818 .NET Core 2.2 sts eol 2019-12-23 2.2.8 2.2.207 .NET Core 2.0 sts eol 2018-10-01 2.0.9 2.1.202 .NET Core 1.1 lts eol 2019-06-27 1.1.13 1.1.14 .NET Core 1.0 lts eol 2019-06-27 1.0.16 1.1.14 #> $releases = Invoke-RestMethod https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json foreach ($release in $releases.'releases-index') { [PSCustomObject]@{ PSTypeName = 'DotnetReleaseInfo' product = $release.'product' channel = $release.'channel-version' type = $release.'release-type' support = $release.'support-phase' eolDate = $release.'eol-date' version = $release.'latest-release' sdkVersion = $release.'latest-sdk' } } } #------------------------------------------------------- #endregion Public functions #------------------------------------------------------- #region Argument completers #------------------------------------------------------- $sbEOLCategories = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $eolCategories | Where-Object { $_.name -like "$wordToComplete*" } | Select-Object -ExpandProperty name } Register-ArgumentCompleter -CommandName Get-EndOfLife -ParameterName Category -ScriptBlock $sbEOLCategories #------------------------------------------------------- #endregion Argument completers #------------------------------------------------------- |