SqlServer-Version-Management.psm1
# Include Directive: [ src\Synopsis.ps1 ] # Include Directive: [ ..\Includes\*.ps1 ] # Include File: [\Includes\$Full7zLinksMetadata.ps1] $Full7zLinksMetadata_onWindows = @( @{ Ver = 2301; X64Links = @( "https://www.7-zip.org/a/7z2301-x64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x64-2301.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x64-2301.7z?viasf=1" ); ARM64Links = @( "https://www.7-zip.org/a/7z2301-arm64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-arm64-2301.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-arm64-2301.7z?viasf=1" ); X86Links = @( "https://www.7-zip.org/a/7z2301.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x86-2301.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x86-2301.7z?viasf=1" ) }, @{ Ver = 2201; X64Links = @( "https://www.7-zip.org/a/7z2201-x64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x64-2201.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x64-2201.7z?viasf=1" ); ARM64Links = @( "https://www.7-zip.org/a/7z2201-arm64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-arm64-2201.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-arm64-2201.7z?viasf=1" ); X86Links = @( "https://www.7-zip.org/a/7z2201.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x86-2201.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x86-2201.7z?viasf=1" ) }, @{ Ver = 1900; X64Links = @( "https://www.7-zip.org/a/7z1900-x64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x64-1900.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x64-1900.7z?viasf=1" ); X86Links = @( "https://www.7-zip.org/a/7z1900.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x86-1900.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x86-1900.7z?viasf=1" ) }, @{ Ver = 1604; X64Links = @( "https://www.7-zip.org/a/7z1604-x64.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x64-1604.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x64-1604.7z?viasf=1" ); X86Links = @( "https://www.7-zip.org/a/7z1604.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x86-1604.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x86-1604.7z?viasf=1" ) }, @{ Ver = 920; X86Links = @( "https://sourceforge.net/projects/p7zz-repack/files/windows/7z-full-x86-920.7z/download", "https://master.dl.sourceforge.net/project/p7zz-repack/windows/7z-full-x86-920.7z?viasf=1" ) } ); <# https://www.7-zip.org/a/7z2301-arm64.exe https://www.7-zip.org/a/7z2301-x64.exe https://www.7-zip.org/a/7z2301.exe https://www.7-zip.org/a/7z2201-arm64.exe https://www.7-zip.org/a/7z2201-x64.exe https://www.7-zip.org/a/7z2201.exe https://www.7-zip.org/a/7z1900-x64.exe https://www.7-zip.org/a/7z1900.exe https://www.7-zip.org/a/7z1604-x64.exe https://www.7-zip.org/a/7z1604.exe https://www.7-zip.org/a/7z920.exe https://www.7-zip.org/a/7z920-arm.exe https://www.7-zip.org/a/7zr.exe #> # Include File: [\Includes\$VcRuntimeLinksMetadata.ps1] $VcRuntimeLinksMetadata = @( @{ Ver=14; Args="/install /passive /norestart"; X64Link="https://aka.ms/vs/17/release/vc_redist.x64.exe"; X86Link="https://aka.ms/vs/17/release/vc_redist.x86.exe"; ARM64Link="https://aka.ms/vs/17/release/vc_redist.arm64.exe" }, @{ Ver=12; Args="/install /passive /norestart"; X64Link="https://aka.ms/highdpimfc2013x64enu"; X86Link="https://aka.ms/highdpimfc2013x86enu"; }, @{ Ver=11; Args="/install /passive /norestart"; X64Link="https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe"; X86Link="https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe"; }, @{ Ver=10; Args="/q /norestart"; X64Link="https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe"; X86Link="https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe"; }, @{ Ver=9; Args="/q /norestart"; X64Link="https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x64.exe"; X86Link="https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x86.exe"; }, @{ Ver=8; Args="/q:a"; # FULLY SILENT X64 on x86: /q /c:"msiexec /i vcredist.msi IACCEPTSQLLOCALDBLICENSETERMS=YES /qn /L*v c:\vc8b-x64.log" X64Link="https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x64.EXE"; X86Link="https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x86.EXE"; } ); # Include File: [\Includes\Append-All-Text.ps1] function Append-All-Text( [string]$file, [string]$text ) { Create-Directory-for-File $file $utf8=new-object System.Text.UTF8Encoding($false); [System.IO.File]::AppendAllText($file, $text, $utf8); } function Write-All-Text( [string]$file, [string]$text ) { Create-Directory-for-File $file $utf8=new-object System.Text.UTF8Encoding($false); [System.IO.File]::WriteAllText($file, $text, $utf8); } # Include File: [\Includes\Bootstrap-Aria2-If-Required.ps1] # on windows 7 api.gitgub.com, etc are not available function Bootstrap-Aria2-If-Required( [bool] $force = $false, [string] $deployMode = "copy-to", # copy-to | modify-path [string] $copyToFolder = $ENV:SystemRoot ) { if ((Get-Os-Platform) -ne "Windows") { return; } $major = [System.Environment]::OSVersion.Version.Major; $minor = [System.Environment]::OSVersion.Version.Minor; $canWebClient = ($major -gt 6) -or ($major -eq 6 -and $minor -ge 2); $okAria=$false; try { & aria2c.exe -h *| out-null; $okAria=$? } catch {} if (-not $force) { if ($canWebClient -or $okAria) { return; } } $ariaExe = Get-Aria2c-Exe-FullPath-for-Windows if ($deployMode -eq "copy-to") { Copy-Item $ariaExe $copyToFolder -Force -EA Continue Write-Host "Provisioning aria2.exe for Windows $major.$minor. Copied to $copyToFolder" } elseif ($deployMode -eq "modify-path") { $dir=[System.IO.Path]::GetDirectoryName($ariaExe) $ENV:PATH="$($ENV:PATH);$($dir)" Write-Host "Provisioning aria2.exe for Windows $major.$minor. Added $dir to PATH" } } # Include File: [\Includes\Combine-Path.ps1] function Combine-Path($start) { foreach($a in $args) { $start=[System.IO.Path]::Combine($start, $a); }; $start } # Include File: [\Includes\Create-Directory.ps1] function Create-Directory($dirName) { if ($dirName) { $err = $null; try { $_ = [System.IO.Directory]::CreateDirectory($dirName); return; } catch { $err = "Create-Directory failed for `"$dirName`". $($_.Exception.GetType().ToString()) $($_.Exception.Message)" Write-Host "Warning! $err"; throw $err; } } } function Create-Directory-for-File($fileFullName) { $dirName=[System.IO.Path]::GetDirectoryName($fileFullName) Create-Directory "$dirName"; } # Include File: [\Includes\Demo-Test-of-Is-Vc-Runtime-Installed.ps1] function Demo-Test-of-Is-Vc-Runtime-Installed() { foreach($arch in @("X86", "X64", "ARM64")) { Write-Host -NoNewline "$("{0,5}" -f $arch)| " foreach($ver in $VcRuntimeLinksMetadata | % {$_.Ver}) { $isInstalled = Is-Vc-Runtime-Installed $ver $arch $color="Red"; if ($isInstalled) { $color="Green"; } Write-Host -NoNewline "v$($ver)=$("{0,-8}" -f $isInstalled) " -ForegroundColor $color } Write-Host "" } } # Include File: [\Includes\Demo-Test-of-Platform-Info.ps1] function Demo-Test-of-Platform-Info() { echo "Memory $((Get-Memory-Info).Description)" echo "OS Platform: '$(Get-Os-Platform)'" if ("$(Get-Os-Platform)" -ne "Windows") { echo "UName System: '$(Get-Nix-Uname-Value "-s")'" } echo "CPU: '$(Get-Cpu-Name)'" Measure-Action "The Greeting Test Action" {echo "Hello World"} Measure-Action "The Fail Test Action" {$x=0; echo "Cant devide by zero $(42/$x)"; } Measure-Action "The CPU Name" {echo "CPU: '$(Get-Cpu-Name)'"} }; # test # Include File: [\Includes\Download-And-Install-Specific-VC-Runtime.ps1] function Download-And-Install-Specific-VC-Runtime([string] $arch, [int] $version, [bool] $wait = $true) { $fullPath = Download-Specific-VC-Runtime $arch $version $commandLine=$VcRuntimeLinksMetadata | where { "$($_.Ver)" -eq "$version" } | % { $_.Args } # & "$fullPath" $commandLine.Split([char]32) # $isOk = $?; # return $isOk; $isOk = $false try { Start-Process -FilePath "$fullPath" -ArgumentList ($commandLine.Split([char]32)) -Wait:$wait -NoNewWindow $isOk = $true } catch {} return $isOk } # Include File: [\Includes\Download-File-FailFree-and-Cached.ps1] function Download-File-FailFree-and-Cached([string] $fullName, [string[]] $urlList, [string] $algorithm="SHA512") { if ((Is-File-Not-Empty "$fullName") -and (Is-File-Not-Empty "$fullName.$algorithm")) { $hashActual = Get-Smarty-FileHash "$fullName" $algorithm $hashExpected = Get-Content -Path "$fullName.$algorithm" if ($hashActual -eq $hashExpected -and "$hashActual" -ne "") { Troubleshoot-Info "File already downloaded: '" -Highlight "$fullName" "'" return $true; } } $isOk = [bool] ((Download-File-FailFree $fullName $urlList) | Select -Last 1) if ($isOk) { $hashActual = Get-Smarty-FileHash "$fullName" $algorithm echo "$hashActual" > "$($fullName).$algorithm" return $true; } return $false; } # Include File: [\Includes\Download-File-Managed.ps1] function Download-File-Managed([string] $url, [string]$outfile) { $dirName=[System.IO.Path]::GetDirectoryName($outfile) Create-Directory "$dirName"; $okAria=$false; try { & aria2c.exe -h *| out-null; $okAria=$? } catch {} if ($okAria) { Troubleshoot-Info "Starting download `"" -Highlight "$url" "`" using aria2c as `"" -Highlight "$outfile" "`"" # "-k", "2M", $startAt = [System.Diagnostics.Stopwatch]::StartNew() & aria2c.exe @("--allow-overwrite=true", "--check-certificate=false", "-x", "16", "-j", "16", "-d", "$($dirName)", "-o", "$([System.IO.Path]::GetFileName($outfile))", "$url"); if ($?) { <# Write-Host "aria2 rocks ($([System.IO.Path]::GetFileName($outfile)))"; #> try { $length = (new-object System.IO.FileInfo($outfile)).Length; } catch {}; $milliSeconds = $startAt.ElapsedMilliseconds; $size=""; if ($length -gt 0) { $size=" ($($length.ToString("n0")) bytes)"; } $speed=""; if ($length -gt 0 -and $milliSeconds -gt 0) { $speed=" Speed is $(($length*1000/1024/$milliSeconds).ToString("n0")) Kb/s."; } $duration=""; if ($milliSeconds -gt 0) {$duration=" It took $(($milliSeconds/1000.).ToString("n1")) seconds."; } $downloadReport="Download of '$outfile'$($size) completed.$($duration)$($speed)"; Write-Host $downloadReport; if ("$($ENV:SYSTEM_ARTIFACTSDIRECTORY)") { Append-All-Text (Combine-Path "$($ENV:SYSTEM_ARTIFACTSDIRECTORY)" "Download Speed Report.log") "$downloadReport$([Environment]::NewLine)"; } return $true; } } elseif (([System.Environment]::OSVersion.Version.Major) -eq 5 -and (Get-Os-Platform) -eq "Windows" ) { Write-Host "Warning! Windows XP and Server 2003 requires aria2c.exe in the PATH for downloading." -ForegroundColor Red; } [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; if ($PSVersionTable.PSEdition -ne "Core") { [System.Net.ServicePointManager]::ServerCertificateValidationCallback={$true}; } for ($i=1; $i -le 3; $i++) { Troubleshoot-Info "Starting download attempt #$i `"" -Highlight "$url" "`" using built-in http client as `"" -Highlight "$outfile" "`"" $d=new-object System.Net.WebClient; # $d.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"); try { $startAt = [System.Diagnostics.Stopwatch]::StartNew() $d.DownloadFile("$url","$outfile"); try { $length = (new-object System.IO.FileInfo($outfile)).Length; } catch {}; $milliSeconds = $startAt.ElapsedMilliseconds; $size=""; if ($length -gt 0) { $size=" ($($length.ToString("n0")) bytes)"; } $speed=""; if ($length -gt 0 -and $milliSeconds -gt 0) { $speed=" Speed is $(($length*1000/1024/$milliSeconds).ToString("n0")) Kb/s."; } $duration=""; if ($milliSeconds -gt 0) {$duration=" It took $(($milliSeconds/1000.).ToString("n1")) seconds."; } $downloadReport="Download of '$outfile'$($size) completed.$($duration)$($speed)"; Write-Host $downloadReport; if ("$($ENV:SYSTEM_ARTIFACTSDIRECTORY)") { Append-All-Text (Combine-Path "$($ENV:SYSTEM_ARTIFACTSDIRECTORY)" "Download Speed Report.log") "$downloadReport$([Environment]::NewLine)"; } return $true } catch { $fileExists = (Test-Path $outfile) if ($fileExists) { Remove-Item $outfile -force } # Write-Host $_.Exception -ForegroundColor DarkRed; if ($i -lt 3) { Write-Host "The download of the '$url' url failed.$([System.Environment]::NewLine)Retrying, $($i+1) of 3. $($_.Exception.Message)" -ForegroundColor Red; sleep 1; } else { Write-Host "Unable to download of the '$url' url.$([System.Environment]::NewLine)$($_.Exception.Message)" -ForegroundColor Red; } } } return $false } function Download-File-FailFree([string] $outFile, [string[]] $urlList) { foreach($url in $urlList) { $isOk = Download-File-Managed $url $outFile | Select -Last 1; if ($isOk) { return $true; } } return $fasle; } # Include File: [\Includes\Download-Specific-VC-Runtime.ps1] function Download-Specific-VC-Runtime([string] $arch, [int] $version) { $algorithm="SHA512" $downloadFolder = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "VC-Runtime" $link = $VcRuntimeLinksMetadata | where {"$($_.Ver)" -eq "$version"} | % { $_."$($arch)Link"} if (-not "$link") { Write-Host "Warning! Undefined link for Visual C++ Runtime v$($version) for $arch architecture" -ForegroundColor Red } else { $fullPath = Combine-Path $downloadFolder "$arch-v$version" "$([System.IO.Path]::GetFilename($link))" if (-not ($fullPath.ToLower().EndsWith(".exe"))) { $fullPath = "$($fullPath).exe"; } if ((Is-File-Not-Empty "$fullPath") -and (Is-File-Not-Empty "$fullPath.$algorithm")) { $hashActual = Get-Smarty-FileHash "$fullPath" $algorithm $hashExpected = Get-Content -Path "$fullPath.$algorithm" if ($hashActual -eq $hashExpected -and "$hashActual" -ne "") { Troubleshoot-Info "Already downloaded " -Highlight "$arch" - "v" -Highlight "$($version)" ": '$fullPath'" return $fullPath; } } $isOk = [bool] (Download-File-Managed $link $fullPath) if ($isOk) { $hashActual = Get-Smarty-FileHash "$fullPath" $algorithm echo "$hashActual" > "$($fullPath).$algorithm" return $fullPath; } } return ""; } # Include File: [\Includes\Execute-Process-Smarty.ps1] function Execute-Process-Smarty { Param( [string] $title, [string] $launcher, [string[]] $arguments, [string] $workingDirectory = $null, [int] $waitTimeout = 3600, [switch] $Hidden = [switch] $false ) $arguments = @($arguments | ? { "$_".Trim() -ne "" }) Troubleshoot-Info "[$title] `"$launcher`" $arguments"; $startAt = [System.Diagnostics.Stopwatch]::StartNew() $ret = @{}; $windowStyle = if ($Hidden) { "Hidden" } else { "Normal" }; try { if ($workingDirectory) { $app = Start-Process "$launcher" -ArgumentList $arguments -WorkingDirectory $workingDirectory -PassThru -WindowStyle $windowStyle; } else { $app = Start-Process "$launcher" -ArgumentList $arguments -PassThru -WindowStyle $windowStyle; } } catch { $err = "$($_.Exception.GetType()): '$($_.Exception.Message)'"; $ret = @{Error = "$title failed. $err"; }; } $exitCode = $null; $okExitCode = $false; if (-not $ret.Error) { if ($app -and $app.Id) { $isExited = $app.WaitForExit(1000*$waitTimeout); if (-not $isExited) { $ret = @{ Error = "$title timed out." }; } if (-not $ret.Error) { sleep 0.01 # background tasks $exitCode = [int] $app.ExitCode; $isLegacy = ([System.Environment]::OSVersion.Version.Major) -eq 5; if ($isExited -and $isLegacy -and "$exitCode" -eq "") { $exitCode = 0; } $okExitCode = $exitCode -eq 0; # Write-Host "Exit Code = [$exitCode], okExitCode = [$okExitCode]" $ret = @{ExitCode = $exitCode}; if (-not $okExitCode) { $err = "$title failed."; if ($app.ExitCode) { $err += " Exit code $($app.ExitCode)."; } $ret = @{ Error = $err }; } } } else { if (-not "$($ret.Error)") { $ret["Error"] = "$title failed."; } } } $isOk = ((-not $ret.Error) -and $okExitCode); $status = IIF $isOk "Successfully completed" $ret.Error; if ($isOk) { Write-Host "$title $status. It took $($startAt.ElapsedMilliseconds.ToString("n0")) ms"; } else { Write-Host "$title $status. It took $($startAt.ElapsedMilliseconds.ToString("n0")) ms" -ForegroundColor DarkRed; } if (!$isOk -and ($app.Id)) { # TODO: Windows Only & taskkill.exe @("/t", "/f", "/pid", "$($app.Id)") | out-null; } return $ret; } # Include File: [\Includes\Extract-Archive-by-Default-Full-7z.ps1] function Extract-Archive-by-Default-Full-7z([string] $fromArchive, [string] $toDirectory, $extractCommand = "x") { New-Item -Path "$($toDirectory)" -ItemType Directory -Force -EA SilentlyContinue | Out-Null $full7zExe = "$(Get-Full7z-Exe-FullPath-for-Windows)" try { $fileOnly = [System.IO.Path]::GetFileName($fromArchive); } catch { $fileOnly = $fromArchive; } $execResult = Execute-Process-Smarty "'$fileOnly' Extractor" $full7zExe @($extractCommand, "-y", "-o`"$toDirectory`"", "$fromArchive") -Hidden; $ret = $true; if ($execResult -and $execResult.Error) { $ret = $fasle; } return $ret; } # Include File: [\Includes\Format-Table-Smarty.ps1] function Format-Table-Smarty { $arr = (@($Input) | % { [PSCustomObject]$_} | Format-Table -AutoSize | Out-String -Width 2048).Split(@([char]13, [char]10)) | ? { "$_".Length -gt 0 }; if (-not $arr) { return; } [string]::Join([Environment]::NewLine, $arr); } # Include File: [\Includes\Get-7z-Exe-FullPath-for-Windows.ps1] function Get-Mini7z-Exe-FullPath-for-Windows() { $algorithm="SHA512" $ret = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "7z-mini-x86" "7zr.exe"; $isOk = Download-File-FailFree-and-Cached $ret @("https://www.7-zip.org/a/7zr.exe", "https://sourceforge.net/projects/p7zz-repack/files/windows/7zr.exe/download") return (IIF $isOk $ret $null); } function Get-Mini7z-Exe-FullPath-for-Windows-Prev() { $algorithm="SHA512" $ret = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "7z-mini-x86" "7zr.exe"; if ((Is-File-Not-Empty "$ret") -and (Is-File-Not-Empty "$ret.$algorithm")) { $hashActual = Get-Smarty-FileHash "$ret" $algorithm $hashExpected = Get-Content -Path "$ret.$algorithm" if ($hashActual -eq $hashExpected -and "$hashActual" -ne "") { return $ret } } else { $isOk = Download-File-Managed "https://www.7-zip.org/a/7zr.exe" $ret if ($isOk) { $hashActual = Get-Smarty-FileHash "$ret" $algorithm echo "$hashActual" > "$($ret).$algorithm" return $ret; } } return $null } # Include File: [\Includes\Get-Aria2c-Exe-FullPath-for-Windows.ps1] # arch: x86|x64|arm64|Xp function Get-Aria2c-Exe-FullPath-for-Windows([string] $arch) { $linkXp="https://github.com/q3aql/aria2-static-builds/releases/download/v1.19.2/aria2-1.19.2-win-xp-build1.7z" $linkX86="https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-32bit-build1.zip" $linkX64="https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-64bit-build1.zip" if (-not $arch) { $currentArch = Get-CPU-Architecture-Suffix-for-Windows; if ($currentArch -eq "arm64") { if (Is-Intel-Emulation-Available 32) { $arch="x86"; } if (Is-Intel-Emulation-Available 64) { $arch="x64"; } } else { $arch=$currentArch; } if (([System.Environment]::OSVersion.Version.Major) -eq 5) { $arch="Xp"; } } $link = Get-Variable -Name "Link$arch" -Scope Local -ValueOnly # $link="$($"Link$arch")" # return "Not Implemented"; $archiveFileOnly="aria2c-$arch.$([System.IO.Path]::GetExtension($link).Trim([char]46))" $downloadFolder = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "aria2-setup" $archiveFullName = Combine-Path $downloadFolder $archiveFileOnly $plainFolder = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "aria2-$arch" $ret = Combine-Path "$plainFolder" "aria2c.exe" Troubleshoot-Info "Download Link for [$arch] : $link" Troubleshoot-Info "archiveFullName for [$arch] : $archiveFullName" Troubleshoot-Info "plainFolder for [$arch] : $plainFolder" $algorithm="SHA512" if ((Is-File-Not-Empty "$ret") -and (Is-File-Not-Empty "$ret.$algorithm")) { $hashActual = Get-Smarty-FileHash "$ret" $algorithm $hashExpected = Get-Content -Path "$ret.$algorithm" if ($hashActual -eq $hashExpected -and "$hashActual" -ne "") { return $ret; } } else { $isDownloadOk = Download-File-Managed "$link" "$archiveFullName" | Select -Last 1 if (-not $isDownloadOk) { Write-Host "Error downloading $link" -ForeGroundColor Red; } else { Troubleshoot-Info "Starting extract of '$archiveFullName'" $isExtractOk = ExtractArchiveByDefault7zFull "$archiveFullName" "$plainFolder" "e" | Select -Last 1 Troubleshoot-Info "isExtractOk: $isExtractOk ($archiveFullName)" if (-not $isExtractOk) { Write-Host "Error extracting $archiveFullName" -ForeGroundColor Red; } else { $hashActual = Get-Smarty-FileHash "$ret" $algorithm echo "$hashActual" > "$($ret).$algorithm" return $ret; } } } return $null; } <# https://github.com/q3aql/aria2-static-builds/releases/download/v1.19.2/aria2-1.19.2-win-xp-build1.7z https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-32bit-build1.zip https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-64bit-build1.zip #> # Include File: [\Includes\Get-CPU-Architecture-Suffix-for-Windows.ps1] # x86 (0), MIPS (1), Alpha (2), PowerPC (3), ARM (5), ia64 (6) Itanium-based systems, x64 (9), ARM64 (12) function Get-CPU-Architecture-Suffix-for-Windows-Implementation() { # on multiple sockets x64 $proc = Select-WMI-Objects "Win32_Processor"; $a = ($proc | Select -First 1).Architecture if ($a -eq 0) { return "x86" }; if ($a -eq 1) { return "mips" }; if ($a -eq 2) { return "alpha" }; if ($a -eq 3) { return "powerpc" }; if ($a -eq 5) { return "arm" }; if ($a -eq 6) { return "ia64" }; if ($a -eq 9) { # Is 32-bit system on 64-bit CPU? # OSArchitecture: "ARM 64-bit Processor", "32-bit", "64-bit" $os = Select-WMI-Objects "Win32_OperatingSystem"; $osArchitecture = ($os | Select -First 1).OSArchitecture if ($osArchitecture -like "*32-bit*") { return "x86"; } return "x64" }; if ($a -eq 12) { return "arm64" }; return ""; } function Get-CPU-Architecture-Suffix-for-Windows() { if ($Global:CPUArchitectureSuffixforWindows -eq $null) { $Global:CPUArchitectureSuffixforWindows = Get-CPU-Architecture-Suffix-for-Windows-Implementation; } return $Global:CPUArchitectureSuffixforWindows } # Include File: [\Includes\Get-Cpu-Name.ps1] function Get-Cpu-Name-Implementation { $platform = Get-Os-Platform if ($platform -eq "Windows") { $proc = Select-WMI-Objects "Win32_Processor" | Select -First 1; return "$($proc.Name)".Trim() } if ($platform -eq "MacOS") { return (& sysctl "-n" "machdep.cpu.brand_string" | Out-String-And-TrimEnd) } if ($platform -eq "Linux") { # TODO: Replace grep, awk, sed by NET $shell="cat /proc/cpuinfo | grep -E '^(model name|Hardware)' | awk -F':' 'NR==1 {print `$2}' | sed -e 's/^[[:space:]]*//'" $ret = "$(& bash -c "$shell" | Out-String-And-TrimEnd)" if (-not $ret) { $parts = @( (Get-Nix-Uname-Value "-m"), "$(& bash -c "getconf LONG_BIT" | Out-String-And-TrimEnd) bit" ); $ret = ($parts | where { "$_" }) -join ", " } return $ret } $ret = $null; try { $ret = Get-Nix-Uname-Value "-m"; } catch {} if ($ret) { return "$ret"; } return "Unknown" } function Get-Cpu-Name { [OutputType([string])] param() if (-not $Global:_Cpu_Name) { $Global:_Cpu_Name = "$(Get-Cpu-Name-Implementation)"; } return $Global:_Cpu_Name; } # Include File: [\Includes\Get-Folder-Size.ps1] function Get-Folder-Size([string] $folder) { if (Test-Path "$folder" -PathType Container) { $subFolderItems = Get-ChildItem "$folder" -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum return $subFolderItems.sum; } } # Include File: [\Includes\Get-Full7z-Exe-FullPath-for-Windows.ps1] # arch: x86|x64|arm64 # version: 1604|2301 function Get-Full7z-Exe-FullPath-for-Windows([string] $arch, [string] $version = "2301") { if (-not $arch) { $currentArch = Get-CPU-Architecture-Suffix-for-Windows; $arch = "x86" if ($currentArch -eq "arm64") { $arch="arm64"; } if ($currentArch -eq "x64") { $arch="x64"; } # arm64 below 2201 is not supported if ($arch -eq "arm64" -and (([int] $version) -lt 2201)) { if (Is-Intel-Emulation-Available 32) { $arch="x86"; } if (Is-Intel-Emulation-Available 64) { $arch="x64"; } } # v9.2 available as x86 only if ((([int] $version) -eq 920)) { $arch="x86"; } } # $suffix="-$arch"; if ($suffix -eq "-x86") { $suffix=""; } # $link="https://www.7-zip.org/a/7z$($version)$($suffix).exe" $versionLinks = $Full7zLinksMetadata_onWindows | where { "$($_.Ver)" -eq "$version" } | Select -First 1 $archLinks = $versionLinks."$($arch)Links" if (-not $archLinks) { TroubleShoot-Info "ERROR. Unknown links for full 7z v$($version) arch $arch" } $archiveFileOnly="7z-$version-$arch.exe" $downloadFolder = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "7z-Full-Setup" $archiveFullName = Combine-Path $downloadFolder $archiveFileOnly $plainFolder = Combine-Path "$(Get-PS1-Repo-Downloads-Folder)" "7z-Full-$arch-$version" $ret = Combine-Path "$plainFolder" "7z.exe" $algorithm="SHA512" if ((Is-File-Not-Empty "$ret") -and (Is-File-Not-Empty "$ret.$algorithm")) { $hashActual = Get-Smarty-FileHash "$ret" $algorithm $hashExpected = Get-Content -Path "$ret.$algorithm" if ($hashActual -eq $hashExpected -and "$hashActual" -ne "") { return $ret; } } else { $isDownloadOk = Download-File-FailFree $archiveFullName $archLinks | Select -Last 1 if (-not $isDownloadOk) { Write-Host "Error downloading any link of [$archLinks]" -ForeGroundColor Red; return $null; } $isExtractOk = ExtractArchiveBy7zMini "$archiveFullName" "$plainFolder" | Select -Last 1 popd if (-not $isExtractOk) { Write-Host "Error extracting $archiveFullName" -ForeGroundColor Red; } else { $hashActual = Get-Smarty-FileHash "$ret" $algorithm echo "$hashActual" > "$($ret).$algorithm" return $ret; } } return $null; } function ExtractArchiveBy7zMini([string] $fromArchive, [string] $toDirectory) { New-Item -Path "$($toDirectory)" -ItemType Directory -Force -EA SilentlyContinue | Out-Null pushd "$($toDirectory)" $mini7z = "$(Get-Mini7z-Exe-FullPath-for-Windows)" # "-o`"$plainFolder`"" $commandLine=@("x", "-y", "$fromArchive") Troubleshoot-Info "fromArchive: '$fromArchive'; commandLine: '$commandLine'" # ok on pwsh and powersheel & "$mini7z" @commandLine $isExtractOk = $?; return $isExtractOk; } function ExtractArchiveByDefault7zFull([string] $fromArchive, [string] $toDirectory, $extractCommand = "x") { New-Item -Path "$($toDirectory)" -ItemType Directory -Force -EA SilentlyContinue | Out-Null # pushd "$($toDirectory)" $full7zExe = "$(Get-Full7z-Exe-FullPath-for-Windows)" Troubleshoot-Info "`"$fromArchive`" $([char]8594) " -Highlight "`"$($toDirectory)`"" " by `"$full7zExe`"" & "$full7zExe" @("$extractCommand", "-y", "-o`"$($toDirectory)`"", "$fromArchive") $isExtractOk = $?; return $isExtractOk; } <# https://www.7-zip.org/a/7z2301-arm64.exe https://www.7-zip.org/a/7z2301-x64.exe https://www.7-zip.org/a/7z2301.exe https://www.7-zip.org/a/7z2201-arm64.exe https://www.7-zip.org/a/7z2201-x64.exe https://www.7-zip.org/a/7z2201.exe https://www.7-zip.org/a/7z1900-x64.exe https://www.7-zip.org/a/7z1900.exe https://www.7-zip.org/a/7z1604-x64.exe https://www.7-zip.org/a/7z1604.exe https://www.7-zip.org/a/7z920.exe https://www.7-zip.org/a/7z920-arm.exe https://www.7-zip.org/a/7zr.exe #> # Include File: [\Includes\Get-Github-Latest-Release.ps1] function Get-Github-Latest-Release([string] $owner, [string] $repo) { $queryLatest="https://api.github.com/repos/$owner/$repo/releases/latest" # "tag_name": "v3.227.2", $qyeryResultFullName = Combine-Path (Get-PS1-Repo-Downloads-Folder) "Queries" "Github Latest Release" "$(([System.Guid]::NewGuid()).ToString("N")).json" $isOk = Download-File-FailFree $qyeryResultFullName @($queryLatest) if (-not $isOk) { Write-Host "Error query latest version for '$owner/$repo'" -ForegroundColor Red } $jsonResult = Get-Content $qyeryResultFullName | ConvertFrom-Json $ret = $jsonResult.tag_name; if (-not $ret) { Write-Host "Maflormed query latest version for '$owner/$repo'. Missing property 'tag_name'" -ForegroundColor Red } else { Remove-Item $qyeryResultFullName -Force } return $ret; } # Include File: [\Includes\Get-Github-Releases.ps1] function Get-Github-Releases([string] $owner, [string] $repo) { $url="https://api.github.com/repos/$owner/$repo/releases?per_page=128" # https://api.github.com/repos/microsoft/azure-pipelines-agent/releases?per_page=128 $qyeryResultFullName = Combine-Path (Get-PS1-Repo-Downloads-Folder) "Queries" "Github Releases" "$(([System.Guid]::NewGuid()).ToString("N")).json" $isOk = Download-File-FailFree $qyeryResultFullName @($url) if (-not $isOk) { Write-Host "Error query release list for '$owner/$repo'" -ForegroundColor Red } $jsonResult = Get-Content $qyeryResultFullName | ConvertFrom-Json <# "tag_name":"v3.230.0", "target_commitish":"6ee2a6be8f5e0cccac6079e4fb42b5fe9f8de04e", "name":"v3.230.0", "draft":false, "prerelease":true, "created_at":"2023-11-03T02:33:23Z", "published_at":"2023-11-07T11:17:01Z", "tarball_url":"https://api.github.com/repos/microsoft/azure-pipelines-agent/tarball/v3.230.0", "zipball_url":"https://api.github.com/repos/microsoft/azure-pipelines-agent/zipball/v3.230.0", "body":"## Features\r\n - Add `AllowWorkDirectoryRepositories` knob (#4423)\r\n - Update process handler (#4425)\r\n - Check task deprecation (#4458)\r\n - Enable Domains for Pipeline Artifact (#4460)\r\n - dedupStoreHttpClient honors redirect timeout from client settings and update ADO lib to 0.5.227-262a3469 (#4504)\r\n\r\n## Bugs\r\n - Detect the OS and switch node runner if not supported for Node20 (#4470)\r\n - Revert \"Enable Domains for Pipeline Artifact\" (#4477)\r\n - Add capability to publish/download pipeline artifact in a different domain. (#4482)\r\n - Mount Workspace (#4483)\r\n\r\n## Misc\r\n\r\n\r\n\r\n## Agent Downloads\r\n\r\n| | Package | SHA-256 |\r\n| -------------- | ------- | ------- |\r\n| Windows x64 | [vsts-agent-win-x64-3.230.0.zip](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-win-x64-3.230.0.zip) | cbb21ea2ec0b64663c35d13f204e215cfe41cf2e3c8efff7c228fdab344d00de |\r\n| Windows x86 | [vsts-agent-win-x86-3.230.0.zip](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-win-x86-3.230.0.zip) | 7182a054b1f58c5d104f7b581fe00765c32f1bd544dc2bcc423d0159929f4692 |\r\n| macOS x64 | [vsts-agent-osx-x64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-osx-x64-3.230.0.tar.gz) | 988234fe3a1bbc6f79c3f6d94d70ea1908f2395ce6b685118d1dae983f03479e |\r\n| macOS ARM64 | [vsts-agent-osx-arm64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-osx-arm64-3.230.0.tar.gz) | 82f670482ffb45de2e533687c5eefa9506cbe0686edaa6a3c02487887729101c |\r\n| Linux x64 | [vsts-agent-linux-x64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-linux-x64-3.230.0.tar.gz) | bc222ec99ff675c1035efd0a086cea02adb5847ae7df8ee36e89db14aee8673d |\r\n| Linux ARM | [vsts-agent-linux-arm-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-linux-arm-3.230.0.tar.gz) | f399e0ddceb10f09cd768c29e31fa51eb05c51c092e2392282e63795729f6a39 |\r\n| Linux ARM64 | [vsts-agent-linux-arm64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-linux-arm64-3.230.0.tar.gz) | 3c6fa98e26c7d8b19e8a35ca5b45a32122088a3bc12e817e7ccdead303893789 |\r\n| Linux musl x64 | [vsts-agent-linux-musl-x64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/vsts-agent-linux-musl-x64-3.230.0.tar.gz) | 3461bef5756e452b920779b1f163cd194fa1971267acd582c2ad4870b1f611c2 |\r\n\r\nAfter Download:\r\n\r\n## Windows x64\r\n\r\n``` bash\r\nC:\\> mkdir myagent && cd myagent\r\nC:\\myagent> Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory(\"$HOME\\Downloads\\vsts-agent-win-x64-3.230.0.zip\", \"$PWD\")\r\n```\r\n\r\n## Windows x86\r\n\r\n``` bash\r\nC:\\> mkdir myagent && cd myagent\r\nC:\\myagent> Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory(\"$HOME\\Downloads\\vsts-agent-win-x86-3.230.0.zip\", \"$PWD\")\r\n```\r\n\r\n## macOS x64\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-osx-x64-3.230.0.tar.gz\r\n```\r\n\r\n## macOS ARM64\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-osx-arm64-3.230.0.tar.gz\r\n```\r\n\r\n## Linux x64\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-linux-x64-3.230.0.tar.gz\r\n```\r\n\r\n## Linux ARM\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-linux-arm-3.230.0.tar.gz\r\n```\r\n\r\n## Linux ARM64\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-linux-arm64-3.230.0.tar.gz\r\n```\r\n\r\n## Alpine x64\r\n\r\n``` bash\r\n~/$ mkdir myagent && cd myagent\r\n~/myagent$ tar xzf ~/Downloads/vsts-agent-linux-musl-x64-3.230.0.tar.gz\r\n```\r\n\r\n***Note:*** Node 6 does not exist for Alpine.\r\n\r\n## Alternate Agent Downloads\r\n\r\nAlternate packages below do not include Node 6 and are only suitable for users who do not use Node 6 dependent tasks. \r\nSee [notes](docs/node6.md) on Node version support for more details.\r\n\r\n| | Package | SHA-256 |\r\n| ----------- | ------- | ------- |\r\n| Windows x64 | [pipelines-agent-win-x64-3.230.0.zip](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-win-x64-3.230.0.zip) | f5bbae6dad8c39ea809db9b04abbcf3add37962d67ef9c67245a09fb536d38ca |\r\n| Windows x86 | [pipelines-agent-win-x86-3.230.0.zip](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-win-x86-3.230.0.zip) | 00d5f1776767ead3e70036f63cdbd38a007b7d971c287a4d24d7346f4d3715a6 |\r\n| macOS x64 | [pipelines-agent-osx-x64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-osx-x64-3.230.0.tar.gz) | e6e602c6664414b8a9b27a2df73511156d32a6bc76f8b4bb69aa960767aa9684 |\r\n| macOS ARM64 | [pipelines-agent-osx-arm64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-osx-x64-3.230.0.tar.gz) | a00182572b1be649fe6836336bde3d4d3f79ceee42822fe44707afa9950b2232 |\r\n| Linux x64 | [pipelines-agent-linux-x64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-linux-x64-3.230.0.tar.gz) | d46581abbf0eb5c3aef534825b51f92ade9d86a5b089b9489e84387070366d1b |\r\n| Linux ARM | [pipelines-agent-linux-arm-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-linux-arm-3.230.0.tar.gz) | 1dc871562bd6266567f7accced8d4a9ec3b4b85139891cf563a8fa305968ad40 |\r\n| Linux ARM64 | [pipelines-agent-linux-arm64-3.230.0.tar.gz](https://vstsagentpackage.azureedge.net/agent/3.230.0/pipelines-agent-linux-arm64-3.230.0.tar.gz) | 4ce243af0a09d5be2a6194b94d98c11fc323607b083ec5dcf3893bf67abb2dda |\r\n" #> $ret=@() foreach($release in $jsonResult) { $ret += New-Object PSObject -Property @{ Tag = $release.tag_name Commit = $release.target_commitish Name = $release.name IsDraft = [bool] $release.draft IsPrerelease = [bool] $release.prerelease CreatedAt = $release.created_at PublishedAt = $release.published_at TarballUrl = $release.tarball_url ZipballUrl = $release.zipball_url } } if (-not ($ret | Select -First 1)) { Write-Host "Empty release list for '$owner/$repo'" -ForegroundColor Red } else { Remove-Item $qyeryResultFullName -Force } return $ret | where { -not ($_.IsDraft) }; } # Include File: [\Includes\Get-Installed-VC-Runtimes.ps1] function Get-Installed-VC-Runtimes() { $softwareFilter = { $_.name -like "*Visual C++*" -and $_.vendor -like "*Microsoft*" -and ($_.name -like "*Runtime*" -or $_.name -like "*Redistributable*")} return Get-Speedy-Software-Product-List | where $softwareFilter } # Include File: [\Includes\Get-Memory-Info.ps1] function Get-Memory-Info { [OutputType([object])] param() $platform = Get-Os-Platform if ($platform -eq "Windows") { $os = Select-WMI-Objects "Win32_OperatingSystem"; $mem=($os | Where { $_.FreePhysicalMemory } | Select FreePhysicalMemory,TotalVisibleMemorySize -First 1); $total=[int] ($mem.TotalVisibleMemorySize / 1024); $free=[int] ($mem.FreePhysicalMemory / 1024); $wmiSwap = @(Select-WMI-Objects "Win32_PageFileUsage") $swapCurrent = $wmiSwap | Measure-Object -property CurrentUsage -sum | % { $_.Sum } | Select -First 1 $swapPeak = $wmiSwap | Measure-Object -property PeakUsage -sum | % { $_.Sum } | Select -First 1 $swapAllocated = $wmiSwap | Measure-Object -property AllocatedBaseSize -sum | % { $_.Sum } | Select -First 1 if ($swapAllocated) { $customDescription = ". Swap Usage: $(FormatNullableNumeric $swapCurrent) (peak $(FormatNullableNumeric $swapPeak)) of $(FormatNullableNumeric $swapAllocated) Mb" } } if ($platform -eq "MacOS") { $total=[long] (& sysctl -n hw.memsize | Out-String).TrimEnd(@([char]13,[char]10)) $total=[int] ($total/1024/1024) $free=[long] (& vm_stat | grep "Pages free" | awk -v OFMT="%.0f" '{print (4 * $NF / 1024)}' | Out-String-And-TrimEnd) $inactive=[long] (& vm_stat | grep "Pages inactive" | awk -v OFMT="%.0f" '{print (4 * $NF / 1024)}' | Out-String-And-TrimEnd) $free = [int]$free + [int]$inactive; # Write-Host "Mem Total: $total, Free: $free" } if ($platform -eq "Linux") { # total: $2, $used: $3, shared: $5. free = total-(used+shared) $total=[int] (& free -m | awk 'NR==2 {print $2}' | Out-String-And-TrimEnd) $used =[int] (& free -m | awk 'NR==2 {print $3 + $5}' | Out-String-And-TrimEnd) $free=$total-$used $swapAllocated = [int] (& free -m | awk '$1 ~ /^[S|s]wap/ {print $2}' | Out-String-And-TrimEnd) $swapCurrent = [int] (& free -m | awk '$1 ~ /^[S|s]wap/ {print $3}' | Out-String-And-TrimEnd) if ($swapAllocated) { $customDescription = ". Swap Usage: $(FormatNullableNumeric $swapCurrent) of $(FormatNullableNumeric $swapAllocated) Mb" } } if ($total) { $info="Total RAM: $($total.ToString("n0")) MB. Free: $($free.ToString("n0")) MB ($([Math]::Round($free * 100 / $total, 1))%)$customDescription"; $ret = @{ Total=$total; Free=$free; Description=$info; } if ($swapAllocated) { $ret["SwapAllocated"] = $swapAllocated; $ret["SwapCurrent"] = $swapCurrent; } return $ret; } <# .OUTPUTS Object with 3 properties: [int] Total, [int] Free, [string] Description #> } function FormatNullableNumeric($n, $fractionalDigits = 0) { try { $num = [int] $n } catch { $num = 0 } return $num.ToString("n$fractionalDigits"); } # Include File: [\Includes\Get-Nix-Uname-Value.ps1] # Linux/Darwin/FreeBSD, Error on Windows function Get-Nix-Uname-Value { param([string] $arg) return (& uname "$arg" | Out-String-And-TrimEnd) } # Include File: [\Includes\Get-Os-Platform.ps1] # Returns Linux/Windows/Mac/FreeBSD function Get-Os-Platform { [OutputType([string])] param() $platform = [System.Environment]::OSVersion.Platform; if ($platform -like "Win*") { return "Windows"; } $nixUnameSystem = Get-Nix-Uname-Value "-s" if ($nixUnameSystem -eq "Linux") { return "Linux"; } if ($nixUnameSystem -eq "Darwin") { return "MacOS"; } if ($nixUnameSystem -eq "FreeBSD") { return "FreeBSD"; } return "Unknown" <# .OUTPUTS One of the following values: "Linux", "Windows", "MacOS", "FreeBSD", "Unknown" #> } # Include File: [\Includes\Get-PS1-Repo-Downloads-Folder.ps1] function Get-PS1-Repo-Downloads-Folder() { return (GetPersistentTempFolder "PS1_REPO_DOWNLOAD_FOLDER" "PS1 Repo Downloads"); } function GetPersistentTempFolder([string] $envPrefix, [string] $pathSuffix) { foreach($pair in (gci env:$($envPrefix)* | sort-object name)) { $explicitRet = "$($pair.Value)"; if ($explicitRet) { New-Item -Path $explicitRet -ItemType Directory -Force -EA SilentlyContinue | Out-null $isExplicit = Test-Path -Path $explicitRet -PathType Container -EA SilentlyContinue; if ($isExplicit) { return "$explicitRet"; } } } If (Get-Os-Platform -eq "Windows") { $ret = "$($ENV:TEMP)" } else { $ret = "$($ENV:TMPDIR)"; if (-not $ret) { $ret = "/tmp" }}; $is1 = Test-Path -Path $ret -PathType Container -EA SilentlyContinue if (-not $is1) { try { New-Item -Path $ret -ItemType Directory -Force -EA SilentlyContinue | Out-null } catch { } $is2 = Test-Path -Path $ret -PathType Container -EA SilentlyContinue if (-not $is2) { $ret="" } } if (-not $ret) { $ret="$($ENV:LOCALAPPDATA)"; if ("$ret" -eq "") { $ret="$($ENV:APPDATA)"; }; if ("$ret" -eq "") { $ret="$($ENV:HOME)/.cache"; }; } $separator="$([System.IO.Path]::DirectorySeparatorChar)" if (-not ($ret -like "*\Temp" -or $ret -like "*/.cache")) { $ret += "$($separator)Temp"; } $ret += "$($separator)$pathSuffix"; return $ret; } # Include File: [\Includes\Get-Random-Free-Port.ps1] function Get-Random-Free-Port() { $tcpListener = New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Loopback <# ::Any? #>, 0) $tcpListener.Start() $port = ([System.Net.IPEndPoint] $tcpListener.LocalEndpoint).Port; $tcpListener.Stop() return $port; } # Get-Random-Free-Port # Include File: [\Includes\Get-Smarty-FileHash.ps1] # $algorithm: MD5|SHA1|SHA256|SHA384|SHA512 function Get-Smarty-FileHash([string] $fileName, [string] $algorithm = "MD5") { $fileExists = (Test-Path $fileName -PathType Leaf) if (-not $fileExists) { return $null; } $hashAlg = [System.Security.Cryptography.HashAlgorithm]::Create($algorithm) try { $fileStream = new-object System.IO.FileStream($fileName, "Open", "Read", "ReadWrite") $bytes = $hashAlg.ComputeHash($fileStream); # $ret=""; # foreach($b in $bytes) { $ret = "$($ret)$($b.ToString("X2"))"; } $ret = "$($bytes | % { $_.ToString("X2") })".Replace(" ","") return $ret; } finally { if ($fileStream) { $fileStream.Dispose(); } } return $null; } # Include File: [\Includes\Get-Smarty-FolderHash.ps1] # Get-Smarty-FileHash([string] $fileName, [string] $algorithm = "MD5") { function Get-Smarty-FolderHash([string] $rootFolder, [string] $algorithm = "MD5", [bool] $includeDates = $false) { $startAt = [System.Diagnostics.Stopwatch]::StartNew() $folderExists = (Test-Path $rootFolder -PathType Container) if (-not $folderExists) { return $null; } $colItems = Get-ChildItem $rootFolder -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Sort-Object -Property FullName $summary=New-Object System.Collections.ArrayList; $filesCount = 0; foreach ($i in $colItems) { $filesCount++; $fileHash = Get-Smarty-FileHash $i.FullName $algorithm; if ($includeDates) { foreach($date in $i.CreationTimeUtc, $i.LastWriteTimeUtc) { $fileHash += $date.ToString("s") } } $_=$summary.Add($fileHash) } $utf8 = new-object System.Text.UTF8Encoding($false) $summaryBytes = $utf8.GetBytes("$summary") $hashAlg = [System.Security.Cryptography.HashAlgorithm]::Create($algorithm) $retBytes = $hashAlg.ComputeHash($summaryBytes); $ret = "$($retBytes | % { $_.ToString("X2") })".Replace(" ","") TroubleShoot-Info "Hash $algorithm for folder " -Highlight $rootFolder " (" -Highlight $filesCount " files) took " -Highlight "$($startAt.ElapsedMilliseconds.ToString("n0"))" " ms" return $ret; } # Include File: [\Includes\Get-Speedy-Software-Product-List.ps1] function Get-Speedy-Software-Product-List() { $ret=@(); $origins=@( @{ Path="HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="" }, @{ Path="HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="" }, @{ Path="HKCU:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="X86" }, @{ Path="HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="X86" }, @{ Path="HKCU:\Software\WowAA32Node\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="ARM32" }, @{ Path="HKLM:\Software\WowAA32Node\Microsoft\Windows\CurrentVersion\Uninstall"; Origin="ARM32" } ); foreach($origin in $origins) { $keys = Get-ChildItem $origin.Path -EA SilentlyContinue if ($keys) { foreach($key in $keys) { # Write-Host "$($key.Name): $key" $ret += New-Object PSObject -Property @{ Name = "$($key.GetValue('DisplayName'))".Trim() Vendor = "$($key.GetValue('Publisher'))".Trim() Version = "$($key.GetValue('DisplayVersion'))".Trim() IdentifyingNumber = [System.IO.Path]::GetFileName("$($key.Name)".Trim()) Origin = $origin.Origin } } } } return $ret | where { "$($_.Name)" -ne "" -and "$($_.Vendor)" -ne "" } | Sort-Object Vendor, Name, Version, Origin -Unique } # Get-Speedy-Software-Product-List | ft # $localDbList = Get-Speedy-Software-Product-List | ? { $_.Name -match "LocalDB" -and $_.Vendor -match "Microsoft" } # Include File: [\Includes\Get-System-Drive.ps1] function Get-System-Drive() { $ret = "$($Env:SystemDrive)"; $c = "$([System.IO.Path]::DirectorySeparatorChar)"; if (-not ($ret.EndsWith($c))) { $ret += $c; }; return $ret; } # Include File: [\Includes\Get-Windows-Power-Plans.ps1] function Get-Windows-Power-Plans() { if ((Get-Os-Platform) -ne "Windows") { return @(); } $rawOutput = (& powercfg.exe "-l") | Out-String # Write-Host $rawOutput $lines = "$rawOutput".Split([char]13,[char]10) | ? { "$_" -match ":" } | % { @(@("$_".Split(":")) | Select -Skip 1) -join " " } | % { "$_".Trim() } foreach($line in $lines) { $guid = "$line".Split(" ") | % { "$_".Trim() } | ? { "$_".Length -gt 0 } | Select -First 1 $pSpace = "$line".IndexOf(" "); if ($pSpace -gt 1) { $name = "$line".SubString($pSpace).Trim() $isActive = "$line".EndsWith("*") if ($isActive) { $name = "$name".TrimEnd("*"); } $name = "$name".Trim().TrimStart("(").TrimEnd(")") [PsCustomObject] @{ "Id" = $guid; Name = $name; IsActive = $isActive }; } } } function Get-Windows-Active-Power-Plan() { Get-Windows-Power-Plans | ? { $_.IsActive } | Select -First 1 } function Get-Windows-Active-Power-Plan-Name() { (Get-Windows-Active-Power-Plan).Name } function Set-Windows-Power-Plan-by-Name([string] $newPowerPlanName) { $allPlans = @(Get-Windows-Power-Plans) $newPlan = $allPlans | ? { $_.Name -eq $newPowerPlanName } | Select -First 1 if ($newPlan) { & powercfg.exe @("/s", "$($newPlan.Id)") | Out-Host } else { Write-Host "Warning! Unable to set power plan '$newPowerPlanName'. Not Found." -ForeGroundColor DarkRed } } # Get-Windows-Active-Power-Plan-Name; # Get-Windows-Active-Power-Plan # Get-Windows-Power-Plans | ft * # Set-Windows-Power-Plan-by-Name "High Performance" # Set-Windows-Power-Plan-by-Name "ZXC PPlan" # Set-Windows-Power-Plan-by-Name "Balanced" # Include File: [\Includes\Has-Cmd.ps1] function Has-Cmd { param([string] $arg) if ("$arg" -eq "") { return $false; } [bool] (Get-Command "$arg" -ErrorAction SilentlyContinue) } function Select-WMI-Objects([string] $class) { if (Has-Cmd "Get-CIMInstance") { $ret = Get-CIMInstance $class; } elseif (Has-Cmd "Get-WmiObject") { $ret = Get-WmiObject $class; } if (-not $ret) { Write-Host "Warning ! Missing neither Get-CIMInstance nor Get-WmiObject" -ForegroundColor DarkRed; } return $ret; } # Include File: [\Includes\IIf.ps1] # function IIf([bool] $flag, $trueResult, $falseResult) { # if ($flag) { return $trueResult; } else { return $falseResult; } # } # https://stackoverflow.com/a/54702474 Function IIf($If, $Then, $Else) { If ($If) { If ($Then -is [scriptblock]) { ForEach-Object -InputObject $If -Process $Then } Else { $Then } } Else { If ($Else -is [scriptblock]) { ForEach-Object -InputObject $If -Process $Else } Else { $Else } } } # Include File: [\Includes\Is-BuildServer.ps1] function Is-BuildServer() { return "$(Try-BuildServerType)" -ne ""; } function Try-BuildServerType() { $simpleKeys = @( "APPVEYOR", "bamboo_planKey", "BITBUCKET_COMMIT", "BITRISE_IO", "BUDDY_WORKSPACE_ID", "BUILDKITE", "CIRCLECI", "CIRRUS_CI", "CODEBUILD_BUILD_ARN" "DRONE", "DSARI", "GITHUB_ACTIONS", "GITLAB_CI", "GO_PIPELINE_LABEL", "HUDSON_URL", "MAGNUM", "SAILCI", "SEMAPHORE", "SHIPPABLE", "TDDIUM", "STRIDER", "TDDIUM", "TEAMCITY_VERSION", "TF_BUILD", "TRAVIS"); foreach($varName in $simpleKeys) { $val=[Environment]::GetEnvironmentVariable($varName); if ("$val" -ne "" -and $val -ne "False") { return $varName; } } return $null; } # Write-Host "Try-BuildServerType: [$(Try-BuildServerType)], Is-BuildServer: $(Is-BuildServer)" # Include File: [\Includes\Is-File-Not-Empty.ps1] function Is-File-Not-Empty([string] $fileName) { try { $fi = new-object System.IO.FileInfo($fileName); return $fi.Length -gt 0; } catch {}; return $fasle; } # Include File: [\Includes\Is-Intel-Emulation-Available.ps1] # On non-arm returns $false function Is-Intel-Emulation-Available([int] $bitCount <# 32|64 #> = 64) { $systemRoot="$($ENV:SystemRoot)" $fileOnly = if ($bitCount -eq 64) { "xtajit64.dll" } else { "xtajit.dll" }; $fullName=Combine-Path $systemRoot "System32" $fileOnly; return [bool] (Is-File-Not-Empty $fullName) } # Include File: [\Includes\Is-Vc-Runtime-Installed.ps1] function Is-Vc-Runtime-Installed([int] $major, [string] $arch) { $vcList = Get-Installed-VC-Runtimes # Does not support x86 v8 (2005) on x86 Windows $found = $vcList | where { ($_.Version.StartsWith($major.ToString("0")+".")) -and ($_.Name.ToLower().IndexOf($arch.ToLower()) -ge 0 -or $_.Origin -eq $arch) } # return $found.Length -gt 0; v6+ # return @($found).Length -gt 0; v5+ return "$($found)" -ne ""; # v2+ } # Include File: [\Includes\Lazy-Aggregator.ps1] function Update-Lazy-Aggregator([string] $storageFileName, [string] $keyName, [HashTable] $properties) { # TODO: } # Include File: [\Includes\Measure-Action.ps1] function Measure-Action { Param( [string] $Title, [ScriptBlock] $Action ) $startAt = [System.Diagnostics.Stopwatch]::StartNew() try { Invoke-Command -ScriptBlock $action; $err=$null; } catch { $err=$_.Exception; } $msec = $startAt.ElapsedMilliseconds; $ea = $ErrorActionPreference $ErrorActionPreference = "SilentlyContinue" if (-not $err) { Write-Host "Success. " -ForeGroundColor Green -NoNewLine; Write-Host "'$title' took $($msec.ToString("n0")) ms" } else { # Write-Host $err.GetType() Write-Host "Fail. $($err.Message)" -ForeGroundColor Red -NoNewLine; Write-Host " '$title' took $($msec.ToString("n0")) ms" } $ErrorActionPreference=$ea } # Include File: [\Includes\Out-String-And-TrimEnd.ps1] Function Out-String-And-TrimEnd { Param ([int] $Skip=0, [int] $Take=2000000000) Begin { $n=0; $list = New-Object System.Collections.Generic.List[System.Object]} Process { $n++; if (-not ($n -le $Skip -or $n -gt ($Skip+$Take))) { $list.Add("$_"); } } End { return [string]::join([System.Environment]::NewLine, $list.ToArray()).TrimEnd(@([char]13,[char]10)) } } # Include File: [\Includes\Remove-Windows-Service-If-Exists.ps1] function Remove-Windows-Service-If-Exists([string] $serviceName, [string] $humanName) { # Delete Existing? $serviceStatus = [string](Get-Service -Name $serviceName -EA SilentlyContinue).Status # & sc.exe query "$serviceName" | out-null; $? if ($serviceStatus) { if ($serviceStatus -ne "Stopped") { Say "Stopping existing $humanName" & net.exe stop $serviceName } Say "Deleting existing $humanName" & sc.exe delete $serviceName } } # Remove-Windows-Service-If-Exists "PG$9_26_X86" "Postgres SQL Windows Service" # Include File: [\Includes\Reverse-Pipe.ps1] function Reverse-Pipe() { $copy=@($input); for($i = $copy.Length - 1; $i -ge 0; $i--) { $copy[$i] } } # $null | Reverse-Pipe # $() | Reverse-Pipe # @(42) | Reverse-Pipe # @(1,2,3,4,"42") | Reverse-Pipe # Include File: [\Includes\Say.ps1] function Say { # param( [string] $message ) if ($Global:_Say_Stopwatch -eq $null) { $Global:_Say_Stopwatch = [System.Diagnostics.Stopwatch]::StartNew(); } $milliSeconds=$Global:_Say_Stopwatch.ElapsedMilliseconds if ($milliSeconds -ge 3600000) { $format="HH:mm:ss"; } else { $format="mm:ss"; } $elapsed="[$((new-object System.DateTime(0)).AddMilliseconds($milliSeconds).ToString($format))]" if (-not (Is-Ansi-Supported)) { Write-Host "$($elapsed) " -NoNewline -ForegroundColor Magenta Write-Host "$args" -ForegroundColor Yellow } else { $esc = [char] 27; Write-Host "$esc[95;1m$($elapsed) " -NoNewline -ForegroundColor Magenta Write-Host "$esc[93;1m$esc[1m$($args)$($esc)[m" -ForegroundColor Yellow } } $Global:_Say_Stopwatch = [System.Diagnostics.Stopwatch]::StartNew() # https://ss64.com/nt/syntax-ansi.html function Is-Ansi-Supported() { if ((Get-Os-Platform) -ne "Windows") { return $true; } $buildServerType = Try-BuildServerType; if ("$buildServerType" -eq "GITHUB_ACTIONS" -or "$buildServerType" -eq "TF_BUILD") { return $true; } $rawReleaseId = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseId -EA SilentlyContinue | % {$_.ReleaseId} if ($rawReleaseId) { $releaseId = [int] $rawReleaseId; return ($releaseId -ge 1809); # 1909 } return $false; } function Get-Windows-Release-Id() { if ((Get-Os-Platform) -ne "Windows") { return $null; } $rawReleaseId = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseId -EA SilentlyContinue | % {$_.ReleaseId} if ($rawReleaseId) { $releaseId = [int] $rawReleaseId; return $releaseId; } return $null; } # Include File: [\Includes\Set-Property-Smarty.ps1] function Set-Property-Smarty( [object] $object, <# either [Hashtable] or [PSCustomObject] #> [string] $property, <# name of the property #> [object] $value ) { $GLOBAL:Set_Property_Smarty_Counter = $GLOBAL:Set_Property_Smarty_Counter + 1 if ($object -eq $null) { $object = [PSCustomObject]@{}; } # OR THROW ERROR if ($GLOBAL:DEBUG_Set_Property_Smarty) { Write-Host "[DEBUG $($GLOBAL:Set_Property_Smarty_Counter)] Argument `$object is $($object.GetType())"; $object | Get-Member | % {[PSCustomObject]$_} | format-table -Property "Name", "MemberType", "Definition" | out-host; } if ($object -is [pscustomobject]) { if ($GLOBAL:DEBUG_Set_Property_Smarty) { Write-Host "[DEBUG $($GLOBAL:Set_Property_Smarty_Counter)] arg is [PSCustomObject]"; } $hasProperty = ($null -ne ($object | Get-Member | ? { $_.Name -eq "$property" } | Select -First 1)) if ($hasProperty) { $object."$property" = $value; } else { $memberType = If ($value -is [ScriptBlock]) { "ScriptMethod"; } else { "NoteProperty"; } $__ = Add-Member -InputObject $object -MemberType $memberType -Name "$property" -Value $value } } elseif ($object -is [hashtable]) { if ($GLOBAL:DEBUG_Set_Property_Smarty) { Write-Host "[DEBUG $($GLOBAL:Set_Property_Smarty_Counter)] arg is [HashTable]"; } $object[$property] = $value; } else { Write-Host "Set-Property-Smarty accept only [HashTable] or [PSCustomObject] first argument `$object" -ForeGroundColor Red } if ($GLOBAL:DEBUG_Set_Property_Smarty) { Write-Host "[DEBUG $($GLOBAL:Set_Property_Smarty_Counter)] UPDATED `$object is $($object.GetType())"; $object | Get-Member | % {[PSCustomObject]$_} | format-table -Property "Name", "MemberType", "Definition" | out-host; } } function Test-Set-Property-Smarty() { # $GLOBAL:DEBUG_Set_Property_Smarty = $true Write-Host "TEST HASHTABLE" -ForegroundColor Magenta $ht = @{X=1;T="Yes"}; Set-Property-Smarty $ht "P" "Added"; $ht | ft | out-host Write-Host ""; Write-Host "TEST PSCustomObject" -ForegroundColor Magenta $ps = [PSCustomObject]@{X=1;T="Yes"}; Set-Property-Smarty $ps "M2" {"M2() is invoked "}; Set-Property-Smarty $ps "P2" "Added"; Set-Property-Smarty $ps "P3" "V3"; $ps | Get-Member | % {[PSCustomObject]$_} | format-table -Property "Name", "MemberType", "Definition" | out-host; Write-Host $ps Write-Host $ps.M2() } # Test-Set-Property-Smarty # Include File: [\Includes\Start-Stopwatch.ps1] function Start-Stopwatch() { $ret = [PSCustomObject] @{ StartAt = [System.Diagnostics.Stopwatch]::StartNew(); }; $ret | Add-Member -Force -MemberType ScriptMethod -name GetElapsed -value { $milliSeconds = $this.StartAt.ElapsedMilliseconds if ($milliSeconds -lt 9000) { return "{0:f2}" -f ($milliSeconds / [double] 1000); } if ($milliSeconds -lt 60000) { return "{0:f1}" -f ($milliSeconds / [double] 1000); } if ($milliSeconds -ge 3600000) { $format="HH:mm:ss"; } else { $format="mm:ss.f"; } return "$((new-object System.DateTime(0)).AddMilliseconds($milliSeconds).ToString($format))" } # legacy powershell does not override ToString properly $ret | Add-Member -Force -MemberType ScriptMethod -name ToString -value { $this.GetElapsed(); } return $ret; } <# $x = Start-Stopwatch; Sleep -Milliseconds 123; "[$($x.GetElapsed()) seconds]" #> # Include File: [\Includes\To-Boolean.ps1] function To-Boolean() { param([string] $name, [string] $value) if (($value -eq "True") -Or ($value -eq "On") -Or ($value -eq "1") -Or ("$value".ToLower().StartsWith("enable"))) { return $true; } if (("$value" -eq "") -Or ($value -eq "False") -Or ($value -eq "Off") -Or ($value -eq "0") -Or ("$value".ToLower().StartsWith("disable"))) { return $false; } Write-Host "Validation Error! Invalid $name parameter '$value'. Boolean parameter accept only True|False|On|Off|Enable|Disable|1|0" -ForegroundColor Red return $false; } # Include File: [\Includes\To-Sortable-Version-String.ps1] function To-Sortable-Version-String([string] $arg) { $ret = New-Object System.Text.StringBuilder; $numberBuffer = New-Object System.Text.StringBuilder; for($i=0; $i -lt $arg.Length; $i++) { $c = $arg.Substring($i, 1); if ($c -ge "0" -and $c -le "9") { $__ = $numberBuffer.Append($c) } else { if ($numberBuffer.Length -gt 0) { $__ = $ret.Append($numberBuffer.ToString().PadLeft(42,"0")); $numberBuffer.Length = 0; } $__ = $ret.Append($c) } } # same if ($numberBuffer.Length -gt 0) { $__ = $ret.Append($numberBuffer.ToString().PadLeft(42,"0")) } return $ret.ToString(); } function Test-Version-Sort() { @("PG-9.6.24", "PG-10.1", "PG-11.3", "PG-11.12", "PG-16.4") | % { To-Sortable-Version-String $_ } $objects = @( @{Version = "PG-9.6.24"; InstalledDate = [DateTime] "2020-01-01"}, @{Version = "PG-10.1"; InstalledDate = [DateTime] "2021-02-02"}, @{Version = "PG-11.3"; InstalledDate = [DateTime] "2022-03-03"}, @{Version = "PG-11.12"; InstalledDate = [DateTime] "2023-04-04"}, @{Version = "PG-16.4"; InstalledDate = [DateTime] "2024-05-05"} ); $objects | % { [pscustomobject] $_ } | Sort-Object -Property @{ Expression = { To-Sortable-Version-String $_.Version }; Descending = $true }, @{ Expression = "InstalleDate"; Descending = $false } | Format-Table * -AutoSize } # Test-Version-Sort # Include File: [\Includes\Troubleshoot-Info.ps1] function Troubleshoot-Info() { $enableTroubleShoot = To-Boolean "PS1_TROUBLE_SHOOT" "$($ENV:PS1_TROUBLE_SHOOT)" if (-not $enableTroubleShoot) { return; } $c = (Get-PSCallStack)[1] $cmd = $c.Command; # Write-Host -NoNewLine "[$cmd" -ForegroundColor DarkCyan $toWrite = @("-TextDarkCyan", "[$cmd"); $line=$null; if ($c.Location) { # $line = ":$($c.Location.Split(32) | Select -Last 1)"; $lineRaw = "$($c.Location.Split(32) | Select -Last 1)"; try { $line = [int]::Parse($lineRaw); $line=":$line" } catch { $line="" } } if ($line) { # Write-Host -NoNewLine "$line" -ForegroundColor DarkCyan; $toWrite += "$line" } # Write-Host -NoNewLine "] " -ForegroundColor DarkCyan $toWrite += @("] ", "-Reset"); $color="Gray"; $args | % { if ($_ -eq "-Highlight") { $color = "Cyan"; } else { # if ($color) { Write-Host -NoNewLine "$_" -ForegroundColor $color; } else { Write-Host -NoNewLine "$_"; } if ($color) { # Write-Host -NoNewLine "$_" -ForegroundColor $color; $toWrite += $("-Text$color", "$_"); } else { # Write-Host -NoNewLine "$_"; $toWrite += $("-Reset", "$_"); } $color = "Gray" $toWrite += "-Reset" } } Write-Line -DirectArgs $toWrite; # $toWrite } <# function Troubleshoot-Info-Prev([string] $message) { $enableTroubleShoot = To-Boolean "PS1_TROUBLE_SHOOT" "$($ENV:PS1_TROUBLE_SHOOT)" if (-not $enableTroubleShoot) { return; } $c = (Get-PSCallStack)[1] $cmd = $c.Command; Write-Host -NoNewLine "[$cmd" -ForegroundColor DarkGreen $line=$null; if ($c.Location) { $line = ":$($c.Location.Split(32) | Select -Last 1)"; } if ($line) { Write-Host -NoNewLine "$line" -ForegroundColor Green; } Write-Host -NoNewLine "] " -ForegroundColor DarkGreen Write-Host "$message" } #> # Black DarkBlue DarkGreen DarkCyan DarkRed DarkMagenta DarkYellow Gray DarkGray Blue Green Cyan Red Magenta Yellow White # Include File: [\Includes\Try-And-Retry.ps1] function Try-And-Retry([string] $title, [ScriptBlock] $action, [int] $retryCount = 3, [int] $pauseMilliseconds = 1000) { for($retry=1; $retry -le $retryCount; $retry++) { $exitCode = 0; $err=$null; try { $Global:LASTEXITCODE = 0; $ret = Invoke-Command -ScriptBlock $action; $exitCode = $Global:LASTEXITCODE; $err = $null; if ($exitCode) { $err = new-object Exception("Command Failed. Exit Code $exitCode"); } } catch { $err=$_.Exception; } if ($err -eq $null) { return $ret; } if ($retry -eq $retryCount) { $msg = "The action `"$title`" failed $retry times. $($err.Message)"; Write-Host $msg -ForeGroundColor Red; throw new-object Exception($msg); return; } Write-Host "The action `"$($title)`" failed. Retrying, $($retry+1) of $retryCount. Error reason is $($err.Message)" -ForeGroundColor Red [System.Threading.Thread]::Sleep($pauseMilliseconds) } } # Try-And-Retry "Success 42" { 42; } # Try-And-Retry "Download httttt://xxxx" { & curl.exe httttt://xxxx } # Try-And-Retry "Download https://google.com" { & curl.exe "-I" https://google.com } # Include File: [\Includes\Write-Line.ps1] function Get-ANSI-Colors() { $isAzurePipeline = (Try-BuildServerType) -eq "TF_BUILD"; $Esc=[char]27; $ANSI_COLORS = @{ Reset = "$($Esc)[0m" Bold = "$($Esc)[1m" Underline = "$($Esc)[4m" Inverse = "$($Esc)[7m" TextBlack = "$($Esc)[30m" TextDarkBlue = "$($Esc)[34m" TextDarkGreen = "$($Esc)[32m" TextDarkCyan = "$($Esc)[36m" TextDarkRed = "$($Esc)[31m" TextDarkMagenta = "$($Esc)[35m" TextDarkYellow = "$($Esc)[33m" # 98 is incorrent on azure pipeline TextGray = IIF $isAzurePipeline "$($Esc)[90m$($Esc)[98m" "$($Esc)[98m" #? TextDarkGray = "$($Esc)[90m" #? TextBlue = "$($Esc)[94m" TextGreen = "$($Esc)[92m" TextCyan = "$($Esc)[96m" TextRed = "$($Esc)[91m" TextMagenta = "$($Esc)[95m" TextYellow = "$($Esc)[93m" TextWhite = "$($Esc)[97m" BackBlack = "$($Esc)[40m" BackDarkBlue = "$($Esc)[44m" BackDarkGreen = "$($Esc)[42m" BackDarkCyan = "$($Esc)[46m" BackDarkRed = "$($Esc)[41m" BackDarkMagenta = "$($Esc)[45m" BackDarkYellow = "$($Esc)[43m" BackGray = "$($Esc)[100m" #? BackDarkGray = "$($Esc)[108m" #? BackBlue = "$($Esc)[104m" BackGreen = "$($Esc)[102m" BackCyan = "$($Esc)[106m" BackRed = "$($Esc)[101m" BackMagenta = "$($Esc)[105m" BackYellow = "$($Esc)[103m" BackWhite = "$($Esc)[107m" } $ANSI_COLORS } # Write-Line "Hello " -TextRed -Bold "World" Function Write-Line([string[]] $directArgs = @()) { $ansiColors = Get-ANSI-Colors; $isAnsiSupported = Is-Ansi-Supported; $directArgs += @($args); $arguments = @($directArgs); $text="Gray"; $back="Black"; $ansi=""; foreach($arg in $arguments) { $isControl = $false; $isReset = $false; if ($arg.StartsWith("-")) { if ($arg.Length -gt 1) { $key = $arg.SubString(1); if ($ansiColors -and $ansiColors[$key]) { $ansiValue = $ansiColors[$key]; $ansi += $ansiValue; $isReset = ($key -eq "Reset"); if ($isReset) { $text="Gray"; $back="Black"; } if ($key -like "Text*") { $text = $key.SubString(4) } if ($key -like "Back*") { $back = $key.SubString(4) } $isControl = $true; } } } if (-not $isControl) { if ($isAnsiSupported) { Write-Host "$($ansi)$($arg)" -NoNewLine -ForegroundColor $text -BackgroundColor $back } # if ($isAnsiSupported) { Write-Host "$($ansi)$($arg)" -NoNewLine } else { Write-Host "$($arg)" -NoNewLine -ForegroundColor $text -BackgroundColor $back } } # if ($isReset) { $ansi = ""; } TODO: After Text } Write-Host ""; } # Include Directive: [ ..\Includes.SqlServer\*.ps1 ] # Include File: [\Includes.SqlServer\$SqlServer2010DownloadLinks.ps1] $SqlServer2010DownloadLinks = @( @{ Version="2014-x64"; #SP3 Core ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/SQLEXPR_x64_ENU.exe" Advanced ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/SQLEXPRADV_x64_ENU.exe" #SP3, # SP1 does not work on Pipeline # Developer="https://archive.org/download/sql-server-2014-enterprise-sp-1-x-64/SQL_Server_2014_Enterprise_SP1_x64.rar" #SP1 # DeveloperFormat="ISO-In-Archive" Developer=@("https://archive.org/download/sql_server_2014_sp3_developer_edition_x64.7z/sql_server_2014_sp3_developer_edition_x64.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2014_sp3_developer_edition_x64.7z/download") #SP3, 12.0.6024 DeveloperFormat="Archive" LocalDB ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/ENU/x64/SqlLocalDB.msi" CU=@( ) }; @{ Version="2014-x86"; #SP3 Core ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/SQLEXPR_x86_ENU.exe" Advanced ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/SQLEXPRADV_x86_ENU.exe" # Developer="https://archive.org/download/microsoft-sql-server-2014-enterprise-sp-3-32-bit/Microsoft%20SQL%20Server%202014%20Enterprise%20SP3%20%2832Bit%29.zip" # DeveloperFormat="ISO-In-Archive" Developer=("https://archive.org/download/sql_server_2014_sp3_developer_edition_x86.7z/sql_server_2014_sp3_developer_edition_x86.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2014_sp3_developer_edition_x86.7z/download") DeveloperFormat="Archive" LocalDB ="https://download.microsoft.com/download/3/9/F/39F968FA-DEBB-4960-8F9E-0E7BB3035959/ENU/x86/SqlLocalDB.msi" CU=@( ) }; @{ Version="2012-x64"; #SP4 Core ="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/SQLEXPR_x64_ENU.exe" Advanced="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/SQLEXPRADV_x64_ENU.exe" Developer=@("https://archive.org/download/sql_server_2012_sp4_developer_x86_x64/sql_server_2012_sp4_developer_x64.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2012_sp4_developer_edition_x64.7z/download") # 11.0.7001.0 SP4 DeveloperFormat="Archive" LocalDB ="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/ENU/x64/SqlLocalDB.msi" CU=@( ) }; @{ Version="2012-x86"; #SP4 Core ="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/SQLEXPR_x86_ENU.exe" Advanced="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/SQLEXPRADV_x86_ENU.exe" Developer=@("https://archive.org/download/sql_server_2012_sp4_developer_x86_x64/sql_server_2012_sp4_developer_x86.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2012_sp4_developer_edition_x86.7z/download") # 11.0.7001.0 SP4 DeveloperFormat="Archive" LocalDB ="https://download.microsoft.com/download/B/D/E/BDE8FAD6-33E5-44F6-B714-348F73E602B6/ENU/x86/SqlLocalDB.msi" CU=@( ) }; @{ Version="2008R2-x64"; #SP2 Core ="https://download.microsoft.com/download/0/4/B/04BE03CD-EAF3-4797-9D8D-2E08E316C998/SQLEXPR_x64_ENU.exe" Advanced="https://download.microsoft.com/download/0/4/B/04BE03CD-EAF3-4797-9D8D-2E08E316C998/SQLEXPRADV_x64_ENU.exe" Developer=@("https://archive.org/download/sql_server_2008r2_sp3_developer_edition_x86_x64_ia64/sql_server_2008r2_sp3_developer_edition_x64.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2008r2_sp3_developer_edition_x64.7z/download") DeveloperFormat="Archive" CU=@( @{ Id="SP3"; Url="https://download.microsoft.com/download/D/7/A/D7A28B6C-FCFE-4F70-A902-B109388E01E9/ENU/SQLServer2008R2SP3-KB2979597-x64-ENU.exe" } ) }; @{ Version="2008R2-x86"; #SP2 Core ="https://download.microsoft.com/download/0/4/B/04BE03CD-EAF3-4797-9D8D-2E08E316C998/SQLEXPR_x86_ENU.exe" Advanced="https://download.microsoft.com/download/0/4/B/04BE03CD-EAF3-4797-9D8D-2E08E316C998/SQLEXPRADV_x86_ENU.exe" Developer=@("https://archive.org/download/sql_server_2008r2_sp3_developer_edition_x86_x64_ia64/sql_server_2008r2_sp3_developer_edition_x86.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2008r2_sp3_developer_edition_x86.7z/download") DeveloperFormat="Archive" CU=@( @{ Id="SP3"; Url="https://download.microsoft.com/download/D/7/A/D7A28B6C-FCFE-4F70-A902-B109388E01E9/ENU/SQLServer2008R2SP3-KB2979597-x86-ENU.exe" } ) }; # https://archive.org/download/en_sql_server_2008_r2_developer_x86_x64_ia64_dvd_522665 # 2008 SP2 @{ Version="2008-x64"; # DONE: Updated for the direct publication # Core ="https://web.archive.org/web/20160617214727/https://download.microsoft.com/download/0/F/D/0FD88169-F86F-46E1-8B3B-56C44F6E9505/SQLEXPR_x64_ENU.exe" #SP3 Core ="https://archive.org/download/sql-server-express-2008-x86-x64-sp4/SQL-Core-2008-x64-ENU.exe" Advanced="https://download.microsoft.com/download/e/9/b/e9bcf5d7-2421-464f-94dc-0c694ba1b5a4/SQLEXPRADV_x64_ENU.exe" #RTM Developer=@("https://archive.org/download/sql_server_2008_developer_edition_x86_x64/sql_server_2008_rtm_developer_edition_x64.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2008_rtm_developer_edition_x64.7z/download") # RTM DeveloperFormat="Archive" CU=@( # x64 is alive @{ Id="SP4"; Url="https://download.microsoft.com/download/5/E/7/5E7A89F7-C013-4090-901E-1A0F86B6A94C/ENU/SQLServer2008SP4-KB2979596-x64-ENU.exe" } # https://web.archive.org/web/20200812071912/https://download.microsoft.com/download/5/E/7/5E7A89F7-C013-4090-901E-1A0F86B6A94C/ENU/SQLServer2008SP4-KB2979596-x64-ENU.exe ) }; @{ Version ="2008-x86"; #SP2 # DONE: Updated for the direct publication # Core ="https://web.archive.org/web/20160617214727/https://download.microsoft.com/download/0/F/D/0FD88169-F86F-46E1-8B3B-56C44F6E9505/SQLEXPR_x86_ENU.exe" #SP3 Core ="https://archive.org/download/sql-server-express-2008-x86-x64-sp4/SQL-Core-2008-x86-ENU.exe" Advanced="https://download.microsoft.com/download/e/9/b/e9bcf5d7-2421-464f-94dc-0c694ba1b5a4/SQLEXPRADV_x86_ENU.exe" #RTM Developer=@("https://archive.org/download/sql_server_2008_developer_edition_x86_x64/sql_server_2008_rtm_developer_edition_x86.7z", "https://sourceforge.net/projects/archived-sql-servers/files/sql_server_2008_rtm_developer_edition_x86.7z/download") # RTM DeveloperFormat="Archive" CU=@( # x86 is removed # @{ Id="SP4"; Url="https://download.microsoft.com/download/5/E/7/5E7A89F7-C013-4090-901E-1A0F86B6A94C/ENU/SQLServer2008SP4-KB2979596-x86-ENU.exe" } # It is not reliable # @{ Id="SP4"; Url="https://web.archive.org/web/20200804042408/https://download.microsoft.com/download/5/E/7/5E7A89F7-C013-4090-901E-1A0F86B6A94C/ENU/SQLServer2008SP4-KB2979596-x86-ENU.exe" } # Explicit web archive publication @{ Id="SP4"; Url="https://archive.org/download/sql-server-express-2008-x86-x64-sp4/SQLServer2008SP4-KB2979596-x86-ENU.exe" } ) }; @{ Version="2005-x86"; Core ="https://sourceforge.net/projects/db-engine/files/database-engine-x86-9.0.5000.exe/download" #SP4 # Advanced="https://ia601402.us.archive.org/34/items/Microsoft_SQL_Server_2005/en_sql_2005_express_adv.exe" #SP1 # Advanced="https://archive.org/download/Microsoft_SQL_Server_2005/en_sql_2005_express_adv.exe" #SP1 Advanced="https://archive.org/download/SQLEXPR_ADV_2005_SP2/SQLEXPR_ADV.EXE" CU=@( # Core already SP4 @{ Id="SP4"; Url="https://catalog.s.download.windowsupdate.com/msdownload/update/software/svpk/2011/01/sqlserver2005expressadvancedsp4-kb2463332-x86-enu_b8640fde879a23a2372b27f158d54abb5079033e.exe" } ) }; ) <# (sp2) https://archive.org/download/SQLEXPR_ADV_2005_SP2/SQLEXPR_ADV.EXE was: 9.0.2047 (sp1) https://ia601402.us.archive.org/34/items/Microsoft_SQL_Server_2005/en_sql_2005_express_adv.exe now: 9.0.5000 (sp4) https://catalog.s.download.windowsupdate.com/msdownload/update/software/svpk/2011/01/sqlserver2005expressadvancedsp4-kb2463332-x86-enu_b8640fde879a23a2372b27f158d54abb5079033e.exe #> # Include File: [\Includes.SqlServer\$SqlServerAlreadyUpdatedList.ps1] $SqlServerAlreadyUpdatedList = @( @{ Version = "2008R2-x64"; MediaType = "Developer"; }, @{ Version = "2008R2-x86"; MediaType = "Developer"; }, @{ Version = "2005-x86"; MediaType = "Core"; } ); # Include File: [\Includes.SqlServer\$SqlServerDownloadLinks.ps1] $SqlServerDownloadLinks = @( @{ Version="2022" Advanced="https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLEXPRADV_x64_ENU.exe" Core="https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLEXPR_x64_ENU.exe" LocalDB="https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SqlLocalDB.msi" Developer=@( "https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.box", "https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.exe") CU=@( # @{ Id="CU14"; Url="https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5038325-x64.exe"; } # @{ Id="CU15"; # Url=@( # "https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/updt/2024/09/sqlserver2022-kb5041321-x64_1b40129fb51df67f28feb2a1ea139044c611b93f.exe", # "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/sqlserver2022-kb5041321-x64_1b40129fb51df67f28feb2a1ea139044c611b93f.exe" # ); # } # CU17 @{ Id="CU17"; Url=@( "https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5048038-x64.exe", "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/SQLServer2022-KB5048038-x64.exe" ); } ) }, @{ Version="2019" Advanced="https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLEXPRADV_x64_ENU.exe" Core="https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLEXPR_x64_ENU.exe" LocalDB="https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SqlLocalDB.msi" Developer=@( "https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.box", "https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.exe") CU=@( # @{ Id="CU30"; # Url=@( # "https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5049235-x64.exe", # "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/SQLServer2019-KB5049235-x64.exe" # ); # } # @{ Id="CU28"; Url="https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5039747-x64.exe"; } # CU31 # https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/updt/2025/02/sqlserver2019-kb5049296-x64_df5a52a752a86ff79331698949a99e8a53c97d97.exe # https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/sqlserver2019-kb5049296-x64_df5a52a752a86ff79331698949a99e8a53c97d97.exe @{ Id="CU31"; Url=@( "https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/updt/2025/02/sqlserver2019-kb5049296-x64_df5a52a752a86ff79331698949a99e8a53c97d97.exe", "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/sqlserver2019-kb5049296-x64_df5a52a752a86ff79331698949a99e8a53c97d97.exe" ); } ) }, @{ Version="2017" Advanced="https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLEXPRADV_x64_ENU.exe" Core="https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLEXPR_x64_ENU.exe" LocalDB="https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SqlLocalDB.msi" Developer=@( "https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.box", "https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.exe") CU=@( @{ Id="CU31"; Url=@( "https://download.microsoft.com/download/C/4/F/C4F908C9-98ED-4E5F-88D5-7D6A5004AEBD/SQLServer2017-KB5016884-x64.exe", "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/SQLServer2017-KB5016884-x64.exe" ); } ) }, @{ Version="2016" Advanced="https://download.microsoft.com/download/f/9/8/f982347c-fee3-4b3e-a8dc-c95383aa3020/sql16_sp3_dlc/en-us/SQLEXPRADV_x64_ENU.exe" Core="https://download.microsoft.com/download/f/9/8/f982347c-fee3-4b3e-a8dc-c95383aa3020/sql16_sp3_dlc/en-us/SQLEXPR_x64_ENU.exe" LocalDB="https://download.microsoft.com/download/f/9/8/f982347c-fee3-4b3e-a8dc-c95383aa3020/sql16_sp3_dlc/en-us/SqlLocalDB.msi" Developer=@( "https://download.microsoft.com/download/f/9/8/f982347c-fee3-4b3e-a8dc-c95383aa3020/sql16_sp3_dlc/en-us/SQLServer2016SP3-FullSlipstream-DEV-x64-ENU.box", "https://download.microsoft.com/download/f/9/8/f982347c-fee3-4b3e-a8dc-c95383aa3020/sql16_sp3_dlc/en-us/SQLServer2016SP3-FullSlipstream-DEV-x64-ENU.exe") CU=@( @{ Id="1.KB5040946"; Url=@( "https://download.microsoft.com/download/d/a/1/da18aac1-2cd0-4c52-b30d-39c3172cd156/SQLServer2016-KB5040946-x64.exe", "https://archive.org/download/sql_server_2016_2017_2019_2022_comulative_updates/SQLServer2016-KB5040946-x64.exe" ); } ) } ); $SqlServerDownloadLinks_Via_Manager = @( @{ Version="2016"; BaseDev ="https://download.microsoft.com/download/c/5/0/c50d5f5e-1adf-43eb-bf16-205f7eab1944/SQLServer2016-SSEI-Dev.exe"; #SP3, 3.0 Gb BaseExpress="https://download.microsoft.com/download/f/a/8/fa83d147-63d1-449c-b22d-5fef9bd5bb46/SQLServer2016-SSEI-Expr.exe" #SP3, CU=@( @{ Id="1.KB5040946"; Url="https://download.microsoft.com/download/d/a/1/da18aac1-2cd0-4c52-b30d-39c3172cd156/SQLServer2016-KB5040946-x64.exe"; } ) }; @{ Version="2017"; BaseDev ="https://download.microsoft.com/download/5/A/7/5A7065A2-C81C-4A31-9972-8A31AC9388C1/SQLServer2017-SSEI-Dev.exe"; BaseExpress="https://download.microsoft.com/download/5/E/9/5E9B18CC-8FD5-467E-B5BF-BADE39C51F73/SQLServer2017-SSEI-Expr.exe" CU=@( @{ Id="CU31"; Url="https://download.microsoft.com/download/C/4/F/C4F908C9-98ED-4E5F-88D5-7D6A5004AEBD/SQLServer2017-KB5016884-x64.exe"; } ) }; @{ Version="2019"; BaseDev ="https://download.microsoft.com/download/d/a/2/da259851-b941-459d-989c-54a18a5d44dd/SQL2019-SSEI-Dev.exe"; BaseExpress="https://download.microsoft.com/download/7/f/8/7f8a9c43-8c8a-4f7c-9f92-83c18d96b681/SQL2019-SSEI-Expr.exe" CU=@( @{ Id="CU28"; Url="https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5039747-x64.exe"; } ) }; @{ Version="2022"; BaseDev ="https://download.microsoft.com/download/c/c/9/cc9c6797-383c-4b24-8920-dc057c1de9d3/SQL2022-SSEI-Dev.exe"; BaseExpress="https://download.microsoft.com/download/5/1/4/5145fe04-4d30-4b85-b0d1-39533663a2f1/SQL2022-SSEI-Expr.exe" CU=@( @{ Id="CU14"; Url="https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5038325-x64.exe"; } ) }; ) # $SqlServerDownloadLinks | ConvertTo-Json -Depth 32 # Include File: [\Includes.SqlServer\Create-LocalDB-Instance.ps1] # Using latest SQLLocalDB.exe function Create-LocalDB-Instance([string] $instanceName, [string] $optionalVersion) { $pars = @("create", "`"$instanceName`""); if ($optionalVersion) { $pars += $optionalVersion } $title = "Create LocalDB instance `"$instanceName`"" if ($optionalVersion) { $title += " version $optionalVersion" } return Invoke-LocalDB-Executable -Title $title -Version "Latest" -Parameters @($pars) } function Delete-LocalDB-Instance([string] $instanceName) { if ("$instanceName" -like "(LocalDB)\*" -and "$instanceName".Length -gt 10) { $instanceName = "$instanceName".SubString(10) } # STOP instance by kill $pars = @("stop", "`"$instanceName`"", "-k"); $title = "Stop (by kill) LocalDB Instance `"$instanceName`"" $__ = Invoke-LocalDB-Executable -Title $title -Version "Latest" -Parameters @($pars) # Delete instance $pars = @("delete", "`"$instanceName`""); $title = "Delete LocalDB Instance `"$instanceName`"" return Invoke-LocalDB-Executable -Title $title -Version "Latest" -Parameters @($pars) } function Test-Create-Delete-LocalDB-Instance() { Write-Host "DELETING Custom Instances" -ForegroundColor Magenta $__ = Find-LocalDb-SqlServers | % { "$($_.Instance)" } | ? { "$_" -match "LocalDB-" } | % { Write-Host "Deleting $_" -ForegroundColor Yellow; Delete-LocalDB-Instance "$_" } Find-LocalDb-SqlServers | Populate-Local-SqlServer-Version | ft -AutoSize | Out-String -Width 1234 | Out-Host Write-Host "CREATING Custom Instances" -ForegroundColor Magenta foreach($localDb in Find-LocalDb-Versions) { $instance = "LocalDB-v$($localDb.ShortVersion)" Write-Host "Creating Instance $instance version $($localDb.ShortVersion)" $isCreated = Create-LocalDB-Instance ` -InstanceName $instance ` -OptionalVersion $localDb.ShortVersion } Find-LocalDb-SqlServers | Populate-Local-SqlServer-Version | ft -AutoSize | Out-String -Width 1234 | Out-Host } # Include File: [\Includes.SqlServer\Download-2010-SQLServer-and-Extract.ps1] function Download-2010-SQLServer-and-Extract { Param( [string] $version, # (2014|2012|2008R2|2008)-(x86|x64) [string] $mediaType # Core|Advanced|LocalDB (localdb is missing for 2008R2) ) $rootMedia=Combine-Path "$(Get-SqlServer-Media-Folder)" "SQL-$version-$mediaType-Compressed" $rootSetup=Combine-Path "$(Get-SqlServer-Setup-Folder)" "SQL-$version-$mediaType" $mediaPath = $rootMedia $ext = IIf ($mediaType -eq "LocalDB") ".msi" ".exe" $exeName = "SQL-$mediaType-$Version-ENU$ext" $exeArchive = Combine-Path $mediaPath $exeName $setupPath="$rootSetup" if ($mediaType -eq "LocalDB") { $exeArchive = Combine-Path $setupPath $exeName $mediaPath = $null; } Write-Host "Download Media for '$version $mediaType'" $url=""; $isDeveloper = [bool]($mediaType -eq "Developer"); foreach($meta in $SqlServer2010DownloadLinks) { if ($meta.Version -eq $version) { $url = $meta[$mediaType] $urlFormat=$meta["$($mediaType)Format"] if ($urlFormat) { $ext = ".$urlFormat".ToLower(); $ext = Try-Get-FileExtension-by-Uri $url; $exeName = "SQL-$mediaType-$Version-ENU$ext" $exeArchive = Combine-Path $mediaPath $exeName } } } if (-not $url) { Write-Host "Unknown SQL Server version $version $mediaType" -ForegroundColor DarkRed; return @{}; } Write-Host "Downloading media for version $version $mediaType. URL(s) is '$url'. Setup file is '$exeArchive'"; $isDownloadOk = Download-File-FailFree-and-Cached $exeArchive @($url) if (-not $isDownloadOk) { Write-Host "Download media for version $version $mediaType failed. URL(s) is '$url'" -ForegroundColor DarkRed; return @{}; } $ret = @{ Version=$version; MediaType=$mediaType; }; if ($mediaType -eq "LocalDB") { $ret["Launcher"] = $exeArchive; $ret["Setup"] = $setupPath; } else { if ($null -eq $urlFormat) { $isExtractOk = ExtractSqlServerSetup "SQL Server $version $mediaType" $exeArchive $setupPath "/Q" if ($isExtractOk) { $ret["Launcher"] = Combine-Path $setupPath "Setup.exe"; $ret["Setup"] = $setupPath; $ret["Media"] = $mediaPath; } else { return @{}; } } elseif ($urlFormat -eq "ISO-In-Archive") { $isoFolder = Combine-Path $mediaPath "iso" Write-Host "Extracting '$exeArchive' to '$isoFolder'" $isExtract1Ok = Extract-Archive-by-Default-Full-7z "$exeArchive" "$isoFolder" $isoFile = Get-ChildItem -Path "$isoFolder" -Filter "*.iso" | Select -First 1 Write-Host "ISO found: '$($isoFile.FullName)' ($($isoFile.Length.ToString("n0")) bytes). Extracting it to '$setupPath'"; $isExtract2Ok = Extract-Archive-by-Default-Full-7z "$($isoFile.FullName)" "$setupPath" $ret["Launcher"] = Combine-Path $setupPath "Setup.exe"; $ret["Setup"] = $setupPath; $ret["Media"] = $mediaPath; } elseif ($urlFormat -eq "Archive") { Write-Host "Extracting '$exeArchive' to '$setupPath'" $isExtract1Ok = Extract-Archive-by-Default-Full-7z "$exeArchive" "$setupPath" $ret["Launcher"] = Combine-Path $setupPath "Setup.exe"; $ret["Setup"] = $setupPath; $ret["Media"] = $mediaPath; } else { Write-Host "Warning! Unknown format '$urlFormat' for '$url')" -ForegroundColor DarkRed } } ApplyCommonSqlServerState $ret; return $ret; } # Include File: [\Includes.SqlServer\Download-Fresh-SQLServer-and-Extract.ps1] function Download-Fresh-SQLServer-and-Extract { Param( [string] $version, # 2016|2017|2019|2022 [string] $mediaType # LocalDB|Core|Advanced|Developer ) $rootMedia=Combine-Path "$(Get-SqlServer-Media-Folder)" "SQL-$version-$mediaType-Compressed" $rootSetup=Combine-Path "$(Get-SqlServer-Setup-Folder)" "SQL-$version-$mediaType" if ($mediaType -eq "LocalDB") { $mediaPath = $rootSetup } else { $mediaPath = $rootMedia } $setupPath="$rootSetup" Write-Host "Download and Extract SQL Server $version media '$mediaType' to `"$setupPath`"" $url=""; foreach($meta in $SqlServerDownloadLinks) { if ($meta.Version -eq $version) { $url = $meta["$mediaType"] } } if (-not $url) { Write-Host "Unknown SQL Server version $version" -ForegroundColor DarkRed; return @{}; } Troubleshoot-Info "URL(s) IS " -Highlight "$url" $urlList = IIF ($url -is [array]) $url @($url); foreach($nextUrl in $urlList) { $fileName=[System.IO.Path]::GetFileName($nextUrl); # TODO: trim /download at the end $fileFull = Combine-Path $mediaPath $fileName $isDownloadOk = Download-File-FailFree-and-Cached $fileFull @($nextUrl) if (-not $isDownloadOk) { Write-Host "Download bootstrapper for version $version failed. Unable to download URL '$nextUrl' as '$fileFull'" -ForegroundColor DarkRed; return @{}; } } $ext = IIF ($mediaType -eq "LocalDB") "msi" "exe" $exeArchive = Get-ChildItem -Path "$mediaPath" -Filter "*.$ext" | Select -First 1 Write-Host "(Exe|Msi) Archive `"$exeArchive`"" $ret = @{ Version=$version; MediaType=$mediaType; }; if ($mediaType -eq "LocalDB") { $ret["Launcher"] = Combine-Path $setupPath $exeArchive; $ret["Setup"] = $setupPath; } else { $quietArg = IIF (Is-BuildServer) "/Q" "/QS" $isExtractOk = ExtractSqlServerSetup "SQL Server $version $mediaType" $exeArchive.FullName $setupPath "$quietArg" if ($isExtractOk) { $ret["Launcher"] = Combine-Path $setupPath "Setup.exe"; $ret["Setup"] = $setupPath; $ret["Media"] = $mediaPath; } else { return @{}; } } ApplyCommonSqlServerState $ret; return $ret; } function Download-Fresh-SQLServer-and-Extract-Via-Manager { Param( [string] $version, # 2016|2017|2019|2022 [string] $mediaType # LocalDB|Core|Advanced|Developer ) $key="SQL-$version-$mediaType" $root=Combine-Path "$(Get-SqlServer-Downloads-Folder)" $key if ($mediaType -eq "LocalDB") { $mediaPath = $root } else { $mediaPath = Combine-Path "$(Get-SqlServer-Downloads-Folder)" "SQL-Setup-Compressed" "SQL-$Version-$mediaType" } $setupPath="$root" Write-Host "Download Bootstrapper for '$key'" $url=""; $isDeveloper = [bool]($mediaType -eq "Developer"); foreach($meta in $SqlServerDownloadLinks) { if ($meta.Version -eq $version) { $url = IIf $isDeveloper $meta.BaseDev $meta.BaseExpress } } if (-not $url) { Write-Host "Unknown SQL Server version $version" -ForegroundColor DarkRed; return @{}; } $exeBootstrap = Combine-Path "$(Get-SqlServer-Downloads-Folder)" "SQL-Setup-Bootstrapper" "SQL-$Version-$(IIf $isDeveloper "Developer" "Express")-Bootstapper.exe" $isRawOk = Download-File-FailFree-and-Cached $exeBootstrap @($url) if (-not $isRawOk) { Write-Host "Download bootstrapper for version $version failed. URL is '$url'" -ForegroundColor DarkRed; return @{}; } Write-Host "Download SQL Server $version media '$mediaType'" $mt = IIf $isDeveloper "CAB" $mediaType; # echo Y | "%outfile%" /ENU /Q /Action=Download /MEDIATYPE=%MT% /MEDIAPATH="%Work%\SETUPFILES" $startAt = [System.Diagnostics.Stopwatch]::StartNew() $hideProgressBar=IIF (Is-BuildServer) " /HIDEPROGRESSBAR" ""; & cmd.exe @("/c", "echo Y | `"$exeBootstrap`" /ENU /Q$hideProgressBar /Action=Download /MEDIATYPE=$mt /MEDIAPATH=`"$mediaPath`"") # & "$exeBootstrap" @("/ENU", "/Q", "/Action=Download", "/MEDIATYPE=$mt", "/MEDIAPATH=`"$mediaPath`""); if (-not $?) { Write-Host "Media download for version $version $mediaType. failed" -ForegroundColor DarkRed; return @{}; } try { $length = Get-Folder-Size $mediaPath; } catch {}; $milliSeconds = $startAt.ElapsedMilliseconds; $size=""; if ($length -gt 0) { $size=" ($($length.ToString("n0")) bytes)"; } $speed=""; if ($length -gt 0 -and $milliSeconds -gt 0) { $speed=" Speed is $(($length*1000/1024/$milliSeconds).ToString("n0")) Kb/s."; } $duration=""; if ($milliSeconds -gt 0) {$duration=" It took $(($milliSeconds/1000.).ToString("n1")) seconds."; } Write-Host "Media '$mediaPath'$($size) download complete.$($duration)$($speed)" $ret = @{ Version=$version; MediaType=$mediaType; }; if ($mediaType -eq "LocalDB") { $ret["Launcher"] = Combine-Path $mediaPath "en-US" "SqlLocalDB.msi"; $ret["Setup"] = $setupPath; } else { $exeArchive = Get-ChildItem -Path "$mediaPath" -Filter "*.exe" | Select -First 1 $quietArg = IIF (Is-BuildServer) "/Q" "/QS" $isExtractOk = ExtractSqlServerSetup "SQL Server $version $mediaType" $exeArchive.FullName $setupPath "$quietArg" if ($isExtractOk) { $ret["Launcher"] = Combine-Path $setupPath "Setup.exe"; $ret["Setup"] = $setupPath; $ret["Media"] = $mediaPath; } else { return @{}; } } ApplyCommonSqlServerState $ret; return $ret; } # Include File: [\Includes.SqlServer\Download-SQLServer-and-Extract.ps1] function Download-SQLServer-and-Extract { Param( [string] $version, # 2016|2017|2019|2022 [string] $mediaType # LocalDB|Core|Advanced|Developer ) $major = ($version.Substring(0,4)) -as [int]; $is2020 = $major -ge 2016; if ($is2020) { Download-Fresh-SQLServer-and-Extract $version $mediaType; } else { Download-2010-SQLServer-and-Extract $version $mediaType; } } function ApplyCommonSqlServerState([Hashtable] $ret) { if ($ret.Launcher) { try { $size = (New-Object System.IO.FileInfo($ret.Launcher)).Length; } catch {Write-Host "Warning $($_)"; } $ret["LauncherSize"] = $size; } if ($ret.Setup) { $ret["SetupSize"] = Get-Folder-Size $ret.Setup; if (Is-SqlServer-Setup-Cache-Enabled) { $ret["SetupHash"] = Get-Smarty-FolderHash $ret.Setup "SHA512" } } if ($ret.Media) { $ret["MediaSize"] = Get-Folder-Size $ret.Media; # $ret["MediaHash"] = Get-Smarty-FolderHash $ret.Media "SHA512" } } function ExtractSqlServerSetup([string] $title, [string] $exeArchive, [string] $setupPath, [string] $quietArg <# /QS (Fresh) | /Q (prev) #>) { Write-Host "Extracting $title using [$($exeArchive)] to [$($setupPath)]" $extractStatus = Execute-Process-Smarty "$title Unpacker" "$($exeArchive)" @("$quietArg", "/X:`"$setupPath`"") -WaitTimeout 1800 # $startAt = [System.Diagnostics.Stopwatch]::StartNew() # $extractApp = Start-Process "$($exeArchive)" -ArgumentList @("$quietArg", "/x:`"$setupPath`"") -PassThru # if ($extractApp -and $extractApp.Id) { # Wait-Process -Id $extractApp.Id # if ($extractApp.ExitCode -ne 0) { # Write-Host "Extracting $title failed. Exit code $($extractApp.ExitCode)." -ForegroundColor DarkRed; # return $false; # } # } else { # Write-Host "Extracting $title. failed." -ForegroundColor DarkRed; # return $false; # } # Write-Host "Extraction of $title took $($startAt.ElapsedMilliseconds.ToString("n0")) ms" return ($extractStatus.ExitCode -eq 0); } # Include File: [\Includes.SqlServer\Download-SqlServer-Update.ps1] function Download-SqlServer-Update { Param( [string] $version, # 2005...2022 [string] $mediaType, # LocalDB|Core|Advanced|Developer [object] $update # {Id=;Url=;} ) $ret = $update.Clone(); $key="SQL-$version-Update-$($update.Id)" $archivePath = Combine-Path "$(Get-SqlServer-Media-Folder)" $key $archiveName = [System.IO.Path]::GetFileName($update.Url); # TODO: trim /download at the end $archiveFullName = Combine-Path $archivePath $archiveName; Write-Host "Downloading SQL Server update '$($update.Id)' for version $version $mediaType. URL(s) is '$($update.Url)'" # $isDownloadOk = Download-File-FailFree-and-Cached $archiveFullName @("$($update.Url)") $isDownloadOk = Download-File-FailFree-and-Cached $archiveFullName @($update.Url) if (-not $isDownloadOk) { Write-Host "Download SQL Server update '$($update.Id)' for version $version $mediaType failed. URL is '$($update.Url)'" -ForegroundColor DarkRed; return $ret; } $ret["UpdateId"] = $update.Id; $ret["UpdateFolder"] = $archivePath; $ret["UpdateLauncher"] = $archiveFullName; $ret["UpdateSize"] = (new-object System.IO.FileInfo($archiveFullName)).Length; return $ret; } <# Name Value ---- ----- Url https://download.microsoft.com/download/C/4/F/C4F908C9-98ED-4E5F-88D5-7D6A5004AEBD/SQLServer2017-KB5016884-x64.exe Id CU31 UpdateId CU31 UpdateSize 561206208 UpdateFolder C:\SQL-Downloads\SQL-2017-CU31 UpdateLauncher C:\SQL-Downloads\SQL-2017-CU31\SQLServer2017-KB5016884-x64.exe #> # Include File: [\Includes.SqlServer\Enumerate-SQLServer-Downloads.ps1] function Enumerate-SQLServer-Downloads() { $versions = "2005-x86", "2008-x86", "2008-x64", "2008R2-x86", "2008R2-x64", "2012-x86", "2012-x64", "2014-x86", "2014-x64", "2016", "2017", "2019", "2022"; [array]::Reverse($versions); $mediaTypes = "LocalDB", "Core", "Advanced", "Developer"; [array]::Reverse($mediaTypes); foreach($version in $versions) { foreach($mediaType in $mediaTypes) { $meta = Find-SQLServer-Meta $version $mediaType; if ($meta) { $meta; } }} } function Enumerate-Plain-SQLServer-Downloads() { foreach($meta in Enumerate-SQLServer-Downloads) { $baselineKeywords="$($meta.Version) $($meta.MediaType)" if ("$($meta.CU)") { foreach($update in $meta.CU) { $counter++; @{ Version=$meta.Version; MediaType=$meta.MediaType; UpdateId=$update.Id; Update=$update; Keywords="$baselineKeywords $($update.Id)"; NormalizedKeywords="$baselineKeywords Update"; }; } } @{ Version=$meta.Version; MediaType=$meta.MediaType; Keywords="$baselineKeywords"; NormalizedKeywords="$baselineKeywords"}; } } # Include File: [\Includes.SqlServer\Find-LocalDb-SqlServer.ps1] # Super Fast function Find-LocalDb-SqlServer() { $parentKey = Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server Local DB\Installed Versions" -EA SilentlyContinue $candidates = @(); if ($parentKey) { foreach($subName in $parentKey.GetSubKeyNames()) { $candidates += $subName; } } [Array]::Sort($candidates); $last = $candidates | Select -Last 1; if (-not $last) { return; } if ($last -like "11.*") { $instance="(LocalDB)\v11.0" } else { $instance="(LocalDB)\MSSqlLocalDB" }; @{ InstallerVersion = $last; Instance = $instance; } } function Start-LocalDb-SqlServer([int] $timeoutSec = 60) { $localDb = Find-LocalDb-SqlServer; $startAt = [System.Diagnostics.Stopwatch]::StartNew(); if ($localDb) { $conStr = "Data Source=$($localDb.Instance);Integrated Security=True;Pooling=false;Timeout=2"; do { try { $con = New-Object System.Data.SqlClient.SqlConnection($conStr); $con.Open(); return $true; } catch { } } while($startAt.ElapsedMilliseconds -le ($timeoutSec * 1000)); Write-Host "Warning! can't start SQL Server Local DB v$($localDb.Version) '$($localDb.Instance)' during $($startAt.ElapsedMilliseconds / 1000) seconds" -ForegroundColor DarkRed } } # Find-LocalDb-SqlServers # Start-LocalDb-SqlServer -timeout 1 # Include File: [\Includes.SqlServer\Find-LocalDb-SqlServers.ps1] function Find-LocalDb-Versions([switch] $PopulateInstances) { $parentKey = Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server Local DB\Installed Versions" -EA SilentlyContinue $candidates = @(); if ($parentKey) { # Write-Host $parentKey.PSPath foreach($subName in $parentKey.GetSubKeyNames()) { $parentInstance = Get-ItemProperty -Path "$($parentKey.PSPath)\$subName" -Name ParentInstance -EA SilentlyContinue | % {$_.ParentInstance} if ($parentInstance) { # Version value $versionKey1 = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\$parentInstance\Setup" # CurrentVersion value $versionKey2 = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\$parentInstance\MSSQLServer\CurrentVersion" $version1 = Get-ItemProperty -Path "$versionKey1" -Name Version -EA SilentlyContinue | % {$_.Version} $version2 = Get-ItemProperty -Path "$versionKey2" -Name CurrentVersion -EA SilentlyContinue | % {$_.CurrentVersion} $version = $null; if ($version1) { $version = $version1 } elseif ($version2) { $version = $version2 } } $verInternal = $subName.Replace(".", "") # 16.0 --> 160 $pathToolsKey = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\$verInternal\Tools\ClientSetup" $pathTools = Get-ItemProperty -Path "$pathToolsKey" -Name Path -EA SilentlyContinue | % {$_.Path} if ($pathTools) { $exe = "$pathTools\SQLLocalDB.exe".Replace("\\", "\") $localDbExe = $null; try { if (([System.IO.File]::Exists($exe))) { $localDbExe = $exe } } catch { } } $newItem = [pscustomobject] @{ ShortVersion = $subName; InstallerVersion = $version; ParentInstance = $parentInstance; Exe = $localDbExe; }; # $newItem | Add-Member -MemberType ScriptMethod -Name "GetInstances" -Value { ParseNonEmptyTrimmedLines((& "$($this.Exe)" @("i") | Out-String)) } $candidates += $newItem } } $ret = @($candidates | ? { "$($_.ShortVersion)" -and "$($_.InstallerVersion)" -and "$($_.ParentInstance)" -and "$($_.Exe)" } | Sort-Object -Property ShortVersion -Descending); foreach($localDb in $ret) { if ($populateInstances) { # $instances = @($localDb.GetInstances()); $instances = ParseNonEmptyTrimmedLines((& "$($localDb.Exe)" @("i") | Out-String)) $localDb | Add-Member -MemberType NoteProperty -Name "Instances" -Value $instances; } } $ret } function Find-LocalDb-SqlServers() { $versions = @(Find-LocalDb-Versions -PopulateInstances); $instances = @() foreach($version in $versions) { foreach($i in $version.Instances) { $instances += $i; } } $instances = @($instances | Sort-Object | Get-Unique) # $instances = @(Find-LocalDb-Versions -PopulateInstances | Select -First 1 | % { $_.Instances }) $instances = @($instances | ? { "$_".Length -gt 0 }) foreach($instance in $instances) { [pscustomobject] @{ Instance = "(LocalDB)\$($instance)"} } } function Test-Show-LocalDb-Versions-with-Instances() { Write-Host "LOCALDB VERSIONS" -ForeGroundColor Magenta Find-LocalDb-Versions | ft -Property ShortVersion, InstallerVersion, Exe -AutoSize | Out-String -Width 1234 | Out-Host for($i=1; $i -le 2; $i++) { Write-Host "LOCALDB VERSIONS+INSTANCES MATRIX #$($i)" -ForeGroundColor Magenta Find-LocalDb-Versions -PopulateInstances | ft -Property ShortVersion, InstallerVersion, Instances, Exe -AutoSize | Out-String -Width 1234 | Out-Host } # Find-LocalDb-SqlServers -PopulateInstances | ft -Property ShortVersion, Version, Exe, Instances -AutoSize | Out-Host # $withInstances = Find-LocalDb-SqlServers | % { $_ | Add-Member -MemberType NoteProperty -Name "Instances" -Value $_.GetInstances(); $_ } # $withInstances | ft -Property ShortVersion, Version, Exe, Instances -AutoSize | Out-Host Write-Host "LOCALDB INSTANCES" -ForeGroundColor Magenta Find-LocalDb-SqlServers | ft -AutoSize | Out-String -Width 1234 | Out-Host Write-Host "LOCALDB INSTANCES with MediumVersion" -ForeGroundColor Magenta Find-LocalDb-SqlServers | Populate-Local-SqlServer-Version | ft -AutoSize | Out-String -Width 1234 | Out-Host $instances = @(Find-LocalDb-SqlServers) Write-Host "Total $($instances.Count) instance(s): $instances" foreach($instance in $instances) { $ver = Query-SqlServer-Version -Title "LocalDB `"$instance`"" -Instance "$($instance.Instance)" -Timeout 60 Write-Line -TextYellow $instance.Instance -TextGreen " $ver" } } # Test-Show-LocalDb-Versions-with-Instances # Include File: [\Includes.SqlServer\Find-Local-SqlServers.ps1] # Super Fast function Find-Local-SqlServers() { $candidates = @(@{RegPath="Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer";Service="MSSQLSERVER";Instance="(local)";}); $regNamebase = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server" $namedKey = Get-Item -Path $regNamebase -EA SilentlyContinue if ($namedKey) { foreach($subName in $namedKey.GetSubKeyNames()) { $candidates += @{RegPath="$($regNamebase)\$subName";Service="MSSQL`$$($subName)"; Instance="(local)\$subName";}} } # $candidates | % { [pscustomObject] $_ } | ft -AutoSize | out-Host foreach($candidate in $candidates) { $currentVersion = Get-ItemProperty -Path "$($candidate.RegPath)\MSSQLServer\CurrentVersion" -Name CurrentVersion -EA SilentlyContinue | % {$_.CurrentVersion} if ($currentVersion) { $candidate["InstallerVersion"] = $currentVersion; } $regService = Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\$($candidate.Service)" -EA SilentlyContinue if ($regService) { $candidate["ServiceExists"] = $true; } } # Write-Host "FINAL" -ForegroundColor DarkGreen # $candidates | % { [pscustomObject] $_ } | ft -AutoSize | out-Host $candidates | ? { $_.ServiceExists } | % { $_.Remove("ServiceExists"); $_.Remove("RegPath"); $_; } | % { [PSCustomObject] $_ } } # pipe only function Populate-Local-SqlServer-Version($timeout = 60) { foreach($sqlServer in $input) { $mediumVersion = Query-SqlServer-Version -Title "$($sqlServer.Instance) v$($sqlServer.InstallerVersion)" -Instance "$($sqlServer.Instance)" -Timeout $timeout; $__ = Set-Property-Smarty $sqlServer "Version" $mediumVersion $sqlServer } } function Test-Find-Local-SqlServers() { Write-Host "Find-Local-SqlServers as is" -ForeGroundColor Magenta Find-Local-SqlServers | ft -AutoSize | Out-String -Width 1234 | Out-Host # Get-Service -Name (Find-Local-SqlServers | % {$_.Service}) | ft -AutoSize Write-Host "Find-Local-SqlServers --> Windows Services" -ForeGroundColor Magenta Find-Local-SqlServers | % { Get-Service -Name $_.Service } | ft -AutoSize | Out-String -Width 1234 | Out-Host Write-Host "STOP SERVICES" -ForeGroundColor Magenta # Get-Service -Name (Find-Local-SqlServers | % {$_.Service}) | % { if ($_.Status -ne "Stopped") { Write-Host "Stopping $($_.Name)"; Stop-Service "$($_.Name)" -Force }} Find-Local-SqlServers | % { $_.Service } | % { Get-Service -Name $_ } | ? { $_.Status -ne "Stopped" } | % { Write-Host "Stopping $($_.Name)"; Stop-Service "$($_.Name)" -Force } Write-Host "START SERVICES" -ForeGroundColor Magenta # Get-Service -Name (Find-Local-SqlServers | % {$_.Service}) | % { if ($_.Status -ne "Running") { Write-Host "Starting $($_.Name)"; Start-Service "$($_.Name)" }} Find-Local-SqlServers | % { $_.Service } | % { Get-Service -Name $_ } | ? { $_.Status -ne "Running" } | % { Write-Host "Starting $($_.Name)"; Start-Service "$($_.Name)" } Write-Host "Find-Local-SqlServers | Populate-Local-SqlServer-Version" -ForeGroundColor Magenta Find-Local-SqlServers | Populate-Local-SqlServer-Version | ft -AutoSize | Out-String -Width 1234 | Out-Host } # Test-Find-Local-SqlServers # Include File: [\Includes.SqlServer\Find-SQLServer-Meta.ps1] function Find-SQLServer-Meta([string] $version, [string] $mediaType) { $ret = @{ Version = $version; MediaType = $mediaType; } $missingParticular = $null -ne ($SqlServerAlreadyUpdatedList | where { $_.Version -eq $version -and $_.MediaType -eq $mediaType}); $isMissingUpdates = $missingParticular -or ($mediaType -eq "LocalDB"); foreach($meta in $SqlServerDownloadLinks) { if ($meta.Version -eq $version) { # In case of via manager # $url = IIf ($mediaType -eq "Developer") $meta.BaseDev $meta.BaseExpress $url = $meta["$mediaType"] $ret["Url"] = $url; if (-not $isMissingUpdates) { $ret["CU"] = $meta.CU; } return $ret; } } foreach($meta in $SqlServer2010DownloadLinks) { if ($meta.Version -eq $version) { $url = $meta[$mediaType]; if ("$url") { $ret["Url"] = $url; if (-not $isMissingUpdates) { $ret["CU"] = $meta.CU; } return $ret; } } } } # Include File: [\Includes.SqlServer\Find-SqlServer-SetupLogs.ps1] function Find-SqlServer-SetupLogs() { $sysDrive = "$($ENV:SystemDrive)" $folders = @("$sysDrive\Program Files", "$sysDrive\Program Files (x86)", "C:\Program Files", "C:\Program Files (x86)", "$($Env:ProgramFiles)", "${Env:ProgramFiles(x86)}") $folders = ($folders | sort | Get-Unique) $ret=@() foreach($folder in $folders) { $sqlFolder=[System.IO.Path]::Combine($folder, "Microsoft SQL Server"); if ([System.IO.Directory]::Exists($sqlFolder)) { $subDirs = Get-ChildItem -Path $sqlFolder -Directory -Force -ErrorAction SilentlyContinue foreach($subDir in $subDirs) { $ver=$subDir.Name $verSubFolder=$subDir.FullName $logFolder=[System.IO.Path]::Combine($verSubFolder, "Setup Bootstrap\LOG"); if ([System.IO.Directory]::Exists($logFolder)) { $ret += [System.IO.Path]::GetFullPath($logFolder) } } } } $ret = $ret | sort | Get-Unique # "C:\Program Files (x86)\Microsoft SQL Server\90\Setup Bootstrap\LOG" # "C:\Program Files\Microsoft SQL Server\150\Setup Bootstrap\Log" $ret } # (Find-SqlServer-SetupLogs).Length; Find-SqlServer-SetupLogs # Include File: [\Includes.SqlServer\Get-Builtin-Windows-Group-Name.ps1] function Get-Builtin-Windows-Group-Name([string] $groupKind) { # Windows Only $sid=""; #users: S-1-5-32-545, administrators: S-1-5-32-544, power users: S-1-5-32-547 if ($groupKind -eq "Users") { $sid="S-1-5-32-545"; } elseif ($groupKind -eq "Administrators") { $sid="S-1-5-32-544"; } elseif ($groupKind -eq "PowerUsers") { $sid="S-1-5-32-547"; } $ret="" if ($sid) { if (Has-Cmd "Get-CIMInstance") { $group=Get-CIMInstance Win32_Group; } elseif (Has-Cmd "Get-WmiObject") { $group=Get-WmiObject Win32_Group; } $ret = ($group | where { $_.SID -eq "$sid" } | Select -First 1).Name; } return $ret; } # @("Administrators", "PowerUsers", "Users") | % { "$($_): '$(Get-Builtin-Windows-Group-Name $_)'" } # Get-WmiObject Win32_Group | ft * # Include File: [\Includes.SqlServer\Get-SqlServer-Downloads-Folder.ps1] function Get-SqlServer-Setup-Folder() { return (GetPersistentTempFolder "SQLSERVERS_SETUP_FOLDER" "SQL-Setup"); } function Get-SqlServer-Media-Folder() { return (GetPersistentTempFolder "SQLSERVERS_MEDIA_FOLDER" "SQL Media"); } # Include File: [\Includes.SqlServer\Install-SQLServer.ps1] <# META ---- LauncherSize 133032 SetupHash 2D975BB24E872383C63D676105DFAF548972FA82970A8DB0AAC4E161555C8411466850F1442DDD988542FDB1B2205C08C1A8A97EEB9F1DD3AF7B49BFB80D7A21 SetupSize 1349103806 Version 2022 MediaType Developer Setup C:\Users\VSSADM~1\AppData\Local\Temp\PS1 Repo Downloads\SQL-2022-Developer Launcher C:\Users\VSSADM~1\AppData\Local\Temp\PS1 Repo Downloads\SQL-2022-Developer\Setup.exe MediaSize 1233861846 MediaHash 70DF481879338B608231D7FD0F518642CFAF481708E2EA6343DC217C56D5AF7182008EDB8CDF4D96652D44BD7A4B7FA6F3CD1CBAF7A8E3771760B169390F46F4 Media C:\Users\VSSADM~1\AppData\Local\Temp\PS1 Repo Downloads\SQL-Setup-Compressed\SQL-2022-Developer UPDATE ------ UpdateFolder C:\Users\VSSADM~1\AppData\Local\Temp\PS1 Repo Downloads\SQL-2022-CU14 Url https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5038325-x64.exe UpdateSize 463846640 UpdateId CU14 UpdateLauncher C:\Users\VSSADM~1\AppData\Local\Temp\PS1 Repo Downloads\SQL-2022-CU14\SQLServer2022-KB5038325-x64.exe #> function Install-SQLServer { Param( [object] $meta, [object] $update, # optional nullable, [string] $instanceName, [string[]] $optionsOverride = @() ) # check if sql server server already installed if ($meta.MediaType -ne "LocalDB") { $localSqlServers = @(Find-Local-SqlServers) $localSqlServer = $localSqlServers | ? { if ($instanceName -eq "MSSQLSERVER" -and $_.Instance -eq "(local)") { return $true; } if ("(local)\$($instanceName)" -eq $_.Instance) { return $true; } } | Select -First 1; if ($localSqlServer) { Write-Host "SQL Server $($instanceName) already installed. Its Installer version is $($localSqlServer.InstallerVersion). Skipping."; return; } } if (-not $meta.LauncherSize) { $err="[Install-SQLServer] Invalid `$meta argument. Probably download failed"; Write-Host $err; $meta | Format-Table-Smarty return @{ Error=$err; } } if ($meta.MediaType -eq "LocalDB") { Write-Host "Installing LocalDB MSI `"$($meta.Launcher)`" Version $($meta.Version)" $logDir = if ("$($ENV:SYSTEM_ARTIFACTSDIRECTORY)") { "$($ENV:SYSTEM_ARTIFACTSDIRECTORY)" } else { "$($ENV:TEMP)" } $setupCommandLine = @("/c", "msiexec.exe", "/i", "`"$($meta.Launcher)`"", "IACCEPTSQLLOCALDBLICENSETERMS=YES", "/qn", "/L*v", "SqlLocalDB-Setup-$($meta.Version).log"); $setupStatus = Execute-Process-Smarty "SQL LocalDB $($meta.Version) Setup" "cmd.exe" $setupCommandLine -WaitTimeout 1800 $setupStatus | Format-Table-Smarty | Out-Host return $setupStatus; } if ($update) { $isUpdateValid = ("$($update.UpdateSize)" -and "$($update.UpdateFolder)" -and "$($update.UpdateLauncher)") if (-not $isUpdateValid) { $err="[Install-SQLServer] Invalid `$update argument. Probably download failed"; Write-Host $err; $update | Format-Table-Smarty | Out-Host return @{ Error = $err }; } } $sqlAdministratorsGroup = Get-Builtin-Windows-Group-Name "Administrators"; if (-not $sqlAdministratorsGroup) { $sqlAdministratorsGroup = "Administrators"; } $sqlAdministratorsGroup = "BUILTIN\$($sqlAdministratorsGroup)"; $defaultOptions = @{ InstallTo = Combine-Path "$(Get-System-Drive)" "SQL"; Password = "Meaga`$tr0ng"; Tcp = 1; NamedPipe = 1; SysAdmins = "$sqlAdministratorsGroup"; Features = "SQLENGINE,FullText"; Collation = ""; # Depends on System Language, todo: SQL_Latin1_General_CP1_CI_AS or SQL_Latin1_General_CP1_CI_AS DbDir = ""; # DbLogDir = ""; # TempDbDir = ""; # Using /Slash optional overrides TempDbLogDir = "" # BackupDir = ""; # Startup = "Automatic"; # Manual | Disabled } $options = $defaultOptions.Clone(); # Apply $args $extraArguments=@(); foreach($a in $optionsOverride) { try { $p="$a".IndexOf("="); $k="$a".SubString(0,$p); if (($p+1) -eq "$a".Length) { $v=""; } else { $v="$a".SubString($p+1); }} catch { $k=""; $v=""; } $v = "$v" -replace "{InstanceName}", $instanceName; if ("$k" -ne "" -and (-not "$k".StartsWith("/")) ) { $options[$k] = $v; Write-Host "Overridden option '$k' = `"$v`""; } elseif ("$k" -ne "" -and "$k".StartsWith("/") ) { $extraArguments += "$($k)=`"$v`"" Write-Host "Overridden extra argument '$k' = `"$v`""; } } $major = ($meta.Version.Substring(0,4)) -as [int]; $is2020 = $major -ge 2016; $setupArg=@(); $title = "SQL Server $($meta.Version) $($meta.MediaType) Setup" if ($major -eq 2005) { # SQL_Engine,SQL_Data_Files,SQL_Replication,SQL_FullText,SQL_SharedTools $argFeatures = IIf ($meta.MediaType -eq "Core") "SQL_Engine" "SQL_Engine,SQL_FullText"; $argSQLAUTOSTART = IIf ($options.Startup -eq "Automatic") "1" "0" # /qb for unattended with basic UI $setupArg = "/qn", "ADDLOCAL=$argFeatures", "INSTANCENAME=`"$instanceName`"", "DISABLENETWORKPROTOCOLS=0", # 0: All, 1: None, 2: TCP only "SECURITYMODE=SQL", "SAPWD=`"$($options.Password)`"", "INSTALLSQLDIR=`"$($options.InstallTo)`"", "SQLAUTOSTART=$argSQLAUTOSTART"; $setupStatus = Execute-Process-Smarty "SQL Server $($meta.Version) $($meta.MediaType) Setup" $meta.Launcher $setupArg -WaitTimeout 3600 $setupStatus | Format-Table-Smarty | Out-Host $err=$setupStatus.Error; # Exec Patch if ($update) { $title = "SQL Server $($meta.Version) Upgrade to $($update.UpdateId)" $updateCommandLine = @("/QUIET", "/Action=Patch", "/InstanceName=$instanceName"); $upgradeResult = Execute-Process-Smarty "$title" $update.UpdateLauncher $updateCommandLine $upgradeResult | Format-Table -AutoSize | Out-String -Width 256 | Out-Host if ($upgradeResult.Error) { $err += " " + $upgradeResult.Error; } } if ($err) { return @{ Error = $err }; } # Write-Host "Workaround for 2005 logs"; sleep 1; & taskkill.exe @("/t", "/f", "/im", "setup.exe"); } else { <# 2008 "%AppData%\Temp\%KEY%\Setup\Setup.exe" /Q /INDICATEPROGRESS /Action=Install ^ /ADDCURRENTUSERASSQLADMIN ^ /FEATURES=SQL ^ /INSTANCENAME=%NEW_SQL_INSTANCE_NAME% ^ /SECURITYMODE=SQL /SAPWD=`1qazxsw2 ^ /SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" ^ /INSTANCEDIR="%SystemDrive%\SQL" ^ /INSTALLSHAREDDIR="%SystemDrive%\SQL\x64b" ^ /INSTALLSHAREDWOWDIR="%SystemDrive%\SQL\x86b" ^ /SQLSYSADMINACCOUNTS="BUILTIN\ADMINISTRATORS" ^ /TCPENABLED=1 /NPENABLED=1 #> $argFeatures = IIf ($meta.MediaType -eq "Advanced") "SQL_Engine,SQL_FullText" "SQL_Engine"; $argQuiet = IIf ((Is-BuildServer) -or $meta.Version -like "2005*" -or $meta.Version -like "2008-*") "/Q" "/QUIETSIMPLE"; $argProgress = "/INDICATEPROGRESS"; $argProgress = ""; $argADDCURRENTUSERASSQLADMIN = IIf ($meta.MediaType -eq "Developer") "" "/ADDCURRENTUSERASSQLADMIN"; # 2008 and R2: The setting 'IACCEPTROPENLICENSETERMS' specified is not recognized. $argIACCEPTROPENLICENSETERMS = IIF ($major -le 2014) "" "/IACCEPTROPENLICENSETERMS"; # 2008 & 2008 R2 Dev 10.50.6000.34: /AGTSVCACCOUNT="NT AUTHORITY\SYSTEM" required on Windows 2016+ $argAGTSVCACCOUNT = IIF (($meta.Version -like "2008*") -and $meta.MediaType -eq "Developer") "/AGTSVCACCOUNT=`"NT AUTHORITY\SYSTEM`"" ""; # 2008-xXX features $argFeatures = "$($options.Features)" if ($meta.Version -match "2008-") { # For Developer use command line "Features=..." If ($meta.MediaType -eq "Core") { $argFeatures = "SQLENGINE" } If ($meta.MediaType -eq "Advanced") { $argFeatures = "SQLENGINE,FULLTEXT" } } $argENU = IIf ($meta.Version -match "2008-") "" "/ENU" $argIACCEPTSQLSERVERLICENSETERMS = IIf ($meta.Version -match "2008-") "" "/IAcceptSQLServerLicenseTerms" $hasUpdateSourceArgument = ($major -ge 2012); $argUpdateEnabled = IIF ([bool]"$update" -and $hasUpdateSourceArgument) "/UpdateEnabled=True" "" $argUpdateSource = If ("$update" -and $hasUpdateSourceArgument) { "/UpdateSource=`"$($update.UpdateFolder)`"" } else { "" }; $argSQLCOLLATION = IIF ([bool]$options.Collation) "/SQLCOLLATION=`"$($options.Collation)`"" "" $argSQLSVCSTARTUPTYPE = IIF ([bool]$options.Startup) "/SQLSVCSTARTUPTYPE=`"$($options.Startup)`"" "" $argX86 = IIf ($meta.Version -match "2008-x86" -and $meta.MediaType -eq "Developer" -and (Get-CPU-Architecture-Suffix-for-Windows) -eq "x64") "/X86" ""; # AddCurrentUserAsSQLAdmin can be used only by Express SKU or set using ROLE. $setupArg = "$argQuiet", "$argENU", "$argProgress", "/ACTION=Install", "/INSTANCENAME=`"$instanceName`"", "$argX86", "/FEATURES=`"$argFeatures`"", "$argIACCEPTSQLSERVERLICENSETERMS", "$argIACCEPTROPENLICENSETERMS", "$argUpdateEnabled", "$argUpdateSource", "$argSQLCOLLATION", "/INSTANCEDIR=`"$($options.InstallTo)`"", "/SECURITYMODE=`"SQL`"", "/SAPWD=`"$($options.Password)`"", "/SQLSVCACCOUNT=`"NT AUTHORITY\SYSTEM`"", "$argAGTSVCACCOUNT", "$argSQLSVCSTARTUPTYPE", "/BROWSERSVCSTARTUPTYPE=AUTOMATIC", "$argADDCURRENTUSERASSQLADMIN", "/SQLSYSADMINACCOUNTS=`"$($sqlAdministratorsGroup)`"", "/TCPENABLED=$($options.Tcp)", "/NPENABLED=$($options.NamedPipe)"; # TODO: Remove Existing $setupArg += @($extraArguments) # Perform Setup, plus upgrade if 2012+ $setupStatus = Execute-Process-Smarty "$title" $meta.Launcher $setupArg -WaitTimeout 3600 $setupStatus | Format-Table-Smarty | Out-Host $err = $setupStatus.Error; if ("$update" -and (-not $hasUpdateSourceArgument)) { $title = "SQL Server $($meta.Version) Upgrade to $($update.UpdateId)" if ($meta.Version -like "2008R2*") { Say "Starting $title" $updateCommandLine = @("/QUIET", "/IAcceptSQLServerLicenseTerms", "/Action=Patch", "/InstanceName=$instanceName"); # SP3 ok $upgradeResult = Execute-Process-Smarty "$title" $update.UpdateLauncher $updateCommandLine $upgradeResult | Format-Table -AutoSize | Out-String -Width 256 | Out-Host } else { # OK on "2008" Say "Starting $title" $updateCommandLine = @("/QUIET", "/Action=Patch", "/InstanceName=$instanceName"); $upgradeResult = Execute-Process-Smarty "$title" $update.UpdateLauncher $updateCommandLine $upgradeResult | Format-Table -AutoSize | Out-String -Width 256 | Out-Host } if ($upgradeResult -and $upgradeResult.Error) { $err += " " + $upgradeResult.Error; } if ($err) { return @{ Error = $err }; } } } } # Include File: [\Includes.SqlServer\Invoke-LocalDB-Executable.ps1] # Version: Latest | 16 | 15 | 14 | 13 | 12 | 11 (16.0, 15.0, ... also supported) function Invoke-LocalDB-Executable([string] $title, [string] $version, [string[]] $parameters) { $localDbList = Find-LocalDb-Versions $exe = $localDbList | Select -First 1 | % { $_.Exe } if ($version) { $exe2 = $localDbList | ? { $_.ShortVersion -like "$version*" } | Select -First 1 | % { $_.Exe } if ($exe2) { $exe = $exe2 } } if ($exe) { $pars = @($parameters); $pars += @($args); Troubleshoot-Info "[$title] `"$exe`" $($pars -join " ")" & "$exe" @($pars) | Out-Host return $? } else { Write-Line -TextDarkRed "SQLLocalDB.Exe Not Found for version `"$version`"" } return $false } # Include File: [\Includes.SqlServer\Invoke-SqlServer-Command.ps1] function Invoke-SqlServer-Command([string] $title, [string] $connectionString, <# or #>[string] $instance, [string] $sqlCommand, [int] $timeoutSec = 30) { if (-not $connectionString) { $connectionString = "Server=$($instance);Integrated Security=SSPI;Connection Timeout=10;Pooling=False" } $startAt = [System.Diagnostics.Stopwatch]::StartNew(); $exception = $null; try { $con = New-Object System.Data.SqlClient.SqlConnection($connectionString); $con.Open(); $cmd = new-object System.Data.SqlClient.SqlCommand($sqlCommand, $con) $cmd.CommandTimeout = $timeoutSec * 1000; $__ = $cmd.ExecuteNonQuery(); $cmd.Dispose(); $con.Close() return; } catch { $exception = $_.Exception; <# Write-Host $_.Exception -ForegroundColor DarkGray #> } Write-Host "Warning! Can't invoke SQL Command on SQL Server '$($title)' during $($startAt.ElapsedMilliseconds / 1000) seconds$([Environment]::NewLine)$($exception)" -ForegroundColor DarkRed } # Invoke-SqlServer-Command -Title "MSSQLSERVER" -Instance "(local)" -Options @{ xp_cmdshell = $true; "clr enabled" = $false; "server trigger recursion" = $true; "min server memory (MB)" = 160; "max server memory (MB)" = 4096 } # Include File: [\Includes.SqlServer\Is-SqlServer-Setup-Cache-Enabled.ps1] function Is-SqlServer-Setup-Cache-Enabled() { $false; } # Include File: [\Includes.SqlServer\ParseNonEmptyTrimmedLines.ps1] # return array of strings function ParseNonEmptyTrimmedLines([string] $raw) { foreach($line in "$raw".Split([char] 13, [char] 10)) { $l = "$line".Trim() if ($l.Length -gt 0) { $l } } } # ParseNonEmptyTrimmedLines "`r`n1`r2`n3`r`n`r`n" # Include File: [\Includes.SqlServer\Parse-SqlServers-Input.ps1] function Parse-SqlServers-Input { param( [string] $list) # Say "Installing SQL Server(s) by tags: $list" $rawServerList = "$list".Replace("`r"," ").Replace("`n"," ").Split(@([char]44, [char]59)); foreach($sqlDef in $rawServerList) { $arr = $sqlDef.Split(@([char]58)); $sqlKey = "$($arr[0])".Trim(); if ($arr.Length -gt 1) { $instanceName=$arr[1].Trim(); } else { $instanceName=$null; } $tags=@("$sqlKey".Split([char]32) | % {$_.Trim()} | where { $_.Length -gt 0 } ) if ($tags.Count -gt 0) { $version = "$($tags[0])"; try { $major = $version.Substring(0,4) -as [int] } catch {} $versionHasBits = ($version -like "*-x86" -or $version -like "*-x64") if ((-not $versionHasBits) -and ($major -le 2014)) { $version += IIF ($major -eq 2005) "-x86" "-$(Get-CPU-Architecture-Suffix-for-Windows)"; } $missingDeveloper = ($version -like "2005*" -or $version -like "2014-x86" -or $version -like "2008-*"); $mediaType = IIF ($tags.Count -ge 2) $tags[1] (IIF $missingDeveloper "Advanced" "Developer") $rawUpdate = IIF ($tags.Count -ge 3) $tags[2] "" if ($instanceName -eq $null -and $mediaType -ne "LocalDB") { $instanceName = $mediaType.Substring(0,3).ToUpper() + "_" + $version.Replace("-", "_"); } if ($instanceName -ne $null) { $instanceName = "$($instanceName.ToUpper())" } $normalizedMeta = Find-SQLServer-Meta $version $mediaType if (-not $normalizedMeta) { Write-Warning "Unknwon SQL Server version $version mediatype $mediaType" } else { # Version and MediaType are clarified. # First (latest) update if not found if ($rawUpdate) { $update = $normalizedMeta.CU | ? { $_.Id -eq $rawUpdate } | Select -First 1; if (-not $update) { $update = $normalizedMeta.CU | Select -First 1; } $updateId = IIF ([bool]"$update") $update.Id $null; } else { $updateId = $null; $update = $null; } @{Version = $version; MediaType = $mediaType; UpdateId = "$updateId"; Update = $update; InstanceName = $instanceName; Definition=$sqlKey } } } } } <# 2014 --> 2014-x64 Developer on x64, #> # Include File: [\Includes.SqlServer\Publish-SQLServer-SetupLogs.ps1] function Publish-SQLServer-SetupLogs([string] $toFolder, $compression=9) { if ((Get-Os-Platform) -ne "Windows") { Write-Host "Publish-SQLServer-SetupLogs() function is Windows only. Skipping."; return; } if ("$toFolder" -ne "") { New-Item -ItemType Directory -Path "$toFolder" -EA SilentlyContinue | out-null; } $folders = Find-SqlServer-SetupLogs $sevenZip = Get-Full7z-Exe-FullPath-for-Windows -Version "1900" foreach($logsFolder in $folders) { $archiveName=$logsFolder.Substring([System.IO.Path]::GetPathRoot($logsFolder).Length).Replace("\", ([char]8594).ToString()) Say "Pack '$logsFolder' as `"$toFolder\$archiveName.7z`"" & "$sevenZip" @("a", "-y", "-mx=$compression", "-ms=on", "-mqs=on", "$toFolder\$archiveName.7z", "$logsFolder\*") | out-null if (-not $?) { Write-Host "Failed publishing '$archiveName' to folder '$toFolder'" -ForegroundColor DarkRed # return $false; } # return $true; } } # Include File: [\Includes.SqlServer\Query-SqlServer-Version.ps1] function Query-SqlServer-Version([string] $title, [string] $connectionString, <# or #>[string] $instance, [int] $timeoutSec = 30) { if (-not $connectionString) { $connectionString = "Server=$($instance);Integrated Security=SSPI;Connection Timeout=3;Pooling=False" } $startAt = [System.Diagnostics.Stopwatch]::StartNew(); $exception = $null; do { try { $sql = @" SELECT Cast(ISNULL(ServerProperty('ProductVersion'), '') as nvarchar) + ' ' + (Case ServerProperty('IsLocalDB') When 1 Then 'LocalDB' Else '' End) + ' ' + Cast(ISNULL(ServerProperty('Edition'), '') as nvarchar) + ' ' + Cast(ISNULL(ServerProperty('ProductLevel'), '') as nvarchar) + ' ' + Cast(ISNULL(ServerProperty('ProductUpdateLevel'), '') as nvarchar) + (Case ServerProperty('IsFullTextInstalled') When 1 Then ' + Full-text' Else '' End); "@; $con = New-Object System.Data.SqlClient.SqlConnection($connectionString); $con.Open(); $cmd = new-object System.Data.SqlClient.SqlCommand($sql, $con) $cmd.CommandTimeout = 3; $rdr = $cmd.ExecuteReader() $__ = $rdr.Read() $ret = "$($rdr.GetString(0))" $ret = $ret.Trim().Replace(" ", " ").Replace(" ", " ").Replace(" ", " ") $con.Close() return $ret; } catch { $exception = $_.Exception; <# Write-Host $_.Exception -ForegroundColor DarkGray #> } } while($startAt.ElapsedMilliseconds -le ($timeoutSec * 1000)); Write-Host "Warning! Can't query version of SQL Server '$($title)' during $($startAt.ElapsedMilliseconds / 1000) seconds$([Environment]::NewLine)$($exception)" -ForegroundColor DarkRed } # Query-SqlServer-Version -Title "FAKE" -Instance "(local)\22" -Timeout 2 # Query-SqlServer-Version -Title "SQL 2005" -Instance "(local)\SQL_2005_SP4_X86" -Timeout 2 # Include File: [\Includes.SqlServer\Set-SqlServer-Database-Files-Size.ps1] # TODO: function Set-SqlServer-Database-Files-Size([string] $title, [string] $connectionString, <# or #>[string] $instance, [string] $dbName, [string] $dataSize, [string] $dataGrow, [string] $logSize, [string] $logGrow, $timeout = 30) { $sql = @" Declare @type tinyint; Declare @name sysname; Declare @sql nvarchar(4000); Declare @newSize varchar(1000); Declare @newGrow varchar(1000); DECLARE FilesCursor Cursor Static FOR SELECT type, name FROM [$dbName].sys.database_files Where type in (0,1); Open FilesCursor While 1=1 Begin Fetch Next From FilesCursor Into @type, @name; If @@FETCH_STATUS <> 0 Break; If @type = 0 Set @newSize = '$dataSize' Else Set @newGrow = '$dataGrow'; If @type = 1 Set @newSize = '$logSize' Else Set @newGrow = '$logGrow'; Set @sql = 'ALTER DATABASE [$dbName] MODIFY FILE ( NAME = N''' + @name + ''', SIZE = ' + @newSize + ', FILEGROWTH = ' + @newGrow + ' );'; -- Print @sql; exec (@sql); End Close FilesCursor; Deallocate FilesCursor; "@; } <# USE [master] GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'tempdev', SIZE = 23552KB , FILEGROWTH = 10%) GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'templog', SIZE = 9216KB , FILEGROWTH = 131072KB ) GO USE [master] GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'temp3', FILEGROWTH = 11%) GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'temp6', FILEGROWTH = 12%) GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'temp8', FILEGROWTH = 131072KB ) GO ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'tempdev', SIZE = 716800KB ) GO #> # Include File: [\Includes.SqlServer\Set-SQLServer-Options.ps1] function Set-SQLServer-Options([string] $title, [string] $connectionString, <# or #>[string] $instance, [hashtable] $options, [int] $timeoutSec = 30) { if (-not $connectionString) { $connectionString = "Server=$($instance);Integrated Security=SSPI;Connection Timeout=10;Pooling=False" } $startAt = [System.Diagnostics.Stopwatch]::StartNew(); $exception = $null; $keys = @($options | % { $_.Keys }) $sqlCommands = @("exec sp_configure 'show advanced option', 1", "reconfigure with override;"); foreach($key in $keys) { $val = $options[$key]; if ($val -is [bool]) { if ($val) { $val = 1 } else { $val = 0 } } $sqlCommands += "exec sp_configure '$key', $val" } $sqlCommands += "reconfigure with override;"; do { try { $con = New-Object System.Data.SqlClient.SqlConnection($connectionString); $con.Open(); Write-Host "Connection to SQL Server $title is Ready for Configuration" foreach($sqlCommand in $sqlCommands) { $cmd = new-object System.Data.SqlClient.SqlCommand($sqlCommand, $con) $cmd.CommandTimeout = 30; try { $__ = $cmd.ExecuteNonQuery(); Write-Host " ok: `"$sqlCommand`"" } catch { Write-Host " fail: `"$sqlCommand`". $($_.Exception.Message)" } $cmd.Dispose(); } $con.Close() return; } catch { $exception = $_.Exception; <# Write-Host $_.Exception -ForegroundColor DarkGray #> } } while($startAt.ElapsedMilliseconds -le ($timeoutSec * 1000)); Write-Host "Warning! Can't apply configuration for SQL Server '$($title)' during $($startAt.ElapsedMilliseconds / 1000) seconds$([Environment]::NewLine)$($exception)" -ForegroundColor DarkRed } # Set-SQLServer-Options -Title "MSSQLSERVER" -Instance "(local)" -Options @{ xp_cmdshell = $true; "clr enabled" = $false; "server trigger recursion" = $true; "min server memory (MB)" = 160; "max server memory (MB)" = 4096 } # Include File: [\Includes.SqlServer\Setup-SqlServers.ps1] function Setup-SqlServers() { <# .SYNOPSIS SQL Server Setup and Management including Developer, Express, and LocalDB editions. The intended use of this project is for Continuous Integration (CI) scenarios, where: 1) A SQL Server or LocalDB needs to be installed without user interaction. 2) A SQL Server or LocalDB installation doesn't need to persist across multiple CI runs. By default it installs SQL Engine and full text search, adds current user to SQL Server Administrators, and turns on TCP/IP and Named Pipe protocols. Default sa password is 'Meaga$trong'. .OUTPUTS Returns array of errors, if occured on installation .EXAMPLE Setup-SqlServers "2022 Developer Updated: MSSQLSERVER, 2019 Advanced: ADV2019, 2017 Core Updated: CORE2017, 2016 Developer: DEV2016" Command above installs SQL Server 2022 Developer Edition as default instance, SQL Server 2019 Express Edition RTM with Advanced Services as ADV2019 instance, SQL Server 2017 Express Edition 2017 as CORE2017 instance, and SQL Server 2016 Developer Edition as DEV2016 instance Options: #> Param( [string] $sqlServers, [string[]] $optionsOverride = @() ) $optionsOverride += @($args) Say "Setting up SQL Server(s) `"$sqlServers`". Cpu is '$(Get-Cpu-Name)'. $((Get-Memory-Info).Description)" $errors = @(); $servers = Parse-SqlServers-Input $sqlServers $servers | % { [pscustomobject] $_ } | Format-Table -AutoSize | Out-String -Width 256 | Out-Host $jsonReport = @(); foreach($server in $servers) { $startAt = [System.Diagnostics.Stopwatch]::StartNew() Say "Downloading SQL Server '$($server.Version) $($server.MediaType)'" $setupMeta = Download-SQLServer-and-Extract $server.Version $server.MediaType; $setupMeta | Format-Table -AutoSize | Out-String -Width 256 | Out-Host $resultGetUpdate = $null; if ($server.UpdateId) { Say "Downloading SQL Server Update $($server.UpdateId) for version '$($server.Version) $($server.MediaType)'" $resultGetUpdate = Download-SqlServer-Update $server.Version $server.MediaType $server.Update; $resultGetUpdate | Format-Table -AutoSize | Out-String -Width 256 | Out-Host } $secondsDownload = $startAt.ElapsedMilliseconds / 1000.0; $startAt = [System.Diagnostics.Stopwatch]::StartNew() Say "Installing $($server.Version) $($server.MediaType)" $installStatus = Install-SQLServer $setupMeta $resultGetUpdate $server.InstanceName @($optionsOverride); Say "SQL Server '$($server.Definition)' Setup Finished. $((Get-Memory-Info).Description)" $secondsInstall = $startAt.ElapsedMilliseconds / 1000.0; $jsonReport += @{ Definition=$server.Definition; Version=$server.Version; MediaType=$server.MediaType; SecondsDownload = $secondsDownload; SecondsInstall = $secondsInstall; Cpu = $cpuName; } if ($installStatus -and $installStatus.Error) { $errors += "SQL Server '$($server.Definition)' Setup failed. $($installStatus.Error)"; } } if ("$($ENV:DEBUG_LOG_FOLDER)") { $reportJsonFullName = "$($ENV:DEBUG_LOG_FOLDER)\SQL Setup Benchmark.json" Create-Directory-for-File $reportJsonFullName $jsonReport | ConvertTo-Json | Out-File $reportJsonFullName -Force } return $errors; } # Include File: [\Includes.SqlServer\Try-Get-FileName-by-Uri.ps1] function Try-Get-FileName-by-Uri ([string] $url) { try { $uri = New-Object System.Uri $url; } catch { return $null; } $path = $uri.AbsolutePath; $parts = $path.Split("/"); $ret = $parts | Select -Last 1; if ("$ret" -eq "download") { $ret = $parts | Select -Last 2 | Select -First 1; } return "$ret"; } function Try-Get-FileExtension-by-Uri ([string] $url) { $name = Try-Get-FileName-by-Uri $url; if ($name -eq $null) { return $null; } return ([System.IO.Path]::GetExtension($name)); } # Include File: [\Includes.SqlServer\Uninstall-LocalDB-List.ps1] function Uninstall-LocalDB-List([string[]] $patterns) { # $patterns # "*" # "2016", "2017" $localDbList = @(Get-Speedy-Software-Product-List | ? { $_.Name -match "LocalDB" -and $_.Vendor -match "Microsoft" }) $names = @($localDbList | % { "$($_.Name)".Trim() }) Write-Host "Uninstalling Microsoft LocalDB by patterns '$patterns'" Write-Host "Total LocalDB Installed: $($localDbList.Count), $names" $total = 0; foreach($localDb in $localDbList) { $isMatch = "$patterns" | ? { if ($_ -eq "*") { return $true }; $localDB.Name -match $_ }; if ($isMatch) { Say "UNINSTALL '$($localDB.Name)'" $result = Execute-Process-Smarty "LocalDB Remover for '$($localDB.Name)'" "msiexec.exe" @("/qn", "/x", "$($localDB.IdentifyingNumber)", "/norestart"); $result | Format-Table-Smarty | Out-Host $total++; } } Say "DONE. Total LocalDB Uninstalled: $total" } Export-ModuleMember -Function Parse-SqlServers-Input Export-ModuleMember -Function Setup-SqlServers Export-ModuleMember -Function Query-SqlServer-Version Export-ModuleMember -Function Uninstall-LocalDB-List Export-ModuleMember -Function Set-SQLServer-Options Export-ModuleMember -Function Bootstrap-Aria2-If-Required Export-ModuleMember -Function Enumerate-Plain-SQLServer-Downloads Export-ModuleMember -Function Enumerate-SQLServer-Downloads Export-ModuleMember -Function Invoke-SqlServer-Command Export-ModuleMember -Function Find-Local-SqlServers Export-ModuleMember -Function Populate-Local-SqlServer-Version Export-ModuleMember -Function Say Export-ModuleMember -Function Troubleshoot-Info Export-ModuleMember -Function Write-Line Export-ModuleMember -Function Set-SqlServer-Database-Files-Size Export-ModuleMember -Function Set-Property-Smarty # This works with all the versions and all instances Export-ModuleMember -Function Find-LocalDb-Versions Export-ModuleMember -Function Find-LocalDb-SqlServers Export-ModuleMember -Function Create-LocalDB-Instance Export-ModuleMember -Function Delete-LocalDB-Instance Export-ModuleMember -Function Invoke-LocalDB-Executable Export-ModuleMember -Function Test-Show-LocalDb-Versions-with-Instances Export-ModuleMember -Function Test-Create-Delete-LocalDB-Instance # This works with SQLLocalDB|v11.0 instance of the latest version only Export-ModuleMember -Function Find-LocalDb-SqlServer Export-ModuleMember -Function Start-LocalDb-SqlServer Export-ModuleMember -Function Out-String-And-TrimEnd Export-ModuleMember -Function Append-All-Text Export-ModuleMember -Function Combine-Path Export-ModuleMember -Function Create-Directory Export-ModuleMember -Function Create-Directory-for-File Export-ModuleMember -Function Download-2010-SQLServer-and-Extract Export-ModuleMember -Function Download-And-Install-Specific-VC-Runtime Export-ModuleMember -Function Download-File-FailFree Export-ModuleMember -Function Download-File-FailFree-and-Cached Export-ModuleMember -Function Download-File-Managed Export-ModuleMember -Function Download-Fresh-SQLServer-and-Extract Export-ModuleMember -Function Download-SQLServer-and-Extract Export-ModuleMember -Function Download-Specific-VC-Runtime Export-ModuleMember -Function Download-SqlServer-Update Export-ModuleMember -Function Execute-Process-Smarty Export-ModuleMember -Function Extract-Archive-by-Default-Full-7z Export-ModuleMember -Function ExtractArchiveBy7zMini Export-ModuleMember -Function ExtractArchiveByDefault7zFull Export-ModuleMember -Function ExtractSqlServerSetup Export-ModuleMember -Function Find-SQLServer-Meta Export-ModuleMember -Function Find-SqlServer-SetupLogs Export-ModuleMember -Function Format-Table-Smarty Export-ModuleMember -Function Get-Aria2c-Exe-FullPath-for-Windows Export-ModuleMember -Function Get-Builtin-Windows-Group-Name Export-ModuleMember -Function Get-CPU-Architecture-Suffix-for-Windows Export-ModuleMember -Function Get-Cpu-Name Export-ModuleMember -Function Get-Folder-Size Export-ModuleMember -Function Get-Full7z-Exe-FullPath-for-Windows Export-ModuleMember -Function Get-Github-Latest-Release Export-ModuleMember -Function Get-Github-Releases Export-ModuleMember -Function Get-Installed-VC-Runtimes Export-ModuleMember -Function Get-Memory-Info Export-ModuleMember -Function Get-Mini7z-Exe-FullPath-for-Windows Export-ModuleMember -Function Get-Nix-Uname-Value Export-ModuleMember -Function Get-Os-Platform Export-ModuleMember -Function Get-PS1-Repo-Downloads-Folder Export-ModuleMember -Function Get-Random-Free-Port Export-ModuleMember -Function Get-Smarty-FileHash Export-ModuleMember -Function Get-Smarty-FolderHash Export-ModuleMember -Function Get-Speedy-Software-Product-List Export-ModuleMember -Function Get-SqlServer-Media-Folder Export-ModuleMember -Function Get-SqlServer-Setup-Folder Export-ModuleMember -Function Get-System-Drive Export-ModuleMember -Function Get-Windows-Release-Id Export-ModuleMember -Function GetPersistentTempFolder Export-ModuleMember -Function Has-Cmd Export-ModuleMember -Function IIf Export-ModuleMember -Function Install-SQLServer Export-ModuleMember -Function Is-Ansi-Supported Export-ModuleMember -Function Is-BuildServer Export-ModuleMember -Function Is-File-Not-Empty Export-ModuleMember -Function Is-Intel-Emulation-Available Export-ModuleMember -Function Is-SqlServer-Setup-Cache-Enabled Export-ModuleMember -Function Is-Vc-Runtime-Installed Export-ModuleMember -Function Measure-Action Export-ModuleMember -Function ParseNonEmptyTrimmedLines Export-ModuleMember -Function Publish-SQLServer-SetupLogs Export-ModuleMember -Function Reverse-Pipe Export-ModuleMember -Function Select-WMI-Objects Export-ModuleMember -Function Remove-Windows-Service-If-Exists Export-ModuleMember -Function Start-LocalDb-SqlServer Export-ModuleMember -Function Start-Stopwatch Export-ModuleMember -Function To-Boolean Export-ModuleMember -Function To-Sortable-Version-String Export-ModuleMember -Function Try-BuildServerType Export-ModuleMember -Function Try-Get-FileExtension-by-Uri Export-ModuleMember -Function Try-Get-FileName-by-Uri Export-ModuleMember -Function Write-All-Text Export-ModuleMember -Function Try-And-Retry Export-ModuleMember -Function Get-Windows-Power-Plans Export-ModuleMember -Function Get-Windows-Active-Power-Plan Export-ModuleMember -Function Get-Windows-Active-Power-Plan-Name Export-ModuleMember -Function Set-Windows-Power-Plan-by-Name # Variables are exported for tests only. Should be used directly Export-ModuleMember -Variable "SqlServerDownloadLinks" Export-ModuleMember -Variable "SqlServer2010DownloadLinks" Export-ModuleMember -Variable "SqlServerAlreadyUpdatedList" Export-ModuleMember -Variable "Full7zLinksMetadata_onWindows" Export-ModuleMember -Variable "VcRuntimeLinksMetadata" |