Noções básicas sobre a codificação de arquivos no VS Code e PowerShell

Ao usar o VS Code para criar e editar scripts do PowerShell, é importante salvar seus arquivos usando o formato de codificação de caracteres correto.

O que é codificação de arquivos e por que ela é importante?

O VS Code gerencia a interface entre um humano inserindo cadeias de caracteres em um buffer e lendo/gravando blocos de bytes no sistema de arquivos. Quando o VS Code salva um arquivo, ele usa uma codificação de texto para decidir quais bytes cada caractere se torna. Para obter mais informações, confira about_Character_Encoding.

De forma semelhante, quando o PowerShell executa um script, ele precisa converter os bytes em um arquivo em caracteres para reconstruir o arquivo em um programa do PowerShell. Como o VS Code grava o arquivo e o PowerShell lê o arquivo, eles precisam usar o mesmo sistema de codificação. O processo de análise de um script do PowerShell é: bytes ->caracteres ->tokens ->árvore de sintaxe abstrata ->execução.

O VS Code e o PowerShell são instalados com uma configuração de codificação padrão adequada. No entanto, a codificação padrão usada pelo PowerShell foi alterada com a versão do PowerShell 6. Para garantir que não tenha problemas para usar o PowerShell ou a extensão do PowerShell no VS Code, você precisa definir corretamente suas configurações do VS Code e do PowerShell.

Causas comuns de problemas de codificação

Problemas de codificação ocorrem quando a codificação do VS Code ou o arquivo de script não corresponde à codificação esperada do PowerShell. Não há nenhuma maneira de o PowerShell determinar automaticamente a codificação do arquivo.

Você tem mais probabilidade de ter problemas de codificação quando usa caracteres que não estão no conjunto de caracteres ASCII de 7 bits. Por exemplo:

  • Caracteres não alfabéticos estendidos, como travessão (), espaço contínuo ( ) ou aspas duplas à esquerda (")
  • Caracteres latinos acentuados (É, ü)
  • Caracteres não latinos, como cirílico (Д, Ц)
  • Caracteres CJK (, , )

Motivos comuns para problemas de codificação são:

  • As codificações do VS Code e do PowerShell não foram alteradas dos padrões. Para o PowerShell 5.1 e versões anteriores, a codificação padrão é diferente da codificação do VS Code.
  • Outro editor abriu e substituiu o arquivo em uma nova codificação. Isso costuma acontecer com o ISE.
  • O check-in do arquivo foi feito no controle do código-fonte em uma codificação diferente da esperada pelo VS Code ou pelo PowerShell. Isso pode acontecer quando colaboradores usam editores com configurações de codificação diferentes.

Como saber que você tem problemas de codificação

Com frequência, erros de codificação são apresentados como erros de análise nos scripts. Se você encontrar sequências de caracteres estranhos em seu script, esse poderá ser o problema. No exemplo a seguir, um traço () é exibido como os caracteres â€":

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

Esse problema ocorre porque o VS Code codifica o caractere em UTF-8 como os bytes 0xE2 0x80 0x93. Quando esses bytes são decodificados como Windows-1252, eles são interpretados como os caracteres â&euro;".

Algumas sequências de caracteres estranhos que você pode ver incluem:

  • â&euro;" em vez de (um en-dash)
  • â&euro;" em vez de (um en-dash)
  • Ä2 em vez de Ä
  • Â em vez de   (um espaço contínuo)
  • Ã&copy; em vez de é

Esta referência útil lista os padrões comuns que indicam que há um problema de codificação UTF-8/Windows-1252.

Como a extensão do PowerShell no VS Code interage com codificações

A extensão do PowerShell interage com scripts de várias maneiras:

  1. Quando scripts são editados no VS Code, o conteúdo é enviado pelo VS Code para a extensão. O Protocolo de servidor de linguagem exige que esse conteúdo seja transferido em UTF-8. Portanto, não é possível que a extensão obtenha a codificação errada.
  2. Quando são executados diretamente no Console integrado, os scripts são lidos do arquivo diretamente pelo PowerShell. Se a codificação do PowerShell for diferente da codificação do VS Code, algo poderá dar errado aqui.
  3. Quando um script aberto no VS Code faz referência a outro script que não está aberto nele, a extensão faz fallback para carregar o conteúdo do script por meio do sistema de arquivos. A extensão do PowerShell usa por padrão a codificação UTF-8, mas usa a detecção de marca de ordem de byte, ou BOM, para selecionar a codificação correta.

O problema ocorre ao assumir a codificação de formatos sem BOM (como UTF-8 sem BOM e Windows-1252). A extensão do PowerShell usa UTF-8 por padrão. A extensão não pode alterar as configurações de codificação do VS Code. Para obter mais informações, confira problema #824.

Escolher a codificação correta

Aplicativos e sistemas diferentes podem usar codificações diferentes:

  • No .NET Standard, na Web e no universo Linux, UTF-8 é a codificação dominante.
  • Muitos aplicativos .NET Framework usam UTF-16. Por razões históricas, às vezes ele é chamado de "Unicode", um termo que hoje se refere a um padrão amplo que inclui UTF-8 e UTF-16.
  • No Windows, muitos aplicativos nativos anteriores ao Unicode continuam usando o Windows-1252 por padrão.

Codificações Unicode também têm o conceito de uma BOM (marca de ordem de byte). BOMs ocorrem no início do texto para informar ao decodificador qual codificação o texto está usando. Para codificações de múltiplos bytes, a BOM também indica a ordenação da codificação. BOMs são designadas como bytes que raramente ocorrem em texto não Unicode, permitindo presumir de forma razoável que o texto é Unicode quando uma BOM está presente.

BOMs são opcionais e sua adoção não é tão popular no universo Linux, pois uma convenção confiável de UTF-8 é usada em todo lugar. A maioria dos aplicativos Linux presume que a entrada de texto está codificada em UTF-8. Embora muitos aplicativos Linux reconheçam e manipulem corretamente um BOM, alguns não o fazem, acarretando em artefatos no texto manipulado com esses aplicativos.

Portanto:

  • se trabalha principalmente com aplicativos do Windows e Windows PowerShell, você deve preferir uma codificação como UTF-8 com BOM ou UTF-16.
  • Se trabalha com plataformas cruzadas, você deve preferir UTF-8 com BOM.
  • Se trabalha principalmente em contextos associados ao Linux, você deve preferir UTF-8 sem BOM.
  • Windows-1252 e latin-1 são essencialmente codificações herdadas que você deve evitar se possível. No entanto, alguns aplicativos do Windows mais antigos podem depender delas.
  • Também vale observar que a assinatura de script é dependente da codificação, o que significa que uma alteração na codificação de um script assinado exigirá uma nova assinatura.

Configurar o VS Code

A codificação padrão do VS Code é UTF-8 sem BOM.

Para definir a Codificação de VS Code, vá para a seção correspondente (Ctrl+,) e defina a configuração "files.encoding":

"files.encoding": "utf8bom"

Alguns valores possíveis são:

  • utf8: [UTF-8] sem BOM
  • utf8bom: [UTF-8] com BOM
  • utf16le: little endian [UTF-16]
  • utf16be: big endian [UTF-16]
  • windows1252: [Windows-1252]

Você deve obter uma lista suspensa deles no modo de exibição de GUI ou preenchimentos no modo de exibição JSON.

Você também pode adicionar o seguinte para obter detecção automática da codificação quando possível:

"files.autoGuessEncoding": true

Caso não queira que essas configurações afetem todos os tipos de arquivos, o VS Code também permite configurações por idioma. Crie uma configuração específica a um idioma colocando as configurações em um campo [<language-name>]. Por exemplo:

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

Considere também instalar o rastreador do Gremlins para Visual Studio Code. Essa extensão revela certos caracteres Unicode que são facilmente corrompidos por serem invisíveis ou se parecem com outros caracteres normais.

Configurar o PowerShell

A codificação padrão do PowerShell varia dependendo da versão:

  • No PowerShell 6 +, a codificação padrão é UTF-8 sem BOM em todas as plataformas.
  • No Windows PowerShell, a codificação padrão costuma ser Windows-1252, que é uma extensão de latin-1 (também conhecida como ISO 8859-1).

No PowerShell 5 +, você pode encontrar sua codificação padrão usando:

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

O seguinte script pode ser usado para determinar qual codificação sua sessão do PowerShell infere para um script sem 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
}

É possível configurar o PowerShell para usar uma determinada codificação de modo mais geral usando configurações de perfil. Veja os artigos a seguir:

Não é possível forçar o PowerShell a usar uma codificação de entrada específica. Quando executado no Windows com a localidade definida como en-US, o PowerShell 5.1 e suas versões anteriores usarão como padrão a codificação Windows-1252 se não houver uma marca de ordem de byte. Outras configurações de localidade podem usar uma codificação diferente. Para garantir a interoperabilidade, é melhor salvar os scripts em um formato Unicode com uma marca de ordem de byte.

Importante

Qualquer outra ferramenta que você tiver que tocar os scripts do PowerShell poderão ser afetadas por suas escolhas de codificação ou recodificar seus scripts com outra codificação.

Scripts existentes

Scripts que já estão no sistema de arquivos poderão precisar ser codificados novamente para sua codificação escolhida. Na barra inferior do VS Code, você verá o rótulo UTF-8. Clique nele para abrir a barra de ação e selecione Salvar com codificação. Agora, você pode escolher uma nova codificação para o arquivo. Confira Codificação de VS Code para obter instruções completas.

Se precisar codificar vários arquivos novamente, você poderá usar o script a seguir:

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

O (ISE) Ambiente de Script Integrado do PowerShell

Caso também edite scripts usando o ISE do PowerShell, você precisará sincronizar suas configurações de codificação nele.

O ISE deve honrar uma BOM, mas também é possível usar reflexão para definir a codificação. Observe que isso não persistiria entre inicializações.

Software de controle do código-fonte

Algumas ferramentas de controle do código-fonte, como git, ignoram as codificações; o git apenas controla os bytes. Outros, como Azure DevOps ou Mercurial, podem não fazer isso. Até mesmo algumas ferramentas baseadas em git dependem da decodificação de texto.

Quando for esse o caso, não deixe de:

  • Configure a codificação de texto no controle do código-fonte para corresponder à configuração do VS Code.
  • Garantir que todos os arquivos sejam verificados no controle do código-fonte na codificação relevante.
  • Estar atento a alterações na codificação recebidas por meio do controle do código-fonte. Um sinal importante disto é uma comparação indicando alterações, mas em que nada parece ter sido alterado (porque os bytes foram, mas os caracteres não).

Ambientes de colaboradores

Além de configurar o controle do código-fonte, certifique-se de que seus colaboradores em todos os arquivos que você compartilha não tenham configurações que substituem sua codificação codificando novamente os arquivos do PowerShell.

Outros programas

Qualquer outro programa que lê ou grava um script do PowerShell pode codificá-lo novamente.

Alguns exemplos são:

  • Usar a área de transferência para copiar e colar um script. Isso é comum em cenários como:
    • Copiar um script para uma VM
    • Copiar um script para fora de um email ou página da Web
    • Copiar um script de ou para um documento do Microsoft Word ou PowerPoint
  • Outros editores de texto, como:
    • Bloco de notas
    • vim
    • Qualquer outro editor de script do PowerShell
  • Utilitários de edição de texto, como:
    • Get-Content/Set-Content/Out-File
    • Operadores de redirecionamento do PowerShell, como > e >>
    • sed/awk
  • Programas de transferência de arquivos, como:
    • Um navegador da Web, ao baixar scripts
    • Um compartilhamento de arquivo

Algumas dessas ferramentas lidam com bytes em vez de texto, mas outras oferecem configurações de codificação. Nos casos em que precisa configurar uma codificação, você precisa fazer com que ela seja igual à codificação de seu editor para evitar problemas.

Outros recursos sobre codificação no PowerShell

Há algumas outras postagens interessantes sobre codificação e configuração da codificação do PowerShell que merecem uma leitura: