‘*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
‘*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
‘* caducidad-de-cuentas.vbs                                            *
‘*                                                                     *
‘* Este script permite listar todos los usuarios de un dominio,        *
‘* mostrando la fecha de expiración de su cuenta o si nunca expira. El *
‘* script permite especificar el nombre del dominio del que se         *
‘* listarán los usuario o listar los del dominio en el que está logado *
‘* el usuario que lo lanza. La lista obtenida puede ser mostrada por   *
‘* pantalla (predeterminado), volcada a un fichero de texto (separado  *
‘* por tabuladores) o volcarla en un libro Excel.                      *
‘*                                                                     *
‘* Sintaxis                                                            *
‘*                                                                     *
‘* cscript [//nologo] caducidad-de-cuentas.vbs[/dominio:dominio]       *
‘* [/txt:fichero] [/xls:libro]                                         *
‘*                                                                     *
‘* Siendo                                                              *
‘*                                                                     *
‘* – dominio (Opcional):                                               *
‘*         FQDN del dominio al que se conectará para listar los        *
‘*         usuarios (ej: minasmorgul.mordor.org). Si se omite, se      *
‘*         listará el dominio en el que está logado el usuario que     *
‘*         lanza el script.                                            *
‘*                                                                     *
‘* – fichero (Opcional):                                               *
‘*         Ruta y nombre del fichero de texto, separado por            *
‘*         tabuladores, al que se volcará el listado.                  *
‘*                                                                     *
‘* – libro (Opcional):                                                 *
‘*         Ruta y nombre del libro de Excel al que se volcará el       *
‘*         listado.                                                    *
‘*                                                                     *
‘* – ? (Opcional):                                                     *
‘*         Muestra la ayuda en línea.                                  *
‘*                                                                     *
‘*                                                                     *
‘* © Fernando Reyes                                                    *
‘* Julio De 2007                                                       *
‘*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
‘*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

‘Declaración de variables requerida
Option Explicit

Dim str_Error ‘As String
Dim int_Error ‘As String
Dim str_Dominio ‘As String
Dim str_TXT ‘As String
Dim str_XLS ‘As String
Dim obj_Conexion ‘As ADODB.Connection
Dim obj_Comando ‘As ADODB.Command
Dim rs_Usuarios ‘As ADODB.Recordset
Dim obj_Usuario ‘As Object
Dim str_Fecha ‘As String
Dim app_Excel ‘As Excel.Application
Dim wb_Libro ‘As Excel.Workbook
Dim ws_Hoja ‘As Excel.Worksheet
Dim obj_FS ‘As Scripting.Filesystemobject
Dim obj_TS ‘As Scripting.TextStream
Dim str_TS ‘As String
Dim arr_Dominio ‘As Variant
Dim lng_Linea ‘As Long

‘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 una conexión ADO
Set obj_Conexion = CreateObject("ADODB.Connection")

‘Establecemos el proveedor ADSI
obj_Conexion.Open "Provider=ADsDSOObject;"

‘Creamos un objeto comando
Set obj_Comando = CreateObject("ADODB.Command")

‘Establecemos que su conexión es la anteriormente
‘creada
obj_Comando.ActiveConnection = obj_Conexion

‘Establecemos propiedades de acceso a los datos
‘para evitar el límite de 1000 resultados que
‘tiene ADSI de forma predeterminada.
obj_Comando.Properties("Page Size") = 100
obj_Comando.Properties("Timeout") = 30
obj_Comando.Properties("Cache Results") = False

‘Establecemos la cadena de consulta
obj_Comando.CommandText = _
    "<GC://" & str_Dominio & ">;(objectCategory=User)" & _
        ";accountExpires,distinguishedName;subtree" 

‘Creamos el Recordset
Set rs_Usuarios = obj_Comando.Execute

‘Recorremos el recordset
Do Until rs_Usuarios.EOF

    ‘Creamos un objeto usuario con el proveedor LDAP,
    ‘usando el nombre distinguido obtenido de la consulta
    Set obj_Usuario = GetObject("LDAP://" & _
                     rs_Usuarios.Fields("distinguishedName"))

    ‘Establecemos control de errores
    On Error Resume Next

    ‘Obtenemos la fecha de caducidad
    str_Fecha = FormatDateTime( _
               obj_Usuario.AccountExpirationDate,vbShortDate)

    ‘Si se produce el error -2147467259 o la fecha devuelta
    ‘es igual o menor a 1/1/1970 la cuenta no caduca nunca
    If Err.Number = -2147467259 Or CDate(str_Fecha) <= _
        CDate(FormatDateTime("01/01/1970",vbShortDate)) Then

        str_Fecha = "No expira"

    End If

    ‘Una vez pasada la posibilidad de error, devolvemos el
    ‘control de errores al interprete de VBScript
    On Error Goto 0

    ‘Si se ha recibido parámetro de fichero de texto,
    ‘escribimos la línea correspondiente
    If Len(str_TXT) > 0 Then _
        obj_TS.WriteLine _
            rs_Usuarios.Fields("distinguishedName") & _
            vbTab & str_Fecha

    ‘Si se ha recibido parámetro de libro de excel…
    If Len(str_XLS) > 0 Then

        ‘Escribimos en la columna A el nombre del usuario
        ws_Hoja.Range("A" & lng_Linea).Value = _
                    rs_Usuarios.Fields("distinguishedName")  

        ‘Escribimos en la columna B su caducidad
        ws_Hoja.Range("B" & lng_Linea).Value = str_Fecha

        ‘Incrementamos el contador de líneas
        lng_Linea = lng_Linea + 1

    End If

    ‘Si no se hyan pasado ni fichero de texto ni libro de Excel
    ‘se mostrará la información en pantalla
    If Len(str_TXT) = 0 And Len(str_XLS) = 0 Then _
        WScript.echo rs_Usuarios.Fields("distinguishedName") & _
        vbTab & str_Fecha

    ‘Vamos al siguiente usuario
    rs_Usuarios.MoveNext

Loop

‘Fase de limpieza de bullarenga 🙂

‘Cerramos el recordset y vaciamos su variable
rs_Usuarios.Close
Set rs_Usuarios = Nothing

‘Cerramos la conexión y vaciamos las variables
‘de conexión y comando
obj_Conexion.Close
Set obj_Conexion = Nothing
Set obj_Comando = Nothing

‘Limpiamos si hay fichero de texto, cerrando
‘el fichero y vaciando los objetos TextStream
‘y FileSystemObject
If Len(str_TXT) > 0 Then

    obj_TS.Close
    Set obj_TS = Nothing
    Set obj_FS = Nothing

End If

‘Limpiamos si hay libro de Excel, salvando
‘el libro con el nombre recibido, vaciando
‘la variable de hoja, cerrando el libro,
‘vaciando la variable del libro, cerrando
‘la aplicación Excel y vaciando su variable
If Len(str_XLS) > 0 Then

    ‘Auto-ajustamos las columnas de la hoja
    ws_Hoja.Columns.Autofit

    wb_Libro.SaveAs str_XLS
    Set ws_Hoja = Nothing
    wb_Libro.Close
    Set wb_Libro = Nothing
    app_Excel.Quit
    Set app_Excel = Nothing

End If

Function f_RevisarArgumentos( _
                             str_Error, _
                             int_Error _
                             ) ‘As Boolean
‘***********************************************************************
‘* Procedimiento: f_RevisarArgumentos                                  *
‘* Tipo         : Función                                              *
‘* Devolución   : Booleana                                             *
‘* Fecha y Hora : 17/07/2007 13:03:36                                  *
‘* 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 dos tipos de error;      *
‘*                error 1 para los parámetros sin nombre requeridos y  *
‘*                error 2 para los parámetros con nombre requeridos.   *
‘*                En el caso de producirse ambos tipos de errores, el  *
‘*                número de error será la suma de ambos: 3             *
‘***********************************************************************

    Dim bol_Devolucion ‘As Boolean
    Dim bol_Error1 ‘As Boolean
    Dim bol_Error2 ‘As Boolean
    Dim int_SheetsInNewWorkBook ‘As Integer

    ‘Iniciamos los indicadores
    bol_Devolucion = False
    bol_Error1 = False
    bol_Error2 = False

    If WScript.Arguments.Named.Exists("?") Then

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

        WScript.Quit 0

    End If

    ‘Revisamos si ha sido pasado el argumento
    ‘/dominio (dominio)
    If WScript.Arguments.Named.Exists("dominio") Then

        arr_Dominio = Split( _
               WScript.Arguments.Named("dominio"),".")
        str_Dominio = "dc=" & Join(arr_Dominio,",dc=")

    ‘Si no se ha pasado lo obtenemos usando RootDSE
    Else

        Dim obj_RootDSE
        Set obj_RootDSE = GetObject("LDAP://RootDSE")

        str_Dominio = obj_RootDSE.Get("defaultNamingContext")

        Set obj_RootDSE = Nothing

    End If

    ‘Revisamos si ha sido pasado el argumento
    ‘/txt (fichero)
    If WScript.Arguments.Named.Exists("txt") Then

        str_TXT =  _
               WScript.Arguments.Named("txt")

        ‘Creamos el fichero de texto
        Set obj_FS = CreateObject("Scripting.FileSystemObject")
        Set obj_TS = obj_FS.CreateTextFile(str_TXT,True,False)                   

    End If

    ‘Revisamos si ha sido pasado el argumento
    ‘/xls (libro)
    If WScript.Arguments.Named.Exists("xls") Then

        str_XLS =  _
               WScript.Arguments.Named("xls")

        ‘Creamos un objeto aplicación de Excel
        Set app_Excel = CreateObject("Excel.Application")

        ‘Recogemos el número de hojas que tienen los libros
        ‘al ser creados
        int_SheetsInNewWorkBook = _
                               app_Excel.SheetsInNewWorkbook

        ‘Establecemos que sólo se cree una hoja al crear un
        ‘libro
        app_Excel.SheetsInNewWorkbook = 1

        ‘Creamos un libro
        Set wb_Libro = app_Excel.Workbooks.Add

        ‘Restauramos el número de hojas que tiene
        ‘un libro al ser creado
        app_Excel.SheetsInNewWorkbook = _
                               int_SheetsInNewWorkBook

        ‘Cargamos en la variable de hoja la única que
        ‘contiene el libro
        Set ws_Hoja = wb_Libro.Worksheets(1)

        ‘Establecemos el nombre de la hoja
        ws_Hoja.Name = "Usuarios – Caducidad"

        ‘Ponemos los encabezados de columna
        ws_Hoja.Range("A1").Value = "Usuario"
        ws_Hoja.Range("B1").Value = "Caducidad"

        ‘Establecemos la línea actual de la hoja
        lng_Linea = 2

    End If

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

    ‘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 : 17/07/2007 13:03:36                                  *
‘* Autor        : Fernando Reyes                                       *
‘*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
‘* Propósito    : Este procedimiento muestra la ayuda en línea.        *
‘*                Recibe un parámetro de tipo cadena que si no viene   *
‘*                será mostrado antes de la línea; pensado para que    *
‘*                se muestre un error que se haya detectado.           *
‘***********************************************************************

    If Len(str_Error) > 0 Then

        WScript.Echo str_Error & vbCrLf & vbCrLf

    End If

    WScript.Echo "Este script permite listar todos los usuarios de " & _
                 "un dominio, mostrando la fecha"
    WScript.Echo "de expiración de su cuenta o si nunca expira. El " & _
                 "script permite especificar el"
    WScript.Echo "nombre del dominio del que se listarán los usuari" & _
                 "o o listar los del dominio en"
    WScript.Echo "el que está logado el usuario que lo lanza. La li" & _
                 "sta obtenida puede ser"
    WScript.Echo "mostrada por pantalla (predeterminado), volcada a" & _
                 " un fichero de texto (separado"
    WScript.Echo "por tabuladores) o volcarla en un libro Excel."
    WScript.Echo ""
    WScript.Echo "Sintaxis"
    WScript.Echo ""
    WScript.Echo "cscript [//nologo] caducidad-de-cuentas.vbs[/domi" & _
                 "nio:dominio] [/txt:fichero]"
    WScript.Echo "[/xls:libro]"
    WScript.Echo ""
    WScript.Echo "Siendo"
    WScript.Echo ""
    WScript.Echo "- dominio (Opcional):"
    WScript.Echo "FQDN del dominio al que se conectará para listar " & _
                 "los usuarios"
    WScript.Echo "(ej: minasmorgul.mordor.org). Si se omite, se lis" & _
                 "tará el"
    WScript.Echo "dominio en el que está logado el usuario que lanz" & _
                 "a el script."
    WScript.Echo ""
    WScript.Echo "- fichero (Opcional):"
    WScript.Echo "Ruta y nombre del fichero de texto, separado por " & _
                 "tabuladores,"
    WScript.Echo "al que se volcará el listado."
    WScript.Echo ""
    WScript.Echo "- libro (Opcional):"
    WScript.Echo "Ruta y nombre del libro de Excel al que se volcar" & _
                 "á el listado."
    WScript.Echo ""

End Sub ‘s_Ayuda