Powershell SetEnvironmentVariable 未按预期设置变量 [英] Powershell SetEnvironmentVariable not setting the variables as expected

查看:15
本文介绍了Powershell SetEnvironmentVariable 未按预期设置变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据命令wsl --list"的输出保存一些环境变量.使用 Powershell,当我调试此代码时,它似乎按预期流动,但是当我检查我的环境变量时,我无法找到预期的键和值.

I'm attempting to save some environment variables based on the output of the command "wsl --list" using Powershell, when I debug this code it seems to be flowing as expected however when I inspect my environment variables I'm unable to find the expected keys and values.

当我使用与任何其他硬编码值相同的 SetEnvironmentVariable 方法时,它似乎可以工作.$distroName 上的 Write-Host 也会产生预期的字符串,所以我真的迷失了这一点.任何帮助,将不胜感激!这是我的代码:

When I use the same SetEnvironmentVariable method with any other hardcoded value it seems to work. Write-Host on $distroName results in the expected string too so I'm honestly lost on this. Any help would be appreciated! Here is my code:

$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 输出:

my wsl --list output:

┖[~]> wsl --list
Windows Subsystem for Linux Distributions:
Debian (Default)
Alpine

推荐答案

原因

这是一个编码问题.wsl 的重定向输出是 UTF-16 LE 编码的,PowerShell 不会自动识别(从 PS 7.1.5 开始).相反,它总是使用存储在 [Console]::OutputEncoding 中的编码来解释输出,在 Windows 上默认为给定系统的旧版 OEM 代码页(例如,美国英语系统上的 437).

Cause

This is an encoding issue. Redirected output of wsl is UTF-16 LE encoded, which is not automatically recognized by PowerShell (as of PS 7.1.5). Instead it always interprets the output using the encoding stored in [Console]::OutputEncoding, which on Windows defaults to the given system's legacy OEM code page (e.g. 437 on US-English systems).

由于 UTF-16 是一种两字节编码,我们通常会嵌入 字符(低于 256 的代码点,例如 ASCII 字符集).在调用 SetEnvironmentVariable 时,这些会导致字符串被剪裁,因为 API 需要以 null 结尾的字符串.

As UTF-16 is a two-byte encoding we typically end up with embedded characters (code points below 256, such as the ASCII character set). These cause the string to be clipped, when calling SetEnvironmentVariable, because the API expects null-terminated strings.

在启动前设置[Console]::OutputEncoding以匹配进程的输出编码,然后恢复原始编码.

Set [Console]::OutputEncoding to match the output encoding of the process, before launching it and restore the original encoding afterwards.

$oldEncoding = [Console]::OutputEncoding
[Console]::OutputEncoding = [Text.Encoding]::Unicode  # on Windows: UTF-16 LE

$wslListOutput = wsl --list

[Console]::OutputEncoding = $oldEncoding

一些程序使用的另一种常见的输出编码是[Text.Encoding]::UTF8.

Another common output encoding used by some programs is [Text.Encoding]::UTF8.

请参阅 this answer 了解更深入的信息和 Invoke-WithEncoding cmdlet,它将临时更改和恢复编码的过程自动化.

See this answer for more in-depth information and an Invoke-WithEncoding cmdlet, which automates the process of temporarily changing and restoring the encoding.

这篇关于Powershell SetEnvironmentVariable 未按预期设置变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆