<# Install-PCDMISPDFConverter.ps1 Installs the PC-DMIS PDF converter (Amyuni Document Converter 500, printer name "PC-DMIS 50 Converter"). Why this exists: our CMM image installs PC-DMIS from a patched STANDALONE MSI, bypassing Hexagon's Burn bundle. The Amyuni PDF converter is NOT a custom action in the main MSI (INSTALLPDFCONVERTER is a bundle property the MSI never reads). The bundle would have run the Amyuni install as a separate chained step - which we skip. The MSI does lay the installer down on disk at: C:\Program Files\Hexagon\PC-DMIS 64-bit\PDFDriverInstallFiles\BatFileInstallPDF50.zip but nothing ever executes it. This script does. The zip ships InstallPDF50.exe + the Amyuni driver (amyuni.inf, acfpdf*.dll, cdintf*.dll, atpdf500.cat) + InstallPDF50.bat. We do NOT run the .bat (it ends in `pause` and hangs under /qn) - we parse its InstallPDF50.exe invocation (printer name + Wilcox licensee + license code) and run that directly from the extracted folder so the sibling DLLs resolve. The converter is ONE system printer shared by every PC-DMIS version, so we install from the first PDFDriverInstallFiles we find and stop once the printer exists. Idempotent: if the "PC-DMIS 50 Converter" printer already exists, exits 0 without reinstalling. Run as administrator / SYSTEM (driver install needs it). Exit: 0 = printer present (installed or already there), 1 = failed. #> param( [string]$PrinterName = 'PC-DMIS 50 Converter', [string]$OutDir = 'C:\Logs\CMM' ) $ErrorActionPreference = 'Continue' New-Item -ItemType Directory -Path $OutDir -Force -ErrorAction SilentlyContinue | Out-Null $ts = Get-Date -Format 'yyyyMMdd-HHmmss' $log = Join-Path $OutDir "pdfconverter-$ts.log" function Log($m){ $line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $m"; Write-Host $line; $line | Out-File -FilePath $log -Append -Encoding ascii } function Test-ConverterPresent { # Get-Printer is the authoritative check. Fall back to the printer-name key # in the registry for old hosts where the Printing cmdlets are absent. try { if (Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue) { return $true } } catch {} $k = 'HKLM:\SYSTEM\CurrentControlSet\Control\Print\Printers\' + $PrinterName return (Test-Path $k) } Log "==== PC-DMIS PDF converter install on $env:COMPUTERNAME ====" if (Test-ConverterPresent) { Log "Printer '$PrinterName' already present - nothing to do." exit 0 } # Find the Amyuni installer the MSI laid down. PC-DMIS 2016 (vendor Wai) and # 2019/2026 (vendor Hexagon) all install under Program Files\Hexagon, but scan # both Hexagon and Wai trees to be safe. $zips = @() foreach ($root in @("$env:ProgramFiles\Hexagon","$env:ProgramFiles\Wai","${env:ProgramFiles(x86)}\Hexagon","${env:ProgramFiles(x86)}\Wai")) { if (-not (Test-Path $root)) { continue } $zips += Get-ChildItem -Path $root -Recurse -Filter 'BatFileInstallPDF50.zip' -ErrorAction SilentlyContinue } $zips = $zips | Sort-Object FullName -Unique if (-not $zips) { Log "ERROR: no BatFileInstallPDF50.zip found under any PC-DMIS install dir." Log " PC-DMIS may not be installed yet, or PDFDriverInstallFiles is missing." exit 1 } Log ("Found {0} Amyuni installer zip(s):" -f $zips.Count) $zips | ForEach-Object { Log " $($_.FullName)" } Add-Type -AssemblyName System.IO.Compression.FileSystem foreach ($zip in $zips) { $stage = Join-Path $env:TEMP ("amyuni-pdf-" + $ts + "-" + [Guid]::NewGuid().ToString('N').Substring(0,6)) try { New-Item -ItemType Directory -Path $stage -Force | Out-Null [System.IO.Compression.ZipFile]::ExtractToDirectory($zip.FullName, $stage) Log "Extracted $($zip.Name) -> $stage" $exe = Join-Path $stage 'InstallPDF50.exe' $bat = Join-Path $stage 'InstallPDF50.bat' if (-not (Test-Path $exe)) { Log " no InstallPDF50.exe in zip - skipping"; continue } # Parse InstallPDF50.bat for the exact InstallPDF50.exe arguments (printer # name + Wilcox licensee + license code). License code can differ per # version, so read it rather than hardcode. Strip the leading exe token. $args = $null if (Test-Path $bat) { $cmd = (Get-Content $bat | Where-Object { $_ -match 'InstallPDF50\.exe' } | Select-Object -First 1) if ($cmd) { $args = ($cmd -replace '(?i)^\s*[^"]*InstallPDF50\.exe\s*','').Trim() } } if (-not $args) { # Fallback to the known-good invocation if the bat is missing/odd. $args = '"' + $PrinterName + '" -n "Wilcox Associates, Inc."' Log " WARN: could not parse args from bat - using fallback (no license code): $args" } else { Log " parsed install args from bat" } $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.FileName = $exe $psi.Arguments = $args $psi.WorkingDirectory = $stage # sibling DLLs (cdintf64.dll, acfpdf*, amyuni.inf, atpdf500.cat) must resolve $psi.UseShellExecute = $false $psi.CreateNoWindow = $true $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden Log " running: InstallPDF50.exe $args (cwd=$stage)" $proc = [System.Diagnostics.Process]::Start($psi) # InstallPDF50.exe creates the printer in a few seconds but then hangs # (does not self-exit, same as Hexagon's Burn bundle). Poll for the # printer instead of blocking; once it appears, kill the hung exe and # move on. Hard cap at 90s as a backstop for a genuinely stuck install. $deadline = (Get-Date).AddSeconds(90) $appeared = $false while ((Get-Date) -lt $deadline) { if ($proc.HasExited) { Log " InstallPDF50.exe exited on its own (code $($proc.ExitCode))"; break } if (Test-ConverterPresent) { $appeared = $true; break } Start-Sleep -Seconds 2 } if (-not $proc.HasExited) { Log (" printer {0} - killing InstallPDF50.exe (it does not self-exit)" -f $(if ($appeared) { 'present' } else { 'NOT present after 90s' })) try { $proc.Kill() } catch {} } Start-Sleep -Seconds 2 if (Test-ConverterPresent) { Log "SUCCESS: printer '$PrinterName' is now present." Remove-Item $stage -Recurse -Force -ErrorAction SilentlyContinue exit 0 } Log " printer not present after this attempt - trying next zip if any." } catch { Log " ERROR during install from $($zip.Name): $($_.Exception.Message)" } finally { Remove-Item $stage -Recurse -Force -ErrorAction SilentlyContinue } } if (Test-ConverterPresent) { Log "Printer '$PrinterName' present."; exit 0 } Log "ERROR: printer '$PrinterName' still not present after all attempts." exit 1