Update-FSLogix.ps1

<#PSScriptInfo
 
.VERSION 0.0.1
.GUID 37311878-913e-4dd0-bc2f-a9400438f589
.AUTHOR Jörg Brors
.COMPANYNAME
.COPYRIGHT (c) 2025 Jörg Brors. All rights reserved.
.TAGS FSLogix Update GoldenImage ZipCompare OnlineCompare
.LICENSEURI https://opensource.org/licenses/MIT
.PROJECTURI https://github.com/joergbrors/Update-FSLogix
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.DESCRIPTION Update-FSLogix checks, downloads, and updates Microsoft FSLogix to the latest available release.
.RELEASENOTES
    0.0.1 – Initial release, created by ChatGPT on behalf of Jörg Brors.
#>

<#
.SYNOPSIS
    Checks, downloads, and updates Microsoft FSLogix to the latest available release.
 
.DESCRIPTION
    Update-FSLogix checks the installed FSLogix version on the host and, if requested, downloads
    the current package via the official aka.ms redirect, extracts the ZIP, reads the
    FSLogixAppsSetup.exe FileVersion, compares it to the installed build, and performs a
    silent in-place upgrade when newer. Created by ChatGPT on behalf of Jörg Brors.
    All output is in English.
 
.PARAMETER Update
    Perform the in-place silent upgrade if a newer build is available.
 
.PARAMETER ZipCompare
    Download the latest ZIP, extract it, read the EXE FileVersion, and compare only (no install).
 
.PARAMETER ResolveOnly
    Resolve the final download URL behind https://aka.ms/fslogix_download and show it.
 
.PARAMETER NoProxy
    Disable system proxy usage for HTTP requests (useful for strict corporate proxies).
 
.PARAMETER KeepTemp
    Keep the downloaded ZIP and extracted temp folder for troubleshooting.
 
.EXAMPLE
    Update-FSLogix.ps1
    Performs a check only (no changes).
 
.EXAMPLE
    Update-FSLogix.ps1 -ZipCompare
    Downloads current package, extracts, and compares version with installed build.
 
.EXAMPLE
    Update-FSLogix.ps1 -Update
    Performs a silent in-place upgrade if the downloaded build is newer.
 
.NOTES
    Run in an elevated PowerShell session (Administrator). Works with Windows PowerShell 5.1 and newer.
#>


[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [switch]$AcceptEula,
    [switch]$Update,
    [switch]$ResolveOnly,
    [switch]$OnlineCompare,
    [switch]$ZipCompare,
    [string]$InstallerPath = "",
    [string]$DownloadUrl = "https://aka.ms/fslogix_download",
    [switch]$UseBits,
    [switch]$NoProxy,
    [switch]$KeepTemp,
    [string]$LogPath = "C:\ProgramData\FSLogix\Update"
)

# --- Logging helper ---
function Write-Log {
    param([string]$Message, [string]$Level="INFO")
    $line = "[{0}] [{1}] {2}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Level, $Message
    Write-Output $line
    if ($global:LogFile) { Add-Content -Path $global:LogFile -Value $line }
}

# --- Prepare logging ---
if (-not (Test-Path $LogPath)) { New-Item -Path $LogPath -ItemType Directory -Force | Out-Null }
$global:LogFile = Join-Path $LogPath ("fslogix_update_{0}.log" -f (Get-Date -Format "yyyyMMdd_HHmmss"))
Write-Log "Log file: $global:LogFile"

# --- Get installed FSLogix version ---
function Get-FSLogixInstalledVersion {
    $reg = "HKLM:\SOFTWARE\FSLogix\Apps"
    $result = [ordered]@{
        Installed = $false; Running = $false; FileVersion = $null; RegistryVersion = $null
    }

    if (Test-Path $reg) {
        $val = Get-ItemProperty -Path $reg -ErrorAction SilentlyContinue
        $result.RegistryVersion = $val.Version
        $exe = "C:\Program Files\FSLogix\Apps\frx.exe"
        if (Test-Path $exe) {
            $fv = (Get-Item $exe).VersionInfo.FileVersion
            $result.FileVersion = $fv
            $result.Installed = $true
        }
        $svc = Get-Service -Name "frxsvc" -ErrorAction SilentlyContinue
        if ($svc -and $svc.Status -eq "Running") { $result.Running = $true }
    }
    [pscustomobject]$result
}

$installed = Get-FSLogixInstalledVersion
Write-Log "Installed before: Installed=$($installed.Installed), Running=$($installed.Running), FileVersion=$($installed.FileVersion), RegistryVersion=$($installed.RegistryVersion)"

# --- Resolve aka.ms link ---
function Resolve-FslogixUrl {
    param([string]$Url)
    try {
        $req = [System.Net.WebRequest]::Create($Url)
        $req.AllowAutoRedirect = $false
        $resp = $req.GetResponse()
        $final = $resp.GetResponseHeader("Location")
        $resp.Close()
        return $final
    } catch {
        Write-Log "Failed to resolve URL: $_" "ERROR"
        return $null
    }
}

# --- Download helper ---
function Download-File {
    param([string]$Url, [string]$Destination)
    if ($UseBits) {
        Write-Log "Using BITS transfer..."
        Start-BitsTransfer -Source $Url -Destination $Destination -DisplayName "FSLogix Download"
    }
    else {
        try {
            Write-Log "Using WebClient for download..."
            $wc = New-Object System.Net.WebClient
            if ($NoProxy) { $wc.Proxy = [System.Net.GlobalProxySelection]::GetEmptyWebProxy() }
            $wc.DownloadFile($Url, $Destination)
        }
        catch {
            Write-Log "WebClient failed, trying Invoke-WebRequest..." "WARN"
            Invoke-WebRequest -Uri $Url -OutFile $Destination -UseBasicParsing
        }
    }
}

# --- Compare version inside ZIP ---
function Compare-ZipVersion {
    param([string]$Url)

    $temp = New-Item -Path ([IO.Path]::GetTempPath()) -Name ("fslogix_{0}" -f (Get-Random)) -ItemType Directory
    $zipPath = Join-Path $temp "fslogix.zip"
    Write-Log "Downloading package to $zipPath"
    Download-File -Url $Url -Destination $zipPath

    $extract = Join-Path $temp "extract"
    Expand-Archive -Path $zipPath -DestinationPath $extract -Force
    $setup = Get-ChildItem -Path $extract -Recurse -Filter "FSLogixAppsSetup.exe" | Select-Object -First 1
    if ($setup) {
        $filever = (Get-Item $setup.FullName).VersionInfo.FileVersion
        Write-Log "Extracted FSLogixAppsSetup.exe version: $filever"
        if ($installed.FileVersion -ne $null) {
            if ([version]$installed.FileVersion -lt [version]$filever) {
                Write-Log "Installed version $($installed.FileVersion) is older than package version $filever" "WARN"
            } else {
                Write-Log "Installed version $($installed.FileVersion) is up-to-date (>= $filever)"
            }
        }
    } else {
        Write-Log "Setup executable not found in ZIP" "ERROR"
    }

    if (-not $KeepTemp) { Remove-Item -Path $temp -Recurse -Force }
}

# --- Main flow ---
$finalUrl = Resolve-FslogixUrl -Url $DownloadUrl
if ($finalUrl) { Write-Log "Resolved final download URL: $finalUrl" }

if ($ZipCompare) {
    if ($finalUrl) { Compare-ZipVersion -Url $finalUrl }
    return
}

if ($OnlineCompare) {
    if ($finalUrl -match "FSLogix_(?<mver>\d{2}\.\d{2})\.zip") {
        Write-Log "Info: version in URL (marketing): $($matches['mver'])"
        Write-Log "No full build in filename to compare against installed build." "WARN"
    }
    return
}

if ($ResolveOnly) {
    Write-Log "ResolveOnly: final URL = $finalUrl"
    return
}

Write-Log "Default: check only. Use -Update or -ZipCompare for actions."