Last active
November 22, 2019 15:57
-
-
Save mklement0/9c494216681c4c25d17abda2b60cdff9 to your computer and use it in GitHub Desktop.
Get-CmdletMinPsVersion: PowerShell function for determining the minimum PowerShell version required to run given standard cmdlets.
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-MinPsVersionForCmdlet { | |
<# | |
.SYNOPSIS | |
Determines the minimum PowerShell version required for a given standard cmdlet. | |
.DESCRIPTION | |
NOTE: | |
* v3 or higher is required to run this function. | |
* Only cmdlets with help topics defined in the GitHub | |
PowerShell-documentation repository at | |
https://github.com/PowerShell/PowerShell-Docs | |
can be examined. | |
* In general, this INCLUDES the cmdlets that ship with PowerShell Core. | |
* It EXCLUDES: | |
* inherently Windows-only cmdlets such as Set-WinSystemLocale | |
(some of which are tied to an *OS* version rather than a PowerShell | |
version) | |
* cmdlets that have not yet or may never be ported to | |
PowerShell Core, such as Set-Culture. | |
* If a given cmdlet is not available on this machine, it must be specified | |
CASE-EXACTLY. | |
CAVEATS: | |
The minimum PowerShell version that supports a given cmdlet (i.e., the version | |
in which a give cmdlet was introduced) is derived from the version-specific | |
help-topic links at https://github.com/PowerShell/PowerShell-Docs | |
The lowest version represented there is v3, so in order to determine whether | |
a cmdlet was available in v2 already, the text of the v3 help topic must | |
be searched for a hint that the cmdlet was introduced in v3. | |
From the *absence* of such a hint, this function infers v2 availability, but | |
note that this method is not foolproof, because not all cmdlet help topics | |
explicitly state in what version they were introduced. | |
.PARAMETER Name | |
The name of one or more cmdlets whose minimum version requirement to | |
determine. | |
Wildcards are supported. | |
If the cmdlet exists on the local machine, you may also specify an alias | |
for it for brevity. | |
If the cmdlet does NOT exist, you must specify it CASE-EXACTLY. | |
.EXAMPLE | |
Get-MinPsVersionForCmdlet Get-FileHash | |
Name MinVersion | |
---- ---------- | |
Get-FileHash 4.0 | |
.EXAMPLE | |
Get-MinPsVersionForCmdlet Get-Content | |
Name MinVersion Comment | |
---- ---------- ------- | |
Get-Content 2.0 CAVEAT: v2 availability inferred from absence of version note in v3 topic | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] | |
[SupportsWildCards()] | |
[string[]] $Name | |
) | |
begin { | |
function getCmdlet($rawName) { | |
# See if the command can be found. | |
$cmd = Get-Command -EA SilentlyContinue -Name $rawName | |
if (-not $cmd) { | |
# Pass the input name through, because it could be the name of a cmdlet | |
# that happens not to be available in the PS edition running this function. | |
# !! GitHub's filename search *should* be case-INsensitive, but, as of 3 Apr 2018, | |
# !! it apparently requires camel-case *transitions* to be case-exact. | |
# !! e.g., to match `Get-CimClass.md`, you'd have to specify `CimClass` or `cimClass` or `CImClass` or `CImCLASS`, | |
# !! but not `cimclass` or `CIMclass` or `cimcLASS`. | |
# !! It's too complex and brittle to try to *guess* these transitions and auto-correct them here, | |
# !! so we simply issue a warning. | |
Write-Warning "Cmdlet $rawName not found on this machine. If it is a cmdlet in a later version / different edition, it will still be found, but be sure to specify it CASE-EXACTLY (or at least with case-exact camel-case transitions)." | |
$rawName | |
} else{ | |
# As a courtesy, resolve an alias to the underlying cmdlet name. | |
if ($cmd.ResolvedCommand) { $cmd = $cmd.ResolvedCommand } | |
$cmd.Name | |
} | |
} | |
function getMinVersion($name) { | |
$nameEsc = [uri]::EscapeDataString($name) | |
# Derive the minimum version from the lowest-versioned help topic for | |
# the specified cmdlet at https://github.com/PowerShell/PowerShell-Docs/tree/staging/reference | |
# Note: | |
# * The lowest version maintained there is v3.0, so to determine whether a given cmdlet | |
# is available in v2, more work is needed. | |
# * The help topics for Windows-only cmdlets tied to specific versions are NOT maintained on GitHub; | |
# e.g., Set-WinSystemLocale can be found at https://docs.microsoft.com/en-us/powershell/module/international/set-winsystemlocale | |
# with version query parameters reflecting a specific *OS* version, e.g., ?view=win10-ps | |
[string[]] $uris = (Invoke-WebRequest "https://github.com/PowerShell/PowerShell-Docs/search?utf8=%E2%9C%93&q=filename%3A${nameEsc}+extension%3Amd+path%3Areference&type=Code").Links.href -match '/reference/' | |
if (-not $uris) { | |
Write-Error "No help topics found for cmdlet ${name}." | |
} else { | |
$uris | Write-Verbose | |
$verStrings = $uris -replace ('.*?/(\d+(?:\.\d+)?)/.*?/{0}\b.*\.md' -f [regex]::escape($name)), '$1' -notmatch '/' | |
$minVer = [version] ('{0}.0' -f [int]::MaxValue) | |
$minVerUri = ''; $i = 0 | |
foreach ($verString in $verStrings) { | |
wv $verString | |
$ver = [version] $(if ($verString -match '\.') { $verString } else { $verString + '.0' }) | |
if ($ver -lt $minVer) { $minVer = $ver; $minVerUri = 'https://github.com/' + $uris[$i] } | |
++$i | |
} | |
$comment = $null | |
if ($minVer.Major -eq 3) { | |
# If the minimum version is 3, the cmdlet may have been introduced in v2 or even v1 - | |
# we can't tell by version-specific URIs, because the minimum version online is v3. | |
# The best we can do is to search the v3 version link's *content* for a string | |
# indicating that the cmdlet was introduced in v3 - this is not foolproof, as | |
# the cmdlet topics do not contain that information consistently - see https://github.com/PowerShell/PowerShell-Docs/issues/2270 | |
Write-verbose "Minimum version reflected in links is v3; must dig deeper, via $minVerUri" | |
if ((Invoke-WebRequest $minVerUri).RawContent -notmatch 'cmdlet (?:is|was) introduced in .*?PowerShell 3.0') { | |
$minVer = [version] '2.0' | |
$comment = 'CAVEAT: v2 availability inferred from absence of version note in v3 topic' | |
} | |
} | |
if ($minVer.Major -eq [int]::MaxValue) { | |
# 'n/a', 'No help topics named for the cmdlet found.' | |
Write-Error "No help topics found for cmdlet ${name}." | |
} else { | |
# !! | |
if ($name -match '-cim' -and $minVer.Major -eq 6) { | |
Write-Warning "Generally, CIM CMDLETS WERE INTRODUCED IN V3. As of 3 Apr 2018, https://github.com/PowerShell/PowerShell-Docs only contains v6 help topics, however." | |
} | |
$minVer, $comment | |
} | |
} | |
} | |
# Windows PowerShell: Supports only SSL3 and TLS 1.0 by default, which doesn't work with GitHub | |
# To avoid a "Could not create SSL/TLS secure channel" error, we must add TLS 1.1 and TLS 1.2 explicitly | |
if ($PSVersionTable.PSEdition -eq 'Desktop') { | |
[Net.ServicePointManager]::SecurityProtocol += 'Tls11, Tls12' | |
} | |
} | |
process { | |
foreach ($n in $Name) { | |
foreach ($cmdletName in getCmdlet $n) { # due to wildcard support, getCmdlet may return multiple cmdlets | |
$minVer, $comment = getMinVersion $cmdletName | |
if ($minVer) { | |
$oht = [ordered] @{ | |
Name = $cmdletName | |
MinVersion = $minVer | |
} | |
if ($comment) { | |
$oht['Comment'] = $comment | |
} | |
[pscustomobject] $oht | |
} | |
} | |
} | |
} | |
} | |
# If this script is invoked directly - as opposed to being dot-sourced in order | |
# to define the embedded function for later use - invoke the embedded function, | |
# relaying any arguments passed. | |
if (-not ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq '')) { | |
Get-MinPsVersionForCmdlet @Args | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment