param( [object]$Config, [string]$LogFile ) $ErrorActionPreference = "Continue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" Add-Content -Path $LogFile -Value $line -Encoding UTF8 } # ----------------------------------------------------------------------- # Check winget availability # ----------------------------------------------------------------------- Write-Log "Checking winget availability" -Level INFO $winget = Get-Command winget -ErrorAction SilentlyContinue if (-not $winget) { # Try to find winget in known locations $wingetPaths = @( "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe" "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller*\winget.exe" ) foreach ($p in $wingetPaths) { $found = Get-Item $p -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { $winget = $found.FullName; break } } } if (-not $winget) { Write-Log "winget not found - software installation skipped" -Level ERROR exit 1 } Write-Log "winget found: $($winget.Source -or $winget)" -Level OK # Accept agreements upfront & winget source update --accept-source-agreements 2>&1 | Out-Null # ----------------------------------------------------------------------- # Install packages from config # ----------------------------------------------------------------------- if (-not $Config -or -not $Config.software -or -not $Config.software.install) { Write-Log "No software list in config - skipping installs" -Level WARN } else { foreach ($pkg in $Config.software.install) { Write-Log "Installing $($pkg.name) ($($pkg.wingetId))" -Level INFO $result = & winget install --id $pkg.wingetId ` --silent ` --accept-package-agreements ` --accept-source-agreements ` --disable-interactivity ` 2>&1 $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { Write-Log " Installed OK: $($pkg.name)" -Level OK } elseif ($exitCode -eq -1978335189) { # 0x8A150011 = already installed Write-Log " Already installed: $($pkg.name)" -Level OK } else { Write-Log " Failed: $($pkg.name) (exit $exitCode)" -Level ERROR Write-Log " Output: $($result -join ' ')" -Level ERROR } } } # ----------------------------------------------------------------------- # Set Adobe Reader as default PDF app # ----------------------------------------------------------------------- $forcePdf = $true if ($Config -and $Config.pdfDefault) { $forcePdf = [bool]$Config.pdfDefault.forceAdobeReader } if ($forcePdf) { Write-Log "Setting Adobe Reader as default PDF app" -Level INFO # Find Adobe PDF viewer executable (Acrobat DC or Reader DC) $acroPaths = @( "$env:ProgramFiles\Adobe\Acrobat DC\Acrobat\Acrobat.exe" "${env:ProgramFiles(x86)}\Adobe\Acrobat DC\Acrobat\Acrobat.exe" "${env:ProgramFiles(x86)}\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" "$env:ProgramFiles\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" "${env:ProgramFiles(x86)}\Adobe\Reader\Reader\AcroRd32.exe" ) $acroExe = $acroPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 if (-not $acroExe) { Write-Log " Adobe PDF viewer not found - PDF default not set" -Level WARN } else { Write-Log " Found: $acroExe" -Level INFO # Set file type association via HKCR (system-wide, requires admin) $progId = "AcroExch.Document.DC" $openCmd = "`"$acroExe`" `"%1`"" # HKCR\.pdf -> progId if (-not (Test-Path "HKCR:\.pdf")) { New-Item -Path "HKCR:\.pdf" -Force | Out-Null } Set-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -Value $progId # HKCR\AcroExch.Document.DC\shell\open\command $cmdPath = "HKCR:\$progId\shell\open\command" if (-not (Test-Path $cmdPath)) { New-Item -Path $cmdPath -Force | Out-Null } Set-ItemProperty -Path $cmdPath -Name "(Default)" -Value $openCmd # Note: HKCU UserChoice requires a Windows-computed Hash value to be valid. # Direct ProgId write without Hash is silently reset by Windows on next access. # HKCR write above provides the system-wide default; per-user default is # handled by the PDF-DefaultApp scheduled task via HKCR on every logon. Write-Log " PDF default set to AcroRd32 (HKCR)" -Level OK } } Write-Log "Step 2 complete" -Level OK