martes, 26 de mayo de 2026

WINDOWS. GPO. Documento GPO-OU

Propósito:

Tengo que hacer limpieza de un montón de OUs, ya que he movido mis usuarios/Pcs a una estructura nueva. No me he llevado las mismas OUs, ni las mismas GPOs para no arrastrar la "suciedad" y partir de una estructura entendible y bien organizada.

El problema podría venir si me he dejado algo, con lo que antes de limpiar la estructura antigua he preferido hacer una exportación donde relaciono las OU con las GPO, por si necesito recrearlo.

Pasos

El resultado vendría ser un fichero html con el siguiente formato


La ejecución podría tardar un par de minutos, depende lo grande que sea la estructura de OUs y el número de GPOs.

El código es el siguiente:

Import-Module ActiveDirectory -ErrorAction Stop
Import-Module GroupPolicy -ErrorAction Stop

$fecha = Get-Date -Format "yyyyMMdd_HHmm"
$output = "AD_Informe_Completo_$fecha.html"

$html = @()

$html += @"
<html>
<head>
<title>Auditoria AD</title>
<style>
body { font-family: Arial; font-size: 12px; }
h1 { color:#2E86C1; }
h2 { color:#1F618D; }
table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
th, td { border:1px solid #ccc; padding:6px; text-align:left; }
th { background-color:#f2f2f2; }

.directa { background-color:#D4EFDF; }
.heredada { background-color:#FDEBD0; }

.ok { color:green; font-weight:bold; }
.warn { color:red; font-weight:bold; }

.small { font-size: 11px; color: #555; }
</style>
</head>
<body>
"@

$html += "<h1>Auditoria OU y GPO</h1>"
$html += "<p>Fecha: $(Get-Date)</p>"

# Obtener todas las OUs
$ous = Get-ADOrganizationalUnit -Filter * | Sort-Object DistinguishedName

# Cache de links directos por OU
$linksPorOU = @{}

foreach ($ou in $ous) {
    try {
        $inh = Get-GPInheritance -Target $ou.DistinguishedName
        $linksPorOU[$ou.DistinguishedName] = $inh.GpoLinks
    } catch {
        $linksPorOU[$ou.DistinguishedName] = @()
    }
}

# Funcion para obtener padres de una OU
function Get-OUChain {
    param ($dn)

    $chain = @()
    $actual = $dn

    while ($actual -match "OU=") {
        $chain += $actual
        $actual = ($actual -split ',',2)[1]
    }

    # añadir dominio (final)
    if ($actual) { $chain += $actual }

    return $chain
}

foreach ($ou in $ous) {

    try {

        $html += "<h2>OU: $($ou.Name)</h2>"
        $html += "<p><b>DN:</b> $($ou.DistinguishedName)</p>"

        $inheritance = Get-GPInheritance -Target $ou.DistinguishedName

        if ($inheritance.GpoInheritanceBlocked) {
            $html += "<p class='warn'>Herencia bloqueada</p>"
        } else {
            $html += "<p class='ok'>Herencia activa</p>"
        }

        $chain = Get-OUChain $ou.DistinguishedName

        $html += "<table>"
        $html += "<tr>
                    <th>GPO</th>
                    <th>Enforced</th>
                    <th>Link Enabled</th>
                    <th>Origen</th>
                  </tr>"

        foreach ($gpo in $inheritance.InheritedGpoLinks) {

            $origen = "No localizado"
            $class = "heredada"

            # Buscar donde esta linkada realmente
            foreach ($nivel in $chain) {

                if ($linksPorOU.ContainsKey($nivel)) {

                    foreach ($link in $linksPorOU[$nivel]) {

                        if ($link.DisplayName -eq $gpo.DisplayName) {

                            if ($nivel -eq $ou.DistinguishedName) {
                                $origen = "Directa"
                                $class = "directa"
                            } else {
                                $origen = "Heredada desde: $nivel"
                                $class = "heredada"
                            }

                            break
                        }
                    }
                }

                if ($origen -ne "No localizado") { break }
            }

            $html += "<tr class='$class'>
                        <td>$($gpo.DisplayName)</td>
                        <td>$($gpo.Enforced)</td>
                        <td>$($gpo.Enabled)</td>
                        <td class='small'>$origen</td>
                      </tr>"
        }

        $html += "</table>"
        $html += "<hr>"

    }
    catch {
        $html += "<p class='warn'>Error en OU: $($ou.DistinguishedName)</p>"
    }
}

$html += "</body></html>"

$html | Out-File $output -Encoding UTF8

Write-Host "Informe generado: $output" -ForegroundColor Green


by GoN | Published: May 2026 | Last Updated: