Búsqueda de sitios web

Encontrar el último inicio de sesión de PowerShell por ID de evento de inicio de sesión del usuario


Existen muchas herramientas sofisticadas para monitorear la actividad de inicio de sesión de los usuarios. ¿Qué pasaría si le dijera que no necesita gastar dinero creando un script de historial y último inicio de sesión de PowerShell? ¡Puede encontrar la fecha del último inicio de sesión e incluso el ID del evento de inicio de sesión del usuario con el registro de eventos de Windows y un poco de PowerShell!

En este artículo, aprenderá cómo crear un script de PowerShell de actividad del usuario. Este script extraerá información del registro de eventos de Windows para una computadora local y proporcionará un informe detallado sobre la actividad de inicio de sesión del usuario, como encontrar el último inicio de sesión de PowerShell.

Requisitos previos

Si se encuentra en un entorno AD, asegúrese de:

  • están en una PC con Windows 10 unida a un dominio
  • han iniciado sesión con una cuenta que puede leer registros de eventos del controlador de dominio
  • tener permiso para modificar los GPO del dominio

En este artículo, las políticas de auditoría para habilitar la auditoría de inicio de sesión se establecerán mediante GPO. Pero puedes utilizar políticas locales en su lugar.

Habilitación de políticas de auditoría

Para garantizar que el registro de eventos en la computadora registre los inicios de sesión de los usuarios, como registrar el último inicio de sesión de PowerShell, primero debe habilitar algunas políticas de auditoría. En este artículo, aprenderá cómo configurar estas políticas a través de GPO. Pero si no tiene AD, también puede establecer estas mismas políticas a través de la política local.

Para informar sobre el tiempo que los usuarios han iniciado sesión, primero deberá habilitar tres políticas de auditoría avanzadas.

  • Auditar cierre de sesión: cuando un usuario cierra la sesión.
  • Auditar inicio de sesión: cuando un usuario se autentica en Windows
  • Auditar otros eventos de inicio/cierre de sesión: bloqueo y desbloqueo de la computadora, conexiones y desconexiones de RDP

Habilitar todas estas políticas de auditoría garantiza capturar todas las horas posibles de inicio y finalización de la actividad.

Cuando habilita estas políticas de auditoría en una PC local, los siguientes ID de eventos de tiempo de inicio de sesión del usuario (e ID de cierre de sesión) comenzarán a registrarse en los registros de eventos de Windows para permitir la búsqueda a través de PowerShell de los últimos eventos de inicio de sesión. Cada uno de estos eventos representa una hora de inicio y finalización de la actividad del usuario.

  • Inicio de sesión: 4624
  • Cerrar sesión - 4647
  • Inicio - 6005
  • Reconexión de sesión RDP: 4778
  • Desconexión de sesión RDP: 4779
  • Bloqueado - 4800
  • Desbloqueado - 4801

Puede ver un ejemplo a continuación sobre cómo modificar el GPO Política de dominio predeterminada. Modificaría este GPO si habilita estas políticas en todas las PC unidas a un dominio. También puede crear su propio GPO de política de auditoría y asignarlo también a varias unidades organizativas.

Descripción de las sesiones de inicio de sesión de usuario y el último inicio de sesión de PowerShell

Una vez que se hayan generado todos los eventos apropiados, ahora debe definir las sesiones de inicio de sesión de los usuarios. Llamo a una sesión de usuario como el tiempo total entre el momento en que el usuario comienza a trabajar y se detiene; eso es todo. Para crear un informe preciso, el script debe coincidir con las horas de inicio y finalización para comprender estas últimas sesiones de inicio de sesión de PowerShell.

El concepto de sesión de inicio de sesión es importante porque puede haber más de un usuario iniciando sesión en una computadora. Para hacer coincidir las horas de inicio/finalización con una cuenta de usuario en particular, puede utilizar el campo ID de inicio de sesión para cada evento.

Para determinar las horas de inicio y finalización de una sesión de inicio de sesión, el script busca una hora de inicio de sesión y busca en el registro de eventos la hora de finalización de la siguiente sesión con el mismo ID de inicio de sesión. Una vez que se encuentra ese evento (el evento de detención), el script conoce el tiempo total de sesión del usuario.

Puede ver un ejemplo de un ID de evento de inicio de sesión (y cierre de sesión) de un usuario del visor de eventos con el mismo ID de inicio de sesión a continuación.

En este ejemplo, la cuenta LAB\Administrator había iniciado sesión (ID 4624) el 27/8/2015 a las 5:28 p. m. con un ID de inicio de sesión de 0x146FF6. Al buscar anteriormente en el registro de eventos, se encontró un evento de fin de sesión (ID 4634) con el mismo ID de inicio de sesión a las 5:30 p. m. del mismo día. Ahora que conoce la hora de inicio y finalización de esta sesión de inicio de sesión en particular, puede deducir que la cuenta LAB\Administrator había iniciado sesión durante aproximadamente tres minutos.

El script del historial de inicio de sesión del usuario

Una vez que las políticas estén habilitadas y comprenda el concepto de sesión de inicio de sesión, podrá comenzar a escribir algo de PowerShell para encontrar los últimos eventos de inicio de sesión de PowerShell.

En lugar de repasar este script línea por línea, se proporciona en su totalidad a continuación. También puedes descargarlo desde este repositorio de GitHub.

En resumen, el siguiente guión:

  1. Define todos los ID de eventos de inicio y detención importantes necesarios para los eventos del último inicio de sesión de PowerShell.
  2. Crea una consulta XPath para encontrar eventos apropiados.
  3. Consulta cada computadora mediante la consulta del registro de eventos XPath.
  4. Encuentra los ID de eventos de inicio e intenta hacer coincidirlos para detener los ID de eventos.
  5. Salidas de inicio/finalización con otra información.

Nota: Este script puede necesitar algunos ajustes para funcionar 100% correctamente. Emita una solicitud de extracción de GitHub si nota problemas y desea solucionarlos.

<#	
.SYNOPSIS
	This script finds all PowerShell last logon, logoff and total active session times of all users on all computers specified. For this script
	to function as expected, the advanced AD policies; Audit Logon, Audit Logoff and Audit Other Logon/Logoff Events must be
    enabled and targeted to the appropriate computers via GPO or local policy.
.EXAMPLE
	
.PARAMETER ComputerName
	An array of computer names to search for events on. If this is not provided, the script will search the local computer.
.INPUTS
	None. You cannot pipe objects to Get-ActiveDirectoryUserActivity.ps1.
.OUTPUTS
	None. If successful, this script does not output anything.
#>
[CmdletBinding()]
param
(
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string[]]$ComputerName = $Env:COMPUTERNAME
)

try {
	
    #region Defie all of the events to indicate session start or top
    $sessionEvents = @(
        @{ 'Label' = 'Logon'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4624 } ## Advanced Audit Policy --> Audit Logon
        @{ 'Label' = 'Logoff'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4647 } ## Advanced Audit Policy --> Audit Logoff
        @{ 'Label' = 'Startup'; 'EventType' = 'SessionStop'; 'LogName' = 'System'; 'ID' = 6005 }
        @{ 'Label' = 'RdpSessionReconnect'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4778 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events
        @{ 'Label' = 'RdpSessionDisconnect'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4779 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events
        @{ 'Label' = 'Locked'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4800 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events
        @{ 'Label' = 'Unlocked'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4801 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events
    )
    
    ## All of the IDs that designate when user activity starts
    $sessionStartIds = ($sessionEvents | where { $_.EventType -eq 'SessionStart' }).ID
    ## All of the IDs that designate when user activity stops
    $sessionStopIds = ($sessionEvents | where { $_.EventType -eq 'SessionStop' }).ID
    #endregion
	
    ## Define all of the log names we'll be querying
    $logNames = ($sessionEvents.LogName | select -Unique)
    ## Grab all of the interesting IDs we'll be looking for
    $ids = $sessionEvents.Id
		
    ## Build the insane XPath query for the security event log in order to query PowerShell last logon events and others as fast as possible
    $logonXPath = "Event[System[EventID=4624]] and Event[EventData[Data[@Name='TargetDomainName'] != 'Window Manager']] and Event[EventData[Data[@Name='TargetDomainName'] != 'NT AUTHORITY']] and (Event[EventData[Data[@Name='LogonType'] = '2']] or Event[EventData[Data[@Name='LogonType'] = '10']])"
    $otherXpath = 'Event[System[({0})]]' -f "EventID=$(($ids.where({ $_ -ne '4624' })) -join ' or EventID=')"
    $xPath = '({0}) or ({1})' -f $logonXPath, $otherXpath

    foreach ($computer in $ComputerName) {
        ## Query each computer's event logs using the Xpath filter
        $events = Get-WinEvent -ComputerName $computer -LogName $logNames -FilterXPath $xPath
        Write-Verbose -Message "Found [$($events.Count)] events to look through"

        ## Set up the output object
        $output = [ordered]@{
            'ComputerName'          = $computer
            'Username'              = $null
            'StartTime'             = $null
            'StartAction'           = $null
            'StopTime'              = $null
            'StopAction'            = $null
            'Session Active (Days)' = $null
            'Session Active (Min)'  = $null
        }
        
        ## Need current users because if no stop time, they're still probably logged in
        $getGimInstanceParams = @{
            ClassName = 'Win32_ComputerSystem'
        }
        if ($computer -ne $Env:COMPUTERNAME) {
            $getGimInstanceParams.ComputerName = $computer
        }
        $loggedInUsers = Get-CimInstance @getGimInstanceParams | Select-Object -ExpandProperty UserName | foreach { $_.split('\')[1] }
            
        ## Find all user start activity events and begin parsing
        $events.where({ $_.Id -in $sessionStartIds }).foreach({
                try {
                    $logonEvtId = $_.Id
                    $output.StartAction = $sessionEvents.where({ $_.ID -eq $logonEvtId }).Label
                    $xEvt = [xml]$_.ToXml()

                    ## Figure out the login session ID
                    $output.Username = ($xEvt.Event.EventData.Data | where { $_.Name -eq 'TargetUserName' }).'#text'
                    $logonId = ($xEvt.Event.EventData.Data | where { $_.Name -eq 'TargetLogonId' }).'#text'
                    if (-not $logonId) {
                        $logonId = ($xEvt.Event.EventData.Data | where { $_.Name -eq 'LogonId' }).'#text'
                    }
                    $output.StartTime = $_.TimeCreated
        
                    Write-Verbose -Message "New session start event found: event ID [$($logonEvtId)] username [$($output.Username)] logonID [$($logonId)] time [$($output.StartTime)]"
                    ## Try to match up the user activity end event with the start event we're processing
                    if (-not ($sessionEndEvent = $Events.where({ ## If a user activity end event could not be found, assume the user is still logged on
                                    $_.TimeCreated -gt $output.StartTime -and
                                    $_.ID -in $sessionStopIds -and
                                    (([xml]$_.ToXml()).Event.EventData.Data | where { $_.Name -eq 'TargetLogonId' }).'#text' -eq $logonId
                                })) | select -last 1) {
                        if ($output.UserName -in $loggedInUsers) {
                            $output.StopTime = Get-Date
                            $output.StopAction = 'Still logged in'
                        } else {
                            throw "Could not find a session end event for logon ID [$($logonId)]."
                        }
                    } else {
                        ## Capture the user activity end time
                        $output.StopTime = $sessionEndEvent.TimeCreated
                        Write-Verbose -Message "Session stop ID is [$($sessionEndEvent.Id)]"
                        $output.StopAction = $sessionEvents.where({ $_.ID -eq $sessionEndEvent.Id }).Label
                    }

                    $sessionTimespan = New-TimeSpan -Start $output.StartTime -End $output.StopTime
                    $output.'Session Active (Days)' = [math]::Round($sessionTimespan.TotalDays, 2)
                    $output.'Session Active (Min)'  = [math]::Round($sessionTimespan.TotalMinutes, 2)
                    
                    [pscustomobject]$output
                } catch {
                    Write-Warning -Message $_.Exception.Message
                }
            })
    }
} catch {
    $PSCmdlet.ThrowTerminatingError($_)
}

Artículos relacionados