Consulte os logs de eventos de forma eficiente com o comando PowerShell Get-EventLog

Cada administrador de sistema do Windows provavelmente está familiarizado com o Log de Eventos do Windows. Usar este cmdlet no PowerShell permite que os sysadmins analisem muitos eventos de uma só vez em vários computadores ao mesmo tempo. Isso libera os sysadmins de ficarem clicando no Visualizador de Eventos tentando descobrir o filtro certo a usar e determinar exatamente onde esse evento crítico está armazenado. No entanto, o Get-EventLog tem suas desvantagens, como você verá.

Listando Logs de Eventos com o Get-EventLog

O cmdlet Get-EventLog está disponível em todas as versões modernas do Windows PowerShell. Em seu uso mais simples, este cmdlet precisa de um log de eventos para consultar e, em seguida, exibirá todos os eventos nesse log de eventos.

Mas e se você não souber o nome do log de eventos em primeiro lugar? Nesse caso, precisamos descobrir todos os logs de eventos disponíveis em nosso computador local. Fazemos isso usando o comando Get-EventLog -List.

Get-EventLog -List

Você pode ver que tenho alguns logs de eventos no meu sistema local agora, mas você pode estar se perguntando onde estão os outros? Existem dezenas de outros logs de eventos aparecendo em Logs de Aplicativos e Serviços no Visualizador de Eventos. Por que eles não estão aqui?

Se você precisa desses eventos, infelizmente, o Get-EventLog não vai funcionar. Em vez disso, você precisará verificar o Get-WinEvent. O cmdlet Get-EventLog poderia ser considerado um cmdlet legado neste ponto, mas ainda o uso com frequência simplesmente porque é tão fácil de usar.

Consultando Eventos com Get-EventLog

Agora que sabemos todos os registros de eventos disponíveis, podemos ler os eventos dentro desse registro de eventos. Talvez eu queira ver todos os eventos no registro de eventos do Aplicativo. Para obter esses eventos, preciso especificar o parâmetro LogName com Get-EventLog e o cmdlet irá obedecer retornando todos os eventos nesse registro de eventos.

Get-EventLog -LogName Application

Por padrão, você verá apenas seis propriedades na saída:

  • Índice
  • Tempo
  • Tipo de Entrada
  • Fonte
  • Id da Instância
  • Mensagem

Na realidade, Get-EventLog retorna 16 delas. O motivo pelo qual você só vê seis é devido às regras de formatação do PowerShell que definem a saída. Abaixo está um exemplo da saída real encontrada ao canalizar Get-EventLog para Select-Object e selecionando todas as propriedades.

Get-EventLog -LogName Application | Select-Object -Property * EventID

Filtrando com Get-EventLog

É provável que ao procurar eventos, não precisamos de todos os eventos. Em vez disso, só precisamos de alguns. Nesse caso, precisamos filtrar para eventos específicos. Get-EventLog tem algumas maneiras diferentes de fazer isso. O cmdlet Get-EventLog pode filtrar com base no carimbo de data/hora, tipo de entrada, ID do evento, mensagem, fonte e nome de usuário. Isso cuida da maioria das maneiras de encontrar eventos.

Para demonstrar filtragem, talvez eu esteja consultando eventos de tempos em tempos e queira encontrar os dez eventos mais recentes. Nesse caso, posso usar o parâmetro Newest e especificar quantos eventos gostaria de ver. Get-EventLog -LogName Application -Newest 10 retornará apenas os dez eventos mais recentes.

Talvez eu queira encontrar todos os eventos após um ponto específico no tempo. Para isso, temos o parâmetro After. O parâmetro After recebe uma data/hora, então se eu quiser encontrar apenas os eventos dentro do log de Aplicativos que ocorreram após 26/01/19 10:17, eu poderia fazer isso Get-EventLog -LogName Application -After '26/01/19 10:17'. Também podemos realizar o mesmo processo, mas selecionar eventos que ocorreram antes de uma determinada data com, você deve ter adivinhado, o parâmetro Before.

O Get-EventLog tem muitas maneiras diferentes de filtrar, não incluindo com base em um carimbo de data/hora. Também podemos filtrar eventos com base em outros atributos como ID do evento (ID da instância) e mensagem, que tendem a ser atributos comuns para pesquisar. Talvez eu saiba que estou procurando um evento com ID 916; passaríamos 916 para o parâmetro InstanceId.

PS> Get-EventLog -LogName Application -InstanceId 916

Também podemos combinar filtros. Talvez eu receba muitos eventos retornados com um ID de 916, mas queira esses eventos com a sequência svchost na mensagem. Nesse caso, podemos adicionar o parâmetro Message ao Get-EventLog e especificar um caractere curinga como svchost.

PS> Get-EventLog -LogName Application -InstanceId 916 -Message '*svchost*'

Script de bônus!

Você precisa de um ótimo exemplo de como usar o Get-EventLog em um script do mundo real? Se sim, você está com sorte! Abaixo está um caso de uso avançado do Get-EventLog que você pode baixar e usar hoje!

<#
.SINOPSE
    Este script pesquisa um computador com Windows por todas as entradas de log de eventos ou de texto
    entre um horário de início e término especificado.
.DESCRIÇÃO
    Este script enumera todos os logs de eventos dentro de um intervalo de tempo especificado e todos os logs de texto
 que têm um último horário de gravação no intervalo de tempo ou contêm uma linha que tem uma data/hora
 referência dentro do intervalo de tempo. Ele registra essas informações em um conjunto de arquivos e copia
 qualquer arquivo de log interessante para análise adicional.
.EXEMPLO
    PS> .\Get-EventsFromTimeframe.ps1 -StartTimestamp '01-29-2014 13:25:00' -EndTimeStamp '01-29-2014 13:28:00' -ComputerName NOME_DO_COMPUTADOR
 
    Este exemplo encontra todas as entradas de log de eventos entre StartTimestamp e EndTimestamp e qualquer arquivo
    com uma extensão dentro do parâmetro $FileExtension que foi escrito pela última vez dentro do intervalo de tempo
    ou contém uma linha com uma referência de data/hora dentro do intervalo de tempo.
.PARAMÊTRO StartTimestamp
 A data/hora mais antiga que você gostaria de começar a procurar eventos.
.PARAMÊTRO EndTimestamp
 A data/hora mais recente que você gostaria de começar a procurar eventos.
.PARAMÊTRO NomeDoComputador
 O nome do computador remoto (ou local) que você gostaria de pesquisar.
.PARAMÊTRO CaminhoDaPastaDeSaída
 O caminho da pasta que conterá os arquivos de texto que conterão os eventos.
.PARAMÊTRO CaminhoDoArquivoDeAuditoriaDeLog
 O caminho para o arquivo de texto que documentará o arquivo de log, número da linha e tipo de correspondência
 para os logs que foram correspondidos.
.PARAMÊTRO SomenteLogsDeEventos
 Use este parâmetro de chave se você quiser pesquisar apenas nos logs de eventos.
.PARAMÊTRO ApenasArquivosDeLog
 Use este parâmetro se você quiser pesquisar apenas logs no sistema de arquivos.
.PARAMÊTRO ExcluirDiretório
 Se estiver pesquisando no sistema de arquivos, especifique quaisquer caminhos de pastas que você gostaria de pular.
.PARAMÊTRO ExtensãoDoArquivo
 Especifique um ou mais conjuntos de extensões de arquivo separados por vírgula que você gostaria de pesquisar no sistema de arquivos.
 Isso padrão para as extensões 'log,txt,wer'.
#>
[CmdletBinding(DefaultParameterSetName = 'Neither')]
param (
    [Parameter(Mandatory)]
    [datetime]$StartTimestamp,
    [Parameter(Mandatory)]
    [datetime]$EndTimestamp,
    [Parameter(ValueFromPipeline,
        ValueFromPipelineByPropertyName)]
    [string]$ComputerName = 'localhost',
    [Parameter()]
 [string]$OutputFolderPath = ".\$Computername",
 [Parameter(ParameterSetName = 'LogFiles')]
 [string]$LogAuditFilePath = "$OutputFolderPath\LogActivity.csv",
 [Parameter(ParameterSetName = 'EventLogs')]
 [switch]$EventLogsOnly,
    [Parameter(ParameterSetName = 'LogFiles')]
    [switch]$LogFilesOnly,
    [Parameter(ParameterSetName = 'LogFiles')]
 [string[]]$ExcludeDirectory,
 [Parameter(ParameterSetName = 'LogFiles')]
 [string[]]$FileExtension = @('log', 'txt', 'wer')
)
 
begin {
 if (!$EventLogsOnly.IsPresent) {
 ## Crie o diretório local onde armazenar os arquivos de log que correspondem aos critérios
 $LogsFolderPath = "$OutputFolderPath\logs"
 if (!(Test-Path $LogsFolderPath)) {
 mkdir $LogsFolderPath | Out-Null
 }
 }
 
 function Add-ToLog($FilePath,$LineText,$LineNumber,$MatchType) {
 $Audit = @{
 'FilePath' = $FilePath;
 'LineText' = $LineText
 'LineNumber' = $LineNumber
 'MatchType' = $MatchType
 }
 [pscustomobject]$Audit | Export-Csv -Path $LogAuditFilePath -Append -NoTypeInformation
 }
}
 
process {
 
    ## Execute somente se o usuário desejar encontrar entradas de log de eventos
    if (!$LogFilesOnly.IsPresent) {
 ## Encontre todos os nomes de logs de eventos que contenham pelo menos 1 evento
 $Logs = (Get-WinEvent -ListLog * -ComputerName $ComputerName | where { $_.RecordCount }).LogName
 $FilterTable = @{
 'StartTime' = $StartTimestamp
 'EndTime' = $EndTimestamp
 'LogName' = $Logs
 }
 
 ## Encontre todos os eventos em todos os logs de eventos que estão entre os carimbos de data/hora de início e término
 $Events = Get-WinEvent -ComputerName $ComputerName -FilterHashtable $FilterTable -ea 'SilentlyContinue'
 Write-Verbose "Found $($Events.Count) total events"
 
 ## Converta as propriedades para algo mais amigável e anexe cada evento ao arquivo de texto do log de eventos
 $LogProps = @{ }
 [System.Collections.ArrayList]$MyEvents = @()
 foreach ($Event in $Events) {
 $LogProps.Time = $Event.TimeCreated
 $LogProps.Source = $Event.ProviderName
 $LogProps.EventId = $Event.Id
 if ($Event.Message) {
 $LogProps.Message = $Event.Message.Replace("<code>n", '|').Replace("</code>r", '|')
 }
 $LogProps.EventLog = $Event.LogName
 $MyEvents.Add([pscustomobject]$LogProps) | Out-Null
 }
 $MyEvents | sort Time | Export-Csv -Path "$OutputFolderPath\eventlogs.txt" -Append -NoTypeInformation
 }
 
 ## Execute somente se o usuário desejar encontrar arquivos de log
 if (!$EventLogsOnly.IsPresent) {
        ## Enumere todas as compartilhamentos de administração remota no computador remoto. Faço isso em vez de enumerar todas as unidades físicas porque
        ## a unidade pode estar lá e o compartilhamento pode não estar, o que significa que eu não consigo acessar a unidade de qualquer maneira.
 $Shares = Get-WmiObject -ComputerName $ComputerName -Class Win32_Share | where { $_.Path -match '^\w{1}:\\$' }
 [System.Collections.ArrayList]$AccessibleShares = @()
 ## Certifique-se de que posso acessar todos os compartilhamentos de administração remota
 foreach ($Share in $Shares) {
 $Share = "\\$ComputerName\$($Share.Name)"
 if (!(Test-Path $Share)) {
 Write-Warning "Unable to access the '$Share' share on '$Computername'"
 } else {
 $AccessibleShares.Add($Share) | Out-Null 
 }
 }
 
 $AllFilesQueryParams = @{
 Path = $AccessibleShares
 Recurse = $true
 Force = $true
 ErrorAction = 'SilentlyContinue'
 File = $true
 }
 ## Adicione quaisquer diretórios especificados no parâmetro $ExcludeDirectory para não pesquisar arquivos de log
 if ($ExcludeDirectory) {
 $AllFilesQueryParams.ExcludeDirectory = $ExcludeDirectory 
 }
 ## Crie a string regex louca que uso para pesquisar por diferentes formatos de data/hora.
 ## Isso é usado na tentativa de pesquisar cadeias de data/hora em cada arquivo de texto encontrado
 ##TODO: Adicionar capacidade de corresponder em Jan,Feb,Mar,etc
 $DateTimeRegex = "($($StartTimestamp.Month)[\\.\-/]?$($StartTimestamp.Day)[\\.\-/]?[\\.\-/]$($StartTimestamp.Year))|($($StartTimestamp.Year)[\\.\-/]?$($StartTimestamp.Month)[\\.\-/]?[\\.\-/]?$($StartTimestamp.Day))"
 ## Enumere todos os arquivos que correspondem aos parâmetros de consulta que têm conteúdo
 Get-ChildItem @AllFilesQueryParams | where { $_.Length -ne 0 } | foreach {
 try {
 Write-Verbose "Processing file '$($_.Name)'"
 ## Grave o arquivo se a última hora de gravação estiver dentro do intervalo de tempo. Isso encontra arquivos de log que podem não registrar um 
 ## carimbo de data/hora, mas podem estar envolvidos em qualquer evento que o usuário esteja tentando encontrar.
 if (($_.LastWriteTime -ge $StartTimestamp) -and ($_.LastWriteTime -le $EndTimestamp)) {
 Write-Verbose "Last write time within timeframe for file '$($_.Name)'"
 Add-ToLog -FilePath $_.FullName -MatchType 'LastWriteTime'
 }
 ## Se o arquivo encontrado corresponder ao conjunto de extensões que estou tentando encontrar e for realmente um arquivo de texto simples.
 ## Eu uso o Get-Content para apenas verificar novamente se é texto simples antes de analisá-lo.
 if ($FileExtension -contains $_.Extension.Replace('.','') -and !((Get-Content $_.FullName -Encoding Byte -TotalCount 1024) -contains 0)) {
 ## Verifique o conteúdo do arquivo de texto para referências a datas no intervalo de tempo
 Write-Verbose "Checking log file '$($_.Name)' for date/time match in contents"
 $LineMatches = Select-String -Path $_.FullName -Pattern $DateTimeRegex
 if ($LineMatches) {
 Write-Verbose "Date/time match found in file '$($_.FullName)'"
 ## Grave todas as linhas correspondentes no arquivo de auditoria.
 foreach ($Match in $LineMatches) {
 Add-ToLog -FilePath $_.FullName -LineNumber $Match.LineNumber -LineText $Match.Line -MatchType 'Contents'
 }
 ## Crie o mesmo caminho para o arquivo de log no computador remoto dentro do diretório de log de saída e 
 ## copie o arquivo de log com um evento dentro do intervalo de tempo para esse caminho.
 ## Isso não funcionará se um caminho de arquivo acima de 255 caracteres for encontrado.
 $Trim = $_.FullName.Replace("\\$Computername\", '')
 $Destination = "$OutputFolderPath\$Trim"
 if (!(Test-Path $Destination)) {
 ##TODO: Remover a ação de erro quando o suporte a caminhos longos for implementado
 mkdir $Destination -ErrorAction SilentlyContinue | Out-Null
 }
 Copy-Item -Path $_.FullName -Destination $Destination -ErrorAction SilentlyContinue -Recurse
 }
 }
 } catch {
 Write-Warning $_.Exception.Message 
 }
 }
 }
}

Resumo

O cmdlet Get-EventLog é um ótimo comando para usar se você precisar consultar rapidamente um dos logs de eventos comuns. É fácil de usar e fornece alguma capacidade básica de filtragem. No entanto, se você precisar fazer uma investigação mais aprofundada nos logs de eventos, o comando Get-WinEvent provavelmente funcionará melhor, mas é um pouco mais difícil de usar e às vezes requer o conhecimento de sintaxe como XPath.

Source:
https://adamtheautomator.com/get-eventlog/