Private/check-office-accessibility.ps1
|
<# .SYNOPSIS Dispatcher that runs the right OOXML accessibility checker for a Word, Excel, or PowerPoint file, mirroring the veraPDF-style CLI surface. Also supports bulk scanning when given a directory. .PARAMETER Path Path to a .docx, .docm, .xlsx, .xlsm, .pptx, or .pptm file, or a directory containing such files. The legacy parameter name -FilePath is kept as an alias. .PARAMETER Recurse When -Path is a directory, also descend into subdirectories. Ignored when -Path is a file. .PARAMETER Format 'text' (default) emits a single PASS/FAIL line per file. 'detailed' emits every issue found, one per line, followed by a PASS/FAIL summary per file. .PARAMETER Fix Forwards to the per-format checker. Each fixable file is copied to <basename>.fixed.<ext> and the deterministic structural remediations are applied. Originals are never modified. In bulk mode, every input file is independently fixed; the scan summary reflects post-fix exit codes. .OUTPUTS Exit codes (single-file mode, and worst-of in bulk mode): 0 no errors found 1 one or more accessibility errors found 2 tool error (file not found, unsupported format, SDK missing, etc.) #> [CmdletBinding()] param( [Parameter(Mandatory, Position=0)] [Alias('FilePath')] [string] $Path, [switch] $Recurse, [ValidateSet('text','detailed')] [string] $Format = 'text', [switch] $Fix ) $ErrorActionPreference = 'Stop' if (-not (Test-Path -LiteralPath $Path)) { [Console]::Error.WriteLine("Path not found: $Path") exit 2 } $item = Get-Item -LiteralPath $Path # --- Single-file dispatch (leaf) ---------------------------------------------- if (-not $item.PSIsContainer) { $ext = [IO.Path]::GetExtension($item.FullName).ToLowerInvariant() $childArgs = @{ FilePath = $item.FullName; Format = $Format } if ($Fix) { $childArgs.Fix = $true } switch ($ext) { { $_ -in '.docx', '.docm' } { & (Join-Path $PSScriptRoot 'check-docx-accessibility.ps1') @childArgs exit $LASTEXITCODE } { $_ -in '.xlsx', '.xlsm' } { & (Join-Path $PSScriptRoot 'check-xlsx-accessibility.ps1') @childArgs exit $LASTEXITCODE } { $_ -in '.pptx', '.pptm' } { & (Join-Path $PSScriptRoot 'check-pptx-accessibility.ps1') @childArgs exit $LASTEXITCODE } { $_ -in '.doc', '.xls', '.ppt' } { [Console]::Error.WriteLine("Unsupported format: legacy binary Office files ($ext) are not supported. Re-save as .docx/.xlsx/.pptx.") exit 2 } default { [Console]::Error.WriteLine("Unsupported file type: $ext") exit 2 } } } # --- Bulk scan (container) ---------------------------------------------------- $gciParams = @{ LiteralPath = $item.FullName File = $true Force = $true ErrorAction = 'SilentlyContinue' } if ($Recurse) { $gciParams.Recurse = $true } # Inaccessible subdirectories (permissions, reparse points) are skipped via # SilentlyContinue rather than aborting the scan. $allFiles = @(Get-ChildItem @gciParams) # Office creates ~$<name> lock files in the same folder while a document is # open. They share the .docx/.xlsx extension but are not real documents and # would error noisily; filter them out. Also skip *.fixed.* outputs from # previous -Fix runs so a re-scan doesn't treat them as new inputs (and a # re-fix doesn't produce *.fixed.fixed.*). $supported = @( $allFiles | Where-Object { $_.Extension -match '^\.(docx|docm|xlsx|xlsm|pptx|pptm)$' ` -and $_.Name -notlike '~$*' ` -and $_.BaseName -notlike '*.fixed' } ) $skipped = $allFiles.Count - $supported.Count $total = $supported.Count $pass = 0 $fail = 0 $err = 0 $worstExit = 0 for ($i = 0; $i -lt $total; $i++) { $f = $supported[$i] if ($total -gt 1) { Write-Progress -Activity 'Scanning Office files' ` -Status $f.FullName ` -PercentComplete (($i / $total) * 100) } if ($Fix) { & $PSCommandPath -Path $f.FullName -Format $Format -Fix } else { & $PSCommandPath -Path $f.FullName -Format $Format } $exit = $LASTEXITCODE switch ($exit) { 0 { $pass++ } 1 { $fail++ } default { $err++ # Child writes its diagnostic to stderr and exits without a stdout # PASS/FAIL line. Emit a stable stdout marker so downstream greps # see the failure. Write-Output "ERROR $($f.FullName)" } } if ($exit -gt $worstExit) { $worstExit = $exit } } if ($total -gt 1) { Write-Progress -Activity 'Scanning Office files' -Completed } [Console]::Error.WriteLine( "Scanned $total files: $pass passed, $fail failed, $err errors, $skipped skipped" ) exit $worstExit |