From c0ffd6350795a52fe26add8b3f0210ca06444ffe Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Thu, 26 Mar 2026 11:59:43 +0800 Subject: [PATCH] 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) --- .../installer/platform_windows.go | 60 +++++++++++++------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/edge-ai-platform/installer/platform_windows.go b/edge-ai-platform/installer/platform_windows.go index e616e74..12093f6 100644 --- a/edge-ai-platform/installer/platform_windows.go +++ b/edge-ai-platform/installer/platform_windows.go @@ -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 {