fix: improve WinUSB driver install with proper cert store and fallback

- Clean old certs from all stores before creating new one
- Use '& certutil.exe' syntax in PowerShell for reliable execution
- Write results to temp file (elevated process stdout not capturable)
- Try pnputil /force flag as fallback if signature check fails
- Report actual pnputil error message instead of silent skip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-03-26 11:59:43 +08:00
parent d9d5b2e4e0
commit c0ffd63507

View File

@ -164,45 +164,60 @@ func installWinUSBDriver(installDir string) error {
infPath := filepath.Join(driverDir, "kneron_winusb.inf")
certPath := filepath.Join(driverDir, "kneron_selfsign.cer")
resultPath := filepath.Join(os.TempDir(), "edge-ai-driver-result.txt")
os.Remove(resultPath)
// Run all admin operations in a single elevated PowerShell script (one UAC prompt)
// Run all admin operations in a single elevated PowerShell script (one UAC prompt).
// The script creates a self-signed cert, signs the INF catalog, installs the cert
// to TrustedPublisher, then uses pnputil to register the driver.
// Results are written to a temp file since elevated process stdout is not captured.
psScript := fmt.Sprintf(`
$ErrorActionPreference = 'Stop'
$resultFile = '%s'
try {
# Step 1: Create self-signed code signing certificate
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue
Get-ChildItem Cert:\LocalMachine\TrustedPublisher | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue
$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Kneron Edge AI Platform" -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10)
Export-Certificate -Cert $cert -FilePath '%s' -Force | Out-Null
# Step 2: Install certificate to TrustedPublisher and Root stores
certutil -addstore TrustedPublisher '%s' | Out-Null
certutil -addstore Root '%s' | Out-Null
& certutil.exe -addstore TrustedPublisher '%s' 2>&1 | Out-Null
& certutil.exe -addstore Root '%s' 2>&1 | Out-Null
# Step 3: Install driver via pnputil
pnputil /add-driver '%s' /install
$pnpResult = & pnputil.exe /add-driver '%s' /install 2>&1
$pnpText = $pnpResult -join "`n"
# Cleanup
# If pnputil failed with signature error, try with /force (Windows 11 23H2+)
if ($LASTEXITCODE -ne 0 -and $pnpText -match '簽章|signature|sign') {
$pnpResult = & pnputil.exe /add-driver '%s' /install /force 2>&1
$pnpText = $pnpResult -join "`n"
}
# Cleanup cert file
Remove-Item -Path '%s' -Force -ErrorAction SilentlyContinue
Write-Output 'SUCCESS'
if ($LASTEXITCODE -eq 0) {
Set-Content -Path $resultFile -Value "SUCCESS"
} else {
Set-Content -Path $resultFile -Value "PNPUTIL_FAILED: $pnpText"
}
} catch {
Write-Output "FAILED: $_"
exit 1
Set-Content -Path $resultFile -Value "FAILED: $_"
}
`, certPath, certPath, certPath, infPath, certPath)
`, resultPath, certPath, certPath, certPath, infPath, infPath, certPath)
// Use Start-Process -Verb RunAs to trigger UAC elevation
// Write the script to a temp file so it can be executed elevated
// Write script to temp file
scriptPath := filepath.Join(os.TempDir(), "edge-ai-install-driver.ps1")
resultPath := filepath.Join(os.TempDir(), "edge-ai-driver-result.txt")
os.Remove(resultPath)
if err := os.WriteFile(scriptPath, []byte(psScript), 0644); err != nil {
return fmt.Errorf("failed to write driver install script: %w", err)
}
defer os.Remove(scriptPath)
// Launch elevated PowerShell and wait for completion
// Launch elevated PowerShell (triggers one UAC prompt) and wait for completion
elevateCmd := fmt.Sprintf(
`Start-Process -FilePath powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%s' -Verb RunAs -Wait -WindowStyle Hidden`,
scriptPath,
@ -212,10 +227,17 @@ try {
return fmt.Errorf("WinUSB driver installation requires administrator permission. If you declined the prompt, please install the driver manually using Zadig (https://zadig.akeo.ie/). Details: %s", string(out))
}
// Cleanup
os.Remove(certPath)
return nil
// Check result
resultData, err := os.ReadFile(resultPath)
os.Remove(resultPath)
if err != nil {
return fmt.Errorf("WinUSB driver install completed but could not read result — please verify in Device Manager or install manually using Zadig (https://zadig.akeo.ie/)")
}
result := strings.TrimSpace(string(resultData))
if result == "SUCCESS" {
return nil
}
return fmt.Errorf("WinUSB driver install issue: %s — you can install manually using Zadig (https://zadig.akeo.ie/)", result)
}
func checkLibusbInstalled() bool {