如何透過 PowerShell 自動寫入執行檔路徑到 PATH 使用者環境變數

今天看到微軟推出 Azure Developer CLI 工具 (預覽版) 的消息,便立即安裝起來玩看看,而在安裝的過程中有發現他有用 PowerShell 寫入 PATH 環境變數,我就把安裝程式解析了一下,發現有一段 Code Snippet 相當實用,以後寫安裝程式的時候就可以直接沿用了。

PATH

以下是 Azure Developer CLI 的安裝命令:

powershell -c "Set-ExecutionPolicy Bypass Process -Force; irm 'https://aka.ms/install-azd.ps1' | iex"

其中 irm 是 Invoke-RestMethod 的 Alias,用來抓取 https://aka.ms/install-azd.ps1 這個 PowerShell 安裝指令檔,而將內容 pipe 給 iex (Invoke-Expression) 則是用來直接執行 PowerShell 命令。

你也可以先下載 install-azd.ps1 回來,然後提供參數執行安裝命令:

irm 'https://aka.ms/install-azd.ps1' -OutFile install-azd.ps1
.\install-azd.ps1 -NoPath

這支 PowerShell 安裝程式最讓我感興趣的地方,其實是設定 PATH 環境變數的地方,因為無論是 Command Prompt 環境或是 PowerShell 環境,在設定環境變數這件事情上,一直都沒有完美的解決方案,網路上可以找到的解決方案,我可以說 99% 都有瑕疵,無法應付各種設定 PATH 環境變數的情境,這個比例一點也不誇張!

在這之前,我所找到的解決方案是透過一個相當不知名的 SetEnv 命令列工具,這是我測試過可以符合所有情境的 PATH 設定工具,我在過往的好幾篇文章中都有用到。

這套 SetEnv.exe 的使用方式如下:

# 先用 PowerShell 下載設定環境變數的利器 SetEnv(你也可以手動下載)
Invoke-WebRequest -Uri "https://github.com/doggy8088/SetEnv/releases/download/1.0/SetEnv.exe" -OutFile "SetEnv.exe"

# 增加 PATH 使用者環境變數(這段命令支援 PowerShell 也支援 Command Prompt 環境)
SetEnv.exe -ua PATH %"C:\Program Files\Git\usr\bin"

由於這個解決方案需要下載額外的 SetEnv.exe 執行檔,我們有些客戶的部署環境是完全無法下載 *.exe 執行檔的,所以這個解決方案一直不是太理想。

今天我從 install-azd.ps1 擷取出以下程式碼片段:

# 這個 $InstallFolder 變數用來指定你要加入 PATH 環境變數的路徑
$InstallFolder = 'C:\Program Files\Git\usr\bin'

# $env:Path, [Environment]::GetEnvironmentVariable('PATH'), and setx all expand
# variables (e.g. %JAVA_HOME%) in the value. Writing the expanded paths back
# into the environment would be destructive so instead, read the path directly
# from the registry with the DoNotExpandEnvironmentNames option and write that
# value back using the non-destructive [Environment]::SetEnvironmentVariable
# which also broadcasts environment variable changes to Windows.
try {
    $registryKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $false)
    $originalPath = $registryKey.GetValue(`
        'PATH', `
        '', `
        [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames `
    )
    $pathParts = $originalPath -split ';'

    if (!($pathParts -contains $InstallFolder)) {
        Write-Host "Adding $InstallFolder to PATH"

        # SetEnvironmentVariable broadcasts the "Environment" change to
        # Windows and is NOT destructive (e.g. expanding variables)
        [Environment]::SetEnvironmentVariable(
            'PATH', `
            "$originalPath;$InstallFolder", `
            [EnvironmentVariableTarget]::User`
        )

        # Also add the path to the current session
        $env:PATH += ";$InstallFolder"
    } else {
        Write-Host "An entry for $InstallFolder is already in PATH"
    }
} finally {
    if ($registryKey) {
        $registryKey.Close()
    }
}

這段程式可以非常完美的解決設定 PATH 環境變數的問題,實在是太棒了! 😍

相關連結

留言評論