Automatización de Auditoría de GPOs con PowerShell y XML: Extracción de Datos Relevantes a CSV

Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero

En entornos corporativos donde la gestión de Políticas de Grupo (GPOs) es esencial para el control de seguridad y configuración de equipos, automatizar auditorías puede ahorrar tiempo y reducir errores. El siguiente script de PowerShell permite procesar múltiples archivos XML de GPOs generados desde la consola de administración, extrayendo información clave y exportándola a un archivo CSV legible.

¿Qué hace este script?

Este script recorre de forma recursiva todos los archivos XML dentro de un directorio (y subdirectorios) especificado, lee su contenido, extrae datos importantes de cada GPO y los guarda en un archivo CSV para su posterior análisis.

# Ruta del directorio con los archivos XML de GPO
$directorio = "C:\Datos\Reportes_xml" 

# Salida del CSV
$salidaCSV = "$directorio\gpos_exportadas.csv"

# Crear lista para guardar resultados
$resultados = @()

# Procesar cada archivo XML en el directorio (con subcarpetas)
Get-ChildItem -Path $directorio -Filter *.xml -Recurse | ForEach-Object {
    $archivo = $_.FullName
    try {
        [xml]$xml = Get-Content $archivo

        $dominio = $xml.GPO.Identifier.Domain.'#text'
        $nombreGPO = $xml.GPO.Name

        # --- Corrección para obtener Owner con namespaces ---
        $nsManager = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
        $nsManager.AddNamespace("gp", "http://www.microsoft.com/GroupPolicy/Types/Security")
        $nsManager.AddNamespace("gpTypes", "http://www.microsoft.com/GroupPolicy/Types")

        $ownerNameNode = $xml.SelectSingleNode("//gp:Owner/gpTypes:Name", $nsManager)
        $owner = if ($ownerNameNode) { $ownerNameNode.InnerText } else { "Desconocido" }

        $activoMaquina = $xml.GPO.Computer.Enabled
        $activoUsuario = $xml.GPO.User.Enabled

        $politicasActivas = @()

        if ($xml.GPO.Computer.ExtensionData) {
            foreach ($ext in $xml.GPO.Computer.ExtensionData.Extension.Policy) {
                if ($ext.State -eq "Enabled") {
                    $politicasActivas += $ext.Name
                }
            }
        }

        if ($xml.GPO.User.ExtensionData) {
            foreach ($ext in $xml.GPO.User.ExtensionData.Extension.Policy) {
                if ($ext.State -eq "Enabled") {
                    $politicasActivas += $ext.Name
                }
            }
        }

        $activaPolitica = if ($politicasActivas.Count -gt 0) { "Si" } else { "No" }

        # --- Extraer info de LinksTo ---
        $linkada = "No"
        if ($xml.GPO.LinksTo) {
            if ($xml.GPO.LinksTo.Enabled -and $xml.GPO.LinksTo.Enabled -eq "true") {
                $linkada = "Si"
            }
        }

        # Concatenar políticas activas en una sola cadena
        $politicasConcatenadas = $politicasActivas -join ", "
        $numeroPoliticas = $politicasActivas.Count

        # Guardar resultado como objeto
        $resultados += [PSCustomObject]@{
            Dominio              = $dominio
            NombreGPO            = $nombreGPO
            ActivaLaPolitica     = $activaPolitica
            ActivoUsuario        = $activoUsuario
            ActivoMaquina        = $activoMaquina
            OwnerPolitica        = $owner
            Linkada              = $linkada
            PoliticasActivas     = $politicasConcatenadas
            NumeroPoliticasActivas = $numeroPoliticas
        }
    }
    catch {
        Write-Warning "Error procesando ${archivo}: $($_.Exception.Message)"
    }
}

# Exportar a CSV
$resultados | Export-Csv -Path $salidaCSV -NoTypeInformation -Encoding UTF8

Write-Output "Exportado a: $salidaCSV"

Desglose del script

1. Definición de rutas

$directorio = "C:\Datos\Reportes_xml" 
$salidaCSV = "$directorio\gpos_exportadas.csv"

Se define el directorio que contiene los archivos XML y la ruta de salida para el archivo CSV.

2. Inicialización de la lista de resultados

$resultados = @()

Se crea un array vacío que almacenará los objetos de resultados por cada GPO procesada.

3. Lectura y procesamiento de archivos XML

Get-ChildItem -Path $directorio -Filter *.xml -Recurse | ForEach-Object {

Se buscan todos los archivos XML dentro del directorio, incluyendo subcarpetas.

4. Carga del archivo XML y manejo de excepciones

try {
[xml]$xml = Get-Content $archivo
...
}
catch {
Write-Warning "Error procesando ${archivo}: $($_.Exception.Message)"
}

Cada archivo se carga como un objeto XML y se maneja cualquier error que pueda surgir en el proceso.

5. Extracción de datos básicos

$dominio = $xml.GPO.Identifier.Domain.'#text'
$nombreGPO = $xml.GPO.Name
$activoMaquina = $xml.GPO.Computer.Enabled
$activoUsuario = $xml.GPO.User.Enabled

Se obtienen el dominio, nombre de la GPO, y si está activa para equipos y/o usuarios.

6. Lectura del propietario (Owner) usando namespaces XML

powershellCopiarEditar$nsManager = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsManager.AddNamespace("gp", "http://www.microsoft.com/GroupPolicy/Types/Security")
$nsManager.AddNamespace("gpTypes", "http://www.microsoft.com/GroupPolicy/Types")

$ownerNameNode = $xml.SelectSingleNode("//gp:Owner/gpTypes:Name", $nsManager)
$owner = if ($ownerNameNode) { $ownerNameNode.InnerText } else { "Desconocido" }

Se definen los espacios de nombres necesarios para localizar correctamente el nodo del propietario de la GPO.

7. Detección de políticas activas

$politicasActivas = @()

if ($xml.GPO.Computer.ExtensionData) {
foreach ($ext in $xml.GPO.Computer.ExtensionData.Extension.Policy) {
if ($ext.State -eq "Enabled") {
$politicasActivas += $ext.Name
}
}
}

Se revisan las políticas tanto de equipo como de usuario, y se almacenan aquellas activas.

8. Verificación si la GPO está enlazada

$linkada = "No"
if ($xml.GPO.LinksTo) {
if ($xml.GPO.LinksTo.Enabled -and $xml.GPO.LinksTo.Enabled -eq "true") {
$linkada = "Si"
}
}

Se determina si la GPO está vinculada a alguna Unidad Organizativa (OU).

9. Registro del resultado

$resultados += [PSCustomObject]@{
Dominio = $dominio
NombreGPO = $nombreGPO
ActivaLaPolitica = $activaPolitica
ActivoUsuario = $activoUsuario
ActivoMaquina = $activoMaquina
OwnerPolitica = $owner
Linkada = $linkada
PoliticasActivas = $politicasConcatenadas
NumeroPoliticasActivas = $numeroPoliticas
}

Se crea un objeto con toda la información recolectada para cada archivo XML.

10. Exportación a CSV

$resultados | Export-Csv -Path $salidaCSV -NoTypeInformation -Encoding UTF8
Write-Output "Exportado a: $salidaCSV"

Finalmente, se exporta toda la información a un archivo CSV con codificación UTF-8.

Resultado

El archivo CSV generado incluirá columnas como:

  • Dominio
  • NombreGPO
  • ActivaLaPolitica
  • ActivoUsuario
  • ActivoMaquina
  • OwnerPolitica
  • Linkada
  • PoliticasActivas
  • NumeroPoliticasActivas

Esto facilita la visualización y análisis de configuraciones GPO de forma centralizada, ideal para auditorías de cumplimiento, revisión de configuración o migraciones de políticas.

Conclusión

Este script es una herramienta poderosa para administradores de sistemas que gestionan grandes volúmenes de GPOs. Automatiza la extracción de información útil de archivos XML y la convierte en datos estructurados listos para análisis en Excel u otras herramientas.

Binario 0
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.