Winget PowerShell Help

 avatar
unknown
powershell
a year ago
14 kB
168
No Index
#Set the execution policy for the current process to Unrestricted. This change applies only to the current script or session.
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force

# Function to check if the script is running as Administrator
function Test-IsAdmin {
    $currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $currentPrincipal = New-Object System.Security.Principal.WindowsPrincipal($currentIdentity)
    return $currentPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}

# Function to restart the script with elevated permissions
function Start-Elevated {
    $scriptPath = $PSCommandPath
    Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`"" -Verb RunAs
    exit
}

<###########################################################################################################
# Only need if Install-Module Microsoft.WinGet.Client & Install-PackageProvider -Name NuGet are required
# Check if the script is running as Administrator; if not, restart with elevated permissions
if (-not (Test-IsAdmin)) {
    Start-Elevated
}
###########################################################################################################>

# Define log file path
$logDirectory = "C:\CompanyName-IT"
$logFile = "$logDirectory\winget_install_log.txt"
# Create log directory if it doesn't exist
if (-not (Test-Path -Path $logDirectory)) {
    New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null
}

# Function to log messages
function Write-Log {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Host $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to install winget & dependencies
Function Install_Winget {
    $instDir = "C:\Winget"
    if (-not (Test-Path -Path $instDir)) {
        New-Item -ItemType Directory -Path $instDir -Force | Out-Null
    }

    $webClient = New-Object System.Net.WebClient
    Write-Log "Downloading WinGet and its dependencies..."

    try {
        # Step 1: Download Microsoft.VCLibs.x64.14.00.Desktop
        Write-Log "Step 1: Downloading Microsoft.VCLibs.x64.14.00.Desktop..."
        $urlMSVclibs = "https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx"
        $outputMSVclibs = "$instDir\Microsoft.VCLibs.x64.14.00.Desktop.appx"
        $webClient.DownloadFile($urlMSVclibs, $outputMSVclibs)
        Write-Log "Download complete: Microsoft.VCLibs.x64.14.00.Desktop.appx"
        Add-AppxPackage -Path $outputMSVclibs -ErrorAction SilentlyContinue
        Write-Log "Microsoft.VCLibs.x64.14.00.Desktop installed successfully."

        # Step 2: Download Microsoft.UI.Xaml.2.8.x64
        Write-Log "Step 2: Downloading Microsoft.UI.Xaml.2.8.x64..."
        $urlMSXamlx64 = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx"
        $outputMSXamlx64 = "$instDir\Microsoft.UI.Xaml.2.8.x64.appx"
        $webClient.DownloadFile($urlMSXamlx64, $outputMSXamlx64)
        Write-Log "Download complete: Microsoft.UI.Xaml.2.8.x64.appx"
        Add-AppxPackage -Path $outputMSXamlx64 -ErrorAction SilentlyContinue
        Write-Log "Microsoft.UI.Xaml.2.8.x64 installed successfully."

        # Step 3: Download Microsoft.DesktopAppInstaller (Winget)
        Write-Log "Step 3: Downloading Microsoft.DesktopAppInstaller..."
        $urlWingetLic = "https://github.com/microsoft/winget-cli/releases/download/v1.7.10582/5e4a105df01840b0bbf00985e4f57c1e_License1.xml"
        $outputWingetLic = "$instDir\5e4a105df01840b0bbf00985e4f57c1e_License1.xml"
        $urlWinget = "https://github.com/microsoft/winget-cli/releases/download/v1.7.10582/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
        $outputWinget = "$instDir\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
        $webClient.DownloadFile($urlWingetLic, $outputWingetLic)
        $webClient.DownloadFile($urlWinget, $outputWinget)
        Write-Log "Download complete: Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
        Add-AppxPackage -Path $outputWinget -ErrorAction SilentlyContinue
        #Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope AllUsers -Force # Is this needed? Need to check.
        #Install-Module Microsoft.WinGet.Client -Scope AllUsers -Force # Is this needed? Need to check.
        Write-Log "WinGet client installed successfully."
    }
    catch {
        Write-Log "An error occurred: $_"
    }
    finally {
        $webClient.Dispose()
    }
    Write-Log "All steps completed successfully."
}

# Function to verify Winget install
function Verify_Winget {
    try {
        Write-Log "Initializing Winget..."
        Start-Sleep -Seconds 15
        
        # Verify Winget installation
        $msAppInstallerInstalled = Get-AppxPackage -Name 'Microsoft.DesktopAppInstaller' -ErrorAction SilentlyContinue
        if ($msAppInstallerInstalled) {
            $wingetVer = (winget --version)
            Write-Log "Winget $wingetVer is installed."
        } else {
            Write-Log "Winget is not installed."
        }
    }
    catch {
        Write-Log "An error occurred during verification: $_"
        exit 1
    }
}

# Define the list of applications to install using winget
$applicationsToInstall = @(
    "SlackTechnologies.Slack",
    "Google.Chrome",
    "Box.Box",
    "Box.BoxTools",
    "Zoom.Zoom",
    "Mozilla.Firefox",
    "Notepad++.Notepad++",
    "DominikReichl.KeePass",
    "7zip.7zip",
    "Greenshot.Greenshot",
    "Microsoft.EdgeWebView2Runtime",
    "Microsoft.OpenJDK.21",
    "Microsoft.Office",
    "Zoom.ZoomOutlookPlugin",
    "Microsoft.Teams"
)

# Function to install an application using winget
function Install-App {
    param (
        [string]$appName
    )

    Write-Log "Checking $appName..."

    # Winget Error Code Hash Table # https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/returnCodes.md
    $errorCodes = @{
        -1978335231 = "Internal Error"
        -1978335230 = "Invalid command line arguments"
        -1978335229 = "Executing command failed"
        -1978335228 = "Opening manifest failed"
        -1978335227 = "Cancellation signal received"
        -1978335226 = "Running ShellExecute failed"
        -1978335225 = "Cannot process manifest. The manifest version is higher than supported. Please update the client."
        -1978335224 = "Downloading installer failed"
        -1978335223 = "Cannot write to index; it is a higher schema version"
        -1978335222 = "The index is corrupt"
        -1978335221 = "The configured source information is corrupt"
        -1978335220 = "The source name is already configured"
        -1978335219 = "The source type is invalid"
        -1978335218 = "The MSIX file is a bundle"
        -1978335217 = "Data required by the source is missing"
        -1978335216 = "None of the installers are applicable for the current system"
        -1978335215 = "The installer file's hash does not match the manifest"
        -1978335214 = "The source name does not exist"
        -1978335213 = "The source location is already configured under another name"
        -1978335212 = "No packages found"
        -1978335211 = "No sources are configured"
        -1978335210 = "Multiple packages found matching the criteria"
        -1978335209 = "No manifest found matching the criteria"
        -1978335208 = "Failed to get Public folder from source package"
        -1978335207 = "Command requires administrator privileges to run"
        -1978335206 = "The source location is not secure"
        -1978335205 = "The Microsoft Store client is blocked by policy"
        -1978335204 = "The Microsoft Store app is blocked by policy"
        -1978335203 = "The feature is currently under development. It can be enabled using winget settings."
        -1978335202 = "Failed to install the Microsoft Store app"
        -1978335201 = "Failed to perform auto complete"
        -1978335200 = "Failed to initialize YAML parser"
        -1978335199 = "Encountered an invalid YAML key"
        -1978335198 = "Encountered a duplicate YAML key"
        -1978335197 = "Invalid YAML operation"
        -1978335196 = "Failed to build YAML doc"
        -1978335195 = "Invalid YAML emitter state"
        -1978335194 = "Invalid YAML data"
        -1978335193 = "LibYAML error"
        -1978335192 = "Manifest validation succeeded with warning"
        -1978335191 = "Manifest validation failed"
        -1978335190 = "Manifest is invalid"
        -1978335189 = "App exist but no applicable updates found"
        -1978335188 = "winget upgrade --all completed with failures"
        -1978335187 = "Installer failed security check"
        -1978335186 = "Download size does not match expected content length"
        -1978335185 = "Uninstall command not found"
        -1978335184 = "Running uninstall command failed"
        -1978335183 = "ICU break iterator error"
        -1978335182 = "ICU casemap error"
        -1978335181 = "ICU regex error"
        -1978335180 = "Failed to install one or more imported packages"
        -1978335179 = "Could not find one or more requested packages"
        -1978335178 = "Json file is invalid"
        -1978335177 = "The source location is not remote"
        -1978335176 = "The configured rest source is not supported"
        -1978335175 = "Invalid data returned by rest source"
        -1978335174 = "Operation is blocked by Group Policy"
        -1978335173 = "Rest API internal error"
        -1978335172 = "Invalid rest source url"
        -1978335171 = "Unsupported MIME type returned by rest API"
        -1978335170 = "Invalid rest source contract version"
        -1978335169 = "Failed to connect to source"
        -1978335168 = "Invalid response returned from rest source"
        -1978335167 = "Rest source not found"
        -1978335166 = "Invalid source identifier"
        -1978335165 = "Source mismatch"
        -1978335164 = "YAML syntax error"
        -1978335163 = "Unsupported YAML version"
        -1978335162 = "Missing required YAML field"
        -1978335161 = "Invalid YAML parser state"
        -1978335160 = "Failed to parse manifest"
        -1978335159 = "API retry limit reached"
        -1978335158 = "API limit reached"
        -1978335157 = "Invalid action specified"
        -1978335156 = "Invalid command-line arguments"
        -1978335155 = "Unknown argument provided"
        -1978335154 = "Invalid configuration provided to parser"
        -1978335153 = "Parser syntax error"
        -1978335152 = "Unknown parser error"
        -1978335151 = "System command is invalid"
        -1978335150 = "System command not supported"
        -1978335149 = "System command failed"
        -1978335148 = "System command timed out"
        -1978335147 = "System command returned invalid result"
        -1978335146 = "System command returned an invalid file"
        -1978335145 = "System command returned an invalid path"
        -1978335144 = "System command returned an invalid parameter"
        -1978335143 = "System command returned invalid format"
        -1978335142 = "System command returned invalid state"
        -1978335141 = "System command returned invalid output"
        -1978335140 = "System command returned invalid input"
        -1978335139 = "System command timed out"
        -1978335138 = "System command failed with unknown error"
    }

    try {
        $process = Start-Process -FilePath "winget" -ArgumentList "install --id $appName --silent --scope `"machine`" --accept-package-agreements --accept-source-agreements" -NoNewWindow -PassThru -Wait
        # Log the exit code for debugging
        $exitCode = $process.ExitCode
        # Check exit code
        if ($errorCodes.ContainsKey($exitCode) -eq 0) {
            Write-Log "$appName processed successfully."
        } else {
            if ($errorCodes.ContainsKey($exitCode)) {
                $errorMessage = "Error: $($errorCodes[$process.ExitCode])."
            } else {
                $errorMessage = "Error: Unknown error code."
            }
            
            Write-Log "$errorMessage"

            # Optionally, retry the process without --scope "machine"
            if ($exitCode -ne -1978335189) {
                Write-Log "Cannot install machine wide. Retry 1:1"
                $process = Start-Process -FilePath "winget" -ArgumentList "install --id $appName --silent --accept-package-agreements --accept-source-agreements" -NoNewWindow -PassThru -Wait
                $exitCode = $process.ExitCode
                # Check exit code
                if ($exitCode -eq 0) {
                    Write-Log "$appName processed successfully."
                } else {
                        $errorMessage = "Error: $($errorCodes[$process.ExitCode])."
                }
            }
        }
    }
    catch {
        # Handle any unexpected errors
        $errorMessage = "An unexpected error occurred. Reason: $_"
        Write-Log "$errorMessage Check error log for details."
    }
}

# Call the Winget install function
Install_Winget

# Call the Winget verification function
Verify_Winget

Write-Log "Starting Application Installs..."
# Loop through applications and install or update each one
foreach ($app in $applicationsToInstall) {
    Install-App -appName $app
    Start-Sleep -Seconds 5 # Pause the script for 5 seconds
}
Write-Log "Applications have been installed."

# Create a Windows native notification
$notificationMessage = "Welcome to CompanyName! Your standard applications have been installed."
$notificationCommand = "New-BurntToastNotification -Text 'Installation Complete', '$notificationMessage'"
if (-not (Get-Command New-BurntToastNotification -ErrorAction SilentlyContinue)) {
    Install-Module -Name BurntToast -Force -Scope CurrentUser -Confirm:$false
    Import-Module BurntToast
}
Invoke-Expression $notificationCommand
Write-Log "Installation notification displayed."
Write-Log "Script execution completed."
Editor is loading...
Leave a Comment