154 lines
9.9 KiB
PowerShell
154 lines
9.9 KiB
PowerShell
# Verae TimeStamp PDF — printer installer (DEBUG build). Must run elevated.
|
|
# Every Add-* is followed by a Get-* verification. Full transcript + JSON summary
|
|
# go to %ProgramData%\Verae\logs. Exit code 0 = at least one printer verified.
|
|
param(
|
|
[string]$InstallDir = (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)),
|
|
[switch]$SkipIpp,
|
|
[switch]$SkipFallback,
|
|
[string]$IppAddr = "127.0.0.1:8631"
|
|
)
|
|
$ErrorActionPreference = "Continue"
|
|
$PrinterName = "Verae TimeStamp PDF"
|
|
$FallbackName = "Verae TimeStamp PDF (Local Port)"
|
|
$LogDir = Join-Path $env:ProgramData "Verae\logs"
|
|
$DropDir = Join-Path $env:ProgramData "Verae\spool\fallback"
|
|
$PortPath = Join-Path $DropDir "verae-job.pdf"
|
|
$Bin = Join-Path $InstallDir "bin"
|
|
$Helper = Join-Path $Bin "verae-printhelper.exe"
|
|
$Cli = Join-Path $Bin "verae-print.exe"
|
|
$IppUrl = "http://$IppAddr/ipp/print"
|
|
$ts = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
New-Item -ItemType Directory -Force -Path $LogDir, $DropDir | Out-Null
|
|
$Transcript = Join-Path $LogDir "install-$ts.log"
|
|
Start-Transcript -Path $Transcript -Force | Out-Null
|
|
|
|
$summary = [ordered]@{ started = (Get-Date).ToString("o"); steps = @(); ipp = "not-run"; fallback = "not-run" }
|
|
function Step([string]$Name, [scriptblock]$Do, [scriptblock]$Verify) {
|
|
Write-Host "`n=== STEP: $Name"
|
|
$err = $null; $ok = $false
|
|
try { & $Do | Out-Host } catch { $err = $_; Write-Host " EXCEPTION: $($_.Exception.GetType().FullName): $($_.Exception.Message) HResult=0x$('{0:X8}' -f $_.Exception.HResult)" }
|
|
if ($Verify) {
|
|
try { $ok = [bool](& $Verify) } catch { Write-Host " VERIFY EXCEPTION: $($_.Exception.Message)" }
|
|
} else { $ok = ($null -eq $err) }
|
|
Write-Host (" RESULT: " + $(if ($ok) { "OK" } else { "FAIL" }))
|
|
$script:summary.steps += [ordered]@{ step = $Name; ok = $ok; error = $(if ($err) { "$($err.Exception.Message)" } else { $null }) }
|
|
return $ok
|
|
}
|
|
|
|
Write-Host "Verae printer install (debug) $ts"
|
|
Write-Host "InstallDir=$InstallDir User=$(whoami) PS=$($PSVersionTable.PSVersion) 64bitProcess=$([Environment]::Is64BitProcess)"
|
|
$os = Get-CimInstance Win32_OperatingSystem
|
|
Write-Host "OS: $($os.Caption) $($os.Version) build $($os.BuildNumber) $($os.OSArchitecture)"
|
|
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
Write-Host "Elevated: $isAdmin"
|
|
if (-not $isAdmin) { Write-Host "ERROR: not elevated — printer/port creation will fail (Access denied)." }
|
|
if (-not [Environment]::Is64BitProcess -and [Environment]::Is64BitOperatingSystem) { Write-Host "WARNING: 32-bit PowerShell on 64-bit Windows (WOW64) — should be launched via Sysnative." }
|
|
|
|
Write-Host "`n--- WPP / policy registry"
|
|
foreach ($k in 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\WPP','HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers','HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint') {
|
|
if (Test-Path $k) { Write-Host "[$k]"; Get-ItemProperty $k | Format-List | Out-String | Write-Host } else { Write-Host "(absent) $k" }
|
|
}
|
|
Write-Host "--- BEFORE: printers / drivers / ports"
|
|
Get-Printer | Format-Table Name,DriverName,PortName,Type -AutoSize | Out-String -Width 250 | Write-Host
|
|
Get-PrinterDriver | Format-Table Name,MajorVersion,PrinterEnvironment -AutoSize | Out-String -Width 250 | Write-Host
|
|
Get-PrinterPort | Format-Table Name,Description,PortMonitor -AutoSize | Out-String -Width 250 | Write-Host
|
|
|
|
Step "Spooler running" { $s = Get-Service Spooler; if ($s.Status -ne 'Running') { Start-Service Spooler } } { (Get-Service Spooler).Status -eq 'Running' } | Out-Null
|
|
Step "Enable PrintService/Operational log" { wevtutil sl Microsoft-Windows-PrintService/Operational /e:true | Out-Host } { (Get-WinEvent -ListLog Microsoft-Windows-PrintService/Operational).IsEnabled } | Out-Null
|
|
Step "ACL logs+spool dirs (Users: Modify)" {
|
|
icacls (Join-Path $env:ProgramData "Verae") /grant "*S-1-5-32-545:(OI)(CI)M" /T /C | Out-Host
|
|
} { Test-Path $LogDir } | Out-Null
|
|
Step "Debug flag HKLM\Software\Verae\PrintStamp\Debug=1" {
|
|
New-Item -Path 'HKLM:\Software\Verae\PrintStamp' -Force | Out-Null
|
|
Set-ItemProperty 'HKLM:\Software\Verae\PrintStamp' -Name Debug -Value 1 -Type DWord
|
|
Set-ItemProperty 'HKLM:\Software\Verae\PrintStamp' -Name InstallDir -Value $InstallDir
|
|
} { (Get-ItemProperty 'HKLM:\Software\Verae\PrintStamp').Debug -eq 1 } | Out-Null
|
|
Step "Helper autostart (HKLM Run)" {
|
|
Set-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run' -Name VeraePrintHelper -Value "`"$Helper`""
|
|
} { (Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run').VeraePrintHelper -like "*verae-printhelper.exe*" } | Out-Null
|
|
Step "Add bin to machine PATH" {
|
|
$p = [Environment]::GetEnvironmentVariable("Path","Machine")
|
|
if ($p -notlike "*$Bin*") { [Environment]::SetEnvironmentVariable("Path", ($p.TrimEnd(';') + ";" + $Bin), "Machine") }
|
|
} { [Environment]::GetEnvironmentVariable("Path","Machine") -like "*$Bin*" } | Out-Null
|
|
|
|
function Test-Ipp { try { $r = Invoke-WebRequest -UseBasicParsing -TimeoutSec 3 "http://$IppAddr/"; return ($r.StatusCode -eq 200) } catch { return $false } }
|
|
|
|
# ---------------- Primary: IPP class driver → loopback helper ----------------
|
|
if (-not $SkipIpp) {
|
|
$helperUp = Step "Helper listening on $IppAddr" {
|
|
Get-Process verae-printhelper -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " existing helper pid=$($_.Id)" }
|
|
if (-not (Test-Ipp)) {
|
|
# explorer.exe launches the exe with the (non-elevated) shell token = the real user session
|
|
Write-Host " starting helper un-elevated via explorer.exe"
|
|
Start-Process explorer.exe -ArgumentList "`"$Helper`""
|
|
for ($i = 0; $i -lt 20 -and -not (Test-Ipp); $i++) { Start-Sleep -Milliseconds 500 }
|
|
}
|
|
if (-not (Test-Ipp)) {
|
|
Write-Host " explorer launch did not bring IPP up; starting elevated temporary helper for discovery"
|
|
Start-Process -FilePath $Helper -WindowStyle Hidden
|
|
for ($i = 0; $i -lt 20 -and -not (Test-Ipp); $i++) { Start-Sleep -Milliseconds 500 }
|
|
}
|
|
& $Cli ipp-selftest --addr $IppAddr | Out-Host
|
|
} { Test-Ipp }
|
|
|
|
if ($helperUp) {
|
|
Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " removing stale '$($_.Name)'"; Remove-Printer -Name $_.Name }
|
|
$before = @(Get-Printer | Select-Object -ExpandProperty Name)
|
|
$hasIppUrl = (Get-Command Add-Printer).Parameters.ContainsKey('IppURL')
|
|
Write-Host "Add-Printer supports -IppURL: $hasIppUrl"
|
|
$added = Step "Add IPP printer ($IppUrl)" {
|
|
if ($hasIppUrl) {
|
|
Add-Printer -IppURL $IppUrl -ErrorAction Stop
|
|
} else {
|
|
Add-Printer -Name $PrinterName -DriverName "Microsoft IPP Class Driver" -PortName $IppUrl -ErrorAction Stop
|
|
}
|
|
} {
|
|
Start-Sleep 2
|
|
$new = @(Get-Printer | Where-Object { $before -notcontains $_.Name })
|
|
Write-Host " new printers: $(( $new | ForEach-Object { "$($_.Name) [$($_.DriverName) / $($_.PortName)]" }) -join '; ')"
|
|
$script:newIpp = $new | Select-Object -First 1
|
|
($null -ne $script:newIpp) -or (Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue)
|
|
}
|
|
if ($added -and $script:newIpp -and $script:newIpp.Name -ne $PrinterName) {
|
|
Step "Rename '$($script:newIpp.Name)' → '$PrinterName'" { Rename-Printer -Name $script:newIpp.Name -NewName $PrinterName -ErrorAction Stop } { Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue } | Out-Null
|
|
}
|
|
$p = Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue
|
|
if ($p) { $p | Format-List * | Out-String | Write-Host; $summary.ipp = "OK: driver=$($p.DriverName) port=$($p.PortName)" } else { $summary.ipp = "FAIL" }
|
|
} else { $summary.ipp = "FAIL: helper not reachable" }
|
|
}
|
|
|
|
# ---------------- Fallback: Microsoft Print To PDF → Local file port ----------------
|
|
if (-not $SkipFallback) {
|
|
$drv = Step "Driver 'Microsoft Print To PDF' present" {
|
|
if (-not (Get-PrinterDriver -Name "Microsoft Print To PDF" -ErrorAction SilentlyContinue)) { Add-PrinterDriver -Name "Microsoft Print To PDF" -ErrorAction Stop }
|
|
} { Get-PrinterDriver -Name "Microsoft Print To PDF" -ErrorAction SilentlyContinue }
|
|
$port = Step "Local port '$PortPath'" {
|
|
if (-not (Get-PrinterPort -Name $PortPath -ErrorAction SilentlyContinue)) { Add-PrinterPort -Name $PortPath -ErrorAction Stop }
|
|
} { Get-PrinterPort -Name $PortPath -ErrorAction SilentlyContinue }
|
|
if ($drv -and $port) {
|
|
Get-Printer -Name $FallbackName -ErrorAction SilentlyContinue | ForEach-Object { Remove-Printer -Name $_.Name }
|
|
$fb = Step "Add printer '$FallbackName'" {
|
|
Add-Printer -Name $FallbackName -DriverName "Microsoft Print To PDF" -PortName $PortPath -ErrorAction Stop
|
|
} { Get-Printer -Name $FallbackName -ErrorAction SilentlyContinue }
|
|
$summary.fallback = $(if ($fb) { "OK" } else { "FAIL" })
|
|
} else { $summary.fallback = "FAIL: driver=$drv port=$port" }
|
|
}
|
|
|
|
Write-Host "`n--- AFTER: printers / ports"
|
|
Get-Printer | Format-Table Name,DriverName,PortName,Type,PrinterStatus -AutoSize | Out-String -Width 250 | Write-Host
|
|
Get-PrinterPort | Format-Table Name,Description,PortMonitor -AutoSize | Out-String -Width 250 | Write-Host
|
|
Write-Host "--- PrintService events (last 15 min)"
|
|
foreach ($ln in 'Microsoft-Windows-PrintService/Admin','Microsoft-Windows-PrintService/Operational') {
|
|
Get-WinEvent -FilterHashtable @{LogName=$ln; StartTime=(Get-Date).AddMinutes(-15)} -ErrorAction SilentlyContinue |
|
|
Format-Table TimeCreated,Id,LevelDisplayName,Message -Wrap | Out-String -Width 250 | Write-Host
|
|
}
|
|
$summary.finished = (Get-Date).ToString("o")
|
|
$summary.transcript = $Transcript
|
|
$summaryPath = Join-Path $LogDir "install-summary-$ts.json"
|
|
$summary | ConvertTo-Json -Depth 5 | Set-Content -Encoding UTF8 $summaryPath
|
|
$okAny = ($summary.ipp -like "OK*") -or ($summary.fallback -eq "OK")
|
|
Write-Host "`nVerae printer install: $(if ($okAny) {'OK'} else {'FAIL'}) ipp=[$($summary.ipp)] fallback=[$($summary.fallback)]"
|
|
Write-Host "Log: $Transcript"
|
|
Write-Host "Summary: $summaryPath"
|
|
Stop-Transcript | Out-Null
|
|
if ($okAny) { exit 0 } else { exit 1 }
|