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 " `n Winget is already installed. `r " -ForegroundColor Green
return
} elseif ( $isWingetInstalled -eq " outdated " ) {
Write-Host " `n Winget is Outdated. Continuing with install. `r " -ForegroundColor Yellow
} else {
Write-Host " `n Winget 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' ,
'Microsoft.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 = " $ env:APPDATA\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 " )
}
Write-Warning " !!! CLOSE THIS POWERSHELL AND START A NEW ONE TO UPDATE PATH! "