$URL64 = (Resolve-Uri -Uri 'https://aka.ms/ssmsfullsetup').Uri
$Version = Get-Version -Uri 'https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms' -Pattern 'Release number: ((?:\d+\.)+\d+)'
New-NevergreenApp -Name 'Microsoft SSMS' -Version $Version -Uri $URL64 -Architecture 'x64' -Type 'Exe'
only returns the latest new full version in 'English (United States)' language, but does not return any earlier versions.
Earlier versions are sometimes still required as Microsoft may still update earlier versions to fix security issues.
Earlier versions are required to work with specific components of certain SQL server releases (SSIS for example requires v18.x)
# Get-SSMS.ps1
# Define AppName
$AppName = "Microsoft SQL Server Management Studio"
# Main script to fetch and process links
$ReleaseURL = "https://learn.microsoft.com/en-us/sql/ssms/release-notes-ssms?view=sql-server-ver16" # Replace with the URL of the web page you want to process
Write-Verbose "Obtaining $($AppName) Release Versions...`n=============================================================================`n"
# Fetch the HTML content of the webpage
$htmlContent = Invoke-WebRequest -Uri $ReleaseUrl
# Define the RegEx pattern to match the links and capture the version number and BaseURI
$pattern = '<a[^>]*href="([^"]*)"[^>]*>\s*Download SSMS ([\d.]+)\s*</a>'
$SearchCount = ([regex]::Matches($htmlContent.RawContent, $pattern)).Count
Write-Verbose "$($AppName) Release Versions found: $($SearchCount)`n-------------------------------------------------------------------------`n"
do {
# Use RegEx to find matches
foreach ($patternmatch in [regex]::Matches($htmlContent.Content, $pattern)) {
# Extract the URI and version number
$ThisVersionUri = $patternmatch.Groups[1].Value
[version]$ThisVersion = $patternmatch.Groups[2].Value
$BaseVersion = $($ThisVersion.Major)
# Regular expression to match the release information
$regex = "<li>Release number: $($ThisVersion)</li>`n<li>Build number: (.*?)</li>`n<li>Release date: (.*?)</li>"
$BuildCount = ([regex]::Matches($htmlContent.RawContent, $regex)).Count
foreach ($regexmatch in [regex]::Matches($htmlContent.RawContent, $regex)) {
#$ReleaseVersion = $regexmatch.Groups[1].Value
[version]$BuildNumber = $regexmatch.Groups[1].Value
$ReleaseDate = $regexmatch.Groups[2].Value
do {
$AppVersions = @(
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Chinese (Simplified)'; Pattern = '&clcid=0x804'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Chinese (Traditional)'; Pattern = '&clcid=0x404'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'English'; Pattern = '&clcid=0x409'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'French'; Pattern = '&clcid=0x40c'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'German'; Pattern = '&clcid=0x407'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Italian'; Pattern = '&clcid=0x410'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Japanese'; Pattern = '&clcid=0x411'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Korean'; Pattern = '&clcid=0x412'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Portuguese (Brazil)'; Pattern = '&clcid=0x416'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Russian'; Pattern = '&clcid=0x419'}
@{Version = $ThisVersion; BuildNumber = $BuildNumber; ReleaseDate = $ReleaseDate; Language = 'Spanish'; Pattern = '&clcid=0x40a'}
)
foreach ($AppVersion in $AppVersions) {
if ($ThisVersionUri) {
#Build each link with Language specific versions
$URL = (Resolve-Uri -Uri "$($ThisVersionUri)$($AppVersion.Pattern)").Uri
New-NevergreenApp -Name $AppName -Ring $BaseVersion -Version $AppVersion.Version -BuildNumber $AppVersion.BuildNumber -ReleaseDate $AppVersion.ReleaseDate -Uri $URL -Architecture 'x64' -Language $AppVersion.Language -Type 'Exe'
#break
}
}
$BuildCount--
} until ($BuildCount -eq 0)
}
$SearchCount--
}
} until ($SearchCount -eq 0)
function New-NevergreenApp {
<#
.SYNOPSIS
Returns a PSCustomObject to output.
.DESCRIPTION
Returns a PSCustomObject to output.
.NOTES
Site: https://packageology.com
Author: Dan Gough
Twitter: @packageologist
.LINK
https://github.com/DanGough/Nevergreen
.PARAMETER Name
Mandatory. The name of the application.
.PARAMETER Uri
Mandatory. The download URI for the application.
.PARAMETER Version
Mandatory. The application version.
.PARAMETER Architecture
Mandatory. Must match x86, x64, ARM32, ARM64 or Multi.
.PARAMETER Type
Mandatory. Must match Msi, Msp, Exe, Zip, Msix, AppX, AppV, 7z if supplied.
.PARAMETER Language
Optional. The language of the application installer, e.g. 'en'.
.PARAMETER Ring
Optional. The deployment ring, e.g. 'General', 'Preview'.
.PARAMETER Channel
Optional. The channel, e.g. 'Enterprise'.
.PARAMETER Platform
Optional. The platform, e.g. 'Windows Server'.
.PARAMETER BuildNumber
Optional. The Build Version (used where available - example SSMS).
.PARAMETER ReleaseDate
Optional. The Date the version was released.
.PARAMETER MD5
Optional. The MD5 hash of the file.
.PARAMETER SHA256
Optional. The SHA256 hash of the file.
.EXAMPLE
New-NevergreenApp -Uri 'http://somewhere.com/something.exe' -Version '1.0' -Architecture 'x64' -Type 'Exe'
Description:
Outputs a PSCustomObject with the chosen properties.
#>
[CmdletBinding(SupportsShouldProcess = $False)]
param (
[Parameter(
Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Name,
[Parameter(
Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Version,
[Parameter(
Mandatory = $true)]
[ValidatePattern('^(http|https)://')]
[Alias('Url')]
[String] $Uri,
[Parameter(
Mandatory = $true)]
[ValidateSet('x86', 'x64', 'ARM32', 'ARM64', 'Multi')]
[String] $Architecture,
[Parameter(
Mandatory = $true)]
[ValidateSet('Msi', 'Msp', 'Exe', 'Zip', 'Msix', 'AppX', 'AppV', '7z')]
[String] $Type,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $Language,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $Ring,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $Channel,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $Platform,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $BuildNumber,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $ReleaseDate,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $MD5,
[Parameter(
Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String] $SHA256
)
$Output = [PSCustomObject]@{
Name = $Name
}
if ($Ring) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Ring' -Value $Ring
}
if ($Channel) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Channel' -Value $Channel
}
if ($Language) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Language' -Value $Language
}
if ($BuildNumber) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'BuildNumber' -Value $BuildNumber
}
if ($ReleaseDate) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'ReleaseDate' -Value $ReleaseDate
}
if ($Platform) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Platform' -Value $Platform
}
if ($Architecture) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Architecture' -Value $Architecture
}
if ($Type) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Type' -Value $Type
}
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Version' -Value $Version
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Uri' -Value $Uri
if ($MD5) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'MD5' -Value $MD5
}
if ($SHA256) {
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'SHA256' -Value $SHA256
}
$Output
}