Get-LatestPSMacVersion.psm1
|
function processVersionArray { #param is a string array param ( [Parameter(Mandatory = $true)][string[]] $theVersionArray ) #the return from invoke-restmethod is a PSCustomObject, so create a list of those so we can add items to it $theReturnArray = [System.Collections.Generic.List[PSCustomObject]]::new() #iterate through the array, get the json results, and shove them onto the list foreach ($item in $theVersionArray) { $theJsonResult = Invoke-RestMethod -Uri $item $theReturnArray.Add($theJsonResult) } #return the list return $theReturnArray } function downloadPackage { #all the params are mandatory param( [Parameter(Mandatory = $true)][string]$versionTag, [Parameter(Mandatory = $true)][string]$version, [Parameter(Mandatory = $true)][string]$cpuType ) #build the download URL $macOSPowerShellASPKGDownloadURL = "https://github.com/PowerShell/PowerShell/releases/download/$versionTag/powershell-$version-osx-$cpuType.pkg" #build the output package name $macOSPowerShellASPKG = "powershell-$version-osx-$cpuType.pkg" #downlaod the package to /tmp Invoke-RestMethod -Uri $macOSPowerShellASPKGDownloadURL -Method Get -OutFile "/tmp/$macOSPowerShellASPKG" } function Get-LatestPSMacVersion { <# .SYNOPSIS This module makes it easier to download the latest version of PowerShell for macOS. You can download the LTS, Current, or Preview version. It also lets you download the Apple Silcon (arm64) or Intel (x64) versions .DESCRIPTION This module downloads the latest version of PowerShell for macOS Note that PowerShell is case insensitive, so the parameters are as well. If no parameters are specified the stable Apple Silicon version is downloaded. The parameters are: -PSVersion or PowerShell Version. This accepts stable, lts, preview or all, default is stable -CPUArch, or CPU architecture. This accepts x64 for intel, arm64 for Apple Silicon (M1/M2/A19/etc.) or all default is arm64 one, both, or no parameters can be used .INPUTS None, there's nothing you can pipe to this .OUTPUTS An installer package in /tmp .EXAMPLE Get-LatestPSMacVersion This grabs the latest stable (not LTS or Preview) version of PowerShell for your computer's CPU architectures. On Intel, you get that version (x64), on Apple Silicon you get that version (arm64) .EXAMPLE Get-LatestPSMacVersion [-PSVersion stable/lts/preview] This grabs the specificed version for your computer's CPU architecture .EXAMPLE Get-LatestPSMacVersion [-CPUArch x64/arm64] This grabs the stable version for the specified CPU architecture .EXAMPLE Get-LatestPSMacVersion [-PSVersion all] This gets all three versions of Powershell (LTS, Stable, and Preview) for your computer's CPU architecture .EXAMPLE Get-LatestPSMacVersion [-PSVersion all] [-CPUArch x64/arm64] This gets all three versions of Powershell (LTS, Stable, and Preview) for the specified CPU architecture .EXAMPLE Get-LatestPSMacVersion [-PSVersion lts/stable/preview] [-CPUArch all] This gets the specified versions of Powershell (LTS, Stable, or Preview) for both x64 and arm64 .EXAMPLE Get-LatestPSMacVersion [-PSVersion all] [-CPUArch all] This gets all three versions of Powershell (LTS, Stable, and Preview) for both x64 and arm64 .LINK #> #input params, all are strings and optional param( [Parameter(Mandatory = $false)][string]$PSVersion, [Parameter(Mandatory = $false)][string]$cpuARCH ) #test to make sure this is running on a Mac, dump out if not if (-Not $IsMacOS) { Write-Output "This Script only runs on macOS, exiting" Exit-PSSession } #this is mostly to avoid scope issues. It's also a real help for things that are sometimes an array and sometimes a string #or a single json objecgt $PSLatestVersionInfo = $null $PSLatestVersionArray = $null $cpuARCHInfo = $null $PSLatestReleaseTag = $null $PSLatestVersion = $null #test the version for nothing, allowed terms, or all. if all, we build an array of URLs, if null/bad value, it's select switch ($PSVersion) { {$PSVersion -eq "stable" -or $PSVersion -eq "lts" -or $PSVersion -eq "preview"} { #if it's one of the good options, get the json info for that version $PSLatestVersionInfo = Invoke-RestMethod -Uri "https://aka.ms/pwsh-buildinfo-$PSVersion" break } {$PSVersion -eq "all"} { #if it's all, build an array of json objects $PSLatestVersionArray = @( "https://aka.ms/pwsh-buildinfo-stable" "https://aka.ms/pwsh-buildinfo-lts" "https://aka.ms/pwsh-buildinfo-preview" ) $PSLatestVersionInfo = processVersionArray -theVersionArray $PSLatestVersionArray break } Default { #use stable $PSLatestVersionInfo = Invoke-RestMethod -Uri "https://aka.ms/pwsh-buildinfo-stable" } } #for this, we really only care about "all", null, or invalid input switch ($cpuARCH) { {$cpuARCH -eq "arm64" -or $cpuARCH -eq "x64"} { $cpuARCHInfo = $cpuARCH break } {$cpuARCH -eq "all"} { #if it's all, build an array $cpuARCHInfo = @( "arm64" "x64" ) break } {$null -eq $cpuARCH} { #if they don't enter any CPU arch param, we check for the architecture on the mac this is running on #and set $cpuArch accordingly $myCPUArch = Invoke-Expression -Command "/usr/bin/uname -m" if ($myCPUArch -eq "x86_64") { $cpuARCH = "x64" } else { $cpuARCH = "arm64" } } Default { #arm64 $cpuARCHInfo = "arm64" } } #test for version array if ($PSLatestVersionInfo.GetType().BaseType.Name -eq "Array") { #it's an array #set the release tags to a list of strings $PSLatestReleaseTag = [System.Collections.Generic.List[string]]::new() #get a list of tags foreach ($item in $PSLatestVersionInfo) { #get the tags $PSLatestReleaseTag.Add($item.ReleaseTag) } #set the version to a list of strings $PSLatestVersion = [System.Collections.Generic.List[string]]::new() #get a list of version numbers sans the leading 'v' foreach ($item in $PSLatestReleaseTag) { #strip the leading v off the tag and add it to PS latest version $PSLatestVersion.Add($item.Substring(1)) } } else { #not an array #get the releasetag $PSLatestReleaseTag = $PSLatestVersionInfo.ReleaseTag #build the version sans the leading v $PSLatestVersion = $PSLatestReleaseTag.Substring(1) } #download selector. the vars we care about are either lists, arrays or strings, so we check first for neither being an array/list #we only have to test either releasetag or version, since both are always made lists or strings together. there's no chance #for one to be a different type than the other #because the release tag is a list and the CPUArchInfo is an array, we have to test differently if ((!($PSLatestReleaseTag.GetType().Name.Contains("List"))) -and ($cpuARCHInfo.GetType().BaseType.Name -ne "Array")) { #all the tags are strings, simplest case, call the function to download downloadPackage -versionTag $PSLatestReleaseTag -version $PSLatestVersion -cpuType $cpuARCHInfo Write-Output "PowerShell $PSLatestReleaseTag for $cpuARCHInfo downloaded to /tmp" } elseif ((!($PSLatestReleaseTag.GetType().Name.Contains("List"))) -and ($cpuARCHInfo.GetType().BaseType.Name -eq "Array")) { #the release type is NOT an array, but the CPU arch IS an array #we iterate through the CPUArchInfo array and run once for each foreach ($item in $cpuARCHInfo) { downloadPackage -versionTag $PSLatestReleaseTag -version $PSLatestVersion -cpuType $item Write-Output "PowerShell $PSLatestReleaseTag for $item downloaded to /tmp" } } elseif (($PSLatestReleaseTag.GetType().Name.Contains("List")) -and ($cpuARCHInfo.GetType().BaseType.Name -ne "Array")) { #the release type IS an array, but the CPU arch is NOT an array #because we have two different lists, albeit identical in content, #we need to know the current index so both can be sync'd foreach ($item in $PSLatestReleaseTag) { #get the index of $item $theIndex = $PSLatestReleaseTag.IndexOf($item) #download the package for that version and CPU type. For this If, CPU type is a constant string downloadPackage -versionTag $PSLatestReleaseTag[$theIndex] -version $PSLatestVersion[$theIndex] -cpuType $cpuARCHInfo #this just makes the output look nicer $tempTag = $PSLatestReleaseTag[$theIndex] Write-Output "PowerShell $tempTag for $cpuARCHInfo downloaded to /tmp" } } elseif (($PSLatestReleaseTag.GetType().Name.Contains("List")) -and ($cpuARCHInfo.GetType().BaseType.Name -eq "Array")) { #EVERYTHING IS AN ARRAY OR A LIST #we'll use two loops here, the outer loop will be based on CPU type, inner loop on version foreach ($cpu in $cpuARCHInfo) { foreach ($item in $PSLatestReleaseTag) { #get the index of $item $theIndex = $PSLatestReleaseTag.IndexOf($item) #download downloadPackage -versionTag $PSLatestReleaseTag[$theIndex] -version $PSLatestVersion[$theIndex] -cpuType $cpu $tempTag = $PSLatestReleaseTag[$theIndex] Write-Output "PowerShell $tempTag for $cpu downloaded to /tmp" } } } else { Write-Output "Something went very wrong. Double-check your parameters and/or your internet connection" } } Export-ModuleMember -Function Get-LatestPSMacVersion # SIG # Begin signature block # MIIMgQYJKoZIhvcNAQcCoIIMcjCCDG4CAQMxDTALBglghkgBZQMEAgEwewYKKwYB # BAGCNwIBBKBtBGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCcSlWSjL/Mlza+ # wUGnaUgo/Sfqxc9HCXneeYRyLXPiI6CCCawwggQEMIIC7KADAgECAggYeqmowpYh # DDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUg # SW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAU # BgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMTIwMjAxMjIxMjE1WhcNMjcwMjAxMjIx # MjE1WjB5MS0wKwYDVQQDDCREZXZlbG9wZXIgSUQgQ2VydGlmaWNhdGlvbiBBdXRo # b3JpdHkxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMw # EQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBAIl2TwZbmkHupSMrAqNf13M/wDWwi4QKPwYkf6eVP+tP # DpOvtA7QyD7lbRizH+iJR7/XCQjk/1aYKRXnlJ25NaMKzbTA4eJg9MrsKXhFaWlg # a1+KkvyeI+Y6wiKzMU8cuvK2NFlC7rCpAgMYkQS2s3guMx+ARQ1Fb7sOWlt/OufY # CNcLDjJt+4Y25GyrxBGKcIQmqp9E0fG4xnuUF5tI9wtYFrojxZ8VOX7KXcMyXw/g # Un9A6r6sCGSVW8kanOWAyh9qRBxsPsSwJh8d7HuvXqBqPUepWBIxPyB2KG0dHLDC # ThFpJovL1tARgslOD/FWdNDZCEtmeKKrrKfi0kyHWckCAwEAAaOBpjCBozAdBgNV # HQ4EFgQUVxftos/cfJihEOD8voctLPLjF1QwDwYDVR0TAQH/BAUwAwEB/zAfBgNV # HSMEGDAWgBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAuBgNVHR8EJzAlMCOgIaAfhh1o # dHRwOi8vY3JsLmFwcGxlLmNvbS9yb290LmNybDAOBgNVHQ8BAf8EBAMCAYYwEAYK # KoZIhvdjZAYCBgQCBQAwDQYJKoZIhvcNAQELBQADggEBAEI5dGuh3MakjzcqjLMd # CkS8lSx/vFm4rGH7B5CSMrnUvzvBUDlqRHSi7FsfcOWq3UtsHCNxLV/RxZO+7puK # cGWCnRbjGhAXiS2ozf0MeFhJDCh/M+4Aehu0dqy2tbtP36gbncgZl0oLVmcvwj62 # s8SDOvB3bXTELiNR7pqlA29g9KVIpwbCu1riHx9GRX7kl/UnELcgInJvctrGUHXF # PSWPXaMA6Z82jEg5j7M76pCALpWaYPR4zvQOClM+ovpP2B6uhJWNMrxWTYnpeBjg # rJpCunpGG4Siic4U6IjRWIv2rlbELAUqRa8L2UupAg80rIjHYVWJRMkncwfuguVO # 9XAwggWgMIIEiKADAgECAgg4/t1QcpKr9DANBgkqhkiG9w0BAQsFADB5MS0wKwYD # VQQDDCREZXZlbG9wZXIgSUQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJjAkBgNV # BAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBs # ZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0yNTA1MjAxNzI2MzZaFw0yNzAyMDEyMjEy # MTVaMIGPMRowGAYKCZImiZPyLGQBAQwKNzk2NDg4Vkc5NTE6MDgGA1UEAwwxRGV2 # ZWxvcGVyIElEIEFwcGxpY2F0aW9uOiBKb2huIFdlbGNoICg3OTY0ODhWRzk1KTET # MBEGA1UECwwKNzk2NDg4Vkc5NTETMBEGA1UECgwKSm9obiBXZWxjaDELMAkGA1UE # BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDG5iTyi/Llb8QR # mKSVEMaSkIAyXssehEKC1nJKp9ZkaRLxan/q6B7JeWzTNa6XCBG3Pf4Dz0IQnU6U # qDsPFYpwhRtS14CNVnwmcMJeJ/hy6MW++cBymq9xEZD80c69muLZmYr2KLKFu6WJ # nPK4JvYNqZ5Iug7UthcVeZBTdCDHCsVui8WMrFwDe112hqHFb9YiwrZF3w4v3G7X # cU6KO6oiD79C26xelHqAjuPZUxHbiJDhrgI2xbr4phtyukq/aaUyvOEGRuzr9ViT # imxjMH0Dzd3eYQNyZ/OgpBTg/u5bt4c4L+ivLNWpkImm5NLByjPWj2Rgxex9q7gu # d8eXX5PBAgMBAAGjggITMIICDzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFFcX # 7aLP3HyYoRDg/L6HLSzy4xdUMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYk # aHR0cDovL29jc3AuYXBwbGUuY29tL29jc3AwMy1kZXZpZDA2MIIBHQYDVR0gBIIB # FDCCARAwggEMBgkqhkiG92NkBQEwgf4wgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFu # Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl # cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k # IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp # ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wNgYIKwYBBQUHAgEWKmh0dHA6 # Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5LzAWBgNVHSUBAf8E # DDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU+vpKLJ3aUHMJjwgzoV2hMj3fKX8wDgYD # VR0PAQH/BAQDAgeAMB8GCiqGSIb3Y2QGASEEEQwPMjAxOTAyMDYwMDAwMDBaMBMG # CiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3DQEBCwUAA4IBAQAV1Oma8FyEr7uz # iO/jzM9Zv+vfk6USv3P/G444JO51tYK9pfyOBIw1bAQriiW4AmUbgYsOTPBRDaSn # MuZBi/srL1G+mXngoiqaP4sdt3MgCt/mJTmz/PBxVZgLk8XKxZR8C6GBKX9vVSTR # oAbwake9HBhJe4RnNoELGuXk62b1QKnkKDKUizZtuAib13yDSr5bN0KxezeGmySg # t1maDJ+qCYpQUMB3Nls7taCozh4lsl7xtvc/2A8l2Nf9pcT0GGpkZdpf1WwUqm6O # 3fUQ7+GCO2ctz8CfUchecgcBDMP40oTKDsW7d8oLP5LU8YK8lgoAzUeHA5JMscLU # Ud176XtfMYICKzCCAicCAQEwgYUweTEtMCsGA1UEAwwkRGV2ZWxvcGVyIElEIENl # cnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 # aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMC # CDj+3VBykqv0MAsGCWCGSAFlAwQCAaB8MBAGCisGAQQBgjcCAQwxAjAAMBkGCSqG # SIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3 # AgEVMC8GCSqGSIb3DQEJBDEiBCD9QcsGLPhzMhQ7+xPhm/S4UrX544QgiluWNNCh # LfTlrTALBgkqhkiG9w0BAQEEggEAsbhq1BLoyqenqBlQFgx1L/DBIwK879kmhIcn # WuRRnt2YWtWWb7WNPI+/SzLKhrbi5wzpxHKeJkOp7lBFa4jNj66DbzUT4etDQHb0 # h1gfQGd5JDmb5ch/k76VohGNyphJEeKTpCMXDAT8eBeFlBsfbMnxfr9bdJYAvSe4 # yF+n0Fo7BlzV2/0cAw5C/ESmEKSp2UcQin4W3ImDkvhyakZwfK7E8bt23G/ma1yb # +NwjMGx50S2NNrKi9rwgCCOHYFyAWuDGHkl7hVlVt3EVvBC54/awkRHCvOIG7r9j # 2iSyWBXZvH6pmNic9k6nOWFB8rGFTT2aCjdQmQVCoOoS75A+iA== # SIG # End signature block |