<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automation on kenji.blog</title><link>http://kenji.blog/pt/categories/automation/</link><description>Recent content in Automation on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 06:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/categories/automation/index.xml" rel="self" type="application/rss+xml"/><item><title>Exemplo prático de automação completa de tarefas diárias com scripts do PowerShell</title><link>http://kenji.blog/pt/p/powershell-daily-task-automation-scripts/</link><pubDate>Sun, 13 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/powershell-daily-task-automation-scripts/</guid><description>&lt;img src="http://kenji.blog/p/powershell-daily-task-automation-scripts/img/eyecatch.jpg" alt="Featured image of post Exemplo prático de automação completa de tarefas diárias com scripts do PowerShell" />&lt;h2 id="introdução-por-que-automatizar-tarefas-com-powershell">Introdução: Por que automatizar tarefas com PowerShell?
&lt;/h2>&lt;p>Na infraestrutura de TI moderna e nos ambientes de desenvolvimento, as &amp;ldquo;tarefas rotineiras diárias&amp;rdquo; são um desafio inevitável para os usuários que utilizam o sistema operacional Windows como plataforma. Fazer backups de arquivos, monitorar logs do sistema, atualizar e compilar recursos de desenvolvimento (repositórios Git), entre outros, de forma manual, é um terreno fértil para erros humanos e leva ao desperdício de tempo precioso.&lt;/p>
&lt;p>No passado, arquivos de lote (&lt;code>.bat&lt;/code> ou &lt;code>.cmd&lt;/code>) e VBScript eram utilizados, mas hoje a melhor solução, sem dúvida, é o &lt;strong>PowerShell&lt;/strong>. O PowerShell não é apenas um shell baseado em texto, mas é construído sobre a poderosa base orientada a objetos do .NET Framework (e .NET Core). Como os dados passados pelo pipeline são &amp;ldquo;objetos&amp;rdquo; em vez de &amp;ldquo;strings&amp;rdquo;, não há necessidade de implementar análises de texto complexas (como comandos grep, awk ou sed), e você pode acessar facilmente os dados apenas especificando suas propriedades.&lt;/p>
&lt;p>Neste artigo, apresentaremos três exemplos reais de scripts de automação completa com PowerShell diretamente aplicáveis ao seu trabalho (backup para NAS e rotação de logs, monitoramento de logs de eventos e notificações no Slack, atualização em lote e build de vários repositórios Git). Antes disso, explicaremos detalhadamente as tecnologias subjacentes necessárias, como a política de execução do PowerShell, modularização e integração com o Agendador de Tarefas.&lt;/p>
&lt;hr>
&lt;h2 id="preparando-a-base-para-automação-com-powershell">Preparando a base para automação com PowerShell
&lt;/h2>&lt;p>Para que os scripts de automação funcionem de forma segura e confiável em um ambiente de produção, é necessária alguma preparação. Aqui, detalharemos o entendimento das políticas de execução, a modularização para melhorar a reutilização e o tratamento robusto de erros.&lt;/p>
&lt;h3 id="1-política-de-execução-do-powershell-execution-policy">1. Política de Execução do PowerShell (Execution Policy)
&lt;/h3>&lt;p>No Windows, há uma &amp;ldquo;política de execução&amp;rdquo; configurada por padrão para evitar que scripts maliciosos sejam executados acidentalmente. No estado inicial (&lt;code>Restricted&lt;/code>), nenhum script (arquivos &lt;code>.ps1&lt;/code>) pode ser executado. Para realizar automações, é necessário alterar isso para um nível adequado.&lt;/p>
&lt;p>Os tipos de políticas de execução são os seguintes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Restricted&lt;/strong>: Não permite a execução de scripts. (Padrão)&lt;/li>
&lt;li>&lt;strong>AllSigned&lt;/strong>: Permite apenas a execução de scripts assinados por um editor confiável.&lt;/li>
&lt;li>&lt;strong>RemoteSigned&lt;/strong>: Scripts criados localmente podem ser executados como estão, mas os scripts baixados da Internet exigem uma assinatura.&lt;/li>
&lt;li>&lt;strong>Unrestricted&lt;/strong>: Pode executar todos os scripts, mas exibe um aviso ao executar scripts baixados da Internet.&lt;/li>
&lt;li>&lt;strong>Bypass&lt;/strong>: Nada é bloqueado e nenhum aviso é exibido. Freqüentemente usado para execuções temporárias de scripts (como em pipelines de CI/CD).&lt;/li>
&lt;/ul>
&lt;p>Ao executar seus próprios scripts com o Agendador de Tarefas em um ambiente corporativo local, a configuração mais prática e segura é &lt;code>RemoteSigned&lt;/code>. Inicie o PowerShell com privilégios de administrador e execute o seguinte comando:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Set-ExecutionPolicy&lt;/span> &lt;span class="n">RemoteSigned&lt;/span> &lt;span class="n">-Scope&lt;/span> &lt;span class="n">LocalMachine&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso garantirá que os scripts de backup criados localmente sejam executados sem serem bloqueados.&lt;/p>
&lt;h3 id="2-reutilização-de-código-através-da-modularização-psm1--psd1">2. Reutilização de código através da modularização (.psm1 / .psd1)
&lt;/h3>&lt;p>Ao lidar com automações complexas, escrever todo o processamento em um único arquivo &lt;code>.ps1&lt;/code> gigante não é recomendado do ponto de vista de manutenção. Funções frequentemente usadas (por exemplo, saída de log, envio de Webhooks para o Slack, tratamento de erros, etc.) devem ser divididas em &amp;ldquo;módulos&amp;rdquo;.&lt;/p>
&lt;p>Os módulos do PowerShell consistem principalmente em arquivos de módulo de script (&lt;code>.psm1&lt;/code>) e manifestos de módulo (&lt;code>.psd1&lt;/code>).&lt;/p>
&lt;p>Exemplo do &lt;strong>CommonUtils.psm1&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">CmdletBinding&lt;/span>&lt;span class="p">()]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">param&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">Parameter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="na">Mandatory&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="vm">$true&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">ValidateSet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;WARNING&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;ERROR&amp;#39;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Level&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$timestamp&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyy-MM-dd HH:mm:ss&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$logLine&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;[&lt;/span>&lt;span class="nv">$timestamp&lt;/span>&lt;span class="s2">] [&lt;/span>&lt;span class="nv">$Level&lt;/span>&lt;span class="s2">] &lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Executa a saída na tela e a saída em arquivo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\logs\automation.log&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Export-ModuleMember&lt;/span> &lt;span class="n">-Function&lt;/span> &lt;span class="nb">Write-CustomLog&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Para chamar este módulo de outro script, use &lt;code>Import-Module&lt;/code> no início do script.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Import-Module&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Modules\CommonUtils.psm1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="n">-Message&lt;/span> &lt;span class="s2">&amp;#34;Iniciando o processo de backup.&amp;#34;&lt;/span> &lt;span class="n">-Level&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-tratamento-robusto-de-erros-try--catch">3. Tratamento robusto de erros (try / catch)
&lt;/h3>&lt;p>O mais importante na automação é &amp;ldquo;como se comportar quando ocorre uma falha&amp;rdquo;. No PowerShell, ao definir a variável incorporada &lt;code>$ErrorActionPreference&lt;/code>, você pode controlar o comportamento padrão quando um comando falha. O padrão é &lt;code>Continue&lt;/code> (exibir o erro e continuar o processamento), mas em scripts de automação, a melhor prática é defini-lo como &lt;code>Stop&lt;/code> e capturar a exceção explicitamente usando um bloco &lt;code>try / catch&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Processo que pode falhar&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$content&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\NonExistentFile.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">System.Management.Automation.ItemNotFoundException&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Capturar um erro específico&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Arquivo não encontrado: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Capturar todos os outros erros&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Ocorreu um erro inesperado: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">finally&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Processo de limpeza executado sempre, quer haja sucesso ou falha&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Finalizando o processamento.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ao aproveitar esta base, você pode construir scripts seguros e rastreáveis que funcionam sem supervisão durante a noite.&lt;/p>
&lt;hr>
&lt;h2 id="integração-com-o-agendador-de-tarefas-register-scheduledtask">Integração com o Agendador de Tarefas (Register-ScheduledTask)
&lt;/h2>&lt;p>Quando o script estiver concluído, o próximo passo é ter um mecanismo para executá-lo regularmente. A ferramenta mais confiável no Windows é o &amp;ldquo;Agendador de Tarefas&amp;rdquo; (Task Scheduler). É possível configurá-lo pela GUI (&lt;code>taskschd.msc&lt;/code>), mas, do ponto de vista de codificar o manual de infraestrutura (Infrastructure as Code), explicaremos como registrar tarefas usando os cmdlets do PowerShell.&lt;/p>
&lt;p>O PowerShell inclui o módulo &lt;code>ScheduledTasks&lt;/code>, que permite definir detalhadamente os gatilhos (quando executar), ações (o que executar) e a entidade (com quais privilégios de usuário executar).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. Definição da ação (Executar o PowerShell oculto e passar o script especificado)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$action&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskAction&lt;/span> &lt;span class="n">-Execute&lt;/span> &lt;span class="s2">&amp;#34;powershell.exe&amp;#34;&lt;/span> &lt;span class="n">-Argument&lt;/span> &lt;span class="s2">&amp;#34;-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Scripts\DailyTasks.ps1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. Definição do gatilho (Executar diariamente às 3h00 da manhã)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$trigger&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskTrigger&lt;/span> &lt;span class="n">-Daily&lt;/span> &lt;span class="n">-At&lt;/span> &lt;span class="s2">&amp;#34;3:00AM&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. Definição do principal (privilégios do usuário) (Executar com privilégios SYSTEM)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$principal&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskPrincipal&lt;/span> &lt;span class="n">-UserId&lt;/span> &lt;span class="s2">&amp;#34;NT AUTHORITY\SYSTEM&amp;#34;&lt;/span> &lt;span class="n">-LogonType&lt;/span> &lt;span class="n">ServiceAccount&lt;/span> &lt;span class="n">-RunLevel&lt;/span> &lt;span class="n">Highest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 4. Construção das configurações da tarefa&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$settings&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskSettingsSet&lt;/span> &lt;span class="n">-AllowStartIfOnBatteries&lt;/span> &lt;span class="n">-DontStopIfGoingOnBatteries&lt;/span> &lt;span class="n">-StartWhenAvailable&lt;/span> &lt;span class="n">-DontStopOnIdleEnd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 5. Registro da tarefa&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$taskName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MyDailyAutomationTask&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Register-ScheduledTask&lt;/span> &lt;span class="n">-TaskName&lt;/span> &lt;span class="nv">$taskName&lt;/span> &lt;span class="n">-Action&lt;/span> &lt;span class="nv">$action&lt;/span> &lt;span class="n">-Trigger&lt;/span> &lt;span class="nv">$trigger&lt;/span> &lt;span class="n">-Principal&lt;/span> &lt;span class="nv">$principal&lt;/span> &lt;span class="n">-Settings&lt;/span> &lt;span class="nv">$settings&lt;/span> &lt;span class="n">-Description&lt;/span> &lt;span class="s2">&amp;#34;Tarefa que executa automaticamente as rotinas diárias&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Basta executar esse script para registrar a tarefa no Agendador de Tarefas, e o script será executado diariamente no horário especificado, com privilégios SYSTEM (o nível mais alto de privilégio, em segundo plano sem exibir telas).&lt;/p>
&lt;hr>
&lt;h2 id="exemplo-prático-1-backup-em-nas-externo-e-rotação-de-logs">Exemplo prático 1: Backup em NAS externo e Rotação de Logs
&lt;/h2>&lt;p>O backup diário dos dados de trabalho é essencial, mas a cópia manual está fora de questão. Aqui, chamaremos o &lt;code>Robocopy&lt;/code>, o comando de cópia mais poderoso integrado ao Windows, através do PowerShell, criaremos um script que gera logs de execução e exclui automaticamente os logs antigos (rotação).&lt;/p>
&lt;h3 id="valor-teórico-do-tempo-de-execução-em-transferência-de-rede-matemática">Valor teórico do tempo de execução em transferência de rede (Matemática)
&lt;/h3>&lt;p>Ao projetar um script de backup, é importante operacionalmente estimar quanto tempo levará para o processo ser concluído. O tempo estimado necessário $T_{backup}$ para realizar um backup em um NAS através de uma rede pode ser aproximado pela seguinte fórmula:&lt;/p>
$$ T_{backup} = \frac{S_{total}}{B \times (1 - \alpha)} + C \times L $$&lt;p>Onde cada variável é a seguinte:&lt;/p>
&lt;ul>
&lt;li>$S_{total}$ : Quantidade total de dados de backup (Bits)&lt;/li>
&lt;li>$B$ : Largura de banda da rede (bps, ex: 1Gbps = $10^9$ bps)&lt;/li>
&lt;li>$\alpha$ : Sobrecarga (overhead) de rede e protocolos (geralmente entre 0,1 e 0,2 em protocolos TCP/IP ou SMB)&lt;/li>
&lt;li>$C$ : Número total de arquivos&lt;/li>
&lt;li>$L$ : Latência de processamento por arquivo (segundos)&lt;/li>
&lt;/ul>
&lt;p>Especialmente ao fazer backup de um grande número de arquivos pequenos (como código-fonte), o termo de latência devido ao número de arquivos $C$ ($C \times L$) torna-se dominante. Portanto, em processos de backup, é ideal usar o &lt;code>Robocopy&lt;/code>, que permite transferências multitarefa (multi-threaded), em vez de uma ferramenta de cópia de arquivos simples.&lt;/p>
&lt;h3 id="fluxo-de-processamento-do-script-de-backup">Fluxo de processamento do script de backup
&lt;/h3>&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Iniciar Script de Backup&amp;#34;] --&amp;gt; B{&amp;#34;O NAS está acessível?&amp;#34;}
B -- Sim --&amp;gt; C[&amp;#34;Executar Robocopy (Multi-threaded)&amp;#34;]
B -- Não --&amp;gt; D[&amp;#34;Gravar log de erro e sair&amp;#34;]
C --&amp;gt; E{&amp;#34;O Robocopy foi bem-sucedido?&amp;#34;}
E -- Sim (ExitCode &amp;lt; 8) --&amp;gt; F[&amp;#34;Rotacionar logs (Manter últimos 30 dias)&amp;#34;]
E -- Não (ExitCode &amp;gt;= 8) --&amp;gt; D
F --&amp;gt; G[&amp;#34;Finalizar Script de Backup&amp;#34;]
D --&amp;gt; G
&lt;/pre>
&lt;h3 id="exemplo-de-implementação-do-script-powershell-backup-tonasps1">Exemplo de implementação do script PowerShell (&lt;code>Backup-ToNas.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Configurações&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SourceDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetNasDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;\\NAS01\Backup\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$DateStr&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyyMMdd&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogFile&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Backup_&lt;/span>&lt;span class="nv">$DateStr&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$RetainDays&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 1. Verificação prévia: é possível acessar o NAS?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;Não é possível acessar o caminho de destino no NAS: &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Iniciando o backup: &lt;/span>&lt;span class="nv">$SourceDir&lt;/span>&lt;span class="s2"> -&amp;gt; &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 2. Execução do Robocopy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MIR : Espelhamento (arquivos não existentes na origem serão excluídos)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MT:16 : Cópia com 16 threads (multi-threaded)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /NP : Não exibir progresso (%) (para evitar poluição no log)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /R:2 /W:2 : Número de novas tentativas em caso de erro é 2, com 2 segundos de espera&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$SourceDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MIR&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MT:16&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/NP&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/R:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/W:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/LOG+:&lt;/span>&lt;span class="nv">$LogFile&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Usar Start-Process é o método mais seguro ao chamar comandos externos do PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$process&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Start-Process&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="s2">&amp;#34;robocopy.exe&amp;#34;&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="n">-Wait&lt;/span> &lt;span class="n">-NoNewWindow&lt;/span> &lt;span class="n">-PassThru&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$exitCode&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ExitCode&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Especificação dos códigos de saída do Robocopy: 0-7 são sucesso ou comportamentos esperados. 8 ou mais são erros.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$exitCode&lt;/span> &lt;span class="o">-ge&lt;/span> &lt;span class="mf">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;O Robocopy terminou com erro. ExitCode: &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;O backup foi concluído com sucesso. ExitCode: &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 3. Rotação de logs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Excluindo arquivos de log antigos (período de retenção: &lt;/span>&lt;span class="nv">${RetainDays}&lt;/span>&lt;span class="s2"> dias)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddDays&lt;/span>&lt;span class="p">(-&lt;/span>&lt;span class="nv">$RetainDays&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;Backup_*.log&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Where-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">LastWriteTime&lt;/span> &lt;span class="o">-lt&lt;/span> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Remove-Item&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;A limpeza de logs foi concluída.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$errorMessage&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Ocorreu um erro durante o processo de backup: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="nv">$errorMessage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Gravar no arquivo de log de erro real&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Error.log&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;[(Get-Date -Format &amp;#39;yyyy-MM-dd HH:mm:ss&amp;#39;)] &lt;/span>&lt;span class="nv">$errorMessage&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Sair com um código diferente de zero para notificar o erro ao Agendador de Tarefas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Este script, combinado com o Agendador de Tarefas, alcança backups automáticos e completos diariamente. Em particular, o tratamento do código de saída do &lt;code>Robocopy&lt;/code> é de extrema importância. O Robocopy retorna 1 mesmo em caso de sucesso se &amp;ldquo;novos arquivos foram copiados&amp;rdquo;, ou 2 se &amp;ldquo;arquivos extras foram excluídos&amp;rdquo;. Portanto, é necessário ter cuidado, pois uma simples verificação &lt;code>$LASTEXITCODE -eq 0&lt;/code> não funcionará corretamente.&lt;/p>
&lt;hr>
&lt;h2 id="exemplo-prático-2-monitoramento-de-logs-de-eventos-do-sistema-e-notificação-no-slack-webhook">Exemplo prático 2: Monitoramento de logs de eventos do sistema e notificação no Slack (Webhook)
&lt;/h2>&lt;p>Em servidores Windows ou estações de trabalho para criadores, é muito importante detectar precocemente erros de disco, que podem ser precursores de telas azuis (BSoD), ou travamentos de aplicações (Application Error).
Aqui, criaremos um script que extrai logs dos níveis &amp;ldquo;Erro&amp;rdquo; e &amp;ldquo;Crítico&amp;rdquo; dos logs de eventos &lt;code>System&lt;/code> e &lt;code>Application&lt;/code> na última hora, e envia uma notificação para o Slack se encontrar algum.&lt;/p>
&lt;h3 id="diagrama-de-sequência-do-processo-de-notificação">Diagrama de sequência do processo de notificação
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant S as &amp;#34;Agendador de Tarefas&amp;#34;
participant P as &amp;#34;Script PowerShell&amp;#34;
participant W as &amp;#34;Log de Eventos do Windows&amp;#34;
participant Sl as &amp;#34;API do Slack&amp;#34;
S-&amp;gt;&amp;gt;P: &amp;#34;Acionar o script (a cada hora)&amp;#34;
P-&amp;gt;&amp;gt;W: &amp;#34;Get-WinEvent (Crítico/Erro na última 1h)&amp;#34;
W--&amp;gt;&amp;gt;P: &amp;#34;Retornar objetos de log&amp;#34;
alt &amp;#34;Erros encontrados&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;Formatar mensagem (JSON)&amp;#34;
P-&amp;gt;&amp;gt;Sl: &amp;#34;Invoke-RestMethod (POST webhook_url)&amp;#34;
Sl--&amp;gt;&amp;gt;P: &amp;#34;200 OK&amp;#34;
else &amp;#34;Nenhum erro&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;Encerrar de forma elegante&amp;#34;
end
&lt;/pre>
&lt;h3 id="exemplo-de-implementação-do-script-powershell-monitor-eventlogps1">Exemplo de implementação do script PowerShell (&lt;code>Monitor-EventLog.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># URL do Webhook do Slack (Obtido previamente com a integração Incoming Webhooks no Slack)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXXXXXXX&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Intervalo de tempo da pesquisa (Última 1 hora)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$startTime&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddHours&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">-1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Pesquisar logs de eventos rapidamente usando filtro XPath&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Nível 1: Crítico (Critical), 2: Erro (Error)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;0&amp;#34; Path=&amp;#34;System&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;System&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;1&amp;#34; Path=&amp;#34;Application&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;Application&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;/QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#34;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obter os logs com Get-WinEvent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># -ErrorAction SilentlyContinue é usado para ignorar erros quando nenhum log é encontrado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-WinEvent&lt;/span> &lt;span class="n">-FilterXml&lt;/span> &lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">SilentlyContinue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$events&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Foram encontrados &lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> logs críticos/erros na última 1 hora.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Construir o texto da notificação&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;*Alerta do Sistema Windows* :rotating_light:&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;Foram detectados &lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> erros na última hora.&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Incluir detalhes apenas dos 3 logs mais recentes (considerando limite de caracteres, etc.)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Select-Object&lt;/span> &lt;span class="n">-First&lt;/span> &lt;span class="mf">3&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;*&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LogName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">* - &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ProviderName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> (EventID: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">)&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt; &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Message&lt;/span> &lt;span class="o">-replace&lt;/span> &lt;span class="s1">&amp;#39;`n&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39; &amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;※Há &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">-&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> outros erros. Verifique o Visualizador de Eventos.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Criação do payload JSON para POST no Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$messageBody&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SystemMonitor&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">icon_emoji&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;:desktop_computer:&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ConvertTo-Json&lt;/span> &lt;span class="n">-Depth&lt;/span> &lt;span class="mf">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Chamar a API REST e enviar para o Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Invoke-RestMethod&lt;/span> &lt;span class="n">-Uri&lt;/span> &lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="n">-Method&lt;/span> &lt;span class="n">Post&lt;/span> &lt;span class="n">-Body&lt;/span> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="n">-ContentType&lt;/span> &lt;span class="s2">&amp;#34;application/json; charset=utf-8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;A notificação para o Slack foi concluída.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Nenhum log crítico/erro foi encontrado. O sistema está normal.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;Ocorreu um erro no script de monitoramento de logs de eventos: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O ponto técnico chave neste script é o uso de &lt;code>Get-WinEvent -FilterXml&lt;/code>. Ferramentas anteriores como o cmdlet &lt;code>Get-EventLog&lt;/code> ou a filtragem com &lt;code>Where-Object&lt;/code> através de pipeline são extremamente pesadas, pois carregam todos os objetos de evento na memória antes de processá-los. Ao usar o filtro XML, a filtragem é realizada no próprio serviço de Log de Eventos do Windows, o que proporciona uma melhoria impressionante de desempenho, geralmente mantendo o tempo de execução em menos de alguns segundos.&lt;/p>
&lt;hr>
&lt;h2 id="exemplo-prático-3-atualização-em-lote-de-múltiplos-repositórios-git-e-automação-de-build">Exemplo prático 3: Atualização em lote de múltiplos repositórios Git e automação de build
&lt;/h2>&lt;p>Para os desenvolvedores, logo de manhã, sincronizar vários repositórios Git em seus computadores (como repositórios de frontend, backend e infraestrutura) com a ramificação &lt;code>main&lt;/code> mais recente, instalando pacotes conforme necessário (como &lt;code>npm install&lt;/code>) e compilando (build) tudo pode ser uma tarefa entediante.
Criaremos uma ferramenta baseada em scripts do PowerShell para realizar essas tarefas em lote.&lt;/p>
&lt;p>Este script detecta automaticamente todos os repositórios Git em diretórios pai específicos e, se não houver alterações não confirmadas (uncommitted), ele executará um &lt;code>git pull&lt;/code>. Além disso, se houver novas atualizações recebidas após o Pull, ele emitirá automaticamente um comando de build.&lt;/p>
&lt;h3 id="script-de-atualização-automática-para-múltiplos-repositórios-update-gitreposps1">Script de atualização automática para múltiplos repositórios (&lt;code>Update-GitRepos.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Lista de diretórios pai onde os repositórios estão localizados&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetDirectories&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\FrontendProjects&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\BackendProjects&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Explorar cada diretório&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$parentDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$TargetDirectories&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Warning&lt;/span> &lt;span class="s2">&amp;#34;O diretório não foi encontrado: &lt;/span>&lt;span class="nv">$parentDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obter a lista de subdiretórios&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$subDirs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span> &lt;span class="n">-Directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$repoDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$subDirs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$repoDir&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$gitDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="s2">&amp;#34;.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Verificar se a pasta .git existe (Se é um repositório Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$gitDir&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Processando repositório: &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Cyan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Alterar o diretório de trabalho atual do PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-Location&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Verificar se há alterações não confirmadas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$status&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">status&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-porcelain&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$status&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Ignorado porque há alterações não confirmadas (uncommitted).&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obter o branch atual&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$branch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="nb">rev-parse&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-abbrev-ref&lt;/span> &lt;span class="n">HEAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;master&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Ignorado porque a branch atual é &lt;/span>&lt;span class="nv">$branch&lt;/span>&lt;span class="s2"> (Aplica-se apenas a main/master).&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Executar Pull e armazenar o resultado em uma variável&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Obtendo as atualizações mais recentes do remoto (git pull)...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">pull&lt;/span> &lt;span class="n">origin&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="mf">2&lt;/span>&lt;span class="p">&amp;gt;&amp;amp;&lt;/span>&lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Exibir no console&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34; &lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Se a string contiver algo além de &amp;#34;Already up to date.&amp;#34;, será considerado atualizado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$pullResult&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="o">-notmatch&lt;/span> &lt;span class="s2">&amp;#34;Already up to date&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$isUpdated&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;O repositório foi atualizado. Iniciando as tarefas de build...&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Se package.json existir, execute npm install e npm run build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="s2">&amp;#34;package.json&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Executando npm install...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Executando npm run build...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Se existir .sln (Visual Studio Solution), execute msbuild ou dotnet build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$slnFiles&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;*.sln&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Compilando o aplicativo .NET...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dotnet&lt;/span> &lt;span class="n">build&lt;/span> &lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mf">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;Ocorreu um erro durante o processamento do repositório &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;O processo de atualização para todos os repositórios foi concluído.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O design deste script garante que se ocorrer um erro, ele será capturado pelo &lt;code>try / catch&lt;/code> e continuará o loop &lt;code>foreach&lt;/code> para o próximo repositório sem interromper a execução inteira. Além disso, ele utiliza a opção &lt;code>git status --porcelain&lt;/code> para determinar de maneira confiável a limpeza da árvore de trabalho (working tree), o que é ideal para o uso com scripts. Ao colocar este script em uma pasta de inicialização (startup) ou agendá-lo no Agendador de Tarefas no logon do usuário, você pode ter todos os seus ambientes de desenvolvimento atualizados enquanto prepara seu café, logo após inicializar o PC.&lt;/p>
&lt;hr>
&lt;h2 id="considerações-operacionais-e-técnicas-avançadas">Considerações operacionais e técnicas avançadas
&lt;/h2>&lt;p>Ao usar scripts de automação PowerShell a longo prazo, existem várias práticas recomendadas a serem observadas.&lt;/p>
&lt;h3 id="1-gerenciamento-seguro-de-credenciais">1. Gerenciamento seguro de credenciais
&lt;/h3>&lt;p>Embutir senhas e chaves de API em texto puro no script (por exemplo, URL do Webhook do Slack, string de conexão do banco de dados) é um grande risco de segurança. O PowerShell vem equipado com recursos como &lt;code>Export-Clixml&lt;/code> e &lt;code>ConvertFrom-SecureString&lt;/code>, que podem criptografar e armazenar informações de autenticação com segurança.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Executado manualmente pela primeira vez (a caixa de diálogo para digitação da senha aparecerá)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Get-Credential | Export-Clixml -Path &amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Leitura nos scripts de automação&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$cred&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Import-Clixml&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Use $cred para conectar a um servidor remoto, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso permite um gerenciamento seguro de credenciais e pode ser descriptografado apenas pelo perfil do usuário que executa o script.&lt;/p>
&lt;h3 id="2-registro-completo-das-execuções-com-transcript">2. Registro completo das execuções com Transcript
&lt;/h3>&lt;p>Nos exemplos anteriores, os logs foram criados individualmente com &lt;code>Add-Content&lt;/code> ou similares. No entanto, o PowerShell possui um recurso de Transcrição (Transcript) embutido que salva de maneira automática e detalhada todas as informações de saída visíveis no console (incluindo mensagens de erro e a saída padrão) para um arquivo.&lt;/p>
&lt;p>Você pode criar um log de auditoria robusto simplesmente adicionando os seguintes comandos no início e no final do seu script.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Start-Transcript&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs\Execution_&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s1">&amp;#39;yyyyMMdd_HHmmss&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span> &lt;span class="n">-Append&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># (O corpo de processamento principal do seu script aqui)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Stop-Transcript&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-abordagens-matemáticas-no-monitoramento-e-detecção-de-anomalias-math">3. Abordagens matemáticas no monitoramento e detecção de anomalias (Math)
&lt;/h3>&lt;p>Na automação em larga escala, métodos baseados em análises estatísticas para não apenas detectar erros diretos, mas também desvios do normal, podem ser extremamente eficazes. Por exemplo, se o tempo de backup diário se desviar drasticamente da sua média habitual, pode ser um sinal de anomalia na rede ou prenúncio de uma falha de disco.&lt;/p>
&lt;p>Onde o tempo de backup diário é $x_1, x_2, \dots, x_n$, a média da amostra $\mu$ e o desvio padrão $\sigma$ são expressos da seguinte forma:&lt;/p>
$$ \mu = \frac{1}{n} \sum_{i=1}^n x_i $$$$ \sigma = \sqrt{ \frac{1}{n-1} \sum_{i=1}^n (x_i - \mu)^2 } $$&lt;p>Se o tempo de execução de hoje $x_{today}$ exceder $\mu + 3\sigma$ (regra do 3-sigma), o sistema considerará que uma &amp;ldquo;anomalia estatística&amp;rdquo; ocorreu e poderá disparar uma notificação de alerta baseada nessa lógica de regras. Utilizando o cmdlet &lt;code>Measure-Object&lt;/code> do PowerShell, você pode implementar esses cálculos estatísticos em poucas linhas de código.&lt;/p>
&lt;h2 id="conclusão">Conclusão
&lt;/h2>&lt;p>Neste artigo, explicamos como usar o PowerShell para automatizar totalmente suas tarefas rotineiras em ambientes Windows, usando exemplos reais.
Começando desde as bases, como gerenciar políticas de execução e modularização, apresentamos scripts prontos para uso focados no trabalho cotidiano, englobando rotação de logs e backup, monitoramento de logs de eventos e notificações no Slack, além de build automático em múltiplos repositórios Git.&lt;/p>
&lt;p>O PowerShell é um mecanismo de automação extremamente profundo e poderoso que, apesar de ser executado por linha de comando, dá acesso a quase todos os recursos do .NET. Aproveite os scripts apresentados como um ponto de partida, personalize os caminhos e as lógicas de acordo com as necessidades do seu próprio ambiente de trabalho, e desfrute de um tempo criativo onde você está livre de tarefas manuais árduas.&lt;/p>
&lt;p>O sucesso na automação provém de &amp;ldquo;começar com pequenos scripts e gradualmente aumentar a robustez, abordando também o tratamento de erros e a saída de logs&amp;rdquo;. Que tal começar a sua jornada de automação usando PowerShell criando inicialmente um backup de apenas uma pasta de sua preferência no seu próprio PC?&lt;/p></description></item></channel></rss>