Escrever arquivos é uma tarefa fundamental em qualquer linguagem de script, e o PowerShell oferece uma variedade de cmdlets para essa finalidade. Nesta aula, vamos explorar os principais cmdlets para escrita de arquivos: Set-Content, Add-Content e Out-File. Além disso, vamos discutir a importância da codificação (encoding) e os cuidados que você deve ter ao escrever arquivos para evitar perda de dados ou resultados inesperados.

Compreender as diferenças entre esses cmdlets e saber quando usar cada um é essencial para escrever scripts eficientes e confiáveis. Vamos mergulhar em cada um deles, com exemplos práticos e explicações detalhadas.

Set-Content e Add-Content

O cmdlet Set-Content é usado para escrever conteúdo em um arquivo, substituindo qualquer conteúdo existente. Ele é ideal quando você deseja criar um novo arquivo ou sobrescrever completamente o conteúdo de um arquivo existente. O Set-Content aceita uma string ou uma coleção de strings como entrada, e também pode receber dados do pipeline.

Por outro lado, Add-Content é usado para adicionar conteúdo a um arquivo sem remover o conteúdo existente. Se o arquivo não existir, ele será criado. Essa é a principal diferença: Set-Content sobrescreve, enquanto Add-Content acrescenta.

Vejamos um exemplo simples de cada:

# Usando Set-Content para criar um novo arquivo e escrever conteúdo
Set-Content -Path 'C:\Temp\exemplo.txt' -Value 'Olá, mundo!'

# Usando Add-Content para adicionar mais conteúdo ao mesmo arquivo
Add-Content -Path 'C:\Temp\exemplo.txt' -Value 'Linha adicional.'

# Verificando o conteúdo do arquivo
Get-Content -Path 'C:\Temp\exemplo.txt'

No exemplo acima, primeiro criamos um arquivo com Set-Content e depois adicionamos uma linha com Add-Content. O resultado final será um arquivo com duas linhas: "Olá, mundo!" e "Linha adicional.".

Ambos os cmdlets suportam o parâmetro -Encoding, que discutiremos em breve, e também aceitam múltiplos valores para -Value, permitindo que você escreva várias linhas de uma só vez:

# Escrevendo várias linhas de uma vez com Set-Content
$linhas = @('Linha 1', 'Linha 2', 'Linha 3')
Set-Content -Path 'C:\Temp\multilinhas.txt' -Value $linhas

É importante notar que, se você usar Set-Content com um array, cada elemento será gravado em uma linha separada. Já com Add-Content, o mesmo comportamento se aplica, mas adicionando ao final do arquivo.

Out-File

O cmdlet Out-File é outra forma de gravar conteúdo em um arquivo. Ele é frequentemente usado para redirecionar a saída de um comando do PowerShell para um arquivo, similar ao operador de redirecionamento >. No entanto, Out-File oferece mais controle, como a opção de especificar a codificação e a largura da linha.

Uma das principais diferenças entre Out-File e Set-Content é que Out-File formata a saída da mesma forma que seria exibida no console, incluindo a formatação de objetos. Por exemplo, se você enviar um objeto para Out-File, ele será convertido em texto usando a formatação padrão do PowerShell, enquanto Set-Content espera strings ou converte usando o método ToString().

Exemplo básico:

# Usando Out-File para salvar a saída de Get-Process
Get-Process | Out-File -FilePath 'C:\Temp\processos.txt'

# Usando Set-Content para salvar a mesma saída (sem formatação especial)
Get-Process | Set-Content -Path 'C:\Temp\processos_set.txt'

No primeiro caso, o arquivo conterá a lista de processos formatada como no console. No segundo, os processos serão convertidos em strings simples, possivelmente perdendo a formatação tabular.

Outra característica do Out-File é o parâmetro -Append, que funciona de forma semelhante ao Add-Content, adicionando conteúdo ao final do arquivo em vez de sobrescrevê-lo.

# Adicionando saída a um arquivo existente com Out-File -Append
Get-Date | Out-File -FilePath 'C:\Temp\log.txt' -Append

Uma dica: use Out-File quando você quiser capturar a saída formatada de um comando, e Set-Content/Add-Content quando você estiver lidando diretamente com strings e quiser controle mais fino sobre o conteúdo.

Encoding

A codificação (encoding) determina como os caracteres são representados em bytes no arquivo. O PowerShell 5.1 e versões anteriores usam a codificação UTF-16LE (também conhecida como Unicode) por padrão em muitos cmdlets, enquanto o PowerShell 7+ (Core) usa UTF-8 sem BOM por padrão. Isso pode causar problemas de compatibilidade se você estiver compartilhando arquivos com outros sistemas ou ferramentas.

O parâmetro -Encoding está disponível em Set-Content, Add-Content e Out-File, permitindo que você especifique a codificação desejada. Os valores comuns incluem: ASCII, UTF8, UTF8BOM, UTF16LE, UTF16BE, Default (que depende da cultura do sistema), entre outros.

Exemplo:

# Escrevendo um arquivo em UTF-8
Set-Content -Path 'C:\Temp\utf8.txt' -Value 'Ação' -Encoding UTF8

# Escrevendo em UTF-16LE (padrão no Windows PowerShell)
Set-Content -Path 'C:\Temp\utf16.txt' -Value 'Ação' -Encoding Unicode

# Verificando o tamanho dos arquivos
Get-Item C:\Temp\utf8.txt, C:\Temp\utf16.txt | Select-Object Name, Length

No exemplo acima, o arquivo UTF-8 será menor porque caracteres ASCII (como 'A', 'c', 'ã', 'o') são representados com menos bytes em UTF-8, enquanto em UTF-16LE cada caractere ocupa 2 bytes.

Para evitar problemas de encoding, é recomendável especificar explicitamente a codificação ao escrever arquivos, especialmente se você pretende usar os dados em outros sistemas ou em páginas web. No PowerShell 7+, o padrão é UTF-8 sem BOM, que é amplamente aceito.

Cuidados

Ao escrever arquivos, alguns cuidados são essenciais para evitar erros e perda de dados:

  • Verifique se o diretório existe: Se o diretório não existir, o cmdlet falhará. Você pode usar New-Item -ItemType Directory para criar o diretório antes de escrever o arquivo.
  • Use caminhos absolutos ou relativos com cuidado: Caminhos relativos dependem do diretório atual do PowerShell, que pode mudar. Prefira caminhos absolutos para evitar surpresas.
  • Evite sobrescrever arquivos importantes acidentalmente: Sempre verifique se o arquivo já existe e se você realmente deseja substituí-lo. Você pode usar o parâmetro -NoClobber no Set-Content ou Out-File para impedir a sobrescrita.
  • Escolha a codificação correta: Como discutido, use o parâmetro -Encoding para garantir que os caracteres sejam gravados corretamente, especialmente se você estiver trabalhando com caracteres especiais ou acentos.
  • Use Add-Content para logs: Se você estiver criando um arquivo de log, é comum usar Add-Content para adicionar novas linhas ao longo do tempo, em vez de sobrescrever o arquivo a cada execução.

Exemplo de uso com verificação de diretório:

$caminho = 'C:\Logs\app.log'
$dir = Split-Path $caminho -Parent
if (-not (Test-Path $dir)) {
    New-Item -ItemType Directory -Path $dir -Force | Out-Null
}
Add-Content -Path $caminho -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Aplicação iniciada"

Nesse exemplo, garantimos que o diretório exista antes de tentar adicionar conteúdo ao arquivo de log.

Boas Práticas

Aqui estão algumas boas práticas para escrever arquivos no PowerShell:

  • Use Set-Content para criar ou substituir arquivos com conteúdo estático.
  • Use Add-Content para acrescentar dados progressivamente, como logs.
  • Use Out-File quando precisar capturar a saída formatada de comandos.
  • Especifique sempre a codificação (-Encoding UTF8) para garantir consistência.
  • Valide o caminho do arquivo e crie o diretório se necessário.
  • Considere usar -NoClobber para evitar sobrescritas acidentais.

Referências

Exercícios

  1. Escreva um script que crie um arquivo chamado teste.txt no diretório atual com o conteúdo "Primeira linha". Em seguida, adicione "Segunda linha" usando Add-Content. Verifique o conteúdo final.

    ✓ Resposta:
    Set-Content -Path 'teste.txt' -Value 'Primeira linha'
    Add-Content -Path 'teste.txt' -Value 'Segunda linha'
    Get-Content -Path 'teste.txt'
  2. Use Out-File para salvar a saída de Get-Date em um arquivo chamado data.txt e depois leia o arquivo para confirmar.

    ✓ Resposta:
    Get-Date | Out-File -FilePath 'data.txt'
    Get-Content -Path 'data.txt'
  3. Crie um arquivo config.ini com o seguinte conteúdo usando Set-Content: [config], nome=João, idade=30. Depois, adicione uma linha cidade=São Paulo usando Add-Content.

    ✓ Resposta:
    $linhas = @('[config]', 'nome=João', 'idade=30')
    Set-Content -Path 'config.ini' -Value $linhas
    Add-Content -Path 'config.ini' -Value 'cidade=São Paulo'
  4. Escreva um arquivo em UTF-8 com o texto "Olá, mundo!" e depois leia de volta para confirmar que os caracteres foram gravados corretamente.

    ✓ Resposta:
    Set-Content -Path 'ola.txt' -Value 'Olá, mundo!' -Encoding UTF8
    Get-Content -Path 'ola.txt' -Encoding UTF8
  5. Crie um script que verifique se o diretório C:\Temp\Teste existe; se não, crie-o. Em seguida, escreva um arquivo log.txt dentro dele com a data atual usando Add-Content.

    ✓ Resposta:
    $dir = 'C:\Temp\Teste'
    if (-not (Test-Path $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
    }
    $log = Join-Path $dir 'log.txt'
    Add-Content -Path $log -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"