Acciones pendientes de Microsoft Secure Score
Lista las acciones de mejora que aún dan puntos, de mayor a menor, con su impacto en los usuarios, para planear qué hacer primero.
Ejemplo en México
Escuela privada en Puebla, 90 personas
Con un solo técnico y poco tiempo entre periodos escolares, hay que escoger qué ajustes de seguridad dan más por menos esfuerzo.
.\get-acciones-puntuacion.ps1 -RutaCsv .\acciones.csvObtiene la lista priorizada y agenda para vacaciones las acciones que más suman sin afectar a los maestros.
Cómo implementarlo
- Instala el módulo si no lo tienes: Install-Module Microsoft.Graph.Authentication -Scope CurrentUser.
- Corre el script e inicia sesión con una cuenta con el rol Lector de seguridad.
- Abre el CSV: ya viene ordenado por PuntosPendientes.
- Elige las acciones con más puntos y menor ImpactoUsuario, y aplícalas desde la columna Liga.
Ver el código completo de get-acciones-puntuacion.ps1
<#
.SYNOPSIS
¿Qué acciones de Microsoft Secure Score me faltan y cuáles dan más puntos?
.DESCRIPTION
Cruza los perfiles de control con la puntuación más reciente y lista las acciones con puntos
pendientes, de mayor a menor. Omite controles retirados y los que marcaste como ignorados o
resueltos por un tercero.
Solo lectura: no cambia nada en el tenant.
.PARAMETER RutaCsv
Ruta del CSV de salida. Si se omite, solo se muestra en pantalla.
.EXAMPLE
.\get-acciones-puntuacion.ps1 -RutaCsv .\acciones.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(
[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
$reciente = @((Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/security/secureScores?$top=1').value)[0]
if (-not $reciente) { throw 'Graph no devolvió puntuaciones para este tenant.' }
$puntosPorControl = @{}
foreach ($c in $reciente.controlScores) { $puntosPorControl["$($c.controlName)"] = [double]$c.score }
$uri = 'https://graph.microsoft.com/v1.0/security/secureScoreControlProfiles'
$perfiles = while ($uri) {
$pagina = Invoke-MgGraphRequest -Method GET -Uri $uri
$pagina.value
$uri = $pagina.'@odata.nextLink'
}
$filas = foreach ($p in $perfiles) {
if ($p.deprecated) { continue }
$ultimo = @($p.controlStateUpdates | Sort-Object { if ($_.updatedDateTime) { [datetimeoffset]"$($_.updatedDateTime)" } else { [datetimeoffset]::MinValue } })[-1]
if ("$($ultimo.state)" -in @('Ignored', 'ThirdParty')) { continue }
$maximo = [double]$p.maxScore
$actuales = [double]$puntosPorControl["$($p.id)"]
$pendientes = $maximo - $actuales
if ($pendientes -le 0) { continue }
[pscustomobject]@{
Accion = $p.title
PuntosPendientes = $pendientes
PuntosActuales = $actuales
PuntosMaximos = $maximo
Avance = if ($actuales -gt 0) { 'Parcial' } else { 'Sin iniciar' }
Categoria = $p.controlCategory
Servicio = $p.service
ImpactoUsuario = $p.userImpact
Costo = $p.implementationCost
Rango = $p.rank
Liga = $p.actionUrl
}
}
$filas = $filas | Sort-Object @{ Expression = 'PuntosPendientes'; Descending = $true }, Rango
Write-Host "Acciones pendientes: $(@($filas).Count), con $(($filas | Measure-Object PuntosPendientes -Sum).Sum) puntos por ganar"
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
}