.history/Install-WingetBatch_20251110110551.ps1

# WingetBatch Installation Script
# One-liner installer for fresh Windows 11 installs
# Downloads and installs Winget, all required dependencies, and the WingetBatch module

param(
    [switch]$SkipWinget,
    [switch]$SkipModules,
    [switch]$Force
)

$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'

try {
    # Ensure TLS 1.2 for Invoke-WebRequest/Invoke-RestMethod
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
}
catch {
    Write-Verbose "Unable to update TLS settings: $($_.Exception.Message)"
}

function Invoke-DownloadFile {
    param(
        [Parameter(Mandatory)] [string]$Uri,
        [Parameter(Mandatory)] [string]$OutFile
    )

    $invokeParams = @{
        Uri         = $Uri
        OutFile     = $OutFile
        ErrorAction = 'Stop'
    }

    if ($PSVersionTable.PSEdition -eq 'Desktop') {
        # UseBasicParsing avoids IE dependency on Windows PowerShell 5.1
        $invokeParams.UseBasicParsing = $true
    }

    Invoke-WebRequest @invokeParams
}

Write-Host "========================================" -ForegroundColor Cyan
Write-Host "WingetBatch Installation Script" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan

# Function to check admin rights
function Test-AdminRights {
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

if (-not (Test-AdminRights)) {
    Write-Host "`n⚠ This script requires administrator privileges." -ForegroundColor Yellow
    Write-Host "Please run PowerShell as Administrator and try again.`n" -ForegroundColor Yellow
    exit 1
}

# Install Winget if not already installed
if (-not $SkipWinget) {
    Write-Host "`n[1/4] Checking Winget installation..." -ForegroundColor Cyan

    $wingetPath = Get-Command winget -ErrorAction SilentlyContinue

    if ($wingetPath -and -not $Force) {
        Write-Host "✓ Winget is already installed at: $($wingetPath.Source)" -ForegroundColor Green
    }
    else {
        Write-Host "Installing Winget from Microsoft Store..." -ForegroundColor Yellow

        # Try Method 1: Direct GitHub download
        try {
            Write-Host "Attempting to install Winget from GitHub..." -ForegroundColor Gray

            $releaseParams = @{
                Uri         = "https://api.github.com/repos/microsoft/winget-cli/releases/latest"
                ErrorAction = 'Stop'
                Headers     = @{ 'User-Agent' = 'WingetBatchInstaller' }
            }

            if ($PSVersionTable.PSEdition -eq 'Desktop') {
                $releaseParams.UseBasicParsing = $true
            }

            $releases = Invoke-RestMethod @releaseParams
            $assets = $releases.assets

            $appInstallerAsset = $assets | Where-Object { $_.name -like 'Microsoft.DesktopAppInstaller_*_x64.msixbundle' } | Select-Object -First 1

            if (-not $appInstallerAsset) {
                # Fallback to generic name if exact pattern not found
                $appInstallerAsset = $assets | Where-Object { $_.name -match 'Microsoft\.DesktopAppInstaller_.*\.msixbundle$' } | Select-Object -First 1
            }

            if ($appInstallerAsset) {
                $tempDir = Join-Path $env:TEMP "winget-install"
                if (-not (Test-Path $tempDir)) {
                    New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
                }

                $appInstallerPath = Join-Path $tempDir $appInstallerAsset.name
                Write-Host "Downloading App Installer: $($appInstallerAsset.name)" -ForegroundColor Gray
                Invoke-DownloadFile -Uri $appInstallerAsset.browser_download_url -OutFile $appInstallerPath

                # Identify dependency packages (VCLibs, UI.Xaml)
                $dependencyAssets = $assets | Where-Object {
                    $_.name -match 'Microsoft\.UI\.Xaml.*x64.*\.msixbundle$' -or
                    $_.name -match 'Microsoft\.VCLibs.*x64.*\.appx'
                }

                $dependencyFiles = @()
                foreach ($dependency in $dependencyAssets) {
                    $dependencyPath = Join-Path $tempDir $dependency.name
                    Write-Host "Downloading dependency: $($dependency.name)" -ForegroundColor Gray
                    Invoke-DownloadFile -Uri $dependency.browser_download_url -OutFile $dependencyPath
                    $dependencyFiles += $dependencyPath
                }

                Write-Host "Installing dependencies and App Installer..." -ForegroundColor Gray
                try {
                    if ($dependencyFiles.Count -gt 0) {
                        Add-AppxPackage -Path $appInstallerPath -DependencyPath $dependencyFiles -ForceApplicationShutdown -ErrorAction Stop
                    }
                    else {
                        Add-AppxPackage -Path $appInstallerPath -ForceApplicationShutdown -ErrorAction Stop
                    }

                    Write-Host "✓ Winget package installed" -ForegroundColor Green
                }
                catch {
                    Write-Host "⚠ Winget installation error: $($_.Exception.Message)" -ForegroundColor Yellow
                }

                # Clean up downloaded files
                Get-ChildItem -Path $tempDir -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
                Remove-Item $tempDir -Force -ErrorAction SilentlyContinue

                Start-Sleep -Seconds 2

                if (Get-Command winget -ErrorAction SilentlyContinue) {
                    Write-Host "✓ Winget installed successfully" -ForegroundColor Green
                }
                else {
                    Write-Host "⚠ Winget installation completed but may not be in PATH yet." -ForegroundColor Yellow
                    Write-Host " Please close and reopen PowerShell, or manually install from Microsoft Store:" -ForegroundColor Yellow
                    Write-Host " https://apps.microsoft.com/detail/9NBLGGH4NNS1" -ForegroundColor Cyan
                }
            }
            else {
                throw "Could not find App Installer package in GitHub releases"
            }
        }
        catch {
            Write-Host "✗ Error installing Winget from GitHub: $($_.Exception.Message)" -ForegroundColor Red
            Write-Host "`n⚠ MANUAL INSTALLATION REQUIRED" -ForegroundColor Yellow
            Write-Host "Please install Windows Package Manager manually:" -ForegroundColor Yellow
            Write-Host " Option 1: Microsoft Store (recommended)" -ForegroundColor Cyan
            Write-Host " https://apps.microsoft.com/detail/9NBLGGH4NNS1" -ForegroundColor Cyan
            Write-Host " Option 2: GitHub Releases" -ForegroundColor Cyan
            Write-Host " https://github.com/microsoft/winget-cli/releases" -ForegroundColor Cyan
            Write-Host " Option 3: Windows 11 already has it (check 'winget' in Start Menu)" -ForegroundColor Cyan
            Write-Host "`nAfter installing, run this script again with -SkipWinget switch." -ForegroundColor Yellow
        }
    }
}

# Install required PowerShell modules
if (-not $SkipModules) {
    Write-Host "`n[2/4] Installing required PowerShell modules..." -ForegroundColor Cyan

    $modules = @(
        'PwshSpectreConsole',
        'PSWindowsUpdate',
        'ExchangeOnlineManagement'
    )

    foreach ($module in $modules) {
        Write-Host "`n Installing: $module" -ForegroundColor Gray

        $installed = Get-Module -ListAvailable -Name $module -ErrorAction SilentlyContinue

        if ($installed -and -not $Force) {
            Write-Host " ✓ $module already installed (v$($installed.Version | Select-Object -First 1))" -ForegroundColor Green
        }
        else {
            try {
                Install-Module -Name $module -Force -AllowClobber -ErrorAction Stop -Scope CurrentUser
                Write-Host " ✓ $module installed successfully" -ForegroundColor Green
            }
            catch {
                Write-Host " ✗ Failed to install $module : $($_.Exception.Message)" -ForegroundColor Red
            }
        }
    }
}

# Download and install WingetBatch module
Write-Host "`n[3/4] Setting up WingetBatch module..." -ForegroundColor Cyan

# Determine correct module path
if ($PSVersionTable.PSVersion.Major -ge 6) {
    $moduleBase = [System.IO.Path]::Combine([Environment]::GetFolderPath('MyDocuments'), 'PowerShell', 'Modules')
}
else {
    $moduleBase = [System.IO.Path]::Combine([Environment]::GetFolderPath('MyDocuments'), 'WindowsPowerShell', 'Modules')
}

$moduleDir = Join-Path $moduleBase "WingetBatch"
$modulePath = Join-Path $moduleDir "WingetBatch.psm1"

if ((Test-Path $modulePath) -and -not $Force) {
    Write-Host "✓ WingetBatch module already exists at: $moduleDir" -ForegroundColor Green
}
else {
    Write-Host "Downloading WingetBatch from GitHub..." -ForegroundColor Gray

    try {
        $repoUrl = "https://raw.githubusercontent.com/thebubbsy/WingetBatch/main"
        $files = @(
            "WingetBatch.psm1",
            "WingetBatch.psd1",
            "README.md"
        )

        if (-not (Test-Path $moduleDir)) {
            New-Item -ItemType Directory -Path $moduleDir -Force | Out-Null
        }

        foreach ($file in $files) {
            $fileUrl = "$repoUrl/$file"
            $filePath = Join-Path $moduleDir $file
            Write-Host " Downloading: $file" -ForegroundColor Gray
            Invoke-WebRequest -Uri $fileUrl -OutFile $filePath -ErrorAction SilentlyContinue
        }

        if (Test-Path $modulePath) {
            Write-Host "✓ WingetBatch module downloaded successfully" -ForegroundColor Green
        }
        else {
            Write-Host "✗ Failed to download WingetBatch module" -ForegroundColor Red
        }
    }
    catch {
        Write-Host "✗ Error downloading WingetBatch: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Import and configure WingetBatch
Write-Host "`n[4/4] Importing WingetBatch module..." -ForegroundColor Cyan

try {
    Import-Module WingetBatch -Force -ErrorAction Stop
    Write-Host "✓ WingetBatch module imported successfully" -ForegroundColor Green
    Write-Host "`nAvailable commands:" -ForegroundColor Cyan
    Get-Command -Module WingetBatch | Select-Object -ExpandProperty Name | ForEach-Object { Write-Host " • $_" -ForegroundColor Green }
}
catch {
    Write-Host "✗ Failed to import WingetBatch: $($_.Exception.Message)" -ForegroundColor Red
}

# Summary
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "Installation Complete!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "`nYou can now use WingetBatch commands:" -ForegroundColor Cyan
Write-Host " • Install-WingetAll `"search term`"" -ForegroundColor Green
Write-Host " • Get-WingetUpdates" -ForegroundColor Green
Write-Host " • Get-WingetNewPackages -Days 7" -ForegroundColor Green
Write-Host " • Remove-WingetRecent -Days 30" -ForegroundColor Green
Write-Host " • Enable-WingetUpdateNotifications" -ForegroundColor Green
Write-Host "`nFor help: Get-Help Install-WingetAll -Full`n" -ForegroundColor Cyan