Powershell SetEnvironmentVariable 未按预期设置变量
Powershell SetEnvironmentVariable not setting the variables as expected
我正在尝试使用 Powershell 根据命令“wsl --list”的输出保存一些环境变量,当我调试此代码时,它似乎按预期运行但是当我检查我的环境变量时,我无法找到预期的键和值。
当我将相同的 SetEnvironmentVariable 方法与任何其他硬编码值一起使用时,它似乎有效。 $distroName 上的 Write-Host 也会产生预期的字符串,所以老实说我对此一头雾水。任何帮助,将不胜感激!
这是我的代码:
$wslListOutput = wsl --list
((Get-ChildItem env:*).Name | Select-String -Pattern "(SINDAGAL_INIT_DISTRO_([a-zA-Z=])*)|SINDAGAL_DEFAULT_DISTRO")
foreach ($line in $wslListOutput)
{
$lineIsEmpty = ("" -eq $line) -or ([string]::IsNullOrWhiteSpace($line))
$Introline = $line -eq "Windows Subsystem for Linux Distributions:"
if($lineIsEmpty -or $Introline){ continue }
if($line -Match "(([a-zA-Z]*) ([(Default)])*)"){
$distroName = ($line -split ' ',2)[0]
[System.Environment]::SetEnvironmentVariable("SINDAGAL_DEFAULT_DISTRO",$distroName)
} else{
$distroName = $line.ToUpper()
$variablePath = "Env:SINDAGAL_INIT_DISTRO_${distroName}"
[System.Environment]::SetEnvironmentVariable("SINDAGAL_INIT_DISTRO_${distroName}",$true)
}
}
# Cannot see the variables which are supposed to be set in here at all
((Get-ChildItem env:*).Name)
我的 wsl --list 输出:
┖[~]> wsl --list
Windows Subsystem for Linux Distributions:
Debian (Default)
Alpine
原因
这是一个编码问题。 wsl
的重定向输出是 UTF-16 LE 编码的,它不会被 PowerShell 自动识别(从 PS 7.1.5 开始)。相反,它总是使用存储在 [Console]::OutputEncoding
中的编码解释输出,在 Windows 上默认为给定系统的旧 OEM 代码页(例如,美国英语系统上的 437)。
由于 UTF-16 是一种双字节编码,我们通常以嵌入的 [=13=]
字符结束(代码点低于 256,例如 ASCII 字符集)。在调用 SetEnvironmentVariable
时,这些会导致字符串被剪裁,因为 API 需要以 null 结尾的字符串。
解决方案
设置[Console]::OutputEncoding
以匹配进程的输出编码,然后再启动它并在之后恢复原始编码。
$oldEncoding = [Console]::OutputEncoding
[Console]::OutputEncoding = [Text.Encoding]::Unicode # on Windows: UTF-16 LE
$wslListOutput = wsl --list
[Console]::OutputEncoding = $oldEncoding
一些程序使用的另一种常见输出编码是[Text.Encoding]::UTF8
。
有关更深入的信息和 Invoke-WithEncoding
cmdlet,请参阅 ,它会自动执行临时更改和恢复编码的过程。
我正在尝试使用 Powershell 根据命令“wsl --list”的输出保存一些环境变量,当我调试此代码时,它似乎按预期运行但是当我检查我的环境变量时,我无法找到预期的键和值。
当我将相同的 SetEnvironmentVariable 方法与任何其他硬编码值一起使用时,它似乎有效。 $distroName 上的 Write-Host 也会产生预期的字符串,所以老实说我对此一头雾水。任何帮助,将不胜感激! 这是我的代码:
$wslListOutput = wsl --list
((Get-ChildItem env:*).Name | Select-String -Pattern "(SINDAGAL_INIT_DISTRO_([a-zA-Z=])*)|SINDAGAL_DEFAULT_DISTRO")
foreach ($line in $wslListOutput)
{
$lineIsEmpty = ("" -eq $line) -or ([string]::IsNullOrWhiteSpace($line))
$Introline = $line -eq "Windows Subsystem for Linux Distributions:"
if($lineIsEmpty -or $Introline){ continue }
if($line -Match "(([a-zA-Z]*) ([(Default)])*)"){
$distroName = ($line -split ' ',2)[0]
[System.Environment]::SetEnvironmentVariable("SINDAGAL_DEFAULT_DISTRO",$distroName)
} else{
$distroName = $line.ToUpper()
$variablePath = "Env:SINDAGAL_INIT_DISTRO_${distroName}"
[System.Environment]::SetEnvironmentVariable("SINDAGAL_INIT_DISTRO_${distroName}",$true)
}
}
# Cannot see the variables which are supposed to be set in here at all
((Get-ChildItem env:*).Name)
我的 wsl --list 输出:
┖[~]> wsl --list
Windows Subsystem for Linux Distributions:
Debian (Default)
Alpine
原因
这是一个编码问题。 wsl
的重定向输出是 UTF-16 LE 编码的,它不会被 PowerShell 自动识别(从 PS 7.1.5 开始)。相反,它总是使用存储在 [Console]::OutputEncoding
中的编码解释输出,在 Windows 上默认为给定系统的旧 OEM 代码页(例如,美国英语系统上的 437)。
由于 UTF-16 是一种双字节编码,我们通常以嵌入的 [=13=]
字符结束(代码点低于 256,例如 ASCII 字符集)。在调用 SetEnvironmentVariable
时,这些会导致字符串被剪裁,因为 API 需要以 null 结尾的字符串。
解决方案
设置[Console]::OutputEncoding
以匹配进程的输出编码,然后再启动它并在之后恢复原始编码。
$oldEncoding = [Console]::OutputEncoding
[Console]::OutputEncoding = [Text.Encoding]::Unicode # on Windows: UTF-16 LE
$wslListOutput = wsl --list
[Console]::OutputEncoding = $oldEncoding
一些程序使用的另一种常见输出编码是[Text.Encoding]::UTF8
。
有关更深入的信息和 Invoke-WithEncoding
cmdlet,请参阅