Saltar al contenido
Microsoft scripts

Scripts de Purview

Alertas de DLP recientes

Lista las alertas de Microsoft Purview DLP con su severidad, estado y liga para investigarlas. Sirve para ver qué sigue sin atender.

Antes de correrloFiltra con serviceSource igual a dataLossPrevention. Microsoft Learn indica que desde principios de octubre de 2026 una regla integrada de Microsoft Defender XDR maneja las señales DLP como comportamientos: no generan alertas en Defender salvo que desactives la regla en Settings, Microsoft Defender XDR, Alert tuning. Un resultado vacío no significa que no hubo incidentes. Además, las reglas deben estar configuradas para generar alertas.

Ejemplo en México

Despacho legal en Ciudad de México, 45 personas

El equipo de TI revisa cada lunes si se envió información de clientes fuera del despacho, pero nadie entra al portal con regularidad.

.\get-alertas-dlp.ps1 -Dias 7 -RutaCsv .\alertas-dlp.csv

Ven las alertas de la semana en hora de México y asignan las nuevas. El historial les ayuda a documentar cómo dan seguimiento a sus medidas de seguridad.

Cómo implementarlo

  1. Instala el módulo si no lo tienes: Install-Module Microsoft.Graph.Authentication -Scope CurrentUser.
  2. Ejecuta el script con -Dias y -RutaCsv y acepta el permiso SecurityAlert.Read.All.
  3. Ordena por Severidad y Estado para encontrar las alertas sin resolver.
  4. Abre la liga de cada alerta, asígnala y documenta qué decidiste.
Ver el código completo de get-alertas-dlp.ps1
<#
.SYNOPSIS
    Lista las alertas de DLP recientes desde Microsoft Graph.

.DESCRIPTION
    Consulta security/alerts_v2 filtrando por serviceSource dataLossPrevention. Si no hay alertas, avisa que
    desde octubre de 2026 una regla integrada de Microsoft Defender XDR puede estar convirtiéndolas en
    comportamientos. Solo lectura: no cambia nada en el tenant.

.PARAMETER Dias
    Días hacia atrás. Por defecto 30.

.PARAMETER ZonaHoraria
    Zona horaria para mostrar las fechas.

.PARAMETER RutaCsv
    Ruta del CSV de salida. Si se omite, solo se muestra en pantalla.

.EXAMPLE
    .\get-alertas-dlp.ps1 -Dias 30 -RutaCsv .\alertas-dlp.csv

.NOTES
    Permisos: SecurityAlert.Read.All
    Rol mínimo: Lector de seguridad
    Licencia: para investigar en el portal de Defender, Microsoft 365 E5/A5, Office 365 E5/A5, Microsoft 365 E5/A5 Compliance o Information Protection and Governance.
    Licencia del código: MIT. Se entrega TAL CUAL, sin garantía. Pruébalo primero en un tenant de pruebas.
#>
[CmdletBinding()]
param(
    [ValidateRange(1, 3650)]
    [int]$Dias = 30,
    [string]$ZonaHoraria = 'Central Standard Time (Mexico)',
    [string]$RutaCsv
)

$ErrorActionPreference = 'Stop'
$permisos = @('SecurityAlert.Read.All')
$zona = [TimeZoneInfo]::FindSystemTimeZoneById($ZonaHoraria)

if (-not (Get-Command Connect-MgGraph -ErrorAction SilentlyContinue)) {
    throw 'Falta el módulo. Instálalo con: Install-Module Microsoft.Graph.Authentication -Scope CurrentUser'
}

function HoraLocal($valor) {
    if (-not $valor) { return '' }
    $utc = if ($valor -is [datetime]) {
        if ($valor.Kind -eq 'Unspecified') { [datetime]::SpecifyKind($valor, 'Utc') } else { $valor.ToUniversalTime() }
    } else {
        [datetimeoffset]::Parse("$valor", [cultureinfo]::InvariantCulture, 'AssumeUniversal').UtcDateTime
    }
    [TimeZoneInfo]::ConvertTimeFromUtc($utc, $zona).ToString('yyyy-MM-dd HH:mm')
}

$severidades = @{ high = 'Alta'; medium = 'Media'; low = 'Baja'; informational = 'Informativa'; unknown = 'Desconocida' }
$estados = @{ new = 'Nueva'; inProgress = 'En curso'; resolved = 'Resuelta'; unknown = 'Desconocido' }

Connect-MgGraph -Scopes $permisos -NoWelcome

$desde = (Get-Date).ToUniversalTime().AddDays(-$Dias).ToString('yyyy-MM-ddTHH:mm:ssZ')
$filtro = [uri]::EscapeDataString("serviceSource eq 'dataLossPrevention' and createdDateTime ge $desde")
$uri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=$filtro"
$alertas = while ($uri) {
    $pagina = Invoke-MgGraphRequest -Method GET -Uri $uri
    $pagina.value
    $uri = $pagina.'@odata.nextLink'
}

$filas = @(
    foreach ($a in $alertas) {
        [pscustomobject]@{
            Creada        = HoraLocal $a.createdDateTime
            Titulo        = $a.title
            Severidad     = if ($severidades[[string]$a.severity]) { $severidades[[string]$a.severity] } else { $a.severity }
            Estado        = if ($estados[[string]$a.status]) { $estados[[string]$a.status] } else { $a.status }
            AsignadaA     = $a.assignedTo
            Clasificacion = $a.classification
            Incidente     = $a.incidentId
            Liga          = $a.alertWebUrl
        }
    }
)

Write-Host "Alertas de DLP en $Dias días: $($filas.Count). Sin resolver: $(@($filas | Where-Object Estado -ne 'Resuelta').Count)."
if (-not $filas.Count) {
    Write-Warning 'Sin alertas. Revisa que tus reglas DLP generen alertas y, en Microsoft Defender XDR, la regla integrada de Alert tuning para señales DLP: desde octubre de 2026 las maneja como comportamientos en lugar de alertas.'
}
if ($RutaCsv) {
    # UTF-8 con BOM para que Excel en español muestre bien los acentos.
    $filas | Export-Csv -Path $RutaCsv -NoTypeInformation -Encoding utf8BOM
    Write-Host "CSV guardado en $RutaCsv"
} else {
    $filas | Format-Table -AutoSize
}