PowerShell – Script to install Adobe Acrobat Reader

Script to install and Detects Acrobat Reader (32/64), stops processes/services, installs a provided 32-bit installer silently, disables auto-update via registry policy, removes desktop shortcuts, and logs to C:\logs\<date>\acrobats.log
<#
.SYNOPSIS
Detects Acrobat Reader (32/64), stops processes/services, installs a provided 32-bit installer silently,
disables auto-update via registry policy, removes desktop shortcuts, and logs to C:\logs\<date>\acrobats.log
.NOTES
- PowerShell 5.1
- Must run as Administrator
- Provide path to the 32-bit installer via -InstallerPath (EXE or MSI)
- Test in a safe environment before wide use
#>
$InstallerPath = $PSScriptRoot
param(
[Parameter(Mandatory=$true)]
[string]$InstallerPath
)
# -------------------------
# Elevation check
# -------------------------
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "This script must be run as Administrator."
exit 1
}
# -------------------------
# Logging helpers
# -------------------------
function Get-LogFile {
$date = (Get-Date).ToString('yyyy-MM-dd')
$dir = Join-Path -Path 'C:\logs' -ChildPath $date
if (-not (Test-Path $dir)) {
New-Item -Path $dir -ItemType Directory -Force | Out-Null
}
return Join-Path -Path $dir -ChildPath 'acrobat-manage.log'
}
$LogFile = Get-LogFile
function Log {
param(
[string]$Message,
[ValidateSet("INFO","WARN","ERROR","DEBUG")] [string]$Level = "INFO"
)
$ts = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
$line = "$ts [$Level] $Message"
try {
$line | Out-File -FilePath $LogFile -Encoding UTF8 -Append
} catch {
Write-Warning "Failed to write log: $($_.Exception.Message)"
}
Write-Host $line
}
# -------------------------
# Utility: parse uninstall registry entries and detect Acrobat Reader
# -------------------------
function Get-AcrobatReaderEntries {
<#
Returns PSCustomObject entries with:
DisplayName, UninstallString, InstallLocation, Version, RegistryKey, Architecture
#>
$results = @()
$regRoots = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
)
foreach ($root in $regRoots) {
try {
$keys = Get-ChildItem -Path $root -ErrorAction SilentlyContinue
foreach ($k in $keys) {
try {
$props = Get-ItemProperty -Path $k.PSPath -ErrorAction SilentlyContinue
if ($null -eq $props) { continue }
$display = $props.DisplayName
if ($display -and $display -match 'Adobe Acrobat Reader|Acrobat Reader') {
$arch = if ($root -like '*WOW6432Node*') { '32-bit' } else { '64-bit' }
$results += [PSCustomObject]@{
DisplayName = $props.DisplayName
UninstallString = $props.UninstallString
InstallLocation = $props.InstallLocation
Version = $props.DisplayVersion
Publisher = $props.Publisher
RegistryKey = $k.PSPath
Architecture = $arch
}
}
} catch { continue }
}
} catch { continue }
}
# Fallback: check Program Files folders
$possible = @(
Join-Path $env:ProgramFiles 'Adobe\Acrobat Reader*',
Join-Path ${env:ProgramFiles(x86)} '\Adobe\Acrobat Reader*'
)
foreach ($p in $possible) {
foreach ($d in Get-ChildItem -Path $p -Directory -ErrorAction SilentlyContinue) {
if (-not ($results | Where-Object { $_.InstallLocation -and ($_.InstallLocation -eq $d.FullName) })) {
$arch = if ($d.FullName -like '*Program Files (x86)*') { '32-bit' } else { '64-bit' }
$results += [PSCustomObject]@{
DisplayName = "Adobe Acrobat Reader (detected folder)"
UninstallString = $null
InstallLocation = $d.FullName
Version = $null
Publisher = "Adobe"
RegistryKey = $null
Architecture = $arch
}
}
}
}
return $results
}
# -------------------------
# Stop processes and services
# -------------------------
function Stop-AcrobatProcessesAndServices {
param([switch]$Force)
Log "Stopping Acrobat/Adobe processes and services..." "INFO"
$procNames = @('AcroRd32','Acrobat','AdobeARM','AdobeUpdateService','AdobeCollabSync','RdrCEF','AdobeNotificationClient')
foreach ($name in $procNames) {
try {
$procs = Get-Process -Name $name -ErrorAction SilentlyContinue
foreach ($p in $procs) {
try {
Log "Stopping process $($p.ProcessName) (Id $($p.Id))" "INFO"
Stop-Process -Id $p.Id -Force:$Force -ErrorAction Stop
Log "Stopped process Id $($p.Id)" "INFO"
} catch {
Log "Failed to stop process $($p.ProcessName) Id $($p.Id): $($_.Exception.Message)" "WARN"
}
}
} catch {}
}
# Stop Adobe services
try {
$svcCandidates = Get-Service | Where-Object { $_.Name -match 'Adobe|ARM|AdobeUpdate' -or $_.DisplayName -match 'Adobe' } -ErrorAction SilentlyContinue
foreach ($svc in $svcCandidates) {
try {
if ($svc.Status -ne 'Stopped') {
Log "Stopping service $($svc.Name) ($($svc.DisplayName))" "INFO"
Stop-Service -Name $svc.Name -Force -ErrorAction Stop
Log "Stopped service $($svc.Name)" "INFO"
}
} catch {
Log "Failed to stop service $($svc.Name): $($_.Exception.Message)" "WARN"
}
}
} catch {
Log "Service enumeration failed: $($_.Exception.Message)" "WARN"
}
}
# -------------------------
# Install provided 32-bit installer silently
# -------------------------
function Install-ReaderSilently {
param(
[Parameter(Mandatory=$true)][string]$PathToInstaller
)
if (-not (Test-Path $PathToInstaller)) {
Log "Installer not found at path: $PathToInstaller" "ERROR"
return $false
}
$ext = [IO.Path]::GetExtension($PathToInstaller).ToLowerInvariant()
Log "Installer found: $PathToInstaller (ext: $ext)" "INFO"
try {
if ($ext -eq '.msi') {
# Use msiexec for MSI installers
$args = "/i `"$PathToInstaller`" /qn /norestart"
Log "Running MSI installer: msiexec.exe $args" "INFO"
$p = Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -PassThru -WindowStyle Hidden
Log "msiexec exit code: $($p.ExitCode)" "INFO"
return ($p.ExitCode -eq 0)
} else {
# EXE installer - try common silent switches for Adobe Reader
# Common Adobe Reader switch: /sAll (silent), /rs (suppress reboot)
# We'll try: /sAll /rs /msi /norestart (some installers accept /sAll)
$tryArgs = @(
"/sAll /rs",
"/sAll /rs /msi /norestart",
"/s /v/qn",
"/silent"
)
foreach ($a in $tryArgs) {
try {
Log "Attempting installer with args: $a" "INFO"
$proc = Start-Process -FilePath $PathToInstaller -ArgumentList $a -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
Log "Installer returned exit code $($proc.ExitCode) for args: $a" "INFO"
if ($proc.ExitCode -eq 0) {
Log "Installer succeeded with args: $a" "INFO"
return $true
}
} catch {
Log "Installer attempt failed for args [$a]: $($_.Exception.Message)" "WARN"
# continue trying other switches
}
}
# Last resort: run installer without args (interactive) but we avoid that in silent script
Log "All silent attempts failed. Installer may require different switches." "ERROR"
return $false
}
} catch {
Log "Installation attempt failed: $($_.Exception.Message)" "ERROR"
return $false
}
}
# -------------------------
# Verify installation and folder existence
# -------------------------
function Verify-ReaderInstalled {
param(
[string]$ExpectedArch = "32-bit"
)
Log "Verifying Acrobat Reader installation (expecting $ExpectedArch)..." "INFO"
$entries = Get-AcrobatReaderEntries
$match = $entries | Where-Object { $_.DisplayName -and ($_.DisplayName -match 'Adobe Acrobat Reader|Acrobat Reader') -and ($_.Architecture -eq $ExpectedArch) }
if ($match) {
foreach ($m in $match) {
Log "Found: $($m.DisplayName) Version: $($m.Version) InstallLocation: $($m.InstallLocation) Arch: $($m.Architecture)" "INFO"
if ($m.InstallLocation -and (Test-Path $m.InstallLocation)) {
Log "Install folder exists: $($m.InstallLocation)" "INFO"
} else {
Log "Install folder not found or not recorded for this entry." "WARN"
}
}
return $true
} else {
Log "No matching Acrobat Reader installation found for architecture $ExpectedArch." "WARN"
return $false
}
}
# -------------------------
# Disable auto update via registry policy keys
# -------------------------
function Disable-AcrobatAutoUpdate {
Log "Disabling Adobe Acrobat Reader auto-update via registry policy keys..." "INFO"
# Paths to set policy keys for Reader DC and older versions; set both 64-bit and 32-bit (Wow6432Node)
$policyPaths = @(
"HKLM:\SOFTWARE\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown",
"HKLM:\SOFTWARE\WOW6432Node\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown",
"HKLM:\SOFTWARE\Policies\Adobe\Acrobat Reader\*",
"HKLM:\SOFTWARE\WOW6432Node\Policies\Adobe\Acrobat Reader\*"
)
# Primary key/value to disable updater: bUpdater = 0 (DWORD)
foreach ($base in @(
"HKLM:\SOFTWARE\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown",
"HKLM:\SOFTWARE\WOW6432Node\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown",
"HKLM:\SOFTWARE\Policies\Adobe\Acrobat Reader\*",
"HKLM:\SOFTWARE\WOW6432Node\Policies\Adobe\Acrobat Reader\*"
)) {
try {
# Create the key if it doesn't exist (only for the DC path)
$target = $base -replace '\*','DC\FeatureLockDown'
if (-not (Test-Path $target)) {
New-Item -Path $target -Force | Out-Null
Log "Created registry key: $target" "DEBUG"
}
# Set bUpdater = 0
New-ItemProperty -Path $target -Name "bUpdater" -Value 0 -PropertyType DWord -Force | Out-Null
Log "Set bUpdater=0 at $target" "INFO"
} catch {
Log "Failed to set policy at $target : $($_.Exception.Message)" "WARN"
}
}
# Also try to disable Adobe Update Service via service config (set startup to Disabled)
try {
$svc = Get-Service -Name 'AdobeARMservice' -ErrorAction SilentlyContinue
if ($svc) {
try {
Set-Service -Name $svc.Name -StartupType Disabled
Log "Set service $($svc.Name) startup type to Disabled" "INFO"
} catch {
Log "Failed to set service startup type: $($_.Exception.Message)" "WARN"
}
} else {
# Try common service names
foreach ($name in @('AdobeARM','AdobeUpdateService','AdobeUpdateService')) {
$s = Get-Service -Name $name -ErrorAction SilentlyContinue
if ($s) {
try {
Set-Service -Name $s.Name -StartupType Disabled
Log "Set service $($s.Name) startup type to Disabled" "INFO"
} catch {
Log "Failed to set service $($s.Name) startup type: $($_.Exception.Message)" "WARN"
}
}
}
}
} catch {
Log "Service disable attempt failed: $($_.Exception.Message)" "WARN"
}
}
# -------------------------
# Remove desktop shortcuts
# -------------------------
function Remove-AdobeDesktopShortcuts {
<#
Removes Adobe/Acrobat Reader shortcuts from current user and public desktops.
Relies on an existing Log function: Log "message" "LEVEL"
Returns a PSCustomObject summary: @{ Removed = <int>; Skipped = <int>; Errors = <int> }
#>
Log "Removing Adobe Reader desktop shortcuts (current user and public)..." "INFO"
$removedCount = 0
$skippedCount = 0
$errorCount = 0
# Desktop paths: current user and public (all users)
$desktopPaths = @(
[Environment]::GetFolderPath("Desktop"),
[Environment]::GetFolderPath("CommonDesktopDirectory")
) | Where-Object { $_ -and (Test-Path $_) } | Select-Object -Unique
# Helper to test whether a target or name indicates Adobe Reader
$isAdobeTarget = {
param($targetPath, $fileName)
if ($null -ne $targetPath -and $targetPath -ne "") {
return ($targetPath -match '(?i)AcroRd32|Acrobat|Adobe|Reader')
}
if ($null -ne $fileName -and $fileName -ne "") {
return ($fileName -match '(?i)Adobe|Acrobat|Reader')
}
return $false
}
foreach ($d in $desktopPaths) {
try {
# Get both .lnk and .url files
$files = Get-ChildItem -Path $d -Include *.lnk, *.url -File -ErrorAction SilentlyContinue
foreach ($f in $files) {
try {
$target = $null
$isAdobe = $false
if ($f.Extension -ieq ".lnk") {
try {
$wsh = New-Object -ComObject WScript.Shell
$lnk = $wsh.CreateShortcut($f.FullName)
$target = $lnk.TargetPath
$isAdobe = & $isAdobeTarget $target $f.Name
} catch {
# COM resolution failed; fall back to filename check
$isAdobe = & $isAdobeTarget $null $f.Name
}
} elseif ($f.Extension -ieq ".url") {
try {
# .url files are INI-like; read the URL= line
$content = Get-Content -Path $f.FullName -ErrorAction Stop
$urlLine = $content | Where-Object { $_ -match '^\s*URL\s*=' } | Select-Object -First 1
if ($urlLine) {
$target = ($urlLine -split '=',2)[1].Trim()
$isAdobe = & $isAdobeTarget $target $f.Name
} else {
# fallback to filename
$isAdobe = & $isAdobeTarget $null $f.Name
}
} catch {
$isAdobe = & $isAdobeTarget $null $f.Name
}
} else {
# unexpected extension; skip
$skippedCount++
continue
}
if ($isAdobe) {
try {
Remove-Item -Path $f.FullName -Force -ErrorAction Stop
Log "Removed shortcut: $($f.FullName) -> $target" "INFO"
$removedCount++
} catch {
Log "Failed to remove shortcut $($f.FullName): $($_.Exception.Message)" "WARN"
$errorCount++
}
} else {
$skippedCount++
}
} catch {
Log "Error processing file $($f.FullName): $($_.Exception.Message)" "WARN"
$errorCount++
}
}
} catch {
Log "Failed enumerating desktop $d : $($_.Exception.Message)" "WARN"
$errorCount++
}
}
$summary = [PSCustomObject]@{
Removed = $removedCount
Skipped = $skippedCount
Errors = $errorCount
}
Log "Desktop shortcut removal summary Removed=$removedCount Skipped=$skippedCount Errors=$errorCount" "INFO"
return $summary
}
# -------------------------
# Main flow
# -------------------------
Log "=== Acrobat Reader management started ===" "INFO"
# 1) Detect current installations
$entries = Get-AcrobatReaderEntries
if ($entries.Count -eq 0) {
Log "No Adobe Acrobat Reader installations detected." "INFO"
} else {
foreach ($e in $entries) {
Log "Detected: $($e.DisplayName) | Version: $($e.Version) | Arch: $($e.Architecture) | InstallLocation: $($e.InstallLocation)" "INFO"
}
}
# 2) Stop processes and services
Stop-AcrobatProcessesAndServices -Force
Start-Sleep -Seconds 2
# 3) Install provided 32-bit installer silently
$installedOk = $false
try {
Log "Attempting silent install of provided installer: $InstallerPath" "INFO"
$installedOk = Install-ReaderSilently -PathToInstaller $InstallerPath
if ($installedOk) {
Log "Installer reported success." "INFO"
} else {
Log "Installer did not report success. Check installer and silent switches." "ERROR"
}
} catch {
Log "Installation attempt threw exception: $($_.Exception.Message)" "ERROR"
}
# Wait a bit for install to complete and services/processes to settle
Start-Sleep -Seconds 8
# 4) Verify installation (expect 32-bit)
$verify = Verify-ReaderInstalled -ExpectedArch "32-bit"
if ($verify) {
Log "Verification: Acrobat Reader 32-bit appears installed." "INFO"
} else {
Log "Verification: Acrobat Reader 32-bit not detected after install." "WARN"
}
# 5) Disable auto update
Disable-AcrobatAutoUpdate
# 6) Remove desktop shortcuts
Remove-AdobeDesktopShortcuts
# 7) Final detection and log summary
$finalEntries = Get-AcrobatReaderEntries
if ($finalEntries.Count -eq 0) {
Log "Final check: No Acrobat Reader entries detected." "WARN"
} else {
foreach ($f in $finalEntries) {
Log "Final detected: $($f.DisplayName) | Version: $($f.Version) | Arch: $($f.Architecture) | InstallLocation: $($f.InstallLocation)" "INFO"
}
}
Log "=== Acrobat Reader management finished ===" "INFO"
# Exit with code 0 if install succeeded and verification true, else 2
if ($installedOk -and $verify) { exit 0 } else { exit 2 }