<# setup-webview2.ps1 — 拉取 WebView2 SDK(托管 DLL + Loader),供 shell/float-window.ps1 内嵌 Chromium 使用。 为什么要这么绕:本机 PowerShell 的 schannel 凭据在当前沙箱里不可用 (SEC_E_NO_CREDENTIALS),Invoke-WebRequest/curl 走不通;Node 自带 OpenSSL,网络正常。 所以优先用 node 下载,并保留 Invoke-WebRequest 作为通用回退。 #> [CmdletBinding()] param( [string]$Dest, [string]$Cache ) $ErrorActionPreference = 'Stop' # 在无控制台的宿主(被 harness / 计划任务拉起)里 Write-Progress 会抛 Win32 "Access is denied" $ProgressPreference = 'SilentlyContinue' $root = Split-Path -Parent $MyInvocation.MyCommand.Path | Split-Path -Parent if (-not $Dest) { $Dest = Join-Path $root 'shell\lib' } if (-not $Cache) { $Cache = Join-Path $root '.cache' } New-Item -ItemType Directory -Force -Path $Dest, $Cache | Out-Null if (Test-Path (Join-Path $Dest 'Microsoft.Web.WebView2.WinForms.dll')) { Write-Host "[setup] WebView2 SDK 已存在:$Dest" exit 0 } $nupkg = Join-Path $Cache 'webview2.nupkg' $needDownload = $true if (Test-Path $nupkg) { $needDownload = $false } if ($needDownload) { $nodeScript = @' const fs = require('node:fs') const idx = 'https://api.nuget.org/v3-flatcontainer/microsoft.web.webview2/index.json' async function main() { const j = await (await fetch(idx, { signal: AbortSignal.timeout(30000) })).json() const stable = j.versions.filter((v) => !v.includes('-')) const v = stable[stable.length - 1] const url = `https://api.nuget.org/v3-flatcontainer/microsoft.web.webview2/${v}/microsoft.web.webview2.${v}.nupkg` const buf = Buffer.from(await (await fetch(url, { signal: AbortSignal.timeout(120000) })).arrayBuffer()) fs.writeFileSync(process.argv[2], buf) console.log(v) } main().catch((e) => { console.error('download failed: ' + e.message); process.exit(1) }) '@ $nodeFile = Join-Path $Cache 'download-webview2.cjs' Set-Content -Path $nodeFile -Value $nodeScript -Encoding UTF8 $version = $null if (Get-Command node -ErrorAction SilentlyContinue) { $version = (& node $nodeFile $nupkg | Select-Object -Last 1) } if (-not (Test-Path $nupkg)) { # 回退:本机 PowerShell 的 TLS 可用时走这里 $v = (Invoke-RestMethod 'https://api.nuget.org/v3-flatcontainer/microsoft.web.webview2/index.json').versions | Where-Object { $_ -notmatch '-' } | Select-Object -Last 1 Invoke-WebRequest "https://api.nuget.org/v3-flatcontainer/microsoft.web.webview2/$v/microsoft.web.webview2.$v.nupkg" -OutFile $nupkg $version = $v } Write-Host "[setup] 下载 WebView2 SDK $version" } $extract = Join-Path $Cache 'extract' Remove-Item -Recurse -Force $extract -ErrorAction SilentlyContinue # Expand-Archive (PS 5.1) 只认 .zip 扩展名,nupkg 本质就是 zip,复制一份再解 $zip = Join-Path $Cache 'webview2.zip' Copy-Item $nupkg $zip -Force Expand-Archive -Path $zip -DestinationPath $extract -Force # 包内布局随版本变(1.0.4191.47 是 lib\net462\),按文件名找 + 目录偏好挑选 $wanted = @( @{ Leaf = 'Microsoft.Web.WebView2.Core.dll'; Prefer = '\\lib\\net4' }, @{ Leaf = 'Microsoft.Web.WebView2.WinForms.dll'; Prefer = '\\lib\\net4' }, @{ Leaf = 'WebView2Loader.dll'; Prefer = 'runtimes\\win-x64\\native' } ) foreach ($w in $wanted) { $hits = @(Get-ChildItem $extract -Recurse -File -Filter $w.Leaf -ErrorAction SilentlyContinue) if (-not $hits) { throw "包内找不到 $($w.Leaf)" } $pick = @($hits | Where-Object { $_.FullName -match $w.Prefer } | Select-Object -First 1) if (-not $pick) { $pick = @($hits | Select-Object -First 1) } Copy-Item $pick[0].FullName (Join-Path $Dest $w.Leaf) -Force Write-Host "[setup] + $($w.Leaf) <- $($pick[0].FullName.Replace($extract, ''))" } $missing = @($wanted | Where-Object { -not (Test-Path (Join-Path $Dest $_.Leaf)) }) if ($missing) { throw "缺少文件:$(($missing | ForEach-Object { $_.Leaf }) -join ', ')" } Write-Host "[setup] 完成:$Dest"