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

- Link: https://binariocero.com/windows/automatizacion-de-auditoria-de-gpos-con-powershell-y-xml-extraccion-de-datos-relevantes-a-csv
- Published: 2025-06-15T12:25:08+02:00
- Author: Juan José Fernández Durán

![Loading](https://binariocero.com/wp-content/plugins/page-views-count/ajax-loader-
2x.gif)

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.

    ```wp-block-code
    # 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**

    ```wp-block-preformatted
    $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**

    ```wp-block-preformatted
    $resultados = @()
    ```

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

#### 3. **Lectura y procesamiento de archivos XML**

    ```wp-block-preformatted
    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**

    ```wp-block-preformatted
    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**

    ```wp-block-preformatted
    $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**

    ```wp-block-preformatted
    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**

    ```wp-block-preformatted
    $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**

    ```wp-block-preformatted
    $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**

    ```wp-block-preformatted
    $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**

    ```wp-block-preformatted
    $resultados | Export-Csv -Path $salidaCSV -NoTypeInformation -Encoding UTF8Write-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.
