瞭解 VS Code 和 PowerShell 中的檔案編碼

使用 VS Code 來建立和編輯 PowerShell 腳本時,請務必使用正確的字元編碼格式來儲存您的檔案。

什麼是檔案編碼,以及為何很重要?

VS Code 會管理人類在緩衝區中輸入字元字串,以及讀取/寫入檔系統的位元組區塊之間的介面。 當 VS Code 儲存盤案時,它會使用文字編碼來決定每個字元會變成哪些位元組。 如需詳細資訊,請參閱 about_Character_Encoding

同樣地,當 PowerShell 執行腳本時,它必須將檔案中的位元組轉換成字元,以將檔案重建成 PowerShell 程式。 由於 VS Code 會寫入檔案,且 PowerShell 會讀取檔案,因此必須使用相同的編碼系統。 這個剖析 PowerShell 腳本的程式會是:位元組 -characters ->tokens ->>abstract 語法樹狀目錄 ->execution。

VS Code 和 PowerShell 都安裝了合理的預設編碼組態。 不過,PowerShell 使用的預設編碼方式隨著 PowerShell 6 的發行而變更。 若要確定您在 VS Code 中使用 PowerShell 或 PowerShell 擴充功能時沒有任何問題,您必須正確設定 VS Code 和 PowerShell 設定。

編碼問題的常見原因

當 VS Code 或腳本檔案的編碼不符合 PowerShell 的預期編碼時,會發生編碼問題。 PowerShell 無法自動判斷檔案編碼。

當您使用不在 7 位 ASCII 字元集中字元時,更有可能發生編碼問題。 例如:

  • 擴充的非字母字元,例如 em-dash ()、非中斷空格 () 或左雙引號 ( "
  • 輔沙拉丁字元 (Éü
  • 非拉丁字元,如斯拉夫文 (ДЦ
  • CJK 字元 (、 )

編碼問題的常見原因是:

  • VS Code 和 PowerShell 的編碼方式尚未從預設值變更。 針對 PowerShell 5.1 和以下版本,預設編碼方式與 VS Code 不同。
  • 另一個編輯器已以新的編碼方式開啟並覆寫檔案。 這通常會發生在ISE中。
  • 檔案會簽入原始檔控制,其編碼方式與 VS Code 或 PowerShell 預期的方式不同。 當共同作業者使用不同的編碼組態使用編輯器時,就會發生這種情況。

如何判斷您何時發生編碼問題

編碼錯誤通常會在腳本中呈現為剖析錯誤。 如果您在腳本中發現奇怪的字元序列,可能是問題。 在下列範例中,en-dash () 會顯示為字元 â€"

Send-MailMessage : A positional parameter cannot be found that accepts argument 'Testing FuseMail SMTP...'.
At C:\Users\<User>\<OneDrive>\Development\PowerShell\Scripts\Send-EmailUsingSmtpRelay.ps1:6 char:1
+ Send-MailMessage â&euro;"From $from â&euro;"To $recipient1 â&euro;"Subject $subject  ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Send-MailMessage], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.SendMailMessage

發生此問題的原因是 VS Code 會將 UTF-8 中的字元 編碼為位元組 0xE2 0x80 0x93。 當這些位元組譯碼為 Windows-1252 時,這些位元組會解譯為 字元 â&euro;"

您可能會看到一些奇怪的字元序列包括:

  • â&euro;" 而不是 (破折號)
  • â&euro;" 而不是 (em-dash)
  • Ä2 而不是 Ä
  •   而不是 (不中斷的空間)
  • Ã&copy; 而不是 é

這個方便的 參考 會列出指出UTF-8/Windows-1252編碼問題的常見模式。

VS Code 中的 PowerShell 延伸模組如何與編碼互動

PowerShell 擴充功能會以數種方式與腳本互動:

  1. 在 VS Code 中編輯腳本時,VS Code 會將內容傳送至延伸模組。 語言 伺服器通訊協議 會強制在UTF-8中傳輸此內容。 因此,擴充功能無法取得錯誤的編碼。
  2. 直接在整合式控制台中執行腳本時,PowerShell 會直接從檔案讀取這些腳本。 如果 PowerShell 的編碼與 VS Code 不同,這裡可能會發生錯誤。
  3. 當 VS Code 中開啟的腳本參考 VS Code 中未開啟的另一個腳本時,擴充功能會回復為從文件系統載入該腳本的內容。 PowerShell 延伸模組預設為 UTF-8 編碼,但會使用 位元組順序標記或 BOM 偵測來選取正確的編碼。

假設無 BOM 格式的編碼方式(例如沒有 BOM 和 Windows-1252 的 UTF-8時,就會發生此問題。 PowerShell 擴充功能預設為 UTF-8。 延伸模組無法變更 VS Code 的編碼設定。 如需詳細資訊,請參閱 問題 #824

選擇正確的編碼方式

不同的系統與應用程式可以使用不同的編碼方式:

  • 在 .NET Standard 的 Web 和 Linux 世界中,UTF-8 現在是主要的編碼方式。
  • 許多 .NET Framework 應用程式都使用 UTF-16。 基於歷史原因,這有時稱為“Unicode”,這個詞彙現在指的是包含UTF-8和UTF-16的廣泛 標準
  • 在 Windows 上,許多預先述詞 Unicode 的原生應用程式預設會繼續使用 Windows-1252。

Unicode 編碼也有位元組順序標記 (BOM) 的概念。 BOM 會在文字開頭發生,以告訴譯碼器文字所使用的編碼方式。 對於多位元組編碼,BOM也會指出 編碼的結束度 。 BOM 設計成非 Unicode 文字中很少發生的位元元組,允許在 BOM 存在時合理猜測文字為 Unicode。

BOM 是選擇性的,而且其採用在 Linux 世界中並不那麼受歡迎,因為隨處都會使用 UTF-8 的可靠慣例。 大部分的 Linux 應用程式都假設文字輸入是以 UTF-8 編碼。 雖然許多 Linux 應用程式會辨識並正確處理 BOM,但數位不會,導致使用這些應用程式操作的文字中的成品。

因此

  • 如果您主要使用 Windows 應用程式和 Windows PowerShell,您應該偏好使用 BOM 或 UTF-16 的 UTF-8 之類的編碼方式。
  • 如果您跨平臺工作,您應該偏好使用 BOM 的 UTF-8。
  • 如果您主要在Linux相關內容中工作,您應該偏好不使用 BOM 的 UTF-8。
  • Windows-1252 和 latin-1 基本上是您應該盡可能避免的舊版編碼。 不過,某些較舊的 Windows 應用程式可能會相依於這些應用程式。
  • 值得注意的是,腳本簽署是 編碼相依的,這表示簽署腳本上的編碼變更需要辭職。

設定 VS Code

VS Code 的預設編碼方式為 UTF-8,不含 BOM。

若要設定 VS Code 的編碼方式,請移至 VS Code 設定 (Ctrl+) 並設定 "files.encoding" 設定:

"files.encoding": "utf8bom"

一些可能的值為:

  • utf8:[UTF-8] 不含 BOM
  • utf8bom:[UTF-8] 搭配 BOM
  • utf16le:小尾 [UTF-16]
  • utf16be:Big endian [UTF-16]
  • windows1252:[Windows-1252]

您應該會在 GUI 檢視中取得此專案的下拉式清單,或在 JSON 檢視中取得該清單的完成。

您也可以盡可能將下列內容新增至自動偵測編碼:

"files.autoGuessEncoding": true

如果您不想要這些設定會影響所有文件類型,VS Code 也允許個別語言的組態。 將設定 [<language-name>] 放在欄位中,以建立特定語言設定。 例如:

"[powershell]": {
    "files.encoding": "utf8bom",
    "files.autoGuessEncoding": true
}

您也可以考慮安裝適用於 Visual Studio Code 的 Gremlins 追蹤器 。 此延伸模組會顯示某些容易損毀的 Unicode 字元,因為它們是看不見的,或看起來像其他一般字元。

設定 PowerShell

PowerShell 的預設編碼會因版本而異:

  • 在 PowerShell 6+ 中,預設編碼方式是所有平台上沒有 BOM 的 UTF-8。
  • 在 Windows PowerShell 中,預設編碼通常是 Windows-1252,這是 latin-1延伸模組(也稱為 ISO 8859-1)。

在 PowerShell 5+ 中,您可以使用下列方式找到預設編碼方式:

[psobject].Assembly.GetTypes() | Where-Object { $_.Name -eq 'ClrFacade'} |
  ForEach-Object {
    $_.GetMethod('GetDefaultEncoding', [System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @())
  }

下列 腳本 可用來判斷PowerShell工作階段針對沒有 BOM 的腳本推斷的編碼方式。

$badBytes = [byte[]]@(0xC3, 0x80)
$utf8Str = [System.Text.Encoding]::UTF8.GetString($badBytes)
$bytes = [System.Text.Encoding]::ASCII.GetBytes('Write-Output "') + [byte[]]@(0xC3, 0x80) + [byte[]]@(0x22)
$path = Join-Path ([System.IO.Path]::GetTempPath()) 'encodingtest.ps1'

try
{
    [System.IO.File]::WriteAllBytes($path, $bytes)

    switch (& $path)
    {
        $utf8Str
        {
            return 'UTF-8'
            break
        }

        default
        {
            return 'Windows-1252'
            break
        }
    }
}
finally
{
    Remove-Item $path
}

您可以更普遍地使用設定檔設定,將 PowerShell 設定為使用指定的編碼方式。 請參閱以下文章:

您無法強制 PowerShell 使用特定的輸入編碼。 PowerShell 5.1 和以下版本,在 Windows 上執行的地區設定設為 en-US,當沒有 BOM 時,預設為 Windows-1252 編碼。 其他地區設定可能會使用不同的編碼方式。 為了確保互操作性,最好使用 BOM 以 Unicode 格式儲存腳本。

重要

您擁有的任何其他觸控 PowerShell 腳本工具,都可能會受到編碼選擇的影響,或將腳本重新編碼為另一種編碼。

現有的腳本

檔系統上的腳本可能需要重新編碼為新的選擇編碼。 在 VS Code 的底部列中,您會看到標籤 UTF-8。 按兩下它以開啟動作列,然後選取 [使用編碼儲存]。 您現在可以為該檔案挑選新的編碼方式。 如需完整指示,請參閱 VS Code 的編碼

如果您需要重新編碼多個檔案,您可以使用下列腳本:

Get-ChildItem *.ps1 -Recurse | ForEach-Object {
    $content = Get-Content -Path $_
    Set-Content -Path $_.Fullname -Value $content -Encoding UTF8 -PassThru -Force
}

PowerShell 整合式腳稿環境 (ISE)

如果您也使用PowerShell ISE 編輯腳本,則必須同步處理您的編碼設定。

ISE 應該接受 BOM,但也可以使用反映來 設定編碼。 請注意,這不會在啟動之間保存。

原始檔控制軟體

某些原始檔控制工具,例如 git,會忽略編碼;git 只會追蹤位元組。 其他專案,例如 Azure DevOps 或 Mercurial,可能不會。 即使是一些以 Git 為基礎的工具也依賴譯碼文字。

如果是這種情況,請確定您:

  • 在原始檔控制中設定文字編碼,以符合 VS Code 組態。
  • 請確定所有檔案都已簽入相關編碼中的原始檔控制。
  • 請謹慎處理透過原始檔控制收到的編碼變更。 這是一個索引鍵符號,指出變更,但似乎沒有任何變更之處(因為位元組有,但字元沒有)。

共同作業者的環境

在設定原始檔控制之上,請確定您共用的任何檔案上的共同作業者沒有透過重新編碼 PowerShell 檔案覆寫編碼方式的設定。

其他程式

讀取或寫入 PowerShell 腳本的任何其他程式可能會重新編碼。

部份範例如下:

  • 使用剪貼簿複製並貼上腳本。 這在下列案例中很常見:
    • 將腳本複製到 VM
    • 從電子郵件或網頁複製腳本
    • 將腳本複製到或移出 Microsoft Word 或 PowerPoint 檔
  • 其他文字編輯器,例如:
    • 記事本
    • vim
    • 任何其他 PowerShell 腳本編輯器
  • 文字編輯公用程式,例如:
    • Get-Content/Set-Content/Out-File
    • PowerShell 重新導向運算子,例如 >>>
    • sed/awk
  • 檔案傳輸程式,例如:
    • 下載文稿時,網頁瀏覽器
    • 檔案共用

其中有些工具會以位元組而非文字處理,但其他工具則提供編碼組態。 在需要設定編碼的情況下,您必須讓它與編輯器編碼相同,以避免發生問題。

PowerShell 中編碼的其他資源

在 PowerShell 中,有一些關於編碼和設定編碼的其他好文章值得閱讀: