A set of PowerShell scripts that install a base developer environment and multiple languages for Windows.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
14 KiB

function Test-WinUtilPackageManager {
<#
.SYNOPSIS
Checks if Winget is installed
.PARAMETER winget
Check if Winget is installed
#>
Param(
[System.Management.Automation.SwitchParameter]$winget
)
$status = "not-installed"
if ($winget) {
# Check if Winget is available while getting it's Version if it's available
$wingetExists = $true
try {
$wingetVersionFull = winget --version
} catch [System.Management.Automation.CommandNotFoundException], [System.Management.Automation.ApplicationFailedException] {
Write-Warning "Winget was not found due to un-availablity reasons"
$wingetExists = $false
} catch {
Write-Warning "Winget was not found due to un-known reasons, The Stack Trace is:`n$($psitem.Exception.StackTrace)"
$wingetExists = $false
}
# If Winget is available, Parse it's Version and give proper information to Terminal Output.
# If it isn't available, the return of this funtion will be "not-installed", indicating that
# Winget isn't installed/available on The System.
if ($wingetExists) {
# Check if Preview Version
if ($wingetVersionFull.Contains("-preview")) {
$wingetVersion = $wingetVersionFull.Trim("-preview")
$wingetPreview = $true
} else {
$wingetVersion = $wingetVersionFull
$wingetPreview = $false
}
# Check if Winget's Version is too old.
$wingetCurrentVersion = [System.Version]::Parse($wingetVersion.Trim('v'))
# Grabs the latest release of Winget from the Github API for version check process.
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/Winget-cli/releases/latest" -Method Get -ErrorAction Stop
$wingetLatestVersion = [System.Version]::Parse(($response.tag_name).Trim('v')) #Stores version number of latest release.
$wingetOutdated = $wingetCurrentVersion -lt $wingetLatestVersion
Write-Host "===========================================" -ForegroundColor Green
Write-Host "--- Winget is installed ---" -ForegroundColor Green
Write-Host "===========================================" -ForegroundColor Green
Write-Host "Version: $wingetVersionFull" -ForegroundColor White
if (!$wingetPreview) {
Write-Host " - Winget is a release version." -ForegroundColor Green
} else {
Write-Host " - Winget is a preview version. Unexpected problems may occur." -ForegroundColor Yellow
}
if (!$wingetOutdated) {
Write-Host " - Winget is Up to Date" -ForegroundColor Green
$status = "installed"
}
else {
Write-Host " - Winget is Out of Date" -ForegroundColor Red
$status = "outdated"
}
} else {
Write-Host "===========================================" -ForegroundColor Red
Write-Host "--- Winget is not installed ---" -ForegroundColor Red
Write-Host "===========================================" -ForegroundColor Red
$status = "not-installed"
}
}
return $status
}
function Get-WinUtilWingetPrerequisites {
<#
.SYNOPSIS
Downloads the Winget Prereqs.
.DESCRIPTION
Downloads Prereqs for Winget. Version numbers are coded as variables and can be updated as uncommonly as Microsoft updates the prereqs.
#>
# I don't know of a way to detect the prereqs automatically, so if someone has a better way of defining these, that would be great.
# Microsoft.VCLibs version rarely changes, but for future compatibility I made it a variable.
$versionVCLibs = "14.00"
$fileVCLibs = "https://aka.ms/Microsoft.VCLibs.x64.${versionVCLibs}.Desktop.appx"
# Write-Host "$fileVCLibs"
# Microsoft.UI.Xaml version changed recently, so I made the version numbers variables.
$versionUIXamlMinor = "2.8"
$versionUIXamlPatch = "2.8.6"
$fileUIXaml = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v${versionUIXamlPatch}/Microsoft.UI.Xaml.${versionUIXamlMinor}.x64.appx"
# Write-Host "$fileUIXaml"
Try{
Write-Host "Downloading Microsoft.VCLibs Dependency..."
Invoke-WebRequest -Uri $fileVCLibs -OutFile $ENV:TEMP\Microsoft.VCLibs.x64.Desktop.appx
Write-Host "Downloading Microsoft.UI.Xaml Dependency...`n"
Invoke-WebRequest -Uri $fileUIXaml -OutFile $ENV:TEMP\Microsoft.UI.Xaml.x64.appx
}
Catch{
throw [WingetFailedInstall]::new('Failed to install prerequsites')
}
}
function Get-WinUtilWingetLatest {
<#
.SYNOPSIS
Uses GitHub API to check for the latest release of Winget.
.DESCRIPTION
This function grabs the latest version of Winget and returns the download path to Install-WinUtilWinget for installation.
#>
# Invoke-WebRequest is notoriously slow when the byte progress is displayed. The following lines disable the progress bar and reset them at the end of the function
$PreviousProgressPreference = $ProgressPreference
$ProgressPreference = "silentlyContinue"
Try{
# Grabs the latest release of Winget from the Github API for the install process.
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/Winget-cli/releases/latest" -Method Get -ErrorAction Stop
$latestVersion = $response.tag_name #Stores version number of latest release.
$licenseWingetUrl = $response.assets.browser_download_url | Where-Object {$_ -like "*License1.xml"} #Index value for License file.
Write-Host "Latest Version:`t$($latestVersion)`n"
Write-Host "Downloading..."
$assetUrl = $response.assets.browser_download_url | Where-Object {$_ -like "*Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"}
Invoke-WebRequest -Uri $licenseWingetUrl -OutFile $ENV:TEMP\License1.xml
# The only pain is that the msixbundle for winget-cli is 246MB. In some situations this can take a bit, with slower connections.
Invoke-WebRequest -Uri $assetUrl -OutFile $ENV:TEMP\Microsoft.DesktopAppInstaller.msixbundle
}
Catch{
throw [WingetFailedInstall]::new('Failed to get latest Winget release and license')
}
$ProgressPreference = $PreviousProgressPreference
}
function Install-WinUtilWinget {
<#
.SYNOPSIS
Installs Winget if it is not already installed.
.DESCRIPTION
This function will download the latest version of Winget and install it. If Winget is already installed, it will do nothing.
#>
$isWingetInstalled = Test-WinUtilPackageManager -winget
Try {
if ($isWingetInstalled -eq "installed") {
Write-Host "`nWinget is already installed.`r" -ForegroundColor Green
return
} elseif ($isWingetInstalled -eq "outdated") {
Write-Host "`nWinget is Outdated. Continuing with install.`r" -ForegroundColor Yellow
} else {
Write-Host "`nWinget is not Installed. Continuing with install.`r" -ForegroundColor Red
}
# Gets the computer's information
if ($null -eq $sync.ComputerInfo){
$ComputerInfo = Get-ComputerInfo -ErrorAction Stop
} else {
$ComputerInfo = $sync.ComputerInfo
}
if (($ComputerInfo.WindowsVersion) -lt "1809") {
# Checks if Windows Version is too old for Winget
Write-Host "Winget is not supported on this version of Windows (Pre-1809)" -ForegroundColor Red
return
}
# Install Winget via GitHub method.
# Used part of my own script with some modification: ruxunderscore/windows-initialization
Write-Host "Downloading Winget Prerequsites`n"
Get-WinUtilWingetPrerequisites
Write-Host "Downloading Winget and License File`r"
Get-WinUtilWingetLatest
Write-Host "Installing Winget w/ Prerequsites`r"
Add-AppxProvisionedPackage -Online -PackagePath $ENV:TEMP\Microsoft.DesktopAppInstaller.msixbundle -DependencyPackagePath $ENV:TEMP\Microsoft.VCLibs.x64.Desktop.appx, $ENV:TEMP\Microsoft.UI.Xaml.x64.appx -LicensePath $ENV:TEMP\License1.xml
Write-Host "Manually adding Winget Sources, from Winget CDN."
Add-AppxPackage -Path https://cdn.winget.microsoft.com/cache/source.msix #Seems some installs of Winget don't add the repo source, this should makes sure that it's installed every time.
Write-Host "Winget Installed" -ForegroundColor Green
Write-Host "Enabling NuGet and Module..."
Install-PackageProvider -Name NuGet -Force
Install-Module -Name Microsoft.WinGet.Client -Force
# Winget only needs a refresh of the environment variables to be used.
Write-Output "Refreshing Environment Variables...`n"
$ENV:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
} Catch {
Write-Host "Failure detected while installing via GitHub method. Your computer cannot run winget. Please email help@learncodethehardway.com to help find out why." -ForegroundColor Red
throw [WingetFailedInstall]::new('Failed to install!')
}
}
$isAdmin = [System.Security.Principal.WindowsPrincipal]::new(
[System.Security.Principal.WindowsIdentity]::GetCurrent()).
IsInRole('Administrators')
if(-not $isAdmin) {
$params = @{
FilePath = 'powershell' # or pwsh if Core
Verb = 'RunAs'
ArgumentList = @(
'-ExecutionPolicy ByPass'
'-File "{0}"' -f $PSCommandPath
)
}
Write-Warning "About to install winget. Winget is a Microsoft open source package manager."
Write-Warning "To install Winget this script will temporarily launch in Administrator mode, then get out of it."
Write-Warning "If you already have Winget then this will only check that you have it, or upgrade it."
Write-Warning "If you'd prefer to not use it then abort now and good luck getting everything installed."
Read-Host -Prompt "Press any key to continue, or CTRL-C to abort" | Out-Null
Start-Process -Wait @params
Write-Host "Admin stuff done..."
} else {
Write-Host "In Admin stuff..."
Install-WinUtilWinget
return
}
$installs=@(
'Geany.Geany',
'Git.Git',
'Genivia.ugrep',
'Microsoft.WindowsTerminal',
'Kitware.CMake',
'Microsoft.VCRedist.2015+.x64'
)
Write-Warning "About to install the following software:"
Write-Warning "-----------------------------------------"
foreach($pkg in $installs) { Write-Host $pkg }
Write-Warning "-----------------------------------------"
Write-Warning "This will use winget to do the installs. If you already have this software installed then winget should only upgrade them. If you don't want this then abort now."
Read-Host -Prompt "Press any key to continue, or CTRL-C to abort" | Out-Null
foreach($pkg in $installs) {
Start-Process -NoNewWindow -Wait winget -ArgumentList 'install',$pkg
}
$winlibsPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$env:APPDATA\..\Local\Programs\WinLibs")
if(Test-Path -Path $winlibsPath) {
Write-Warning "#=========================================================#"
Write-Warning "!! The directory $winlibsPath already exists, which means"
Write-Warning "!! you already have winlibs installed. Here's the version:"
cat "$winlibsPath\mingw64\version_info.txt"
Write-Warning "#=========================================================#"
Write-Warning "Here's the version that Winget will install:"
winget search BrechtSanders.WinLibs.POSIX.UCRT.LLVM
Write-Warning "--- If you want me to replace your install with this version, then stop and"
Write-Warning "delete the $winlibsPath directory before hitting ENTER to continue."
Write-Warning "!!! If you do NOT want to replace this directory then hit CTRL-C now."
Read-Host -Prompt "Press any key to continue, or CTRL-C to abort" | Out-Null
}
Write-Warning "!! Installing WinLibs in $winlibsPath"
Write-Warning "This has to be installed this way because winget won't add it to the path so I have to do it manually. If you don't want this, then hit CTRL-C and install WinLibs yourself."
Read-Host -Prompt "Press any key to continue, or CTRL-C to abort" | Out-Null
winget install --location "$winlibsPath" -e BrechtSanders.WinLibs.POSIX.UCRT.LLVM
if($env:PATH.contains($winlibsPath)) {
Write-Warning "!! Detected $winLibsPath in your PATH. Will not update your PATH."
Write-Warning "!! This is probably because you already installed it. You'll have"
Write-Warning "!! to manually remove this part of your path if you want to change it."
Write-Warning "!! But, it will probably still work since that's where I installed it."
} else {
$newPath = $env:PATH + ";$winlibsPath\mingw64\bin"
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
}
$gitPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$env:APPDATA\..\Local\Programs\Git\cmd")
if($env:PATH.contains($gitPath)) {
Write-Warning "!! Looks like your git installed correctly, but if it fails to run then uninstall it with 'winget remove git.git' then install it again with 'winget install git.git'"
} else {
Write-Warning "!! Git.Git did not add itself to the Path. The directory $gitPath is missing so I'll add it now."
$newPath = $env:PATH + ";$gitPath"
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
if($env:PATH.contains($gitPath)) {
Write-Warning "?? Great, git is in the path so if it is gone after this then something is going on."
} else {
Write-Warning "!!!!!!!!!!!!!!!!!!!!! Despite manually forcing the git $gitPath into the path it is _still_ not there."
Write-Warning "You'll have to manually install git later with: winget install git.git."
winget remove git.git
}
}