- 因為放到GPO當重覆不能重覆新增
- 原本有的Path內容,不會被覆蓋
- 如果Path內容,有參數問題,也不會造成判斷錯誤,例如%Windows%
- 大小寫不會判斷錯誤
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
# 1. 讀取目前「活著」的原始 PATH(如果完全沒有,則給予空字串,防止 Null 崩潰)
$currentPath = ""
if (Get-ItemProperty -Path $regPath -Name PATH -ErrorAction SilentlyContinue) {
$currentPath = (Get-ItemProperty -Path $regPath -Name PATH).PATH
}
# 2. 定義系統核心路徑與應用程式路徑
$essentialPaths = @(
"%SystemRoot%\system32",
"%SystemRoot%",
"%SystemRoot%\System32\Wbem",
"%SystemRoot%\System32\WindowsPowerShell\v1.0\",
"%SystemRoot%\System32\OpenSSH\",
"C:\Program Files (x86)\Microsoft\Edge\Application",
"C:\Program Files (x86)\Common Files\Oracle\Java\java8path",
"C:\Program Files (x86)\Common Files\Oracle\Java\javapath"
)
# 3. 將目前現有的 PATH 切開成陣列,統一轉小寫並剔除結尾斜線
$currentPathArray = $currentPath -split ';' | ForEach-Object { $_.Trim().ToLower().TrimEnd('\') }
# 3.5 額外產生一個「已經把 %SystemRoot% 換成 C:\Windows」的現有路徑陣列,用來雙重防禦
$expandedCurrentPathArray = $currentPathArray | ForEach-Object {
[Environment]::ExpandEnvironmentVariables($_).ToLower().TrimEnd('\')
}
# 4. 用來累積存放「目前漏掉、需要補上去」的路徑購物車
$pathsToAppend = @()
foreach ($path in $essentialPaths) {
# 將我們要檢查的路徑,分別製作「未展開小寫」與「已展開小寫」兩種版本
$cleanPath = $path.ToLower().TrimEnd('\')
$expandedPath = [Environment]::ExpandEnvironmentVariables($path).ToLower().TrimEnd('\')
# 【核心修正】:如果現有的 PATH 裡面,既沒有原始變數格式,也沒有展開後的 C:\ 格式,才允許加入!
if ($currentPathArray -notcontains $cleanPath -and $expandedCurrentPathArray -notcontains $expandedPath) {
$pathsToAppend += $path
}
}
# 5. 如果有發現缺少的路徑,才進行更新
if ($pathsToAppend.Count -gt 0) {
# 判斷原本的 PATH 是不是空的
if ([string]::IsNullOrWhiteSpace($currentPath)) {
$newPath = $pathsToAppend -join ";"
} else {
# 確保原本使用者自己裝的軟體路徑完全不會被動到
$newPath = $currentPath.Trim(';') + ";" + ($pathsToAppend -join ";")
}
# 6. 強制指定以 ExpandString (REG_EXPAND_SZ) 寫入,保護 %SystemRoot% 變數不變死字串
Set-ItemProperty -Path $regPath -Name PATH -Value $newPath -Type ExpandString
Write-Host "成功!已保留原本的所有路徑,並補上缺少的:($($pathsToAppend -join ', '))" -ForegroundColor Green
# 7. 通知 Windows 系統更新環境變數(免重開機立即生效)
$signature = '[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);'
$win32 = Add-Type -MemberDefinition $signature -Name "Win32" -Namespace "Env" -PassThru
$result = [UIntPtr]::Zero
$win32::SendMessageTimeout([IntPtr]0xffff, 0x001A, [UIntPtr]::Zero, "Environment", 2, 5000, [ref]$result) | Out-Null
} else {
Write-Host "檢查完畢:所有核心路徑與指定路徑已存在(包含變數展開檢查),未重複新增。" -ForegroundColor Yellow
}
補充其他系統變數的Pathnpm 與node 無法執行要加入C:\Program Files\nodejs
choco無法執行要加入C:\ProgramData\chocolatey\bin