El Blog de Gualtrysoft

Windows 2000/2003/2008, Active Directory, VBScript, Hyper-V, PowerShell y todo aquello interesante a la hora de usar, configurar y administrar Windows Server. También tenemos longanizas…

Script VbScript para obtener información de un bosque de Active Directory

Posted by urpiano en Viernes 15 \15\UTC enero \15\UTC 2010

Este script genera una serie de ficheros de valores separados por tabulador (ideales paa ser abiertos por Excel o importarlos a una base de datos), con información del bosque de Active Directory al que pertenece el equipo desde el que se lanza, así como información de Exchange. Obviamente, la cuenta con la que se ejecute debe tener permisos de lectura de AD en los diferentes dominios que conformen el bosque. El script crea los ficheros:

– Dominios.tab: listado de los dominios del bosque. El listado incluye el FQDN, el nombre NetBios, el modo de funcionamiento, el dominio padre, el nombre distinguido, qué DC ostenta el rol de maestro de esquema, el del maestro de nombres, el del PDC, el del RID y el del maestro de infraestructura.

– Sitios.tab: listado de los sitios, sus controladores de dominio y las conexiones que tienen. El listado incluye el nombre del sitio, el del controlador de dominio de origen (el que está en el sitio), el de la conexión, si ésta está o no habilitada y el nombre del controlador de dominio de destino.

– DCs.tab: listado de los controladores de dominio. El listado incluye, el dominio al que pertenece, el nombre, si es catálogo global, el sistema operativo, el nivel de service pack y el modo de funcionamiento del dominio.

-OUs.tab: listado de las OUs de los dominios del bosque. El listado incluye el nombre FQDN del dominio, el nombre NetBios del dominio, la ruta canónica al contenedor padre, el nombre RDN de la OU y su nombre distinguido.

– ErroresOUs.tab: Errores producidos al generarse el listado de OUs.

– Buzones.tab: listado con los buzones de Exchange que incluye el FQDN del dominio, el nombre NetBios del dominio, la base de datos en la que está el buzón, el servidor de Exchange donde está la base de datos, el nombre para mostrar del buzón y su nombre distinguido.

– Contactos.tab: listado con los contactos que incluye el FQDN del dominio, el nombre NetBios del dominio, el nombre para mostrar del buzón, la dirección de correo y su nombre distinguido.

– Listas.tab: listado de las listas de distribución que incluye el FQDN del dominio, el nombre NetBios del dominio, el nombre de la lista, su tipo, la dirección de correo, su información, su nombre pre-Windows 2000 y su nombre distinguido.

Sintaxis

cscript [//nologo] documentar-AD.vbs /C:Carpeta [/?]

Siendo

Etiqueta Dato ¿Requerido? Descripción
C Carpeta
Ruta y nombre de la carpeta en la que se guardarán los ficheros obtenidos al ejecutar el script.
?   No
Muestra la ayuda en línea.

Ejemplos:

– Crea los ficheros con los listados en la carpeta x:\tia\listados-AD:

cscript //nologo documentar-AD.vbs /C:x:\tia\listados-AD

Este es el código del script



'*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
'*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
'* documentar-AD.vbs                                                   *
'*                                                                     *
'* Este script genera una serie de ficheros de valores separados por   *
'* tabulador (ideales paa ser abiertos por Excel o importarlos a una   *
'* base de datos), con información del bosque de Active Directory al   *
'* que pertenece el equipo desde el que se lanza, así como información *
'* de Exchange. Obviamente, la cuenta con la que se ejecute debe tener *
'* permisos de lectura de AD en los diferentes dominios que conformen  *
'* el bosque. El script crea los ficheros:                             *
'*                                                                     *
'* - Dominios.tab: listado de los dominios del bosque. El listado      *
'* incluye el FQDN, el nombre NetBios, el modo de funcionamiento, el   *
'* dominio padre, el nombre distinguido, qué DC ostenta el rol de      *
'* maestro de esquema, el del maestro de nombres, el del PDC, el del   *
'* RID y el del maestro de infraestructura.                            *
'* - Sitios.tab: listado de los sitios, sus controladores de dominio y *
'* las conexiones que tienen. El listado incluye el nombre del sitio,  *
'* el del controlador de dominio de origen (el que está en el sitio),  *
'* el de la conexión, si ésta está o no habilitada y el nombre del     *
'* controlador de dominio de destino.                                  *
'* - DCs.tab: listado de los controladores de dominio. El listado      *
'* incluye, el dominio al que pertenece, el nombre, si es catálogo     *
'* global, el sistema operativo, el nivel de service pack y el modo de *
'* funcionamiento del dominio.                                         *
'* -OUs.tab: listado de las OUs de los dominios del bosque. El listado *
'* incluye el nombre FQDN del dominio, el nombre NetBios del dominio,  *
'* la ruta canónica al contenedor padre, el nombre RDN de la OU y su   *
'* nombre distinguido.                                                 *
'* - ErroresOUs.tab: Errores producidos al generarse el listado de OUs.*
'* - Buzones.tab: listado con los buzones de Exchange que incluye el   *
'* FQDN del dominio, el nombre NetBios del dominio, la base de datos   *
'* en la que está el buzón, el servidor de Exchange donde está la base *
'* de datos, el nombre para mostrar del buzón y su nombre distinguido. *
'* - Contactos.tab: listado con los contactos que incluye el FQDN del  *
'* dominio, el nombre NetBios del dominio, el nombre para mostrar del  *
'* buzón, la dirección de correo y su nombre distinguido.              *
'* - Listas.tab: listado de las listas de distribución que incluye el  *
'* FQDN del dominio, el nombre NetBios del dominio, el nombre de la    *
'* lista, su tipo, la dirección de correo, su información, su nombre   *
'* pre-Windows 2000 y su nombre distinguido.                           *
'*                                                                     *
'*                                                                     *
'* Sintaxis                                                            *
'*                                                                     *
'* cscript [//nologo] documentar-AD.vbs /C:Carpeta [/?]                *
'*                                                                     *
'* Siendo                                                              *
'*                                                                     *
'* - /C: Carpeta (Requerido):                                          *
'*         Ruta y nombre de la carpeta en la que se guardarán los      *
'*         ficheros obtenidos al ejecutar el script.                   *
'*                                                                     *
'* - /?: ayuda (Opcional):                                             *
'*         Muestra la ayuda en línea                                   *
'*                                                                     *
'*                                                                     *
'* Ejemplos:                                                           *
'*                                                                     *
'* - Crea los ficheros con los listados en la carpeta                  *
'* x:\tia\listados-AD:                                                 *
'*                                                                     *
'* cscript //nologo documentar-AD.vbs /C:x:\tia\listados-AD            *
'*                                                                     *
'*                                                                     *
'*                                                                     *
'*                                                                     *
'* © Fernando Reyes                                                    *
'* Enero De 2010                                                       *
'*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
'*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

'Exigimos la declaración de variables
Option Explicit

Const ADS_SCOPE_SUBTREE = 2

Dim obj_FS
Dim obj_DCs
Dim obj_Error
Dim obj_Dominios
Dim obj_Sitios
Dim obj_Buzones
Dim obj_Contactos
Dim obj_Listas
Dim obj_OUs
Dim arr_Dominios
Dim arr_DNDominios
Dim arr_FQDNDominios
Dim arr_ModoDominios
Dim str_MaestroEsquema
Dim str_MaestroNombres
Dim str_Error 'As String
Dim int_Error 'As String
Dim str_Ruta 'As String
Dim int_Dominio



'Validando los argumentos y almacenando
'sus valores
If f_RevisarArgumentos( _
                       str_Error, _
                       int_Error) Then

    Call s_Ayuda(str_Error)
    WScript.Quit int_Error

End If

'Creamos un objeto FileSystemObject
Set obj_FS = CreateObject("Scripting.FileSystemObject")

'Creamos los ficheros con los listados de DCs, errores al intentar
'contactar con los dominios y el listados de dominios
Set obj_DCs = obj_FS.CreateTextFile(str_Ruta & "DCs.tab")
Set obj_Sitios = obj_FS.CreateTextFile(str_Ruta & "Sitios.tab")
Set obj_Error = obj_FS.CreateTextFile(str_Ruta & "ErroresOUs.tab")
Set obj_Dominios = obj_FS.CreateTextFile(str_Ruta & "Dominios.tab")
Set obj_Buzones = obj_FS.CreateTextFile(str_Ruta & "Buzones.tab")
Set obj_Contactos = obj_FS.CreateTextFile(str_Ruta & "Contactos.tab")
Set obj_Listas = obj_FS.CreateTextFile(str_Ruta & "Listas.tab")
Set obj_OUs = obj_FS.CreateTextFile(str_Ruta & "OUs.tab")

obj_Sitios.WriteLine "Sitio" & vbTab  & _
                     "DC" & vbTab & _
                     "Conexión" & vbTab & _
                     "Habilitada" & vbTab & _
                     "DC Destino"


'Ponemos los encabezados de tabla en los ficheros creados
obj_DCs.WriteLine "Dominio" & vbTab & _
                  "Controlador" & vbTab & _
                  "CG" & vbTab & _
                  "SO" & vbTab & _
                  "SP" & vbTab & _
                  "Modo Dominio"

obj_Error.WriteLine "Dominio" & vbTab & _
                    "OU" & vbTab & _
                    "Error"

obj_Dominios.WriteLine "Nombre FQDN" & vbTab & _
                       "Nombre NetBios" & vbTab & _
                       "Modo" & vbTab & _
                       "Dominio Padre" & vbTab & _
                       "Nombre Distinguido" & vbTab & _
                       "Maestro de Esquema" & vbTab & _
                       "Maestro de Nombres" & vbTab & _
                       "Emulador PDC" & vbTab & _
                       "Maestro RID" & vbTab & _
                       "Maestro Infraestructura"
                       
obj_Buzones.WriteLine "FQDN Dominio" & vbTab & _
                      "NetBios Dominio" & vbTab & _
                      "Base de datos" & vbTab & _
                      "Servidor Exchange" & vbTab & _
                      "Nombre para mostrar" & vbTab & _
                      "Nombre distinguido"

obj_Contactos.WriteLine "FQDN Dominio" & vbTab & _
                        "NetBios Dominio" & vbTab & _
                        "Nombre para mostrar" & vbTab & _
                        "Correo" & vbTab & _
                        "Nombre distinguido"

obj_Listas.WriteLine "FQDN Dominio" & vbTab & _
                     "NetBios Dominio" & vbTab & _
                     "Nombre" & vbTab & _
                     "Tipo" & vbTab & _
                     "Correo" & vbTab & _
                     "Información" & vbTab & _
                     "sAMAccountName" & vbTab & _
                     "Nombre distinguido"

obj_OUs.WriteLine "FQDN Dominio" & vbTab & _
                  "NetBios Dominio" & vbTab & _
                  "Padre" & vbTab & _
                  "Nombre" & vbTab & _
                  "Nombre distinguido"

'Listamos los sitios
Call s_ListarSitios

'Obtenemos los nombres de los equipos que ostentan los roles FSMO a
'nivel de bosque (maestro de esquema y maestro de nombres de dominio.
'Los nombres de los equipos quedan almacenados en la variable
'correspondiente
Call s_RolesForest(str_MaestroEsquema,str_MaestroNombres)

'Cargamos el array con los nombres NetBios de los dominios del bosque
'llamando a la función f_ArrDominios, que se encargará de de poblar
'también los arrays con los nombres distinguidos, y los nombres DNS
arr_Dominios = f_ArrDominios

'Una vez listados los dominios cerramos el fichero y vaciamos la
'variable de su objeto TextStream
obj_Dominios.Close
Set obj_Dominios = Nothing

'Recorremos el array de dominios
For int_Dominio = 0 To UBound(arr_DnDominios)

    'Listamos los DCs del dominio actual. El procedimiento para
    'hacerlo tiene una debilidad, pues suponemos que los DCs
    'tienen sus cuentas ubicadas en la OU Domain Controllers o
    'en OUs que estén contenidas en ésta. No debería haber DCs
    'fuera de este subárbol de contenedores del dominio, pero
    '"Cosas veredes, amigo Sancho"...
    Call s_ListarDCsOU("OU=Domain Controllers," &  _
                       arr_DnDominios(int_Dominio),int_Dominio)
    Call s_ListarBuzones(arr_DNDominios(int_Dominio),int_Dominio)
    Call s_ListarContactos(arr_DNDominios(int_Dominio),int_Dominio)
    Call s_ListarListas(arr_DNDominios(int_Dominio),int_Dominio)
    Call s_ListarOUs(arr_DNDominios(int_Dominio),int_Dominio)

Next

'Una vez listados los DCs cerramos los ficheros de salida y errores
obj_DCs.Close
obj_Error.Close
obj_Buzones.Close
obj_Listas.Close
obj_Contactos.Close
obj_OUs.Close

'Vaciamos los objetos TextStream
Set obj_DCs = Nothing
Set obj_Error = Nothing
Set obj_Buzones = Nothing
Set obj_Listas = Nothing
Set obj_Contactos = Nothing
Set obj_OUs = Nothing

'Vaciamos el objeto FileSystemObject
Set obj_FS = Nothing

Sub s_ListarDCsOU(str_DNOU, int_Dominio)
'***********************************************************************
'* Procedimiento: s_ListarDCsOU                                        *
'* Tipo         : Método                                               *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 9:50:27                                   *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método se encarga de listar los DCs del         *
'*                dominio en el que está la OU que recibe como         *
'*                parámetro. El listado es, en formato de tabla,       *
'*                enviado al fichero de DCs y mostrado también por     *
'*                pantalla, en este caso en formato de lista. Una vez  *
'*                listados los DCs de la OU que recibe como            *
'*                parámetro, realiza una llamada recursiva con las     *
'*                OUs que contenga.                                    *
'*                                                                     *
'*                Parámetros:                                          *
'*                                                                     *
'*                - str_DNOU: nombre distinguido de la OU donde están  *
'*                los controladores de dominio (si no hay              *
'*                administradores "locos", será la predeterminada      *
'*                para DCs, es decir Domain Controllers; por ejemplo   *
'*                en el dominio tia.org OU=Domain                      *
'*                Controllers,DC=tia,DC=org.                           *
'*                - int_Dominio: Índice del dominio en los arrays de   *
'*                dominios.                                            *
'***********************************************************************

    Dim obj_OU
    Dim obj_Equipo
    Dim obj_DC
    Dim obj_SubOU

    'Establecemos control de errores
    On Error Resume Next

    Set obj_OU = GetObject("LDAP://" & str_DNOU)

    'Si se produjo algún error...
    If Err.Number <> 0 Then

        'Registramos el error en el fichero de errores
        obj_Error.WriteLine arr_Dominios(int_Dominio) & vbTab & _
                            str_DNOU & vbTab & _
                            "Referencia Nula"
        
        'Vaciamos el objeto Err
        Err.Clear
        
        'Devolvemos el control de errores a cscript
        On Error Goto 0
        
        'Salimos del procedimiento
        Exit Sub

    End If

    'Devolvemos el control de errores a cscript
    On Error Goto 0

    'Filtramos la OU con los equipos
    obj_OU.Filter = Array("computer")

    'Recorremos los equipos de la OU
    For Each obj_Equipo In obj_OU
   
        'Obtenemos el DC
        Set obj_DC = GetObject("LDAP://" & _
                                obj_Equipo.Get("distinguishedName"))

        'Escribimos en el fichero con el listado los datos del DC.
        'Estos son:
        '    * Nombre NetBios del dominio al que pertenece
        '    * Nombre NetBios del DC
        '    * Si es o no catálogo global (lo obtenemos llamando a f_GC)
        '    * Sistema Operativo del DC
        '    * Service Pack
        '    * Modo de funcionamiento del dominio
        obj_DCs.WriteLine arr_Dominios(int_Dominio) & vbTab & _
                         Left(obj_DC.Get("sAMAccountName"), _
                         Len(obj_DC.Get("sAMAccountName")) - 1) & _
                         vbTab & _
                         f_GC(Left(obj_DC.Get("sAMAccountName"), _
                              Len(obj_DC.Get("sAMAccountName")) - 1)) _
                         & vbTab & _
                         obj_DC.Get("OperatingSystem") & vbTab & _
                         obj_DC.Get("OperatingSystemServicePack") & _
                         vbTab & _
                         arr_ModoDominios(int_Dominio)
                             
        'Mostramos la misma información por pantalla
        WScript.Echo "============================================" & _
                     "================="
        WScript.Echo "Dominio: " & arr_FQDNDominios(int_Dominio) 
        WScript.Echo "Modo: " & arr_ModoDominios(int_Dominio)
        WScript.Echo "DC: " & Left(obj_DC.Get("sAMAccountName"), _
                      Len(obj_DC.Get("sAMAccountName")) - 1)
        WScript.Echo "Catalogo Global: " & _
                      f_GC(Left(obj_DC.Get("sAMAccountName"), _
                           Len(obj_DC.Get("sAMAccountName")) - 1))
        WScript.Echo "Sistema Operativo: " & _
                                obj_DC.Get("OperatingSystem")
        WScript.Echo "Service Pack: " & _
                         obj_DC.Get("OperatingSystemServicePack")
        WScript.Echo "=============================================" & _
                     "================"
        WScript.Echo ""
                             

    Next

    'Ahora debemos hacer llamadas recursivas a las OUs que contenga la
    'OU recibida como parámetro. Comenzamos filtrando la OU para
    'obtener las OUs que contiene
    obj_OU.Filter = Array("organizationalUnit")

    'Recorremos las SubOUs
    For Each obj_SubOU In obj_OU

        'Realizamos la llamada recursiva con la SubOU actual
        Call s_ListarDCsOU(obj_SubOU.Get("distinguishedName"))

    Next
    

End Sub 's_ListarDCsOU

Function f_ArrDominios()
'***********************************************************************
'* Procedimiento: f_ArrDominios                                        *
'* Tipo         : Función                                              *
'* Devolución   : Array de cadenas                                     *
'* Fecha y Hora : 15/01/2010 9:56:11                                   *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función obtiene los nombres de los dominio que  *
'*                integran el bosque al que pertenece el equipo desde  *
'*                el que se lanza. Genera un array con los nombres     *
'*                distinguidos de los dominios, otro con los nombres   *
'*                FQDN, otro con los modos de funcionamiento y         *
'*                devuelve un array con los nombres NetBios.           *
'***********************************************************************

    Dim str_Dominios
    Dim str_Padre
    Dim str_DN
    Dim str_Canonico
    Dim str_DNDominios
    Dim str_FQDNDominios
    Dim str_Modo
    Dim str_ModoDominios
    Dim str_RID
    Dim str_PDC
    Dim str_Infraestructura
    Dim obj_RootDSE
    Dim obj_Padre
    Dim str_Base
    Dim str_Filtro
    Dim str_Atributos
    Dim str_Ambito
    Dim ado_Conexion
    Dim ado_RS
    
    'Conectamos con la raíz DSE
    Set obj_RootDSE = GetObject("LDAP://RootDSE")

    'Obtenemos el nombre distiguido del contenedor de particiones del
    'bosque
    str_Base = "<LDAP://cn=Partitions," & _
               obj_RootDSE.Get("ConfigurationNamingContext") & ">;"

    'Sólo nos traeremos los objetos crossRef que cumplan un
    'systemFlags 3; esto significa que cumple con:
    '    * Tiene el bit 1: el objeto está en el contexto de nombres
    '                      NTDS
    '    * Tiene el bit 3: el objeto es un dominio
    str_Filtro  = "(&(objectcategory=crossRef)(systemFlags=3));"
    
    'Nos traeremos su nombre, el del objeto en el que está contenido
    'y su nombre distinguido
    str_Atributos   = "name,trustParent,distinguishedName;"
    str_Ambito   = "onelevel"

    'Creamos una conexión ADODB
    Set ado_Conexion = CreateObject("ADODB.Connection")
    
    'Establecemos el proveedor de Active Directory
    ado_Conexion.Provider = "ADsDSOObject"
    
    'Abrimos la conexión
    ado_Conexion.Open "Active Directory Provider"
    
    'Creamos un Recordset montando la consulta
    Set ado_RS = ado_Conexion.Execute(str_Base & str_Filtro & _
                                      str_Atributos & str_Ambito)

    'Nos movemos al primer registro del recordset
    ado_RS.MoveFirst

    'Recorremos el Recordset
    While Not ado_RS.EOF 

        'Vaciamos los valores de una vuelta anterior
        str_Padre = ""
        str_DN = ""
        str_Canonico = ""
        str_Modo = ""
        str_RID = ""
        str_PDC = ""
        str_Infraestructura = ""

        'Agregamos el dominio actual a la variable que va
        'almacenándolos en valores separados por comas (al ser nombres
        'NetBios no pueden tener comas)
        str_Dominios = str_Dominios & ado_RS.Fields("name").Value & ","

        'Si el dominio es un dominio hijo
        If ado_RS.Fields("trustParent").Value <> "" Then

            'Obtenemos el objeto con el dominio padre
            Set obj_Padre = GetObject("LDAP://" & _
                                    ado_RS.Fields("trustParent").Value)
            
            'Obtenemos el nombre NetBios del padre
            str_Padre = Right(obj_Padre.Name,Len(obj_Padre.Name) - 3)
            
            'Vaciamos el objeto con el padre
            Set obj_Padre = Nothing

        End If

        'Obtenemos ele nombre distinguido del dominio
        str_DN = f_NTaDN(ado_RS.Fields("name").Value & "\","")
        
        'Lo agregamos a la variable con los nombres distinguidos
        'separados por punto (al ser nombres distinguidos no pueden
        'contener con puntos)
        str_DNDominios = str_DNDominios & str_DN & "."

        'Obtenemos ele nombre canónico del dominio
        str_Canonico = f_DNaCanonico(str_DN,"")
        
        'Le quitamos la barra de división final del nombre canónico, con
        'lo que tendremos el nombre FQDN
        str_Canonico = Left(str_Canonico,Len(str_Canonico) - 1)
        
        'Agregamos el nombre a la variable con los FQDNs de los
        'dominios separados por coma
        str_FQDNDominios = str_FQDNDominios & str_Canonico & ","
        
        'Obtenemos el modo de funcionamiento del dominio
        str_Modo = f_ModoAD(str_Canonico)
        
        'Agregamos el modo a la variable que los contiene separados
        'por comas
        str_ModoDominios = str_ModoDominios & str_Modo & ","

        'Obtenemos los nombres NetBios de los controladores de dominio
        'del dominio que ostentan los roles FSMO a nivel de dominio
        Call s_RolesDominio(str_DN,str_RID,str_PDC,str_Infraestructura)
   
        'Escribimos en el fichero del listado de DCs los datos
        'obtenidos
        obj_Dominios.WriteLine str_Canonico & vbTab & _
                               ado_RS.Fields("name").Value & vbTab & _
                               str_Modo & vbTab & _
                               str_Padre & vbTab & _
                               str_DN & vbTab & _
                               str_MaestroEsquema & vbTab & _
                               str_MaestroNombres & vbTab & _
                               str_PDC & vbTab & _
                               str_RID & vbTab & _
                               str_Infraestructura

       
        ado_RS.MoveNext

    wend

    'Quitamos a las variables de almacenamiento el separador de
    'registros final (comas o punto), pues sobra
    str_Dominios = Left(str_Dominios,Len(str_Dominios) - 1)
    str_DNDominios = Left(str_DNDominios,Len(str_DNDominios) - 1)
    str_FQDNDominios = Left(str_FQDNDominios,Len(str_FQDNDominios) - 1)
    str_ModoDominios = Left(str_ModoDominios,Len(str_ModoDominios) - 1)

    'Obtenemos los arrays de nombres distinguidos, nombres FQDNS
    'y modos de dominios
    arr_DNDominios = Split(str_DNDominios,".")
    arr_FQDNDominios = Split(str_FQDNDominios,",")
    arr_ModoDominios = Split(str_ModoDominios,",")

    'La función devuelve el array de nombres NetBios
    f_ArrDominios = Split(str_Dominios,",")

End Function 'f_ArrDominios

Function f_GC(str_DC)
'***********************************************************************
'* Procedimiento: f_GC                                                 *
'* Tipo         : Función                                              *
'* Devolución   : Cadena                                               *
'* Fecha y Hora : 15/01/2010 9:58:37                                   *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función recibe el nombre distinguido de un DC   *
'*                y mira si es o no catálogo global, devolviendo Sí    *
'*                en caso afirmativo y No en caso negativo.            *
'***********************************************************************

    Const NTDSDSA_OPT_IS_GC = 1

    Dim obj_RootDSE
    Dim str_DNServicioDS
    Dim obj_RaizDS
    Dim int_Opciones

    On Error Resume Next

    Set obj_RootDSE = GetObject("LDAP://" & str_DC & "/rootDSE")
    str_DNServicioDS = obj_RootDSE.Get("dsServiceName")
    Set obj_RaizDS  = GetObject("LDAP://" & str_DC & "/" & _
                                  str_DNServicioDS)
    int_Opciones = obj_RaizDS.Get("options")
 
    If (int_Opciones And NTDSDSA_OPT_IS_GC) = NTDSDSA_OPT_IS_GC Then

        f_GC = "Sí"

    Else

       f_GC = "No"

    End If

    On Error Goto 0

End Function 'f_GC 

Function f_NTaDN(str_RutaNT, str_DN)
'***********************************************************************
'* Procedimiento: f_NTaDN                                              *
'* Tipo         : Función                                              *
'* Devolución   : Cadena                                               *
'* Fecha y Hora : May 2007                                             *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función recibe o bien el nombre NT              *
'*                ("dominionombre"), como primer parámetro, de un      *
'*                objeto de dominio y devuelve el nombre distinguido   *
'*                de ese objeto, o bien el nombre distinguido de un    *
'*                objeto, como segundo parámetro, y devuelve el        *
'*                nombre NT.                                           *
'*                Basada en el código de Richard Mueller, MVP de       *
'*                Scripting y ADSI (http://www.rlmueller.net)          *
'***********************************************************************

    'Constantes para el objeto NameTranslate
    Const ADS_NAME_INITTYPE_GC = 3
    Const ADS_NAME_TYPE_NT4 = 3
    Const ADS_NAME_TYPE_1779 = 1

    Dim obj_TraductorDeNombres
    Dim int_De, int_A,str_Nombre

    If  Len(str_RutaNT) > 0 Then

        int_De = ADS_NAME_TYPE_NT4
        int_A = ADS_NAME_TYPE_1779
        str_Nombre = str_RutaNT

    ElseIf Len(str_DN) > 0 Then

        int_De = ADS_NAME_TYPE_1779
        int_A = ADS_NAME_TYPE_NT4
        str_Nombre = str_DN

    Else

        WScript.Echo "Error 1 en f_DNaCanonico: No se ha pasado " & _
                     "ningún nombre para traducir."
        Exit Function
    End If
    'Creamos el objeto NameTranslate.
    Set obj_TraductorDeNombres = CreateObject("NameTranslate")

    On Error Resume Next

    'Lo iniciamos localizando el catálogo global
    obj_TraductorDeNombres.Init ADS_NAME_INITTYPE_GC, ""

    'Establecemos el parámetro de nombre en el traductor de nombres
    obj_TraductorDeNombres.Set int_De, str_Nombre

    'Usamos el método Get del traductor de nombres para obtener el
    'nombre traducido
    f_NTaDN = obj_TraductorDeNombres.Get(int_A)

    'Limpieza de kks :-)
    Set obj_TraductorDeNombres = Nothing

    On Error GoTo 0

End Function 'f_NTaDN

Function f_DNaCanonico(str_DN, str_Canonical)
'***********************************************************************
'* Procedimiento: f_DNaCanonico                                        *
'* Tipo         : Función                                              *
'* Devolución   : Cadena                                               *
'* Fecha y Hora : May 2007                                             *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función recibe o bien el nombre ditinguido,     *
'*                como primer parámetro, de un objeto de dominio y     *
'*                devuelve el nombre canonico de ese objeto, o bien    *
'*                recibe el nombre canonico de un objeto, como segundo *
'*                parámetro, y devuelve el nombre distinguido          *
'*                                                                     *
'*                Basada en el código de Richard Mueller, MVP de       *
'*                Scripting y ADSI (http://www.rlmueller.net)          *
'***********************************************************************

    'Constantes para el objeto NameTranslate
    Const ADS_NAME_INITTYPE_GC = 3
    Const ADS_NAME_TYPE_CANONICAL = 2
    Const ADS_NAME_TYPE_1779 = 1

    Dim obj_TraductorDeNombres
    Dim int_De, int_A,str_Nombre

    'Si hemos recibido el nombre distinguido la traducción
    'será de distinguido a canonico
    If  Len(str_DN) > 0 Then

        int_De = ADS_NAME_TYPE_1779
        int_A = ADS_NAME_TYPE_CANONICAL
        str_Nombre = str_DN

    'Si hemos recibido el nombre canonico, la traducción
    'será de canónico a distinguido
    ElseIf Len(str_Canonical) > 0 Then

        int_De = ADS_NAME_TYPE_CANONICAL
        int_A = ADS_NAME_TYPE_1779
        str_Nombre = str_Canonical

    'Si no hemos recibido parámetros la función dará un error
    'y se terminará
    Else

        WScript.Echo "Error 1 en f_NTaDN: No se ha pasado " & _
                     "ningún nombre para traducir."
        Exit Function
    End If
    
    'Creamos el objeto NameTranslate.
    Set obj_TraductorDeNombres = CreateObject("NameTranslate")

    On Error Resume Next

    'Lo iniciamos localizando el catálogo global
    obj_TraductorDeNombres.Init ADS_NAME_INITTYPE_GC, ""

    'Establecemos el parámetro de nombre en el traductor de nombres
    obj_TraductorDeNombres.Set int_De, str_Nombre

    'Usamos el método Get del traductor de nombres para obtener el
    'nombre traducido
    f_DNaCanonico = obj_TraductorDeNombres.Get(int_A)

    'Limpieza de kks :-)
    Set obj_TraductorDeNombres = Nothing

    On Error GoTo 0

End Function 'f_NTaDN

Function f_ModoAD(str_DN)
'***********************************************************************
'* Procedimiento: f_ModoAD                                             *
'* Tipo         : Función                                              *
'* Devolución   : Cadena                                               *
'* Fecha y Hora : 15/01/2010 10:00:31                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función recibe el nombre distinguido de un      *
'*                dominio y devuelve el modo de funcionamiento del     *
'*                mismo                                                *
'***********************************************************************

    Const DS_BEHAVIOR_WIN2000 = 0
    Const DS_BEHAVIOR_WIN2003_WITH_MIXED_DOMAINS = 1
    Const DS_BEHAVIOR_WIN2003 = 2
    Const DS_BEHAVIOR_WIN2008 = 3
    Const DS_BEHAVIOR_WIN2008R2 = 4

    Dim obj_Dominio
    Dim int_Modo

    'Obtenemos el objeto del dominio
    Set obj_Dominio = GetObject("LDAP://" & str_DN)
    obj_Dominio.GetInfo

    On Error Resume Next

    'Obtenemos el modo del dominio
    int_Modo = obj_Dominio.Get("msDS-Behavior-Version")

    If Err.Number <> 0 Then

        int_Modo = DS_BEHAVIOR_WIN2000
        Err.Clear

    End If

    On Error Goto 0

    WScript.Echo "Dominio revisando modo: " &  obj_Dominio.Name

    Select Case int_Modo

        Case DS_BEHAVIOR_WIN2000

            If obj_Dominio.Get("nTMixedDomain") = 1 Then

                f_ModoAD = "2000 Mixto"

            Else

                f_ModoAD = "2000 Nativo"

            End If

        Case DS_BEHAVIOR_WIN2003_WITH_MIXED_DOMAINS

            f_ModoAD = "2003 Provisional"

        Case DS_BEHAVIOR_WIN2003

            f_ModoAD = "2003 Nativo"

        Case DS_BEHAVIOR_WIN2008

            f_ModoAD = "2008 Nativo"

        Case DS_BEHAVIOR_WIN2008R2

            f_ModoAD = "2008 R2 Nativo"

    End Select

    Set obj_Dominio = Nothing

End Function 'f_ModoAD

Sub s_RolesForest(str_Esquema,str_DomainName)
'***********************************************************************
'* Procedimiento: s_RolesForest                                        *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 10:06:11                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene los nombres de los DC del        *
'*                bosque con los roles maestro de esquema y maestro    *
'*                de nombres. Los nombres obtenidos serán almacenados  *
'*                en las variables de salida str_Esquema y             *
'*                str_DomainName                                       *
'***********************************************************************

    Dim obj_RootDSE
    Dim obj_Esquema
    Dim str_MaestroDeEsquema
    Dim obj_NTDS
    Dim obj_DC
    Dim obj_Particiones
    Dim str_MaestroDeNombresDeDominio

    Set obj_RootDSE = GetObject("LDAP://rootDSE")
 
    Set obj_Esquema = GetObject _
        ("LDAP://" & obj_RootDSE.Get("schemaNamingContext"))
    str_MaestroDeEsquema = obj_Esquema.Get("fSMORoleOwner")
    Set obj_NTDS = GetObject("LDAP://" & str_MaestroDeEsquema)
    Set obj_DC = GetObject(obj_NTDS.Parent)
    str_Esquema = Right(obj_DC.Name,Len(obj_DC.Name) - 3)
 
    Set obj_NTDS = Nothing
    Set obj_DC = Nothing
 
    Set obj_Particiones = GetObject("LDAP://CN=Partitions," & _ 
        obj_RootDSE.Get("configurationNamingContext"))
    str_MaestroDeNombresDeDominio = obj_Particiones.Get("fSMORoleOwner")
    Set obj_NTDS = GetObject("LDAP://" & str_MaestroDeNombresDeDominio)
    Set obj_DC = GetObject(obj_NTDS.Parent)

    str_DomainName = Right(obj_DC.Name,Len(obj_DC.Name) - 3)


End Sub 's_RolesForest

Sub s_RolesDominio(str_DNDominio,str_RID,str_PDC,str_Infraestructura)
'***********************************************************************
'* Procedimiento: s_RolesDominio                                       *
'* Tipo         : Función                                              *
'* Devolución   : Booleana                                             *
'* Fecha y Hora : 15/01/2010 10:08:59                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene los nombres de los DC del        *
'*                dominio con los roles maestro RID y maestro de       *
'*                infraestructura y emulador PDC. Los nombres          *
'*                obtenidos serán almacenados en las variables de      *
'*                salida str_RID, str_PDC y str_Infraestructura        *
'***********************************************************************

    Dim obj_Dominio
    Dim str_EmuladorPDC
    Dim obj_NTDS
    Dim obj_DC
    Dim obj_AdministradorRID
    Dim str_MaestroRID
    Dim obj_Infraestructura
    Dim str_MaestroDeInfraestructura

    'Obtenemos el objeto del dominio
    Set obj_Dominio = GetObject ("LDAP://" & str_DNDominio)
    
    'Obtenemos el objeto de pr
    str_EmuladorPDC = obj_Dominio.Get("fSMORoleOwner")
    Set obj_NTDS = GetObject("LDAP://" & str_EmuladorPDC)
    Set obj_DC = GetObject(obj_NTDS.Parent)
    str_PDC = Right(obj_DC.Name,Len(obj_DC.Name) - 3)
 
    Set obj_AdministradorRID = GetObject( _
                 "LDAP://CN=RID Manager$,CN=System," & str_DNDominio)
    str_MaestroRID = obj_AdministradorRID.Get("fSMORoleOwner")
    Set obj_NTDS = GetObject("LDAP://" & str_MaestroRID)
    Set obj_DC = GetObject(obj_NTDS.Parent)
    str_RID = Right(obj_DC.Name,Len(obj_DC.Name) - 3)
 
    Set obj_Infraestructura = GetObject( _
                          "LDAP://CN=Infrastructure," & str_DNDominio)
    str_MaestroDeInfraestructura = _
                              obj_Infraestructura.Get("fSMORoleOwner")
    Set obj_NTDS = GetObject("LDAP://" & str_MaestroDeInfraestructura)
    Set obj_DC = GetObject(obj_NTDS.Parent)
    str_Infraestructura = Right(obj_DC.Name,Len(obj_DC.Name) - 3)

End Sub 's_RolesDominio

Sub s_ListarBuzones(str_DNDominio, int_Dominio)
'***********************************************************************
'* Procedimiento: s_ListarBuzones                                      *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 10:12:17                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene un listado, en formato tabla,    *
'*                de los buzones pertenecientes al dominio cuyo        *
'*                nombre distinguido es el recibido en el parámetro    *
'*                str_DNDominio, y su índice en los arrays de          *
'*                dominios es el recibido en el parámetro              *
'*                int_Dominio. El listado es volcado a al fichero de   *
'*                buzones.                                             *
'***********************************************************************

    Dim ado_Conexion
    Dim ado_Comando
    Dim ado_RS
    Dim obj_Usuario
    Dim str_HomeMDB
    Dim str_HomeServer
    
     'Creamos una conexión ADODB
    Set ado_Conexion = CreateObject("ADODB.Connection")
    Set ado_Comando =   CreateObject("ADODB.Command")
    
    'Establecemos el proveedor de Active Directory
    ado_Conexion.Provider = "ADsDSOObject"
    
    'Abrimos la conexión
    ado_Conexion.Open "Active Directory Provider"
    Set ado_Comando.ActiveConnection = ado_Conexion
    ado_Comando.CommandText = _
            "<LDAP://" & str_DNDominio & ">;(&(&(& (mailnickname=*)" & _
            " (| (&(objectCategory=person)(objectClass=user)(|(home" & _
            "MDB=*)(msExchHomeServerName=*))) ))))" & _
            ";adspath;subtree"
    ado_Comando.Properties("Page Size") = 100
    
    'Creamos un Recordset montando la consulta
    Set ado_RS = ado_Comando.Execute

    'Nos movemos al primer registro del recordset
    If Not ado_RS.EOF Then ado_RS.MoveFirst

    'Recorremos el Recordset
    While Not ado_RS.EOF 
    
        Set obj_Usuario = GetObject(ado_RS.Fields("adspath").Value)
        str_HomeMDB = ""
        str_HomeServer = ""
        
        On Error Resume Next

        str_HomeMDB = obj_Usuario.Get("homeMDB")
        str_HomeServer = obj_Usuario.Get("msExchHomeServerName")

        If Err.Number = 0 Then

            obj_Buzones.WriteLine _
                        arr_FQDNDominios(int_Dominio) & vbTab & _
                        arr_Dominios(int_Dominio) & vbTab & _
                        str_HomeMDB & vbTab & _
                        str_HomeServer & vbTab & _
                        obj_Usuario.Get("displayName") & vbTab & _
                        obj_Usuario.Get("distinguishedName")

        End If

        Err.Clear
        On Error Goto 0

        ado_RS.MoveNext

    Wend

End Sub 's_ListarBuzones

Sub s_ListarContactos(str_DNDominio, int_Dominio)
'***********************************************************************
'* Procedimiento: s_ListarContactos                                    *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 11:11:23                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene un listado, en formato tabla,    *
'*                de los contactos pertenecientes al dominio cuyo      *
'*                nombre distinguido es el recibido en el parámetro    *
'*                str_DNDominio, y su índice en los arrays de          *
'*                dominios es el recibido en el parámetro              *
'*                int_Dominio. El listado es volcado al fichero de     *
'*                contactos.                                           *
'***********************************************************************

    Dim ado_Conexion
    Dim ado_Comando
    Dim ado_RS
    Dim obj_Usuario
    
     'Creamos una conexión ADODB
    Set ado_Conexion = CreateObject("ADODB.Connection")
    Set ado_Comando =   CreateObject("ADODB.Command")
    
    'Establecemos el proveedor de Active Directory
    ado_Conexion.Provider = "ADsDSOObject"
    
    'Abrimos la conexión
    ado_Conexion.Open "Active Directory Provider"
    Set ado_Comando.ActiveConnection = ado_Conexion
    ado_Comando.CommandText = _
        "<LDAP://" & str_DNDominio & ">;(&(&(& (mailnickname=*) " & _
            "(| (&(objectCategory=person)(objectClass=contact)) " & _
            "))))" & _
        ";adspath;subtree"
    ado_Comando.Properties("Page Size") = 100
    
    'Creamos un Recordset montando la consulta
    Set ado_RS = ado_Comando.Execute

    'Nos movemos al primer registro del recordset
    If Not ado_RS.EOF Then ado_RS.MoveFirst

    'Recorremos el Recordset
    While Not ado_RS.EOF 
    
        Set obj_Usuario = GetObject(ado_RS.Fields("adspath").Value)

        obj_Contactos.WriteLine _
                           arr_FQDNDominios(int_Dominio) & vbTab & _
                           arr_Dominios(int_Dominio) & vbTab & _
                           obj_Usuario.Get("displayName") & vbTab & _
                           obj_Usuario.Get("mailNickName") & vbTab & _
                           obj_Usuario.Get("distinguishedName")
        ado_RS.MoveNext

    Wend

End Sub 's_ListarContactos

Sub s_ListarListas(str_DNDominio, int_Dominio)
'***********************************************************************
'* Procedimiento: s_ListarListas                                       *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 11:12:36                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene un listado, en formato tabla,    *
'*                de las listas de distribución pertenecientes al      *
'*                dominio cuyo nombre distinguido es el recibido en    *
'*                el parámetro str_DNDominio, y su índice en los       *
'*                arrays de dominios es el recibido en el parámetro    *
'*                int_Dominio. El listado es volcado al fichero de     *
'*                listas.                                              *
'***********************************************************************

    Dim ado_Conexion
    Dim ado_Comando
    Dim ado_RS
    Dim obj_Grupo
    
     'Creamos una conexión ADODB
    Set ado_Conexion = CreateObject("ADODB.Connection")
    Set ado_Comando =   CreateObject("ADODB.Command")
    
    'Establecemos el proveedor de Active Directory
    ado_Conexion.Provider = "ADsDSOObject"
    
    'Abrimos la conexión
    ado_Conexion.Open "Active Directory Provider"
    Set ado_Comando.ActiveConnection = ado_Conexion
    ado_Comando.CommandText = _
        "<LDAP://" & str_DNDominio &  ">;" & _
        "(&(&(& (mailnickname=*) (| (objectCategory=group) ))))" & _
        ";adspath;subtree"
    ado_Comando.Properties("Page Size") = 100
    
    'Creamos un Recordset montando la consulta
    Set ado_RS = ado_Comando.Execute

    'Nos movemos al primer registro del recordset
    If Not ado_RS.EOF Then ado_RS.MoveFirst

    'Recorremos el Recordset
    While Not ado_RS.EOF 
    
        Set obj_Grupo = GetObject(ado_RS.Fields("adspath").Value)

        obj_Listas.WriteLine _
                     arr_FQDNDominios(int_Dominio) & vbTab & _
                     arr_Dominios(int_Dominio) & vbTab & _
                     obj_Grupo.Name & vbTab & _
                     f_TipoGrupo(obj_Grupo.GroupType) & vbTab & _
                     obj_Grupo.Mail & vbTab & _
                     obj_Grupo.Info & vbTab & _
                     obj_Grupo.SAMAccountName & vbTab & _
                     obj_Grupo.Get("distinguishedName")
        ado_RS.MoveNext

    Wend

End Sub 's_ListarListas

Function f_TipoGrupo(int_Tipo)
'***********************************************************************
'* Procedimiento: f_TipoGrupo                                          *
'* Tipo         : Función                                              *
'* Devolución   : Booleana                                             *
'* Fecha y Hora : 15/01/2010 11:16:49                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función recive el valor del atributo GroupType  *
'*                de un objeto iADsGroup y devuelve una cadena con el  *
'*                tipo y ámbito del grupo (de seguridad local,         *
'*                distribución global, etc.)                           *
'***********************************************************************

    Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
    Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
    Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
    Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000

    Dim str_Tipo
    Dim str_Ambito
    
    'Averiguamos primero el ámbito
    If int_Tipo AND ADS_GROUP_TYPE_LOCAL_GROUP Then

        str_Ambito = "Dominio local"

    ElseIf int_Tipo AND ADS_GROUP_TYPE_GLOBAL_GROUP Then

        str_Ambito = "Global"

    ElseIf int_Tipo AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then

        str_Ambito = "Universal"

    Else

        str_Ambito = "Desconocido"

    End If

    'Averiguamos ahora el tipo
    If int_Tipo AND ADS_GROUP_TYPE_SECURITY_ENABLED Then

        str_Tipo = "Seguridad"

    Else

        str_Tipo = "Distribución"

    End If
    
    'Devolvemos el resultado
    f_TipoGrupo = str_Tipo & " - " & str_Ambito

End Function 'f_TipoGrupo

Function f_RevisarArgumentos( _
                             str_Error, _
                             int_Error _
                             ) 'As Boolean
'***********************************************************************
'* Procedimiento: f_RevisarArgumentos                                  *
'* Tipo         : Función                                              *
'* Devolución   : Booleana                                             *
'* Fecha y Hora : 15/01/2010 11:22:48                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Esta función revisa los argumentos recibidos,        *
'*                recogiendo los posibles fallos por falta de          *
'*                argumentos requeridos y almacenando en las           *
'*                variables correspondientes los argumentos            *
'*                recibidos. recibe dos parámetros cuyo fin es ser de  *
'*                salida: una cadena que almacenará los errores        *
'*                detectados y un entero que almacenará el código de   *
'*                los errores detectados. Hay tres tipos de error;     *
'*                error 1 para los argumentos sin nombre requeridos y  *
'*                no encontrados, error 2 para los argumentos con      *
'*                nombre requeridos y no encontrados, por último,      *
'*                error 4 para los combos de argumentos opcionales     *
'*                (un combo de argumentos opcionales es aquel          *
'*                conjunto de argumentos opcionales que es requerido   *
'*                que se pase al menos uno de ellos y que si se pasa   *
'*                más de uno se ignorarán aquellos que estén detrás    *
'*                en la prioridad entre ellos; una característica      *
'*                clara de lo que es un combo de argumentos es cuando  *
'*                dos omás argumentos almacenan su valor en la misma   *
'*                variable). En el caso de producirse más de un tipo   *
'*                de error, el número de error será la suma de ambos   *
'*                de los errores recibidos, es decir 3, 5 o 6          *
'***********************************************************************

    Dim bol_Devolucion 'As Boolean
    Dim bol_Error1 'As Boolean
    Dim bol_Error2 'As Boolean
    Dim bol_Error4 'As Boolean

    'Iniciamos los indicadores
    bol_Devolucion = False
    bol_Error1 = False
    bol_Error2 = False
    bol_Error4 = False


    'Si hay que mostrar la ayuda, se muestra y
    'termina el script
    If WScript.Arguments.Named.Exists("?") Then

        Call s_Ayuda("******************" & vbCrLf & _
                     "*     AYUDA      *" & vbCrLf & _
                     "******************")

        WScript.Quit 0

    End If

    'Revisamos que esté el argumento requerido 
    '/C (Carpeta)
    If WScript.Arguments.Named.Exists("C") Then

        str_Ruta =  _
               WScript.Arguments.Named("C")

        If Not Right(str_Ruta,1) = "\" Then _
                str_Ruta = str_Ruta & "\"


    Else

        str_Error = str_Error & vbcrlf & _
                    "Error 2, falta argumento " & _
                    "requerido con nombre: " & _
                    "/C (Carpeta)" & vbCrLf
        bol_Error2 = True

    End If

    'Preparamos las variables de devolucion:
    'el entero como suma de los posibles errores 1, 2 y 4
    int_Error = Abs(bol_Error1) + _
                (2 * Abs(bol_Error2)) + _
                (4 * Abs(bol_Error4))
    'La devolucion de la función será True en caso de
    'haber alguno de los errores
    bol_Devolucion = (bol_Error1 Or bol_Error2 Or bol_Error4)

    'Hacemos la devolución de la función
    f_RevisarArgumentos = bol_Devolucion

End Function 'f_RevisarArgumentos

Sub s_Ayuda(str_Error)
'***********************************************************************
'* Procedimiento: s_Ayuda                                              *
'* Tipo         : Sub                                                  *
'* Devolución   :                                                      *
'* Fecha y Hora : 18/01/2010 16:56:09                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este procedimiento muestra la ayuda en línea.        *
'*                Recibe un parámetro de tipo cadena que si viene      *
'*                será mostrado antes de la línea; pensado para que    *
'*                se muestre un error que se haya detectado.           *
'***********************************************************************

    'Si hay que mostrar algún texto previo a la ayuda, lo hacemos
    If Len(str_Error) > 0 Then

        WScript.Echo str_Error & vbCrLf & vbCrLf

    End If

    'A continuación, mostramos la ayuda por pantalla
    WScript.Echo "Este script genera una serie de ficheros de valor" & _
                 "es separados por tabulador"
    WScript.Echo "(ideales paa ser abiertos por Excel o importarlos" & _
                 " a una base de datos), con"
    WScript.Echo "información del bosque de Active Directory al que" & _
                 " pertenece el equipo desde el"
    WScript.Echo "que se lanza, así como información de Exchange. O" & _
                 "bviamente, la cuenta con la"
    WScript.Echo "que se ejecute debe tener permisos de lectura de " & _
                 "AD en los diferentes dominios"
    WScript.Echo "que conformen el bosque. El script crea los ficheros:"
    WScript.Echo ""
    WScript.Echo "- Dominios.tab: listado de los dominios del bosqu" & _
                 "e. El listado incluye el FQDN,"
    WScript.Echo "el nombre NetBios, el modo de funcionamiento, el " & _
                 "dominio padre, el nombre"
    WScript.Echo "distinguido, qué DC ostenta el rol de maestro de " & _
                 "esquema, el del maestro de"
    WScript.Echo "nombres, el del PDC, el del RID y el del maestro " & _
                 "de infraestructura."
    WScript.Echo "- Sitios.tab: listado de los sitios, sus controla" & _
                 "dores de dominio y las"
    WScript.Echo "conexiones que tienen. El listado incluye el nomb" & _
                 "re del sitio, el del"
    WScript.Echo "controlador de dominio de origen (el que está en " & _
                 "el sitio), el de la conexión,"
    WScript.Echo "si ésta está o no habilitada y el nombre del cont" & _
                 "rolador de dominio de destino."
    WScript.Echo "- DCs.tab: listado de los controladores de domini" & _
                 "o. El listado incluye, el"
    WScript.Echo "dominio al que pertenece, el nombre, si es catálo" & _
                 "go global, el sistema"
    WScript.Echo "operativo, el nivel de service pack y el modo de " & _
                 "funcionamiento del dominio."
    WScript.Echo "-OUs.tab: listado de las OUs de los dominios del " & _
                 "bosque. El listado incluye el"
    WScript.Echo "nombre FQDN del dominio, el nombre NetBios del do" & _
                 "minio, la ruta canónica al"
    WScript.Echo "contenedor padre, el nombre RDN de la OU y su nom" & _
                 "bre distinguido."
    WScript.Echo "- ErroresOUs.tab: Errores producidos al generarse" & _
                 " el listado de OUs."
    WScript.Echo "- Buzones.tab: listado con los buzones de Exchang" & _
                 "e que incluye el FQDN del"
    WScript.Echo "dominio, el nombre NetBios del dominio, la base d" & _
                 "e datos en la que está el"
    WScript.Echo "buzón, el servidor de Exchange donde está la base" & _
                 " de datos, el nombre para"
    WScript.Echo "mostrar del buzón y su nombre distinguido."
    WScript.Echo "- Contactos.tab: listado con los contactos que in" & _
                 "cluye el FQDN del dominio, el"
    WScript.Echo "nombre NetBios del dominio, el nombre para mostra" & _
                 "r del buzón, la dirección de"
    WScript.Echo "correo y su nombre distinguido."
    WScript.Echo "- Listas.tab: listado de las listas de distribuci" & _
                 "ón que incluye el FQDN del"
    WScript.Echo "dominio, el nombre NetBios del dominio, el nombre" & _
                 " de la lista, su tipo, la"
    WScript.Echo "dirección de correo, su información, su nombre pr" & _
                 "e-Windows 2000 y su nombre"
    WScript.Echo "distinguido."
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo "Sintaxis"
    WScript.Echo ""
    WScript.Echo "cscript [//nologo] documentar-AD.vbs /C:Carpeta [/?]"
    WScript.Echo ""
    WScript.Echo "Siendo"
    WScript.Echo ""
    WScript.Echo "- /C: Carpeta (Requerido):"
    WScript.Echo "Ruta y nombre de la carpeta en la que se guardará" & _
                 "n los ficheros"
    WScript.Echo "obtenidos al ejecutar el script."
    WScript.Echo ""
    WScript.Echo "- /?: ayuda (Opcional):"
    WScript.Echo "Muestra la ayuda en línea"
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo "Ejemplos:"
    WScript.Echo ""
    WScript.Echo "- Crea los ficheros con los listados en la carpet" & _
                 "a x:\tia\listados-AD:"
    WScript.Echo ""
    WScript.Echo "cscript //nologo documentar-AD.vbs /C:x:\tia\list" & _
                 "ados-AD"
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo ""

End Sub 's_Ayuda

Sub s_ListarSitios()
'***********************************************************************
'* Procedimiento: s_ListarSitios                                       *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 13:05:58                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene los sitios de Active Directory   *
'*                del bosque. Con cada uno de ellos, llama al método   *
'*                que obtiene los controladores de dominio del sitio   *
'***********************************************************************

    Dim obj_RDSE
    Dim str_NcConfiguracion
    Dim str_ContenedorSitios
    Dim obj_ContenedorSitios
    Dim obj_Sitio
                 
    'Obtenemos el objeto RootDSE del bosque
    Set obj_RDSE = GetObject("LDAP://RootDSE")
    
    'Averiguamos la ruta del contexto de configuración
    str_NcConfiguracion = obj_RDSE.Get("configurationNamingContext")
     
    'Montamos la ruta LDAP del contenedor de sitios
    str_ContenedorSitios = "LDAP://cn=Sites," & str_NcConfiguracion
    
    'Obtenemos el contenedor de sitios
    Set obj_ContenedorSitios = GetObject(str_ContenedorSitios)
    
    'Filtramos los objetos contenidos para obtener únicamente los sitios
    obj_ContenedorSitios.Filter = Array("site")
     
    'Recorremos los sitios
    For Each obj_Sitio In obj_ContenedorSitios

        'Mostramos el nombre del sitio en proceso
        WScript.Echo "Sitio en proceso: " & obj_Sitio.Name
    
        'Listamos los DCs ue hay en el sitio
        Call s_ListarDCs(obj_Sitio.Name)
        
    Next

    'Cerramos el fichero de sitios
    obj_Sitios.Close

    'Vaciamos su objeto TextStream
    Set obj_Sitios = Nothing

    'Ponemos una línea de separación
    WScript.Echo


End Sub 's_ListarSitios

Sub s_ListarDCs(str_CnSitio)
'***********************************************************************
'* Procedimiento: s_ListarDCs                                          *
'* Tipo         : Función                                              *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 13:07:45                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene los sitios controladores de      *
'*                dominio que hay en el sitio cuya ruta LDAP es la     *
'*                recibida como parámetro str_CnSitio                  *
'***********************************************************************

    Dim obj_RDSE
    Dim str_NcConfiguracion
    Dim str_RutaServidores
    Dim obj_ContenedorServidores
    Dim obj_Servidor

    'Obtenemos el objeto RootDSE del bosque
    Set obj_RDSE = GetObject("LDAP://RootDSE")
    
    'Averiguamos la ruta del contexto de configuración
    str_NcConfiguracion = obj_RDSE.Get("configurationNamingContext")
     
    'Montamos la ruta LDAP del contenedor de servidores
    str_RutaServidores = "LDAP://cn=Servers," & str_CnSitio & ",cn=Sites," & _
        str_NcConfiguracion
    
    'Obtenemos el contenedor de servidores
    Set obj_ContenedorServidores = GetObject(str_RutaServidores)
     
    'Recorremos los servidores
    For Each obj_Servidor In obj_ContenedorServidores
    
        'Listamos las conexiones del servidor
        Call s_ListarConexiones(str_CnSitio,obj_Servidor.Get("distinguishedName"))
        
    Next
    
End Sub 's_ListarDCs 


Sub s_ListarConexiones(str_RDNSitio,str_RDNDC)
'***********************************************************************
'* Procedimiento: s_ListarConexiones                                   *
'* Tipo         : Función                                              *
'* Devolución   : Booleana                                             *
'* Fecha y Hora : 15/01/2010 13:09:49                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método obtiene las conexiones del controlador   *
'*                de dominio cuyo RDN es el recibido por el parámetro  *
'*                str_RDNDC y que está en el sitio cuyo RDN es el      *
'*                parámetro str_RDNSitio. Las conexiones son volcadas  *
'*                en el fichero de sitios.                             *
'***********************************************************************

    Dim obj_RDSE
    Dim str_NcConfiguracion
    Dim str_RutaNTDSSettings
    Dim obj_NTDSSettings
    Dim obj_Conexion

    'Obtenemos el objeto RootDSE del bosque
    Set obj_RDSE = GetObject("LDAP://RootDSE")
    
    'Averiguamos la ruta del contexto de configuración
    str_NcConfiguracion = obj_RDSE.Get("configurationNamingContext")
     
    'Montamos la ruta LDAP de configuración de NTDS
    str_RutaNTDSSettings = "LDAP://cn=NTDS Settings," & str_RDNDC

    'Establecemos control de errores
    On Error Resume Next

    'Obtenemos el contenedor de configuración NTDS
    Set obj_NTDSSettings = GetObject(str_RutaNTDSSettings)
     
    'Si se ha producido algún error
    If Err.Number <> 0 Then

        'Vaciamos el objeto de errores
        Err.Clear
        
        'Devolvemos el control de errores a CSCRIPT
        On Error Goto 0
        
        'Salimos del método
        Exit Sub
 
    End If

    'Devolvemos el control de errores a CSCRIPT
    On Error Goto 0

    'Filtramos la configuración NTDS para que obtener sólo
    'las conexiones
    obj_NTDSSettings.Filter = Array("nTDSConnection")
     
    'Recorremos las conexiones 
    For Each obj_Conexion In obj_NTDSSettings

        'Guardamos en el fichero las conexiones
        obj_Sitios.WriteLine _
                     Right(str_RDNSitio, _
                           Len(str_RDNSitio) - 3) & vbTab & _
                     Right(Split(str_RDNDC,",")(0), _
                           Len(Split(str_RDNDC,",")(0)) - 3) & vbTab & _
                     obj_Conexion.Name & vbTab & _
                     obj_Conexion.enabledConnection & vbTab & _
                     Right(Split(obj_Conexion.fromServer, ",")(1), _
                           Len(Split(obj_Conexion.fromServer, _
                                     ",")(1)) - 3)
        
    Next

End Sub 's_ListarConexiones

Sub s_ListarOUs(str_Contenedor,int_Dominio)
'***********************************************************************
'* Procedimiento: s_ListarOUs                                          *
'* Tipo         : Método                                               *
'* Devolución   : Ninguna                                              *
'* Fecha y Hora : 15/01/2010 13:09:49                                  *
'* Autor        : Fernando Reyes                                       *
'*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
'* Propósito    : Este método lista todas las OUs que están en el      *
'*                contenedor cuyo nombre distinguido es pasado como    *
'*                parámetro. El listado es volcado en el fichero de    *
'*                OUs y una vez realizado se produce una llamada       *
'*                recursiva para listar las OUs contenidas en las OUs  *
'*                listadas. Recibe el índice del dominio en el que     *
'*                estan las OUs para poder así usar los arrays de FQDN *
'*                y NetBios.                                           *
'***********************************************************************

    Dim obj_Contenedor
    Dim obj_OU

    'Obtenemos el objeto contenedor de las OUs
    Set obj_Contenedor = GetObject("LDAP://" & str_Contenedor)

    'Filtramos por OUs
    obj_Contenedor.Filter = Array("organizationalUnit")

    'Recorremos las OUs
    For Each obj_OU In obj_Contenedor

       'Guardamos la información en el fichero
        obj_OUs.WriteLine arr_FQDNDominios(int_Dominio) & vbTab & _
                          arr_Dominios(int_Dominio) & vbTab & _
                          f_DNaCanonico(str_Contenedor,"") & vbTab & _
                          obj_OU.Name & vbTab & _
                          obj_OU.Get("distinguishedName")
                          
        'Llamada recursiva para listar las OUs que contiene la OU actual
        Call s_ListarOUs(obj_OU.Get("distinguishedName"),int_Dominio)

    Next 'obj_OU

End Sub 's_ListarOUs

 

 

4 comentarios to “Script VbScript para obtener información de un bosque de Active Directory”

  1. Aldo said

    Sr :urpiano

    Tengo un gran problema que no lo puedo solucionar quiero resolver este grupo BUILTIN\Usuarios ,NT AUTHORITY\SYSTEM, BUILTIN\Administradores,y no consigo convertir a un nombre distinguido con tu funcion f_NTaDN(str_RutaNT, str_DN) para poder asi tener los miemnros que pertenecen a este grupo y use su script para poder sacar los miembros que pertenecen a un grupo y tambien me da error …..

  2. ROSA MARIA said

    LA VEDAD SEA DICHA NO ME ENTERO DE NADA, NUNCA ME HABIA PASADO TAL COSA NO SE NI QUE PROGRAMA ME TIENEN PUESTO PORQUE NUNCA VISTO. TODO NUEVO PARA MI

  3. […] AD en los diferentes dominios que conformen el bosque. Se trata de una actualización de este otro script, y añade la información de equipos y usuarios, que en el anterior no era obtenida. El script crea […]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

 
A %d blogueros les gusta esto: