# Quality Recticel Print Service - PowerShell Implementation # Native Windows solution with no external dependencies param( [int]$Port = 8765, [string]$LogFile = "$env:ProgramFiles\QualityRecticel\PrintService\print_service.log" ) # Ensure log directory exists $logDir = Split-Path $LogFile -Parent if (!(Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } # Logging function function Write-ServiceLog { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logMessage = "[$timestamp] $Message" Write-Host $logMessage Add-Content -Path $LogFile -Value $logMessage -ErrorAction SilentlyContinue } # Get available printers function Get-AvailablePrinters { try { $printers = Get-WmiObject -Class Win32_Printer | Where-Object { $_.Local -eq $true } | ForEach-Object { @{ name = $_.Name driver = $_.DriverName port = $_.PortName is_default = $_.Default status = $_.PrinterStatus } } return @{ success = $true printers = $printers count = $printers.Count } } catch { Write-ServiceLog "Error getting printers: $($_.Exception.Message)" return @{ success = $false error = $_.Exception.Message printers = @() } } } # Print PDF function function Invoke-PrintPDF { param( [string]$PdfUrl, [string]$PrinterName = "default", [int]$Copies = 1 ) try { Write-ServiceLog "Print request: URL=$PdfUrl, Printer=$PrinterName, Copies=$Copies" # Download PDF to temp file $tempFile = [System.IO.Path]::GetTempFileName() + ".pdf" $webClient = New-Object System.Net.WebClient $webClient.DownloadFile($PdfUrl, $tempFile) Write-ServiceLog "PDF downloaded to: $tempFile" # Get default printer if needed if ($PrinterName -eq "default" -or [string]::IsNullOrEmpty($PrinterName)) { $defaultPrinter = Get-WmiObject -Class Win32_Printer | Where-Object { $_.Default -eq $true } $PrinterName = $defaultPrinter.Name } # Print using Windows shell $printJob = Start-Process -FilePath $tempFile -Verb Print -PassThru -WindowStyle Hidden Start-Sleep -Seconds 2 # Clean up temp file Remove-Item $tempFile -Force -ErrorAction SilentlyContinue Write-ServiceLog "Print job sent successfully to printer: $PrinterName" return @{ success = $true message = "Print job sent successfully" printer = $PrinterName timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" } } catch { Write-ServiceLog "Print error: $($_.Exception.Message)" return @{ success = $false error = $_.Exception.Message } } } # HTTP Response function function Send-HttpResponse { param( [System.Net.HttpListenerContext]$Context, [int]$StatusCode = 200, [string]$ContentType = "application/json", [string]$Body = "" ) try { $Context.Response.StatusCode = $StatusCode $Context.Response.ContentType = "$ContentType; charset=utf-8" # Add CORS headers $Context.Response.Headers.Add("Access-Control-Allow-Origin", "*") $Context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS") $Context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization") if ($Body) { $buffer = [System.Text.Encoding]::UTF8.GetBytes($Body) $Context.Response.ContentLength64 = $buffer.Length $Context.Response.OutputStream.Write($buffer, 0, $buffer.Length) } $Context.Response.OutputStream.Close() } catch { Write-ServiceLog "Error sending response: $($_.Exception.Message)" } } # Main HTTP server function function Start-PrintService { Write-ServiceLog "Starting Quality Recticel Print Service on port $Port" try { # Create HTTP listener $listener = New-Object System.Net.HttpListener $listener.Prefixes.Add("http://localhost:$Port/") $listener.Prefixes.Add("http://127.0.0.1:$Port/") $listener.Start() Write-ServiceLog "HTTP server started on http://localhost:$Port" # Main server loop while ($listener.IsListening) { try { # Wait for request $context = $listener.GetContext() $request = $context.Request $response = $context.Response $method = $request.HttpMethod $url = $request.Url.AbsolutePath Write-ServiceLog "$method $url" # Handle different endpoints switch -Regex ($url) { "^/health$" { $healthData = @{ status = "healthy" service = "Quality Recticel Print Service" version = "1.0" timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" platform = "Windows PowerShell" } Send-HttpResponse -Context $context -Body ($healthData | ConvertTo-Json) } "^/printers$" { $printersData = Get-AvailablePrinters Send-HttpResponse -Context $context -Body ($printersData | ConvertTo-Json -Depth 3) } "^/print/(pdf|silent)$" { if ($method -eq "POST") { try { # Read request body $reader = New-Object System.IO.StreamReader($request.InputStream) $body = $reader.ReadToEnd() $reader.Close() # Parse JSON $printData = $body | ConvertFrom-Json # Print PDF $result = Invoke-PrintPDF -PdfUrl $printData.pdf_url -PrinterName $printData.printer_name -Copies $printData.copies if ($result.success) { Send-HttpResponse -Context $context -Body ($result | ConvertTo-Json) } else { Send-HttpResponse -Context $context -StatusCode 500 -Body ($result | ConvertTo-Json) } } catch { $errorResponse = @{ success = $false error = "Invalid request: $($_.Exception.Message)" } Send-HttpResponse -Context $context -StatusCode 400 -Body ($errorResponse | ConvertTo-Json) } } else { $errorResponse = @{ success = $false error = "Method not allowed" } Send-HttpResponse -Context $context -StatusCode 405 -Body ($errorResponse | ConvertTo-Json) } } "^/options$" { # Handle CORS preflight Send-HttpResponse -Context $context -StatusCode 200 } default { $errorResponse = @{ success = $false error = "Endpoint not found" available_endpoints = @("/health", "/printers", "/print/pdf", "/print/silent") } Send-HttpResponse -Context $context -StatusCode 404 -Body ($errorResponse | ConvertTo-Json) } } } catch { Write-ServiceLog "Request error: $($_.Exception.Message)" try { $errorResponse = @{ success = $false error = "Internal server error" } Send-HttpResponse -Context $context -StatusCode 500 -Body ($errorResponse | ConvertTo-Json) } catch { # Ignore response errors } } } } catch { Write-ServiceLog "Fatal error: $($_.Exception.Message)" } finally { if ($listener) { $listener.Stop() $listener.Close() } Write-ServiceLog "Print service stopped" } } # Service entry point Write-ServiceLog "Quality Recticel Print Service starting..." # Handle service stop gracefully Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Write-ServiceLog "Service shutting down..." } # Start the service try { Start-PrintService } catch { Write-ServiceLog "Service failed to start: $($_.Exception.Message)" exit 1 }