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

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何透過 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"

其中 irmInvoke-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 環境變數的問題,實在是太棒了! 😍

相關連結