Keyence VR-3000 G2: imaging-time FIPS opt-out for .exe.configs

Under Intune-enforced LSA FIPS policy, Profilometer / VRAnalyzer /
VRInspection apps crash at device init when MD5CryptoServiceProvider's
ctor is called to verify the probe EEPROM calibration (see keyence3000.txt
+ .png in pxe-images for the dialog + stack).

Patch each .exe.config under C:\Program Files\KEYENCE\<model>\ with
<runtime><enforceFIPSPolicy enabled="false"/></runtime>. Scope is app-CLR
only; OS-wide Lsa FIPS policy stays enforced. CMMC posture: scoped
exception, non-CUI integrity hash, documented in SSP. Each affected bay's
hostname must be on InfoSec's FIPS-exception list before imaging.

09-Setup-Keyence.ps1 gates the patch behind model=vr3000 only. vr5000 /
vr6000 bays do not auto-apply. Verified on win11 VM via qga: 29 configs
across vr5000+vr6000 layouts (vr3000 install was incomplete on VM),
patched + idempotent on re-run, existing <runtime> children preserved.
Also verified on a real PC: 27 patched + 2 skipped (Keyence pre-shipped
the element in two configs), 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-21 14:35:29 -04:00
parent 37357eee43
commit 2a0b4885fe
2 changed files with 149 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
<#
.SYNOPSIS
Patches all Keyence VR-series .exe.config files to opt the app out of .NET
FIPS policy enforcement so the EEPROM MD5 calibration check does not throw
'This implementation is not part of the Windows Platform FIPS validated
cryptographic algorithms.'
Currently approved only for VR-3000 G2. Before running on a production
bay, report the PC hostname to GE InfoSec and confirm the bay is on
the documented FIPS-exception list. Imaging-time auto-apply (in
09-Setup-Keyence.ps1) gates this script behind model=vr3000.
.DESCRIPTION
Scans C:\Program Files\KEYENCE and C:\Program Files (x86)\KEYENCE for any
.exe.config under VR-3000 G2, VR-5000, VR-6000 (and any other Keyence model
that ships in the same root). Injects:
<runtime>
<enforceFIPSPolicy enabled="false"/>
</runtime>
as a sibling under <configuration>. Preserves any existing <runtime>
children (generatePublisherEvidence, useLegacyJit, etc).
Idempotent. Re-running is a no-op for already-patched configs.
This patch is SCOPED to the Keyence app's CLR. It does NOT disable the
OS-wide LSA FIPS policy. Intune / Defender baseline policies that enforce
the LSA key remain in effect.
.PARAMETER InstallRoots
Override the default search roots. By default both C:\Program Files\KEYENCE
and C:\Program Files (x86)\KEYENCE are scanned.
.PARAMETER WhatIf
Show what would be patched without writing any files.
.EXAMPLE
.\Patch-KeyenceFipsConfigs.ps1
.\Patch-KeyenceFipsConfigs.ps1 -WhatIf
.\Patch-KeyenceFipsConfigs.ps1 -InstallRoots 'D:\KEYENCE'
.NOTES
Affected EXEs (Profilometer3.exe, VRAnalyzer*.exe, VRInspection_*.exe, etc.)
must be restarted after the patch for the new config to take effect.
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[string[]]$InstallRoots = @(
'C:\Program Files\KEYENCE',
'C:\Program Files (x86)\KEYENCE'
)
)
$ErrorActionPreference = 'Continue'
$patched = 0
$skipped = 0
$errors = 0
foreach ($root in $InstallRoots) {
if (-not (Test-Path -LiteralPath $root)) {
Write-Host "Root not present, skipping: $root"
continue
}
Write-Host "Scanning: $root"
$configs = Get-ChildItem -LiteralPath $root -Filter '*.exe.config' -Recurse -ErrorAction SilentlyContinue
foreach ($cfg in $configs) {
try {
[xml]$xml = Get-Content -LiteralPath $cfg.FullName
$cfgRoot = $xml.configuration
if (-not $cfgRoot) {
Write-Warning " [SKIP] No <configuration> root: $($cfg.FullName)"
$errors++
continue
}
$rt = $cfgRoot.SelectSingleNode('runtime')
if (-not $rt) {
$rt = $xml.CreateElement('runtime')
$cfgRoot.AppendChild($rt) | Out-Null
}
$existing = $rt.SelectSingleNode("enforceFIPSPolicy[@enabled='false']")
if ($existing) {
Write-Host " [SKIP] already patched: $($cfg.FullName)"
$skipped++
continue
}
# Remove any other enforceFIPSPolicy variants (enabled=true or no attr).
$rt.SelectNodes('enforceFIPSPolicy') | ForEach-Object { $rt.RemoveChild($_) | Out-Null }
$fips = $xml.CreateElement('enforceFIPSPolicy')
$fips.SetAttribute('enabled', 'false')
$rt.AppendChild($fips) | Out-Null
if ($PSCmdlet.ShouldProcess($cfg.FullName, 'Inject enforceFIPSPolicy')) {
$xml.Save($cfg.FullName)
Write-Host " [OK] patched: $($cfg.FullName)"
$patched++
} else {
Write-Host " [WHATIF] would patch: $($cfg.FullName)"
}
} catch {
Write-Warning " [ERR] $($cfg.FullName): $_"
$errors++
}
}
}
Write-Host ""
Write-Host "Summary: patched=$patched skipped=$skipped errors=$errors"
Write-Host ""
Write-Host "Restart Keyence apps (Profilometer3.exe, VRAnalyzer*.exe, VRLauncher.exe,"
Write-Host "VRInspection_*.exe, etc.) for the new config to take effect. No reboot needed."