lunes, 9 de febrero de 2026

WINDOWS. PS. PCs en la OU de computers

Propósito

Cuando añadimos un PC al dominio se va al contendor "Computers" que no es una OU a la que se puedan asignar GPOs.

Esto implica el riesgo que no se les apliquen ninguna GPO, con lo que hay esta atentos para moverlos a su OU correspondiente.

El script que aquí pondré lo ejecuto una vez al día (Tarea programada) y le envío copia al equipo de Help Desk. Básicamente mira si hay algún hosts en el contenedor de Computers y si lo hay envía un email informando.

No modifica nada, solo es informativa.

Pasos

Básicamente mira si hay algún hosts en el contenedor de Computers y si lo hay envía un email informando

 <#
   Busca equipos en el contenedor CN=Computers.
   Si hay equipos → envía correo con la tabla HTML en el CUERPO.
   Si no hay equipos → no envía correo.
#>

# ==========================
#  VARIABLES DEL USUARIO
# ==========================
$SMTPServer = "miservidor.midominio.com"
$SMTPPort   = 25
$From       = "Servidor1@midominio.com"
$To         = "itsecurity@midominio.com" , "HelpDesk@midominio.com",
$Subject    = "PCs en la Ou de Computers"

# Contenedor donde buscar (CORRECTO)
$SearchBase = "CN=Computers,DC=midominio,DC=com"

# ==========================
#  CARGAR MÓDULO AD
# ==========================
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
    Write-Error "El módulo ActiveDirectory no está disponible. Instala RSAT."
    exit 1
}
Import-Module ActiveDirectory

# ==========================
#  VALIDAR CONTENEDOR
# ==========================
try {
    $null = Get-ADObject -Identity $SearchBase -ErrorAction Stop
}
catch {
    Write-Error "ERROR: No se encontró el contenedor/OU: $SearchBase"
    exit 1
}

# ==========================
#  OBTENER EQUIPOS
# ==========================
$Computers = Get-ADComputer -SearchBase $SearchBase `
    -SearchScope OneLevel `
    -Filter * `
    -Properties Name, DNSHostName, Description, OperatingSystem, Enabled, LastLogonDate, whenCreated, whenChanged

$Count = $Computers.Count
Write-Host "Equipos encontrados: $Count"

if ($Count -eq 0) {
    Write-Host "Contenedor vacío. No se envía correo."
    exit 0
}

# ==========================
#  GENERAR HTML
# ==========================
$Sorted = $Computers | Sort-Object Name

$Table = $Sorted | Select-Object `
    @{n="Nombre (sAM)"; e={$_.Name}},
    @{n="Hostname (DNS)"; e={$_.DNSHostName}},
    @{n="Descripción"; e={ if ($_.Description) { $_.Description } else { "N/D" } }},
    @{n="SO"; e={$_.OperatingSystem}},
    @{n="Habilitado"; e={$_.Enabled}},
    @{n="Último logon"; e={ if ($_.LastLogonDate) { $_.LastLogonDate } else { "N/D" } }},
    @{n="Creado"; e={$_.whenCreated}},
    @{n="Modificado"; e={$_.whenChanged}} |
    ConvertTo-Html -As Table -Fragment

$Style = @"
<style>
body { font-family: Segoe UI, Arial; color:#222; }
table { border-collapse: collapse; width:100%; }
th, td { border: 1px solid #ccc; padding:6px; }
th { background:#f0f0f0; }
tr:nth-child(even) { background:#fafafa; }
.notice { font-weight:bold; color:#b00020; }
</style>
"@

$IntroText = "<p class='notice'>Estos PC deben moverse a la OU correspondiente</p>"
$Header    = "<h2>Equipos encontrados en: $SearchBase</h2>"
$BodyHtml  = ConvertTo-Html -Head $Style -Body "$IntroText $Header $Table"

# ==========================
#  ENVIAR CORREO
# ==========================
try {
    $Mail = New-Object System.Net.Mail.MailMessage
    $Mail.From = $From

    foreach ($recipient in $To) {
        if ($recipient.Trim()) { $Mail.To.Add($recipient.Trim()) }
    }

    $Mail.Subject   = $Subject + " (Total: $Count)"
    $Mail.IsBodyHtml = $true
    $Mail.Body      = $BodyHtml

    $SMTP = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
    $SMTP.Send($Mail)

    Write-Host "Correo enviado correctamente."
}
catch {
    Write-Error "Error enviando el correo: $($_.Exception.Message)"
    exit 1

}

El resultado vendría ser algo parecido a lo siguiente


Dificultad: Baja
Utilidad: Alta
by GoN | Published: Feb 2026 | Last Updated: