<# .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 }