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 Registrar Los Inicios Y Cierres De Sesión De Los Usuarios

Posted by urpiano en Viernes 25 \25\UTC abril \25\UTC 2008

Este script está ideado para registrar los inicios y cierres de sesión de los usuarios. A pesar de que se puede obtener los inicios de sesión por medio de una GPO, utilizando la auditoría de inicio de sesión de cuenta, esto no permite registrar el cierre de sesión y además es bastante incómodo el mirar estos datos en el visor de sucesos, si bien se pueden filtrar y exportar a un fichero CSV para después trabajar en Excel con ellos. Por ello, este script es interesante para obtener los datos ya filtrados y reunidos en un fichero.

Los resultados se almacenan en un fichero de valores separados por tabuladores, ideal para abrirse on Excel. Se puede especificar el nombre del fichero utilizando variables de entorno, lo que permite que se pueda crear un fichero por cada usuario, por ejemplo, para así no tener todos los inicios y cierres de sesión de todos los usuarios en un mismo fichero (cosa que también se puede si así se desea)

Para usarse desde una GPO, deberemos hacerlo en una GPO que afecte a las cuentas de usuario de las que queremos registrar sus inicios y cierres de sesión. Editando la GPO, en el panel del árbol, nos situamos en el nodo Configuración de usuario\Configuración de Windows\Secuencia de comandos(inicio de sesión/cierre de sesión); veremos en el panel de detalle las directivas Iniciar sesión y Cerrar sesión. Hacemos doble click en Iniciar sesión, pulsamos el botón Agregar…, en la caja de texto Nombre del archivo de comandos ponemos la ruta y nombre del script VBScript (la ruta deberá ser una ruta UNC, es decir una ruta de red, del tipo \\servidor\carpeta\registrar-sesion.vbs) y en la caja de texto Parámetros del archivo de comandos debemos poner el modificador /I más la ruta y nombre del archivo en el que se quieren guardar los inicios y cierres de sesión, encerrado entre comillas si contiene espacios (por ejemplo /I "\\servidor\carpeta$\Registro de sesiones\%username%.tsv"); pulsamos Aceptar y nuevamente Aceptar. Hacemos doble click en la directiva Cerrar sesión y repetimos los mismos pasos anteriores, poniendo todo igual, salvo en los parámetros del archivo de comandos, que suprimiremos el modificador /I(según el ejemplo anterior, quedaría así: "\\servidor\carpeta$\Registro de sesiones\%username%.tsv"). Para tener los registros centralizados, es conveniente que se guarden en una carpeta de red y, por tanto, es necesario que los usuarios tengan acceso de escritura en ella, por lo que convienen que sea compartida de manera oculta (que su nombre de recurso compartido termine con el carácter dolar "$").

Sintaxis

{wscript | cscript [//nologo]} registrar-sesion.vbs [/I] [/?] fichero

Siendo

Etiqueta Dato ¿Requerido? Descripción
  fichero
Nombre del fichero de valores separados por tabulador en el que se guarda la información. Se pueden incluir variables de entorno en el nombre, que serán sustituidas por su valor.
I inicio No
Indica si se trata de un inicio de sesión o no.
?   No
Muestra la ayuda en línea.

Ejemplos:

– Registra el inicio de sesión en el fichero “\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv”:

cscript //nologo registrar-sesion.vbs /I "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"

– Registra el cierre de sesión en el fichero “\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv”:

cscript //nologo registrar-sesion.vbs "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"

Este es el código del script

'*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
'*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
'* registrar-sesion.vbs                                                *
'*                                                                     *
'* Este script está ideado para registrar los inicios y cierres de     *
'* sesión de los usuarios. A pesar de que se puede obtener los inicios *
'* de sesión por medio de una GPO, utilizando la auditoría de inicio   *
'* de sesión de cuenta, esto no permite registrar el cierre de sesión  *
'* y además es bastante incómodo el mirar estos datos en el visor de   *
'* sucesos, si bien se pueden filtrar y exportar a un fichero CSV para *
'* después trabajar en Excel con ellos. Por ello, este script es       *
'* interesante para obtener los datos ya filtrados y reunidos en un    *
'* fichero.                                                            *
'*                                                                     *
'* Los resultados se almacenan en un fichero de valores separados por  *
'* tabuladores, ideal para abrirse con Excel. Se puede especificar el  *
'* nombre del fichero utilizando variables de entorno, lo que permite  *
'* que se pueda crear un fichero por cada usuario, por ejemplo, para   *
'* así no tener todos los inicios y cierres de sesión de todos los     *
'* usuarios en un mismo fichero (cosa que también se puede si así se   *
'* desea)                                                              *
'*                                                                     *
'* Sintaxis                                                            *
'*                                                                     *
'* {wscript | cscript [//nologo]} registrar-sesion.vbs [/I] [/?]       *
'* fichero                                                             *
'*                                                                     *
'* Siendo                                                              *
'*                                                                     *
'* - fichero (Requerido):                                              *
'*         Nombre del fichero de valores separados por tabulador en el *
'*         que se guarda la información. Se pueden incluir variables   *
'*         de entorno en el nombre, que serán sustituidas por su valor.*
'*                                                                     *
'* - /I: inicio (Opcional):                                            *
'*         Indica si se trata de un inicio de sesión o no.             *
'*                                                                     *
'*                                                                     *
'* Ejemplos:                                                           *
'*                                                                     *
'* - Registra el inicio de sesión en el fichero                        *
'*   "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv":               *
'*                                                                     *
'* wscript //nologo registrar-sesion.vbs /I                            *
'*   "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"                *
'*                                                                     *
'* - Registra el cierre de sesión en el fichero                        *
'*   "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv":               *
'*                                                                     *
'* cscript //nologo registrar-sesion.vbs                               *
'*         "\\sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"          *
'*                                                                     *
'*                                                                     *
'*                                                                     *
'*                                                                     *
'* © Fernando Reyes                                                    *
'* Octubre De 2007                                                     *
'*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
'*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

'Exigimos la declaración de variables
Option Explicit

'Constantes para el método OpenTextFile del objeto FileSystemObject
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Dim arr_Campos         'As String
Dim arr_Lineas         'As String
Dim bol_Encontrado     'As Boolean
Dim bol_InicioDeSesion 'As Boolean
Dim int_Error          'As String
Dim int_Linea          'As Integer
Dim obj_FS             'As Scripting.FileSystemObject
Dim obj_NW             'As IWshRuntimeLibrary.WshNetwork
Dim obj_SH             'As IWshRuntimeLibrary.WshShell
Dim obj_TS             'As Scripting.TextStream
Dim str_Equipo         'As String
Dim str_Error          'As String
Dim str_Fichero        'As String
Dim str_Linea          'As String
Dim str_Servidor       'As String
Dim str_Texto          'As String
Dim str_TSV            'As String
Dim str_Usuario        'As String

bol_InicioDeSesion = False


'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

Set obj_SH = CreateObject("WScript.Shell")
Set obj_NW = CreateObject("Wscript.Network")
Set obj_FS = CreateObject("Scripting.FileSystemObject")

'Obtenemos el nombre de usuario, del equipo en el que está
'y del servidor en el que se loga (en este último caso le
'quitamos el doble back-slash que lleva delante)
str_Usuario = obj_NW.UserName
str_Equipo = obj_NW.ComputerName
str_Servidor = Replace(obj_SH.ExpandEnvironmentStrings( _
                                "%LOGONSERVER%"), _
                       "\\", _
                       "")
                       
'Obtenemos el nombre del fichero en el que guardar los registros
str_Fichero = obj_SH.ExpandEnvironmentStrings(str_TSV)

'Si el fichero no existe, lo crearemos (tercer argumento del
'método OpenTextFile del objeto FileSystemObject con valor True) y
'le pondremos una primera línea con los encabezados
If Not obj_FS.FileExists(str_Fichero) Then _
    str_Linea = "Usuario" & vbTab & _
                "Equipo" & vbTab & _
                "Servidor" & vbTab & _
                "Fecha Inicio" & vbTab & _
                "Hora Inicio" & vbTab & _
                "Fecha Cierre" & vbTab & _
                "Hora Cierre"

'Limpieza de culete :-). Sólo dejaremos el objeto FileSystemObject,
'pues lo necesitamos para abrir/crear el fichero de registro
Set obj_NW = Nothing
Set obj_SH = Nothing

'Si se trata de un inicio de sesión... 
If bol_InicioDeSesion Then
      
    'abrimos el fichero para agregar
    Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
                   ForAppending, _
                   True, _
                   0)
                   
    'agregamos los datos del inicio de sesión a la variable
    str_Linea = str_Linea & vbCrLf & _
                str_Usuario & vbTab & _
                str_Equipo & vbTab & _
                str_Servidor & vbTab & _
                FormatDateTime(Date,vbShortDate) & vbTab & _
                FormatDateTime(Time,vbShortTime)
    
    'Escribimos la información en el fichero            
    obj_TS.Write str_Linea
    
    'Cerramos el fichero y vaciamos su variable
    obj_TS.close
    Set obj_TS = Nothing               

'Se trata de un cierre de sesión.
Else

    'Si es un fichero nuevo (en caso contrario str_Linea está
    'vacío)...
    If Len(str_Linea) > 0 Then
 
        'Creamos el archivo de registro   
        Set obj_TS = obj_FS.CreateTextFile(str_Fichero, _
                        True, _
                        False)
                        
        'Agregamos los datos del cierre de sesión a la variable
        str_Linea = str_Linea & vbCrLf & _
                    str_Usuario & vbTab & _
                    str_Equipo & vbTab & _
                    str_Servidor & vbTab & _
                    vbTab & _
                    vbTab & _
                    FormatDateTime(Date,vbShortDate) & vbTab & _
                    FormatDateTime(Time,vbShortTime)
        
        'Escribimos la información en el fichero            
        obj_TS.Write str_Linea
        
        'Cerramos el fichero y vaciamos su variable
        obj_TS.close
        Set obj_TS = Nothing               

    'el fichero ya existe, lo abrimos para lectura, pues debemos
    'localizar la línea en la que escribir los datos del cierre de sesión.
    'Los criterios a seguir son:
    '
    '        1.- Se busca la última línea en la que haya un inicio
    '            de sesión del usuario en el equipo y que no tenga
    '            hora de cierre de sesión y se escribe en el la hora
    '            y fecha del cierre de sesión.
    '        2.- Si todos los registros que coinciden en usuario y
    '            equipo ya tienen registrado un cierre de sesión,
    '            se creará un registro nuevo en el que no se refleje
    '            la hora de inicio de sesión (en caso de haberse
    '            producido un error al registrar el inicio de sesión)
    
    Else

        'Abrimos el fichero de registro para lectura
        Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
                       ForReading, _
                       True, _
                       0)
                       
        'Obtenemos el contenido del archivo
        str_Texto = obj_TS.ReadAll
        
        'Creamos un array con cada línea del archivo
        arr_Lineas = Split(str_Texto,vbCrLf)
        
        'Marcamos a False el indicador de registro encontrado
        bol_Encontrado = False
        
        'Recorremos el array de líneas de la última a la primera
        For int_Linea = UBound(arr_Lineas) To LBound(arr_Lineas) Step -1
        
            'Creamos un array con los datos de la línea
            arr_Campos = Split(arr_Lineas(int_Linea),vbTab)
            
            On Error Resume Next
            'Si el nombre del equipo y usuario es igual, y no hay
            'no hay información de cierre de sesión, asumimos que
            'se trata de la sesión que se está cerrando
            If LCase(obj_NW.UserName) = LCase(arr_Campos(0)) _
            And LCase(obj_NW.ComputerName) = LCase(arr_Campos(1)) _
            And UBound(arr_Campos)= 4 Then
            
                On Error Goto 0
 
                'Agregamos la fecha y la hora
                arr_Lineas(int_Linea) = _
                        arr_Lineas(int_Linea) & vbTab & _
                        FormatDateTime(Date,vbShortDate) & vbTab & _
                        FormatDateTime(Time,vbShortTime)
                        
                'Marcamos el indicador de registro encontrado
                bol_Encontrado = True
                
                'Salimos del bucle
                Exit For
            
            End If
            On Error Goto 0
            
            'Borramos el array de camoos
            Erase arr_Campos
        
        Next 'int_Linea
        
        'Si no hemos encontrado un registro con el inicio de sesión...
        If Not bol_Encontrado Then
        
            'Agregamos un elemento al array de líneas
            ReDim Preserve arr_Lineas(UBound(arr_Lineas) + 1)
            
            'Ponemos la información del cierre de sesión en él elemento
            'creado
            arr_Lineas(UBound(arr_Lineas)) = _
                    str_Usuario & vbTab & _
                    str_Equipo & vbTab & _
                    str_Servidor & vbTab & _
                    vbTab & _
                    vbTab & _
                    FormatDateTime(Date,vbShortDate) & vbTab & _
                    FormatDateTime(Time,vbShortTime)
                    
        End If
        
        'Vamos ahora a escribir la información
 
        'Abrimos el fichero de registro para escritura
        Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
                       ForWriting, _
                       True, _
                       0)
                       
        str_Texto = ""
        
        'Recorremos los elementos del array del primero al último
        For int_Linea = LBound(arr_Lineas) To UBound(arr_Lineas)
        
            'Escribimos la línea
            str_Texto = str_Texto & arr_Lineas(int_Linea) & vbCrLf
        
        Next 'int_Linea
        
        str_Texto=Left(str_Texto,Len(str_Texto) - 2)
        
        obj_TS.Write str_Texto
        
        'Cerramos el fichero y vaciamos su variable
        obj_TS.Close
        Set obj_TS = Nothing
                    
    End If

End If

'Limpieza de mocos :-)
Set obj_FS = Nothing

Function f_RevisarArgumentos( _
                             str_Error, _
                             int_Error _
                             ) 'As Boolean
'***********************************************************************
'* Procedimiento: f_RevisarArgumentos                                  *
'* Tipo         : Función                                              *
'* Devolución   : Booleana                                             *
'* Fecha y Hora : 24/10/2007 13:09:23                                  *
'* 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 si están todos los argumentos
    'sin nombre requeridos
    If WScript.Arguments.Unnamed.Count < 1 Then

        str_Error = "Error 1, falta/n argumento/s sin " & _
                    "nombre requerido/s"
        bol_Error1 = True

    Else

    'Guardamos los argumentos en las variables
    'correspondientes
        If _
          WScript.Arguments.Unnamed.Count - 1 _
          >= 0 Then _
               str_TSV = _
                       WScript.Arguments.Unnamed(0)


    End If

    'Revisamos que esté el argumento
    '/I (inicio)
    If WScript.Arguments.Named.Exists("I") Then

        bol_InicioDeSesion = 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 : 24/10/2007 16:01:14                                  *
'* 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 está ideado para registrar los inicio" & _
                 "s y cierres de sesión de los"
    WScript.Echo "usuarios. A pesar de que se puede obtener los ini" & _
                 "cios de sesión por medio de"
    WScript.Echo "una GPO, utilizando la auditoría de inicio de ses" & _
                 "ión de cuenta, esto no permite"
    WScript.Echo "registrar el cierre de sesión y además es bastant" & _
                 "e incómodo el mirar estos"
    WScript.Echo "datos en el visor de sucesos, si bien se pueden f" & _
                 "iltrar y exportar a un fichero"
    WScript.Echo "CSV para después trabajar en Excel con ellos. Por" & _
                 " ello, este script es"
    WScript.Echo "interesante para obtener los datos ya filtrados y" & _
                 " reunidos en un fichero."
    WScript.Echo ""
    WScript.Echo "Los resultados se almacenan en un fichero de valo" & _
                 "res separados por tabuladores,"
    WScript.Echo "ideal para abrirse con Excel. Se puede especifica" & _
                 "r el nombre del fichero"
    WScript.Echo "utilizando variables de entorno, lo que permite q" & _
                 "ue se pueda crear un fichero"
    WScript.Echo "por cada usuario, por ejemplo, para así no tener " & _
                 "todos los inicios y cierres de"
    WScript.Echo "sesión de todos los usuarios en un mismo fichero " & _
                 "(cosa que también se puede si"
    WScript.Echo "así se desea)"
    WScript.Echo ""
    WScript.Echo "Sintaxis"
    WScript.Echo ""
    WScript.Echo "{wscript | cscript [//nologo]} registrar-sesion.v" & _
                 "bs [/I] [/?] fichero"
    WScript.Echo ""
    WScript.Echo "Siendo"
    WScript.Echo ""
    WScript.Echo "- fichero (Requerido):"
    WScript.Echo "Nombre del fichero de valores separados por tabul" & _
                 "ador en el que"
    WScript.Echo "se guarda la información. Se pueden incluir varia" & _
                 "bles de"
    WScript.Echo "entorno en el nombre, que serán sustituidas por s" & _
                 "u valor."
    WScript.Echo ""
    WScript.Echo "- /I: inicio (Opcional):"
    WScript.Echo "Indica si se trata de un inicio de sesión o no."
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo "Ejemplos:"
    WScript.Echo ""
    WScript.Echo "- Registra el inicio de sesión en el fichero ""\\" & _
                 "sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"":"
    WScript.Echo ""
    WScript.Echo "wscript //nologo registrar-sesion.vbs /I ""\\saur" & _
                 "on\mordor\usuarios\sesiones\%USERNAME%.tsv"""
    WScript.Echo ""
    WScript.Echo "- Registra el cierre de sesión en el fichero ""\\" & _
                 "sauron\mordor\usuarios\sesiones\%USERNAME%.tsv"":"
    WScript.Echo ""
    WScript.Echo "cscript //nologo registrar-sesion.vbs ""\\sauron\" & _
                 "mordor\usuarios\sesiones\%USERNAME%.tsv"""
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo ""

End Sub 's_Ayuda

52 comentarios to “Script VBScript Para Registrar Los Inicios Y Cierres De Sesión De Los Usuarios”

  1. paco said

    Hola compañero del metal. Me parece super interesante este script pero tengo un problema que seguro que es una chorrada y me puedes ayudar.
    El resultado seria esto.
    Usuario Equipo Servidor Fecha Inicio Hora Inicio Fecha Cierre Hora Cierre
    SYSTEM SER2K3 %LOGONSERVER% 11/21/2007 13:04
    SYSTEM SER2K3 %LOGONSERVER% 11/21/2007 13:05 11/21/2007 13:09
    SYSTEM SER2K3 %LOGONSERVER% 11/21/2007 13:10 11/21/2007 13:17
    SYSTEM SER2K3 %LOGONSERVER% 11/21/2007 13:18

    y lo raro es que de usuario me deja SYSTEM en vez del usuario en concreto y el %LOGONSERVER% en vez del servidor en el que hace logon.

    Bueno un saludo y muchas gracias de antemano.

  2. urpiano said

    Paco,

    ¿No estarás asignando este script a una política de script de inicio de equipo (rama de equipo)? Debe ser asignado a una política de inicio de sesión (rama de usuario). Si se aplica como script de inicio de equipo, el usuario que lanza el script es SYSTEM y la variable de entorno LOGONSERVER no existe, pues es una variable de usuario, no de equipo, de ahí el que registre usuario SYSTEM y sevidor %LOGONSERVER%

  3. paco said

    MUCHAS GRACIASSSSSSSSSSSSSSSS Eres el Puto amo. Este script me acaba de ahorrar un curro increible.

    Un saludo

  4. Marc said

    Acabo de probar tu script, em va eprfecto en el inicio de sesión, pero no me audita el apagado del equipo, sabes alguna manera? Si lo pongo en la rama equipo, me sale lo de Paco.
    Gracias y un saludo amigo

  5. urpiano said

    Marc,

    ¿Cómo haces para ponerlo para el cierre de sesión? A mí me funciona perfectamente editando la política, poniendo en la caja de texto de arriba la ruta + nombre del script (la ruta debe ser UNC) y en la caja de abajo la ruta + nombre del fichero TSV donde se guardan los registros (ruta que también debe ser CSV?

    Respecto a lo de ponerlo en la rama de equipo, la explicación de lo que pasa ya se la di a Paco, revísala.

  6. jordi said

    El problema que yo encuentro es lo saltos de linea, no los hace. Pone todos los datos de Fechas del mismo usuario en la misma linea. No hace una linea nueva para cada conexion del mismo usuario

  7. Javi said

    Esta Genial. El único pero que le pongo es que no agrupe los inicios de sesion por máquina. De esta manera facilitaria la busqueda si es en un equipo en concreto el que quieres auditar los inicios.

    Muchas gracias un MUY BUEN TRABAJO.

  8. miguel a said

    una duda como hago para que solo me muestre un usuario en especifico

  9. urpiano said

    Javi y Miguel A,

    El fichero generado es de valores separados por tabulador; si lo abrís con Excel, vereis que éste pone automáticamente los campos en columnas, con lo que podeis filtrar por usuario y/o por equipo, ordenar por fechas, horas, etc.

  10. urpiano said

    Jordi,

    No sé a qué te refieres, pues a mí sí me pone saltos de línea, en cada línea registra el nombre de usuario, el equipo, la fecha y hora de inicio de sesión y la fecha y hora de cierre de sesión.

  11. Christian Castellanos said

    Buenas Tardes. Muchas Gracias Excelente el script.

  12. hola amigo excelente script, me sirve de mucho, pero tengo 1 inconveniente, en mi empresa tengo 300 usuarios bajo un Controlador de dominio, el scrip funciona a la perfeccion en 200 usuarios o mas, pero en algunos usuarios al iniciar sesion aparece el siguiente mensaje de alerta:

    Secuencia de Comandos: \\servidor\carpeta\registrar-sesion.vbs
    Linea: 139
    Caracter: 5
    Error: permiso denegado
    Codigo: 800A0046
    Origen: Error de Microsoft VBScript en tiempo de ejecucion

    y aparece un Boton de Aceptar para cerrar el mensaje

    Nota: el script esta tal como tu lo pusiste, sin agregar ni eliminar ninguna linea

    Espero puedas apoyarme, gracias :)

  13. Furyto said

    Hola:

    Que es una GPO? Por más que he intentado no entiendo a que te refieres? Tengo un Server 2003 como controlador de dominio y no sé por donde empezar para activar ese script. Agradecería una información más detallada que me ayude.

    Saludos

  14. Osmeidy Pérez Collado said

    Hola a todos, mi pregunta va dirigida al autor del post Urpiano o alguien que me pueda responder.
    Soy nuevo en esto de la administracion de redes, tengo un server 2008 y he intentado colocar este script pero no me genera nada, segui los pasos tal y como lo explica aca.
    Ahora tengo una duda, yo copye el codigo del script dentro de un .txt y despues le cambie la extencion a .vbs, esto funciona asi o tengo que compilarlo en VB.
    saludos y espero qeu mi duda no sea tonta para usuarios de este nivel.
    gracias.

  15. Osmeidy Pérez Collado said

    Hola amigo, ya di con el problema de la extencion,,, ahora tengo el mismo problema de MIler Alberto Garcia, pues me sale el mensaje.

    Secuencia de Comandos: \\servidor\carpeta\registrar-sesion.vbs
    Linea: 139
    Caracter: 5
    Error: permiso denegado
    Codigo: 800A0046
    Origen: Error de Microsoft VBScript en tiempo de ejecucion

    Aclaro que a la carpeta que comparti le agregue el usuario “Usuarios del Dominio” y le di todos los permisos, incluso el mismo usuario con el que el script me da el error al inicio y al final de la sesion, pues tiene permiso desde la red hacer cualquier cosa en esa carpeta.
    espero resolver este problemita.
    saludos.

  16. Pablo said

    Hola
    Solo es una duda, creo que no tiene nada que ver aqui pero se puede conectar una Unidad de Red que no este ni en el Dominio ni en el grupo? esque me da error de usuaio i contraseña, hay algun modo de indicarlo en el script? como? yo tengo esto:

    WSHNetwork.MapNetworkDrive “L:”, “\\servidor2\Software”

    pero al iniciar la session me da error en esta linea i me dice Usuario o contraseña invalidos y es xq el servidor2 no esta en el dominio pero tmpoco quiero meterlo, Si algien me puede ayudar lo agradeceria…

  17. Alexis said

    Sabes, a mi me pasa lo mismo que el usuario:

    “Osmeidy Pérez Collado”

    Cierre de sesión:
    Secuencia de Comandos: \\servidor\carpeta\registrar-sesion.vbs
    Linea: 167
    Caracter: 9
    Error: permiso denegado
    Codigo: 800A0046
    Origen: Error de Microsoft VBScript en tiempo de ejecucion

    Inicio de sesión:
    Secuencia de Comandos: \\servidor\carpeta\registrar-sesion.vbs
    Linea: 139
    Caracter: 5
    Error: permiso denegado
    Codigo: 800A0046
    Origen: Error de Microsoft VBScript en tiempo de ejecucion
    Tengo todos los permisos concedidos, lo intenté con una carpeta oculta y con otra no.

    Lo publique en el Active Directory y nada.

    Siempre, o me da un error de inicio de sesion o de cierre de sesion, y en la carpeta no se crea nada.

    Eso sí, yo tengo direccionados los archivos a la misma ubicacion en donde tengo el archivo .vbs. Eso influye??..

    Mis saludos y espero su respuesta.

  18. Hector Giomenez said

    Hola a todos, excelente script pero me pasa algo, solo me audita inicio se seion, ne el cierre que puede ser?
    gracias

  19. urpiano said

    Hector Giomenez,

    ¿Has puesto el script como script de cierre de sesión, tal y como indica la entrada? Fíjate que se debe poner el script tanto como de inicio de sesión como de cierre de sesión, especificando el modificador /i en el caso de ser un incio de sesión y no especificando nada en caso de ser cierre de sesión.

  20. Muchas Gracias, este Script sirve de maravilla, intentaba hacer esto con un .bat de inicio y cierre de sesion, pero no se si eso es posible; mi idea era hacer un sistema en php de registro de sesiones, en el cual al iniciar sesion colocaba un archivo bat el cual hacia que al usuario se le apareciera una pagina alojada en el servidor en modo kiosko, pero mi problema era al cerrar la sesion, no lograba que de igual forma que el inicio me abriera la pagina en modo kiosko y que realmente se cerrara sesion hasta que se cerrara la pagina, cosa que no se si sea posible, pero este script sirve de maravilla y es muy sencillo.

    Voy a tratar de investigar si es posible guardar los registros en un archivo de excel.

    Muchas gracias.

  21. Josué Dorian Arce Orozco said

    Me sirvio de mucho este script, pero quisiera saber como se puede obtener mas informacion del usuario, como es su nombre completo, a que grupo pertenece, ese tipo de informacion para hacer un reporte mas completo y detallado.

  22. Josué Dorian Arce Orozco said

    Bueno pues el dia de hoy despues de un buen rato de estar checando varios de los script que estan en este blog, pues deseaba ampliar lo que es el registro; me interesaba ademas de saber que usuario se logueaba y a que hora, deseaba saber su nombre completo, y el grupo al que pertenece, ya que yo lo uso para la universidad, para tener una bitacora de acceso de usuarios a los equipos.
    Pues aqui les pongo el script ya modificado, del cual saque algunas funciones de otros scripts aqui publicados, el script sigue los mismos parametros,espero y les sirva este pequeño aporte de mi parte:

    '*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
    '*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
    '* registrar-sesion.vbs *
    '* *
    '* Este script está ideado para registrar los inicios y cierres de *
    '* sesión de los usuarios. A pesar de que se puede obtener los inicios *
    '* de sesión por medio de una GPO, utilizando la auditoría de inicio *
    '* de sesión de cuenta, esto no permite registrar el cierre de sesión *
    '* y además es bastante incómodo el mirar estos datos en el visor de *
    '* sucesos, si bien se pueden filtrar y exportar a un fichero CSV para *
    '* después trabajar en Excel con ellos. Por ello, este script es *
    '* interesante para obtener los datos ya filtrados y reunidos en un *
    '* fichero. *
    '* *
    '* Los resultados se almacenan en un fichero de valores separados por *
    '* tabuladores, ideal para abrirse con Excel. Se puede especificar el *
    '* nombre del fichero utilizando variables de entorno, lo que permite *
    '* que se pueda crear un fichero por cada usuario, por ejemplo, para *
    '* así no tener todos los inicios y cierres de sesión de todos los *
    '* usuarios en un mismo fichero (cosa que también se puede si así se *
    '* desea) *
    '* *
    '* Sintaxis *
    '* *
    '* {wscript | cscript [//nologo]} registrar-sesion.vbs [/I] [/?] *
    '* fichero *
    '* *
    '* Siendo *
    '* *
    '* - fichero (Requerido): *
    '* Nombre del fichero de valores separados por tabulador en el *
    '* que se guarda la información. Se pueden incluir variables *
    '* de entorno en el nombre, que serán sustituidas por su valor.*
    '* *
    '* - /I: inicio (Opcional): *
    '* Indica si se trata de un inicio de sesión o no. *
    '* *
    '* *
    '* Ejemplos: *
    '* *
    '* - Registra el inicio de sesión en el fichero *
    '* "\sauronmordorusuariossesiones%USERNAME%.tsv": *
    '* *
    '* cscript //nologo registrar-sesion.vbs /I *
    '* "\sauronmordorusuariossesiones%USERNAME%.tsv" *
    '* *
    '* - Registra el cierre de sesión en el fichero *
    '* "\sauronmordorusuariossesiones%USERNAME%.tsv": *
    '* *
    '* cscript //nologo registrar-sesion.vbs *
    '* "\sauronmordorusuariossesiones%USERNAME%.tsv" *
    '* *
    '* *
    '* *
    '* *
    '* © Fernando Reyes *
    '* Abril De 2008 *
    '*°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°*
    '*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

    'Exigimos la declaración de variables
    Option Explicit

    'Constantes para el método OpenTextFile del objeto FileSystemObject
    Const ForReading = 1
    Const ForWriting = 2
    Const ForAppending = 8

    Dim arr_Campos 'As String
    Dim arr_Lineas 'As String
    Dim bol_Encontrado 'As Boolean
    Dim bol_InicioDeSesion 'As Boolean
    Dim int_Error 'As String
    Dim int_Linea 'As Integer
    Dim obj_FS 'As Scripting.FileSystemObject
    Dim obj_NW 'As IWshRuntimeLibrary.WshNetwork
    Dim obj_SH 'As IWshRuntimeLibrary.WshShell
    Dim obj_TS 'As Scripting.TextStream
    Dim str_Equipo 'As String
    Dim str_Error 'As String
    Dim str_Fichero 'As String
    Dim str_Linea 'As String
    Dim str_Servidor 'As String
    Dim str_Texto 'As String
    Dim str_TSV 'As String
    Dim str_Usuario 'As String
    Dim str_Ini 'As String
    Dim str_Cie 'As String
    Dim str_NombreMostrar 'As String
    Dim str_NMTemp 'As String
    Dim str_CarreraMostrar 'As String
    Dim str_UserTemp 'As String
    str_Ini = "Inicio:"
    str_Cie = "Cierre:"
    bol_InicioDeSesion = False

    Dim obj_Conexion 'As ADODB.Connection
    Dim obj_Comando 'As ADODB.Command
    Dim obj_Usuario 'As iADsUser
    Dim obj_FSO 'Scripting.FileSystemObject

    Dim str_Dominio 'As String
    Dim str_Filtro 'As String
    Dim str_Consulta 'As String
    Dim obj_Recordset 'As ADODB.Recordset
    Dim str_DN 'As String
    Dim str_Linea2 'As String
    Dim obj_Grupo 'As iADsGroup
    Dim int_ContadorGrupos 'As Integer
    Dim bol_VPN 'As Boolean
    Dim str_Usuario2 'As String
    Dim bol_Grupos 'As Boolean
    Dim dic_Grupos 'As Dictionary
    Dim Compara 'As Integer
    '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

    Set obj_SH = CreateObject("WScript.Shell")
    Set obj_NW = CreateObject("Wscript.Network")
    Set obj_FS = CreateObject("Scripting.FileSystemObject")

    'Obtenemos el nombre de usuario, del equipo en el que está
    'y del servidor en el que se loga (en este último caso le
    'quitamos el doble back-slash que lleva delante)
    str_Usuario = obj_NW.UserName
    str_Equipo = obj_NW.ComputerName
    str_Servidor = Replace(obj_SH.ExpandEnvironmentStrings( _
    "%LOGONSERVER%"), _
    "\", _
    "")

    'Obtenemos el nombre del fichero en el que guardar los registros
    str_Fichero = obj_SH.ExpandEnvironmentStrings(str_TSV)

    'Creamos el diccionario de grupos
    Set dic_Grupos = CreateObject("Scripting.Dictionary")

    'Conectamos con ODBC al Proveedor de Active Directory
    Set obj_Conexion = CreateObject("ADODB.Connection")
    Set obj_Comando = CreateObject("ADODB.Command")
    obj_Conexion.Provider = "ADsDSOObject"
    obj_Conexion.Open = "Active Directory Provider"
    Set obj_Comando.ActiveConnection = obj_Conexion

    str_Dominio = "DC=UMB,DC=MX"
    str_DN = "DC=UMB,DC=MX"
    'Creamos la cadena de consulta
    str_Filtro = "(&(objectCategory=person)(objectClass=user))"
    str_Consulta = ";" & str_Filtro _
    & ";distinguishedName;subtree"

    'Establecemos la consulta y las propiedades de la misma,
    'poniendo paginación para poder superar el límite de
    '1000 resultados que hay si no se la establece
    obj_Comando.CommandText = str_Consulta
    obj_Comando.Properties("Page Size") = 100
    obj_Comando.Properties("Timeout") = 30
    obj_Comando.Properties("Cache Results") = False

    'Ejecutamos la consulta
    Set obj_Recordset = obj_Comando.Execute

    'Recorremos todos los usuarios del dominio
    Do Until obj_Recordset.EOF

    'Vaciamos las variables de montaje de línea
    str_Linea2 = ""
    str_Usuario2 = ""

    'Obtenemos el nombre distinguido del usuario
    str_DN = obj_Recordset.Fields("distinguishedName")

    'Creamos un objeto usuario con su nombre distinguido
    Set obj_Usuario = GetObject("LDAP://" & str_DN)

    'Montamos su nombre distinguido, su nombre para mostrar
    'sus membresías y la OU a la que pertenece. Controlamos
    'si hemos recibido fichero donde volcar la información:
    'en caso afirmativo lo volcamos en el fichero, en caso
    'negativo lo mostramos en pantalla

    'Montamos el nombre distinguido
    'str_Usuario = """" & Replace(obj_Usuario.distinguishedName, _
    ' """","'") & """" & vbTab

    'Como no todos los usuarios tienen nombre para mostrar
    'por ejemplo el administrador), controlamos si esta
    'propiedad tiene valor, para omitir el encerrar entre
    'comillas el mismo.
    str_NMTemp = ""
    str_UserTemp = str_Usuario & "@UMB.MX"

    str_NMTemp = str_NMTemp & _
    Replace(obj_Usuario.userprincipalname, _
    """","'")
    Compara = StrComp(str_UserTemp,str_NMTemp,1)
    If Len(obj_Usuario.displayName) > 0 Then

    if Compara = 0 Then

    str_NombreMostrar = str_Usuario2 & """" & _
    Replace(obj_Usuario.displayName, _
    """","'") & """"
    End if

    End If

    if Compara = 0 Then
    str_CarreraMostrar = str_Usuario2 & """" & _
    f_DNaCanonico(obj_Usuario.Parent,str_Dominio) & _
    """"

    End if
    'Agregamos el contenedor

    'Obtenemos si tiene acceso VPN. Primero iniciamos la variable
    'que lo guarda a False
    bol_VPN = False
    'Ahora establecemos control de errores, pues si no está establecida
    'esta propiedad, se produce un error
    On Error Resume Next
    'Guardamos el valor de la propiedad
    bol_VPN = obj_Usuario.Get("msNPAllowDialin")
    'Vaciamos el objeto de errores
    Err.Clear
    'Devolvemos el control de errores a CScript
    On Error Goto 0

    'Añadimos si tiene o no acceso a la línea de salida
    str_Usuario2 = str_Usuario2 '& bol_VPN & vbTab

    'Ponemos a cero el contador de grupos
    int_ContadorGrupos = 0

    'Ponemos a false el indicador de que se han encontrado grupos
    bol_Grupos = False

    'Vaciamos el diccionario de grupos
    dic_Grupos.RemoveAll

    'Recorremos ahora el array de grupos a los que pertenece
    'el usuario
    For Each obj_Grupo In obj_Usuario.Groups

    'Como hemos entrado, asignamos True al indicador
    'de que se han encontrado grupos
    bol_Grupos = True

    'Si este grupo no lo hemos recorrido con anterioridad
    If (dic_Grupos.Exists( _
    obj_Grupo.sAMAccountName) = False) Then

    'Ponemos el nombre del grupo eliminando el "CN="
    str_Linea2 = str_Usuario2

    'Si no se ha recibido el parámetro de fichero, volcamos
    'la línea en pantalla
    If str_Fichero = "" Then

    WScript.Echo str_Linea2

    'en caso contrario la volcamos en el fichero
    Else

    ' obj_TS.WriteLine str_Linea2

    End If

    'Agregamos el grupo al diccionario para evitar una
    'segunda llamada sobre él
    dic_Grupos.Add obj_Grupo.sAMAccountName, True

    'Llamamos al método que enumerará los grupos a los que
    'pertenece este grupo
    Call s_EnumeraGrupos(obj_Grupo,str_Usuario2,obj_TS)

    End If

    Next

    'Si no se han encontrado grupos hay que mostrar el usuario sin ellos
    If Not bol_Grupos Then

    'Si no se ha recibido el parámetro de fichero, volcamos la línea
    'en pantalla
    If str_Fichero = "" Then

    ' WScript.Echo str_Usuario2 & vbTab & "Sin membresias"

    'en caso contrario la volcamos en el fichero
    Else

    ' obj_TS.WriteLine str_Usuario2 '& vbTab & "Sin membresias"

    End If

    End If

    'Saltamos al siguiente registro
    obj_Recordset.MoveNext

    Loop

    'Si estabamos volcando información en el fichero
    'de salida

    'Si el fichero no existe, lo crearemos (tercer argumento del
    'método OpenTextFile del objeto FileSystemObject con valor True) y
    'le pondremos una primera línea con los encabezados
    If Not obj_FS.FileExists(str_Fichero) Then _
    str_Linea = "Usuario" & vbTab & _
    "Nombre" & vbTab & _
    "Grupo" & vbTab & _
    "Equipo" & vbTab & _
    "Servidor" & vbTab & _
    "Fecha Inicio" & vbTab & _
    "Hora Inicio" & vbTab & _
    "Fecha Cierre" & vbTab & _
    "Hora Cierre"

    'Limpieza de culete :-). Sólo dejaremos el objeto FileSystemObject,
    'pues lo necesitamos para abrir/crear el fichero de registro
    Set obj_NW = Nothing
    Set obj_SH = Nothing

    'Si se trata de un inicio de sesión...
    If bol_InicioDeSesion Then

    'abrimos el fichero para agregar
    Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
    ForAppending, _
    True, _
    0)

    'agregamos los datos del inicio de sesión a la variable
    str_Linea = str_Linea & vbCrLf & _
    str_Usuario & vbTab & _
    str_NombreMostrar & vbTab & _
    str_CarreraMostrar & vbTab & _
    str_Equipo & vbTab & _
    str_Servidor & vbTab & _
    FormatDateTime(Date,vbShortDate) & vbTab & _
    FormatDateTime(Time,vbShortTime)

    'Escribimos la información en el fichero
    obj_TS.Write str_Linea

    'Cerramos el fichero y vaciamos su variable
    obj_TS.close
    Set obj_TS = Nothing

    'Se trata de un cierre de sesión.
    Else

    'Si es un fichero nuevo (en caso contrario str_Linea está
    'vacío)...
    If Len(str_Linea) > 0 Then

    'Creamos el archivo de registro
    Set obj_TS = obj_FS.CreateTextFile(str_Fichero, _
    True, _
    False)

    'Agregamos los datos del cierre de sesión a la variable
    str_Linea = str_Linea & vbCrLf & _
    str_Usuario & vbTab & _
    str_Nombre & vbTab & _
    str_Carrera & vbTab & _
    str_Equipo & vbTab & _
    str_Servidor & vbTab & _
    vbTab & _
    vbTab & _
    FormatDateTime(Date,vbShortDate) & vbTab & _
    FormatDateTime(Time,vbShortTime)

    'Escribimos la información en el fichero
    obj_TS.Write str_Linea

    'Cerramos el fichero y vaciamos su variable
    obj_TS.close
    Set obj_TS = Nothing

    'el fichero ya existe, lo abrimos para lectura, pues debemos
    'localizar la línea en la que escribir los datos del cierre de sesión.
    'Los criterios a seguir son:
    '
    ' 1.- Se busca la última línea en la que haya un inicio
    ' de sesión del usuario en el equipo y que no tenga
    ' hora de cierre de sesión y se escribe en el la hora
    ' y fecha del cierre de sesión.
    ' 2.- Si todos los registros que coinciden en usuario y
    ' equipo ya tienen registrado un cierre de sesión,
    ' se creará un registro nuevo en el que no se refleje
    ' la hora de inicio de sesión (en caso de haberse
    ' producido un error al registrar el inicio de sesión)

    Else

    'Abrimos el fichero de registro para lectura
    Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
    ForReading, _
    True, _
    0)

    'Obtenemos el contenido del archivo
    str_Texto = obj_TS.ReadAll

    'Creamos un array con cada línea del archivo
    arr_Lineas = Split(str_Texto,vbCrLf)

    'Marcamos a False el indicador de registro encontrado
    bol_Encontrado = False

    'Recorremos el array de líneas de la última a la primera
    For int_Linea = UBound(arr_Lineas) To LBound(arr_Lineas) Step -1

    'Creamos un array con los datos de la línea
    arr_Campos = Split(arr_Lineas(int_Linea),vbTab)

    On Error Resume Next
    'Si el nombre del equipo y usuario es igual, y no hay
    'no hay información de cierre de sesión, asumimos que
    'se trata de la sesión que se está cerrando
    If LCase(obj_NW.UserName) = LCase(arr_Campos(0)) _
    And LCase(obj_NW.ComputerName) = LCase(arr_Campos(1)) _
    And UBound(arr_Campos)= 4 Then

    On Error Goto 0

    'Agregamos la fecha y la hora
    arr_Lineas(int_Linea) = _
    arr_Lineas(int_Linea) & vbTab & _
    FormatDateTime(Date,vbShortDate) & vbTab & _
    FormatDateTime(Time,vbShortTime)

    'Marcamos el indicador de registro encontrado
    bol_Encontrado = True

    'Salimos del bucle
    Exit For

    End If
    On Error Goto 0

    'Borramos el array de camoos
    Erase arr_Campos

    Next 'int_Linea

    'Si no hemos encontrado un registro con el inicio de sesión...
    If Not bol_Encontrado Then

    'Agregamos un elemento al array de líneas
    ReDim Preserve arr_Lineas(UBound(arr_Lineas) + 1)

    'Ponemos la información del cierre de sesión en él elemento
    'creado
    arr_Lineas(UBound(arr_Lineas)) = _
    str_Usuario & vbTab & _
    str_Equipo & vbTab & _
    str_Servidor & vbTab & _
    vbTab & _
    vbTab & _
    FormatDateTime(Date,vbShortDate) & vbTab & _
    FormatDateTime(Time,vbShortTime)

    End If

    'Vamos ahora a escribir la información

    'Abrimos el fichero de registro para escritura
    Set obj_TS = obj_FS.OpenTextFile(str_Fichero, _
    ForWriting, _
    True, _
    0)

    str_Texto = ""

    'Recorremos los elementos del array del primero al último
    For int_Linea = LBound(arr_Lineas) To UBound(arr_Lineas)

    'Escribimos la línea
    str_Texto = str_Texto & arr_Lineas(int_Linea) & vbCrLf

    Next 'int_Linea

    str_Texto=Left(str_Texto,Len(str_Texto) - 2)

    obj_TS.Write str_Texto

    'Cerramos el fichero y vaciamos su variable
    obj_TS.Close
    Set obj_TS = Nothing

    End If

    End If

    'Limpieza de mocos :-)
    Set obj_FS = Nothing

    Function f_RevisarArgumentos( _
    str_Error, _
    int_Error _
    ) 'As Boolean
    '***********************************************************************
    '* Procedimiento: f_RevisarArgumentos *
    '* Tipo : Función *
    '* Devolución : Booleana *
    '* Fecha y Hora : 24/10/2007 13:09:23 *
    '* 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 si están todos los argumentos
    'sin nombre requeridos
    If WScript.Arguments.Unnamed.Count = 0 Then _
    str_TSV = _
    WScript.Arguments.Unnamed(0)

    End If

    'Revisamos que esté el argumento
    '/I (inicio)
    If WScript.Arguments.Named.Exists("I") Then

    bol_InicioDeSesion = 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 : 25/10/2007 13:29:55 *
    '* 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 está ideado para registrar los inicio" & _
    "s y cierres de sesión de los"
    WScript.Echo "usuarios. A pesar de que se puede obtener los ini" & _
    "cios de sesión por medio de"
    WScript.Echo "una GPO, utilizando la auditoría de inicio de ses" & _
    "ión de cuenta, esto no permite"
    WScript.Echo "registrar el cierre de sesión y además es bastant" & _
    "e incómodo el mirar estos"
    WScript.Echo "datos en el visor de sucesos, si bien se pueden f" & _
    "iltrar y exportar a un fichero"
    WScript.Echo "CSV para después trabajar en Excel con ellos. Por" & _
    " ello, este script es"
    WScript.Echo "interesante para obtener los datos ya filtrados y" & _
    " reunidos en un fichero."
    WScript.Echo ""
    WScript.Echo "Los resultados se almacenan en un fichero de valo" & _
    "res separados por tabuladores,"
    WScript.Echo "ideal para abrirse con Excel. Se puede especifica" & _
    "r el nombre del fichero"
    WScript.Echo "utilizando variables de entorno, lo que permite q" & _
    "ue se pueda crear un fichero"
    WScript.Echo "por cada usuario, por ejemplo, para así no tener " & _
    "todos los inicios y cierres de"
    WScript.Echo "sesión de todos los usuarios en un mismo fichero " & _
    "(cosa que también se puede si"
    WScript.Echo "así se desea)"
    WScript.Echo ""
    WScript.Echo "Sintaxis"
    WScript.Echo ""
    WScript.Echo "{wscript | cscript [//nologo]} registrar-sesion.v" & _
    "bs [/I] [/?] fichero"
    WScript.Echo ""
    WScript.Echo "Siendo"
    WScript.Echo ""
    WScript.Echo "- fichero (Requerido):"
    WScript.Echo "Nombre del fichero de valores separados por tabul" & _
    "ador en el que"
    WScript.Echo "se guarda la información. Se pueden incluir varia" & _
    "bles de"
    WScript.Echo "entorno en el nombre, que serán sustituidas por s" & _
    "u valor."
    WScript.Echo ""
    WScript.Echo "- /I: inicio (Opcional):"
    WScript.Echo "Indica si se trata de un inicio de sesión o no."
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo "Ejemplos:"
    WScript.Echo ""
    WScript.Echo "- Registra el inicio de sesión en el fichero"
    WScript.Echo """\sauronmordorusuariossesiones%USERNAME%.tsv"":"
    WScript.Echo ""
    WScript.Echo "cscript //nologo registrar-sesion.vbs /I"
    WScript.Echo """\sauronmordorusuariossesiones%USERNAME%.tsv"""
    WScript.Echo ""
    WScript.Echo "- Registra el cierre de sesión en el fichero"
    WScript.Echo """\sauronmordorusuariossesiones%USERNAME%.tsv"":"
    WScript.Echo ""
    WScript.Echo "cscript //nologo registrar-sesion.vbs"
    WScript.Echo """\sauronmordorusuariossesiones%USERNAME%.tsv"""
    WScript.Echo ""
    WScript.Echo ""
    WScript.Echo ""

    End Sub 's_Ayuda

    Sub s_EnumeraGrupos(pobj_Grupo, str_Usuario2, obj_TS)
    '***********************************************************************
    '* Procedimiento: s_EnumeraMiembros *
    '* Tipo : Función *
    '* Devolución : Booleana *
    '* Fecha y Hora : 16/03/2010 16:48:01 *
    '* Autor : Fernando Reyes *
    '*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
    '* Propósito : Este método recibe un objeto de grupo de Active *
    '* Directory y enumera los usuarios que son miembros *
    '* de él y los de los grupos que contenga *
    '***********************************************************************

    Dim obj_Miembro 'As Object
    Dim str_NombreNT 'As String
    Dim str_NombreDN 'As String
    Dim str_Nombre 'Às String
    Dim str_Apellidos 'As String
    Dim int_UAC 'As String
    Dim str_Linea 'As String
    Dim str_Habilitada 'As String
    Dim str_CaducaEl 'As String

    'Recorremos los miembros del grupo
    For Each obj_Miembro In pobj_Grupo.Members

    'Sólo nos interesan los grupos
    If (LCase(obj_Miembro.Class) = "group") Then

    'Evitaremos los grupos que ya se han enumerado, para que
    'no se produzca un bucle infinito
    If (dic_Grupos.Exists( _
    obj_Miembro.sAMAccountName) = False) Then

    'Agregamos el grupo al diccionario para evitar una
    'segunda llamada sobre él
    dic_Grupos.Add obj_Miembro.sAMAccountName, True

    'Montamos la línea a mostrar
    'str_Linea = str_Usuario & """" & _
    ' Replace(obj_Miembro.Name,"CN=","") & _
    ' """" & vbTab & """Heredada"""

    'Si hay que enviar la información a un fichero
    If Len(str_Fichero) > 0 Then

    'Escribimos en el fichero
    ' obj_TS.WriteLine str_Linea

    'Como no hay que enviar la información a un fichero
    'será mostrada por pantalla
    Else

    WScript.Echo str_Linea

    End If

    'Realizamos una llamada recursiva para obtener los
    'miembros del grupo
    Call s_EnumeraGrupos(obj_Miembro,str_Usuario2,obj_TS)

    End If

    End If

    Next 'obj_Grupo.Members

    End Sub 's_EnumeraMiembros

    Function f_DNaCanonico(str_Contenedor, str_Dominio)
    '***********************************************************************
    '* Procedimiento: f_DNaCanonico *
    '* Tipo : Función *
    '* Devolución : Booleana *
    '* Fecha y Hora : 17/11/2010 9:33:36 *
    '* Autor : Fernando Reyes *
    '*¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*
    '* Propósito : Esta función recibe el nombre distinguido de un *
    '* contendor de AD, el nombre distinguido del dominio *
    '* y devuelve el nombre del contenedor como nombre *
    '* canónico. Por ejemplo: *
    '* *
    '* Contendor "OU=OU2,OU=OU1,DC=dominio,DC=local" *
    '* Dominio "DC=dominio,DC=local" *
    '* Devuelve "dominio.local\OU1\OU2 *
    '* *
    '***********************************************************************
    Dim str_Temporal
    Dim int_Elemento
    Dim arr_Contenedor
    Dim arr_Dominio
    Dim int_Dominio

    'Cargamos en un array el nombre del dominio suprimiendo
    'los "DC=" y considerando como separador la coma.
    'Es decir que primero convertimos "DC=dominio,DC=local" en
    '"dominio,local" y esto lo cargamos en el array, con la coma
    'como separador, lo que nos da los elementos "dominio" y "local"
    arr_Dominio = Split(Replace(str_Dominio,"DC=",""),",")

    'Guardamos en la variable el límite superior del array (el
    'dominio podría haber sido subdominio.dominio.local, por ejemplo
    int_Dominio = UBound(arr_Dominio)

    'Cargamos ahora el nombre distinguido del usuario en la variable
    'temporal. Usamos repetidas llamadas a la función replace para
    'conseguir que "CN=Gimli,OU=Montaña Solitaria,DC=enanos,DC=org"
    'se convierta en "Gimli,Montaña Solitaria,enanos,org" y así poder
    'cargar un array usando como separador la coma
    str_Temporal = _
    Replace( _
    Replace( _
    Replace( _
    Replace( _
    Replace( _
    Replace( _
    obj_Usuario.Parent, _
    """", _
    "'"), _
    "LDAP://", _
    ""), _
    "DC=", _
    ""), _
    ",OU=", _
    ","), _
    "OU=", _
    ""), _
    "CN=", _
    "")

    'Cargamos el array
    arr_Contenedor = Split(str_Temporal,",")

    'Vaciamos la variable temporal
    str_Temporal = ""

    'Ahora recorreremos el array del último al primer elemento
    For int_Elemento = UBound(arr_Contenedor) To _
    LBound(arr_Contenedor) Step -1

    'Si el límite superior menos el elemento actual es menor o igual
    'que el límite superior del array de dominio, significa que
    'estamos en la parte del nombre correspondiente al dominio. Como
    'queremos que esta parte quede con el nombre FQDN del dominio,
    'debemos encadenar los elementos por delante de lo anterior y
    'separado por un punto (estamos recibiendo antes el "local" que
    'el "dominio")
    If (UBound(arr_Contenedor) - int_Elemento) <= int_Dominio Then

    str_Temporal = str_Temporal

    Else

    'Ya no estamos en la parte de dominio, a partir de ahora queremos
    'que se encadenen los elementos detrás de lo anterior. Antes debemos
    'comprobar si estamos en el primer elemento después de los de
    'dominio, en cuyo caso hay que borrar el punto que hay siempre al
    'final después de haber montado el nombre del dominio. Necesitamos
    'además que ese punto final sea un slash inverso ("\")
    If (UBound(arr_Contenedor) - int_Elemento) = (int_Dominio + 1) Then

    'Quitamos el punto final y pegamos un slash inverso
    'str_Temporal = Left(str_Temporal,Len(str_Temporal)-1) & "\"

    End If

    'En cualquier caso, concatenamos el elemento y un slash inverso
    'detrás
    str_Temporal = str_Temporal & arr_Contenedor(int_Elemento) & "\"

    End If

    Next

    'Nos sobra un slash inverso al final, lo quitamos
    str_Temporal = Left(str_Temporal,Len(str_Temporal) - 1)

    'Devolvemos la cadena que hemos montado
    f_DNaCanonico = str_Temporal

    End Function 'f_DNaCanonico

  23. Josué Dorian Arce Orozco said

    Se me olvido comentar algo; esto lo personalice para mi dominio(UMB.MX), para que funcione en su servidor, deben de modificar lo siguiente:

    Linea 158 str_Dominio = “DC=UMB,DC=MX” ‘Cambiar por su Dominio
    Linea 159 str_DN = “DC=UMB,DC=MX” ‘Cambiar por su Dominio
    Linea 204 str_UserTemp = str_Usuario & “@UMB.MX” ‘Cambiar por su Dominio

    Esas son las unicas lineas que deben de modificar, ya que es el dominio en el que busca a todos los usuarios y hace las comparaciones con el usuario que se loguea en los equipos.

  24. Como dato pongo los datos que arroja el registro:

    Usuario Nombre Grupo Equipo Servidor Fecha Inicio Hora Inicio Fecha Cierre Hora Cierre

    Usuario, Nombre completo del usuario, grupo al que pertenece y lo demas es lo mismo.

    Ahora solo me falta ver como a la hora de hacer los registros coloque la hora del servidor, ya que toma la hora de la maquina donde accesan los usuarios y en unas maquinas estan mal las horas por cuestiones de la pila.

  25. Christian said

    Genial el script, estoy intentando localizar algún script que muestre la fecha del último logon de los usuarios, por aquello de localizar usuarios que se puede eliminar.

    Alguna idea de esto?

    Gracias!

  26. Jorge said

    Hola y saludos a todos

    Alguien conoce alguna forma de controlar los bloqueos/desbloqueos en una sesion ? El problema es el siguiente: por medio de script inicio/cierre de sesion intentamos evitar conexiones concurrentes pero si un usuario (1) bloquea sesion, aparece otro usuario (2), hace cambio y, posteriormente el usuario1 vuelve a entrar no conseguimos evitar que al entrar 2 quede “abierta” la sesion 1… y la vuelta posterior de este usuario 1 no es detectada… espero no explicarlo de forma retorcida.

    Gracias!

  27. Leire said

    Hola, muy bueno el script, pero me funciona, ni en el login ni en el logoff.

    Los controladores de dominio son windows 2003, y los servidores son windows2000. He ejecutado la actualizacion de la politica de equipo y usuario en ellos, pero no hay manera de que se ejecute el script definido.

    Si ejecuto el script desde un controlador de dominio se ejecuta correctamente, al igual que si lo hago desde uno de los windows 2000.

    La secuencia de comandos para logoff es: %windir%\cscript //nologo \\servidor\pruebas\registrar_accesos.vbs \\servidor\pruebas\%USERNAME%.tsv
    la de login es lo mismo pero incluyendo /I , tal y como indicas en el post.

    Muchas gracias.

    • urpiano said

      ¿Te funciona si lo ejecutas de forma interactiva? (es decir con una sesión abierta lanzar esas línea de invocación en una ventana de comandos).

      • Leire said

        Efectivamente, con la sesión abierta ejecuto el script en la linea de comandos, y no da ningún problema.
        Hay alguna manera de depurar los comandos de login y logoff? , algún fichero de log o algo?
        Gracias

      • urpiano said

        Leire,
        Puedes mirar en el visor de sucesos ¿Cómo has creado la GPO? Tiene que ser un script de incio de sesión y un script de cierre de sesión, no un script de inicio de equipo ¿Has comprobado con GPRESULT si se está aplicando esa GPO y esa directiva?

      • Leire said

        De hecho, si aplico la directiva a nivel local (en las directivas locales del servidor) si se ejecuta perfectamente, pero configurandolo a nivel de directiva GPO en el dominio, no.

      • urpiano said

        Leire,
        ¿No será que no encuentra el equipo cliente el script? En la GPO debes situar el script en la propia carpeta de la GPO

      • Leire said

        >Leire,
        >Puedes mirar en el visor de sucesos ¿Cómo has creado la GPO? Tiene que ser un script de incio de sesión y un script de cierre de sesión, no >un script de inicio de equipo ¿Has comprobado con GPRESULT si se está aplicando esa GPO y esa directiva?

        En el visor de sucesos sólo me salen los errores de la directiva local que he puesto mal a proposito para ver si veia algo, salen eventos de userinit (hasta ahí parece que normal)
        He configurado la misma directiva en local y a nivel de dominio, de la misma forma, en Directivas -> Confguracion de usuario -> Secuencia de comandos -> inicio de sesión, llamando al script \\servidor\pruebas\macro.bat. Macro.bat contiene la llamada a tu script.

        Los equipos donde despliego las directivas del dominio son windows2000 y no tiene el gpresult, yo hago un secedit /REFRESHPOLICY USER_MACHINE /ENFORCE para actualizar las directivas, pero no se cómo comprobar qué directivas se le estan aplicando :-/

        >Leire,
        >¿No será que no encuentra el equipo cliente el script? En la GPO debes situar el script en la propia carpeta de la GPO

        Si a nivel de directiva local, sí encuentra el script, ¿por qué no iba a funcionar puesta como direcitva de dominio? voy a ponerlo ahora en \\DOMINIO\SysVol\DOMINIO\Policies\{9317134E-1D68-40D6-A430-F0188B7D571F}\User\Scripts\Logon

        vamos a ver cómo va ahora.

      • Leire said

        Aunque ponga el script en el directorio del dominio, sigue sin salir nada :-( alguna otra idea?

    • urpiano said

      Leire,

      ¿Y si pruebas a lanzar el script desde un BAT? El bat sería algo así:

      cscript //nologo %0\..\nombre-de-script.vbs

      • Leire said

        Hola, así es como lo dejé despues de la ultimas pruebas de la semana pasada, pero nada.

        tengo macro.BAT en \\DOMINIO\SysVol\DOMINIO\Policies\{9317134E-1D68-40D6-A430-F0188B7D571F}\User\Scripts\Logon que incluye la llamada al otro script.

        macro.bat
        %windir%\system32\wscript.exe //nologo \\servidor\pruebas\registrar_accesos.vbs /I “\\servidor\pruebas\%USERNAME%.tsv”

      • Leire said

        Estoy depurando a tope, y haciendo que solo cree el fichero en c:\ con un usuario administrador del dominio, sigue sin hacer nada.
        Ahora estoy sobre un windows2003 server donde si puedo hacer un gpresult.

        Lo que me mosquea es que si escribe el fichero si lo ejecuto una vez he entrado en la sesión y no en el inicio de la misma…. algún otro modo de depurar? es posible que no esté llamando al script o algo, ¿cómo veo eso? en el visor de sucesos no sale nada

  28. Leire said

    Donde antes pone “pero me funciona”, es “pero no me funciona”, a veces la mente es más rapida que las pulsaciones de teclado …..
    Gracias

  29. Augustina said

    Thаnks fоr finally writing aƅoսt >Script VBScript Paгa Registrar Lοs Inicios Y Cierres Ɗe Sesión De Loѕ Usuarios El Blog
    Ԁe Gualtrysoft <Liked it!

  30. bro quien me puede ayudar en la linea 135 no se q dato poner

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: