Microsoft Secure Score y su tendencia
Da tu puntuación actual de Secure Score, el porcentaje alcanzado y el cambio día con día, para reportar avance con números.
Ejemplo en México
Logística y transporte en Monterrey, 120 personas
El corporativo pide cada mes la evidencia de que la postura de seguridad mejora, y el administrador la armaba a mano con capturas de pantalla.
.\get-puntuacion-seguridad.ps1 -Dias 30 -RutaCsv .\puntuacion.csvObtiene el historial del mes en un CSV y grafica la tendencia para la reunión con el corporativo.
Cómo implementarlo
- Instala el módulo si no lo tienes: Install-Module Microsoft.Graph.Authentication -Scope CurrentUser.
- Corre el script con -Dias y el periodo que vas a reportar.
- Inicia sesión con una cuenta con el rol Lector de seguridad.
- Revisa la columna Cambio: investiga las caídas y lleva la tendencia a tu reporte mensual.
Ver el código completo de get-puntuacion-seguridad.ps1
<#
.SYNOPSIS
¿Cuál es mi Microsoft Secure Score hoy y cómo ha cambiado en los últimos días?
.DESCRIPTION
Muestra la puntuación más reciente, el porcentaje alcanzado y el cambio día con día en los
últimos N días. Sirve para reportar avance a la dirección o al corporativo.
Solo lectura: no cambia nada en el tenant.
.PARAMETER Dias
Días de historial. Por defecto, 30.
.PARAMETER RutaCsv
Ruta del CSV de salida. Si se omite, solo se muestra en pantalla.
.EXAMPLE
.\get-puntuacion-seguridad.ps1 -Dias 90 -RutaCsv .\puntuacion.csv
.NOTES
Permisos: SecurityEvents.Read.All
Rol mínimo: Lector de seguridad
Licencia: Sin plan específico: Secure Score muestra recomendaciones de los productos que tengas con licencia (Microsoft Entra ID, Exchange Online, Microsoft Defender, entre otros). Aplica a Microsoft 365 Business Premium
Licencia del código: MIT. Se entrega TAL CUAL, sin garantía. Pruébalo primero en un tenant de pruebas.
#>
[CmdletBinding()]
param(
[ValidateRange(1, 365)]
[int]$Dias = 30,
[string]$RutaCsv
)
$ErrorActionPreference = 'Stop'
$permisos = @('SecurityEvents.Read.All')
if (-not (Get-Command Connect-MgGraph -ErrorAction SilentlyContinue)) {
throw 'Falta el módulo. Instálalo con: Install-Module Microsoft.Graph.Authentication -Scope CurrentUser'
}
Connect-MgGraph -Scopes $permisos -NoWelcome
function ConvertirUtc($valor) {
if ($valor -is [datetime]) { $valor.ToUniversalTime() } else { ([datetimeoffset]"$valor").UtcDateTime }
}
# Un registro por día; se pide uno de más para calcular el cambio del primer día mostrado.
$uri = "https://graph.microsoft.com/v1.0/security/secureScores?`$top=$($Dias + 1)"
$puntuaciones = while ($uri) {
$pagina = Invoke-MgGraphRequest -Method GET -Uri $uri
$pagina.value
$uri = $pagina.'@odata.nextLink'
}
$historial = @($puntuaciones | Sort-Object { ConvertirUtc $_.createdDateTime } -Descending | Select-Object -First ($Dias + 1))
[array]::Reverse($historial)
$anterior = $null
$filas = foreach ($p in $historial) {
$puntos = [double]$p.currentScore
$maximo = [double]$p.maxScore
[pscustomobject]@{
Fecha = (ConvertirUtc $p.createdDateTime).ToString('yyyy-MM-dd')
Puntos = $puntos
Maximo = $maximo
Porcentaje = if ($maximo) { [math]::Round($puntos / $maximo * 100, 1) } else { $null }
Cambio = if ($null -ne $anterior) { ($puntos - $anterior).ToString('+0.##;-0.##;0') } else { $null }
}
$anterior = $puntos
}
if ($filas) {
$primera = @($filas)[0]
$actual = @($filas)[-1]
Write-Host "Puntuación actual: $($actual.Puntos) de $($actual.Maximo) ($($actual.Porcentaje) %) al $($actual.Fecha)"
Write-Host "Cambio desde $($primera.Fecha): $(($actual.Puntos - $primera.Puntos).ToString('+0.##;-0.##;0')) puntos"
} else {
Write-Host 'Graph no devolvió puntuaciones para este tenant.'
}
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
}