xetup/scripts/02-software.ps1
X9 Dev f5a5de943a Implement Forgejo review changes: Atera, UCPD, PDF default, OA3, dedup
02-software: add Atera RMM agent install (Invoke-WebRequest + msiexec /qn),
stop UCPD driver before PDF association write, restart after; remove
reference to PDF-DefaultApp scheduled task in header

03-system-registry: correct OneDrive uninstall description - intentional
(pre-installed consumer version only, no policy key, M365 can reinstall)

04-default-profile: OneDrive RunOnce blocking removed, ShowRecent=0,
ShowFrequent=0, FullPath=1 in CabinetState already added in prior session

06-scheduled-tasks: PDF-DefaultApp task removed - PDF set once in step 02

08-activation: add OA3/BIOS embedded key check via SoftwareLicensingService
WMI; key priority: config.json > OA3 firmware > GVLK

web/spec: update all status badges, remove mustfix flags, deduplicate
OneDrive entries across steps 01/03/04, add OA3 row to step-08

web/data/descriptions.json: regenerated (65 items)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 09:29:32 +02:00

197 lines
8.7 KiB
PowerShell

<#
.SYNOPSIS
Installs standard business software via winget, sets Adobe PDF default, and installs Atera RMM agent.
.DESCRIPTION
Uses winget to install the standard X9.cz MSP software bundle. Checks winget
availability before running. Each install is logged. After Adobe Acrobat Reader,
temporarily stops the UCPD driver (User Choice Protection Driver, present since
Win11 23H2 / Win10 22H2 update) to allow the HKCR file association write, sets
.pdf -> AcroRd32, then restarts UCPD. Atera RMM agent is installed for MSP
monitoring, remote access, and ticketing integration.
.ITEMS
7-zip-7zip-7zip: Installs 7-Zip (winget ID: 7zip.7zip). Used for archive management. Silent install with --accept-package-agreements --accept-source-agreements flags required for unattended deployment.
adobe-acrobat-reader-64-bit-adobe-acroba: Installs Adobe Acrobat Reader DC 64-bit (Adobe.Acrobat.Reader.64-bit). Required as the default PDF viewer to prevent Edge from handling PDFs in browser mode, which limits functionality.
openvpn-connect-openvpntechnologies-open: Installs OpenVPN Connect client. Used for client VPN access when the client network requires a VPN. The ovpn profile and credentials are configured separately per client.
seznam-sw-je-neuplny-co-dalsiho-patri-do: The standard software list is incomplete. Candidates to add: Notepad++ (Notepad++.Notepad++), Google Chrome (Google.Chrome), possibly Microsoft 365 Apps, remote support tools. Needs decision from X9.cz team.
atera-agent-install: Atera RMM agent installed via msiexec /qn. Download: Invoke-WebRequest from https://x9.servicedesk.atera.com/api/utils/agent-install/windows/?cid=31&aeid=50b72e7113e54a63ac76b96c54c7e337. Agent enables MSP monitoring, remote access, and ticketing integration with the Atera dashboard.
adobe-pdf-default-pdf-acrord32-po-instal: Sets .pdf -> AcroRd32 file association after Acrobat install via HKCR (system-wide, no UserChoice hash issue). UCPD driver is stopped immediately before the write and restarted after to ensure the association persists across Edge updates.
ucpd-sys-kernel-driver-od-feb-2024-bloku: UCPD.sys (User Choice Protection Driver) is stopped before the PDF association write and restarted after. Pattern: Stop-Service ucpd -> set HKCR\.pdf -> Start-Service ucpd. Implemented in this script.
#>
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
# Stop UCPD driver before writing file association.
# UCPD.sys (User Choice Protection Driver) blocks UserChoice registry writes
# on Win11 23H2+ and some Win10 22H2 builds. Stopping it temporarily allows
# the HKCR association to be written reliably.
$ucpdStopped = $false
$ucpdSvc = Get-Service -Name "ucpd" -ErrorAction SilentlyContinue
if ($ucpdSvc) {
try {
Stop-Service -Name "ucpd" -Force -ErrorAction Stop
$ucpdStopped = $true
Write-Log " UCPD driver stopped" -Level OK
}
catch {
Write-Log " Could not stop UCPD: $_ (association may not persist on some builds)" -Level WARN
}
}
# 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
Write-Log " PDF default set to AcroRd32 (HKCR)" -Level OK
}
# Restart UCPD after writing association
if ($ucpdStopped) {
try {
Start-Service -Name "ucpd" -ErrorAction SilentlyContinue
Write-Log " UCPD driver restarted" -Level OK
}
catch {
Write-Log " Could not restart UCPD: $_" -Level WARN
}
}
}
# -----------------------------------------------------------------------
# Install Atera RMM Agent
# -----------------------------------------------------------------------
Write-Log "Installing Atera RMM Agent" -Level INFO
$ateraUrl = "https://x9.servicedesk.atera.com/api/utils/agent-install/windows/?cid=31&aeid=50b72e7113e54a63ac76b96c54c7e337"
$ateraMsi = "$env:TEMP\AteraAgent.msi"
try {
Write-Log " Downloading Atera agent..." -Level INFO
Invoke-WebRequest -Uri $ateraUrl -OutFile $ateraMsi -UseBasicParsing -ErrorAction Stop
Write-Log " Download complete" -Level OK
$msiResult = & msiexec /i $ateraMsi /qn 2>&1
Start-Sleep -Seconds 5
$ateraExe = "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
if (Test-Path $ateraExe) {
Write-Log " Atera agent installed" -Level OK
} else {
Write-Log " Atera agent install may have failed - binary not found at expected path" -Level WARN
Write-Log " msiexec output: $($msiResult -join ' ')" -Level WARN
}
}
catch {
Write-Log " Atera agent download/install failed: $_" -Level ERROR
}
finally {
Remove-Item $ateraMsi -Force -ErrorAction SilentlyContinue
}
Write-Log "Step 2 complete" -Level OK