Como fazer deploy e configuração remota com PowerShell Remoting

1. Fundamentos do PowerShell Remoting

O PowerShell Remoting é a tecnologia nativa da Microsoft para administração remota de sistemas Windows baseada no protocolo WinRM (Windows Remote Management), implementação Microsoft do WS-Management. Diferente de soluções como SSH nativo, o PowerShell Remoting oferece integração profunda com o ecossistema Windows, permitindo execução de comandos, scripts e acesso completo a objetos .NET em máquinas remotas.

Requisitos de infraestrutura:
- Windows PowerShell 5.1 ou PowerShell 7+ (cross-platform)
- WinRM 2.0+ habilitado nas máquinas alvo
- Firewall permitindo porta 5985 (HTTP) ou 5986 (HTTPS)
- Política de execução adequada (RemoteSigned ou superior)
- Privilégios administrativos nas máquinas remotas

Habilitando e testando conectividade:

# Habilitar PowerShell Remoting no servidor alvo (executar como Admin)
Enable-PSRemoting -Force

# Verificar se o serviço WinRM está ativo
Get-Service WinRM

# Testar conectividade remota
Test-WSMan -ComputerName "SERVIDOR01"

# Verificar configuração do listener
Get-WSManInstance -ResourceURI winrm/config/listener

2. Configuração de Sessões Remotas (PSSessions)

Sessões persistentes (PSSessions) são o coração do PowerShell Remoting para operações complexas. Elas mantêm estado, variáveis e módulos carregados entre comandos.

Criação e gerenciamento:

# Criar sessão persistente com credenciais
$creds = Get-Credential
$session = New-PSSession -ComputerName "SERVIDOR01" -Credential $creds -Authentication Default

# Criar sessão com configuração específica (endpoint personalizado)
$sessionCustom = New-PSSession -ComputerName "SERVIDOR02" -ConfigurationName "Microsoft.PowerShell32"

# Entrar em sessão interativa
Enter-PSSession -Session $session

# Sair da sessão interativa
Exit-PSSession

# Listar todas as sessões ativas
Get-PSSession

# Desconectar sessão sem encerrá-la (útil para tarefas longas)
Disconnect-PSSession -Session $session

# Reconectar a sessão desconectada
Connect-PSSession -Session $session

# Remover sessão após uso
Remove-PSSession -Session $session

Boas práticas: Sempre utilize Remove-PSSession para liberar recursos. Em scripts automatizados, considere usar blocos try/catch/finally para garantir o encerramento adequado.

3. Execução de Comandos e Scripts Remotos

Invoke-Command é o cmdlet principal para execução remota, suportando lote, paralelismo e coleta de resultados.

Execução básica e em lote:

# Execução única
Invoke-Command -ComputerName "SRV01" -ScriptBlock { Get-Process | Where-Object CPU -gt 10 }

# Execução em múltiplos computadores
$computadores = @("SRV01", "SRV02", "SRV03")
Invoke-Command -ComputerName $computadores -ScriptBlock {
    Get-Service -Name "Spooler" | Select-Object Name, Status, MachineName
}

# Passagem de variáveis com ArgumentList
$nomeServico = "W3SVC"
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    param($servico)
    Restart-Service -Name $servico -Force
} -ArgumentList $nomeServico

# Uso do escopo Using: (PowerShell 7+)
$limiteCPU = 80
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    Get-Process | Where-Object { $_.CPU -gt $using:limiteCPU }
}

Execução assíncrona com jobs:

# Iniciar job remoto
$job = Invoke-Command -ComputerName @("SRV01","SRV02") -ScriptBlock {
    Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3"
} -AsJob

# Aguardar e receber resultados
$job | Wait-Job
$resultados = $job | Receive-Job

# Verificar status
$job | Get-Job

4. Transferência de Arquivos e Deploy de Pacotes

O PowerShell Remoting permite cópia de arquivos bidirecional através de sessões, essencial para deploys.

Copiando arquivos via sessão:

# Criar sessão para transferência
$session = New-PSSession -ComputerName "SRV01" -Credential $creds

# Copiar pasta local para servidor remoto
Copy-Item -Path "C:\Deploy\App_v2.0" -Destination "C:\Program Files\MyApp" -ToSession $session -Recurse -Force

# Copiar arquivo do servidor remoto para local
Copy-Item -Path "C:\Logs\app.log" -Destination "D:\BackupLogs\" -FromSession $session

# Deploy via caminho UNC (alternativa)
Copy-Item -Path "\\fileserver\deploy\installer.msi" -Destination "C:\Temp\installer.msi" -ToSession $session

Deploy silencioso de software:

# Instalar MSI remotamente
Invoke-Command -Session $session -ScriptBlock {
    Start-Process -FilePath "msiexec.exe" -ArgumentList "/i C:\Temp\app.msi /quiet /norestart" -Wait -NoNewWindow
}

# Executar instalador EXE com parâmetros
Invoke-Command -Session $session -ScriptBlock {
    Start-Process -FilePath "C:\Temp\setup.exe" -ArgumentList "/S /v/qn" -Wait -PassThru
}

5. Configuração Remota de Serviços e Registro

Gerenciamento de serviços:

# Parar e desabilitar serviço
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    Stop-Service -Name "wuauserv" -Force
    Set-Service -Name "wuauserv" -StartupType Disabled
}

# Criar serviço personalizado
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    New-Service -Name "MeuServico" -BinaryPathName "C:\App\meuapp.exe" -DisplayName "Meu Serviço" -StartupType Automatic
}

Alterações no registro e sistema:

# Configurar chave de registro
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    New-Item -Path "HKLM:\SOFTWARE\MinhaEmpresa\AppConfig" -Force
    Set-ItemProperty -Path "HKLM:\SOFTWARE\MinhaEmpresa\AppConfig" -Name "Timeout" -Value 300
}

# Configurar regra de firewall
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    New-NetFirewallRule -DisplayName "App Port 8080" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow
}

# Criar tarefa agendada
Invoke-Command -ComputerName "SRV01" -ScriptBlock {
    $action = New-ScheduledTaskAction -Execute "C:\Scripts\backup.ps1"
    $trigger = New-ScheduledTaskTrigger -Daily -At "02:00AM"
    Register-ScheduledTask -TaskName "BackupDiario" -Action $action -Trigger $trigger -User "SYSTEM"
}

6. Automação de Tarefas em Múltiplas Máquinas

Deploy em lote com arquivo de inventário:

# Inventário em CSV
$inventario = Import-Csv -Path "C:\inventario.csv"
# CSV esperado: ComputerName,Role,Environment

foreach ($maquina in $inventario) {
    Write-Host "Processando $($maquina.ComputerName)..." -ForegroundColor Cyan

    try {
        $session = New-PSSession -ComputerName $maquina.ComputerName -ErrorAction Stop

        Invoke-Command -Session $session -ScriptBlock {
            # Lógica de deploy específica para o role
            param($role)
            if ($role -eq "Web") {
                # Configurar IIS
            } elseif ($role -eq "DB") {
                # Configurar SQL
            }
        } -ArgumentList $maquina.Role

        Remove-PSSession $session
        Write-Host "$($maquina.ComputerName): Sucesso" -ForegroundColor Green
    }
    catch {
        Write-Host "$($maquina.ComputerName): Erro - $_" -ForegroundColor Red
    }
}

Paralelismo com ThrottleLimit:

# Executar deploy em paralelo (máx. 5 simultâneos)
$resultados = Invoke-Command -ComputerName $computadores -ScriptBlock {
    # Script de deploy
    $status = "OK"
    # ... lógica ...
    return $status
} -ThrottleLimit 5

# Logging centralizado
$resultados | Export-Csv -Path "C:\Logs\deploy_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

7. Segurança e Boas Práticas em Ambientes Remotos

Configuração segura do WinRM:

# Configurar listener HTTPS com certificado
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object Subject -like "*servidor*"
New-WSManInstance -ResourceURI winrm/config/Listener -SelectorSet @{
    Address = "*"
    Transport = "HTTPS"
} -ValueSet @{
    CertificateThumbprint = $cert.Thumbprint
    Port = 5986
}

# Configurar trusted hosts (para grupos de trabalho)
Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value "*.dominio.local" -Force

# Restringir endpoints remotos
Set-PSSessionConfiguration -Name "Microsoft.PowerShell" -ShowSecurityDescriptorUI

Gerenciamento de credenciais:

# Salvar credencial de forma segura
$creds = Get-Credential
$creds | Export-Clixml -Path "C:\secure\creds.xml"

# Carregar em script automatizado
$creds = Import-Clixml -Path "C:\secure\creds.xml"

# (Alternativa moderna) Usar Azure Key Vault
# $secret = Get-AzKeyVaultSecret -VaultName "MeuVault" -Name "AdminCred"

Resolução de problemas comuns:

# Verificar logs de erro do WinRM
Get-WinEvent -LogName "Microsoft-Windows-WinRM/Operational" | Where-Object LevelDisplayName -eq "Error"

# Testar conectividade detalhada
Test-WSMan -ComputerName "SRV01" -Authentication Negotiate

# Verificar permissões do usuário remoto
Invoke-Command -ComputerName "SRV01" -ScriptBlock { whoami }

# Aumentar timeout para operações longas
$options = New-PSSessionOption -IdleTimeout 3600000 -OpenTimeout 30000
$session = New-PSSession -ComputerName "SRV01" -SessionOption $options

Referências