Compreender a codificação de ficheiros no VS Code e no PowerShell

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

O que é a codificação de ficheiros e porque é importante?

O VS Code gerencia a interface entre um humano inserindo cadeias de caracteres em um buffer e blocos de leitura/gravação 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, consulte about_Character_Encoding.

Da mesma forma, quando o PowerShell executa um script, ele deve 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. Esse processo de análise de um script do PowerShell vai: bytes -caracteres -tokens -árvore de sintaxe abstrata ->>>>execution.

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

Causas comuns de problemas de codificação

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

É mais provável que você tenha problemas de codificação quando estiver usando caracteres que não estão no conjunto de caracteres ASCII de 7 bits. Por exemplo:

  • Caracteres estendidos sem letras, como em-dash (), espaço não separável () ou aspas duplas esquerdas ( ")
  • Caracteres latinos acentuados (É, ü)
  • Caracteres não-latinos como cirílico (Д, Ц)
  • Caracteres CJK (, , )

As razões comuns para problemas de codificação são:

  • As codificações do VS Code e do PowerShell não foram alteradas de seus padrões. Para o PowerShell 5.1 e inferior, a codificação padrão é diferente da do VS Code.
  • Outro editor abriu e substituiu o arquivo em uma nova codificação. Isso geralmente acontece com o ISE.
  • O arquivo é verificado no controle do código-fonte em uma codificação diferente do que o VS Code ou o PowerShell espera. Isso pode acontecer quando os colaboradores usam editores com diferentes configurações de codificação.

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

Muitas vezes, os erros de codificação apresentam-se como erros de análise em scripts. Se você encontrar sequências de personagens estranhas em seu roteiro, esse pode ser o problema. No exemplo abaixo, um en-dash () aparece 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 estranhas que você pode ver incluem:

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

Esta referência útil lista os padrões comuns que indicam 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 os scripts são editados no VS Code, o conteúdo é enviado pelo VS Code para a extensão. O Language Server Protocol 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 os scripts são executados diretamente no Console Integrado, eles são lidos do arquivo diretamente pelo PowerShell. Se a codificação do PowerShell for diferente da do VS Code, algo pode dar errado aqui.
  3. Quando um script aberto no VS Code faz referência a outro script que não está aberto no VS Code, a extensão volta a carregar o conteúdo desse script do sistema de arquivos. A extensão do PowerShell assume como padrão a codificação UTF-8, mas usa a deteção de marca de ordem de bytes, 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). O padrão da extensão do PowerShell é UTF-8. A extensão não pode alterar as configurações de codificação do VS Code. Para obter mais informações, consulte a edição #824.

Escolhendo a codificação correta

Diferentes sistemas e aplicações podem usar codificações diferentes:

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

As codificações Unicode também têm o conceito de uma marca de ordem de bytes (BOM). As listas técnicas ocorrem no início do texto para indicar a um descodificador qual a codificação que o texto está a utilizar. Para codificações de vários bytes, a lista técnica também indica endianness da codificação. As listas técnicas são projetadas para serem bytes que raramente ocorrem em texto não-Unicode, permitindo uma suposição razoável de que o texto é Unicode quando uma lista técnica está presente.

As listas técnicas são opcionais e sua adoção não é tão popular no mundo Linux porque uma convenção confiável de UTF-8 é usada em todos os lugares. A maioria dos aplicativos Linux presume que a entrada de texto é codificada em UTF-8. Embora muitos aplicativos Linux reconheçam e manipulem corretamente uma lista técnica, alguns não, levando a artefatos em texto manipulados com esses aplicativos.

Por conseguinte:

  • Se você trabalha principalmente com aplicativos do Windows e Windows PowerShell, deve preferir uma codificação como UTF-8 com BOM ou UTF-16.
  • Se você trabalha entre plataformas, deve preferir UTF-8 com BOM.
  • Se você 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 mais antigos do Windows podem depender deles.
  • Também vale a pena notar que a assinatura de script depende da codificação, o que significa que uma alteração de codificação em um script assinado exigirá renúncia.

Configurando o VS Code

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

Para definir a codificação do VS Code, vá para as configurações do VS Code (Ctrl+) e defina a "files.encoding" configuração:

"files.encoding": "utf8bom"

Alguns valores possíveis são:

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

Você deve obter uma lista suspensa para isso na visualização GUI ou finalizações para ela na visualização JSON.

Você também pode adicionar o seguinte para detetar automaticamente a codificação quando possível:

"files.autoGuessEncoding": true

Se você não quiser 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 do idioma colocando as configurações em um [<language-name>] campo. Por exemplo:

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

Você também pode considerar a instalação do rastreador Gremlins para Visual Studio Code. Esta extensão revela certos caracteres Unicode que são facilmente corrompidos porque são invisíveis ou se parecem com outros caracteres normais.

Configurando 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 geralmente é Windows-1252, que é uma extensão do latim-1 (também conhecido como ISO 8859-1 ).

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

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

O script a seguir pode ser usado para determinar o que a codificação de sua sessão do PowerShell infere para um script sem uma 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 forma mais geral usando as configurações de perfil. Consulte os seguintes artigos:

Não é possível forçar o PowerShell a usar uma codificação de entrada específica. O PowerShell 5.1 e inferior, executado no Windows com a localidade definida como en-US, assume como padrão a codificação Windows-1252 quando não há BOM. Outras configurações de localidade podem usar uma codificação diferente. Para garantir a interoperabilidade, é melhor salvar scripts em um formato Unicode com uma lista técnica.

Importante

Quaisquer outras ferramentas que você tenha que toque em scripts do PowerShell podem ser afetadas por suas opções de codificação ou recodificar seus scripts para outra codificação.

Scripts existentes

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

Se precisar recodificar vários arquivos, você pode usar o seguinte script:

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

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

O ISE deve honrar uma lista técnica, mas também é possível usar a reflexão para definir a codificação. Observe que isso não seria persistente entre as startups.

Software de controlo do código-fonte

Algumas ferramentas de controle do código-fonte, como o git, ignoram codificações; O Git apenas rastreia os bytes. Outros, como Azure DevOps ou Mercurial, não podem. Mesmo algumas ferramentas baseadas em git dependem da decodificação de texto.

Quando for esse o caso, certifique-se de que:

  • Configure a codificação de texto no controle do código-fonte para corresponder à configuração do VS Code.
  • Certifique-se de que todos os seus arquivos são verificados no controle do código-fonte na codificação relevante.
  • Desconfie de alterações na codificação recebidas por meio do controle do código-fonte. Um sinal chave disso é um diff indicando mudanças, mas onde nada parece ter mudado (porque bytes têm, mas caracteres não).

Ambientes dos colaboradores

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

Outros programas

Qualquer outro programa que leia ou escreva um script do PowerShell pode recodificá-lo.

Alguns exemplos incluem:

  • Usando a área de transferência para copiar e colar um script. Isso é comum em cenários como:
    • Copiando um script para uma VM
    • Copiar um script de um e-mail ou página Web
    • Copiar um script para dentro ou para fora de um documento do Microsoft Word ou PowerPoint
  • Outros editores de texto, tais como:
    • Bloco de Notas
    • vim
    • Qualquer outro editor de scripts 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 ficheiros, como:
    • Um navegador da Web, ao baixar scripts
    • Um compartilhamento de arquivos

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

Outros recursos sobre codificação no PowerShell

Há alguns outros posts interessantes sobre codificação e configuração de codificação no PowerShell que valem a pena ler: