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…

Trabajar Con Argumentos En VBScript

Posted by urpiano en Sábado 23 \23\UTC junio \23\UTC 2007

Este es un breve tutorial que cuenta cómo se trabaja con argumentos en los scripts VBScript. Conoceremos el objeto wshArguments, que es una colección del objeto WScript con los argumentos que ha recibido el script.

Los Argumentos De CScript.exe Y WScript.exe

Para diferenciar los argumentos propios de un script de los de WScript.exe o CScript.exe, los argumentos de estos dos ejecutables van precedidos siempre por dos barras de división. Los argumentos propios de estos ejecutables son

  • //B Modo por lotes: suprime de la pantalla los mensajes de error y avisos de secuencias de comandos
  • //D Habilitar la depuración activa
  • //E:engine Usar el motor para ejecutar la secuencia de comandos
  • //H:CScript Cambia el host de secuencias de comandos predeterminado por CScript.exe
  • //H:WScript Cambia el host de secuencias de comandos predeterminado por WScript.exe (opción predeterminada)
  • //I Modo interactivo (opción predeterminada, frente a //B)
  • //Job:xxxx Ejecutar una tarea WSF
  • //Logo Mostrar logotipo (opción predeterminada)
  • //Nologo Impedir que se muestre el logotipo: no se mostrará ningún titular en tiempo de ejecución
  • //S Guardar las opciones de la línea de comandos actuales para este usuario
  • //T:nn Tiempo de espera en segundos: tiempo máximo permitido para que se ejecute una secuencia de comandos
  • //X Ejecutar una secuencia de comandos en el depurador
  • //U Usar Unicode para los datos de E/S redirigidos de la consola (solo en CScript)

Es decir que si, por ejemplo, lanzamos un script así, el script se lanzará sin mostrar el logotipo (muy util en scripts que devuelven listados):

cscript //nologo script.vbs

Argumentos De Los Scripts VBScript

Los argumentos de un script VBScript pueden ser con nombre o sin nombre. Los argumentos sin nombre van escritos sin más:

cscript //nologo sin_nombre1 sin_nombre2 sin_nombre3 …

Los argumentos con nombre tienen una etiqueta definida después de una barra de división. Los hay de dos tipos:

  • Modificadores u opciones: sólo se recibe el argumento con nombre, que será usado para que el script se comporte de determinada manera. Ejemplo /R
  • Parámetros: los parámetros son argumentos que sí que tienen un contenido. El parámetro consta de etiqueta y valor, estando el valor separado de la etiqueta por dos puntos. Ejemplo /O:c:listadosents.txt (la etiqueta es /O y el valor c:listadosents.txt).

La etiqueta de los argumentos con nombre no está limitada a un solo caracter, puede ser una palabra completa (ejemplo: /servidor).

Tanto los argumentos con nombre como los argumentos sin nombre puede que incluyan espacios en su contenido. Cuando esto sucede es necesario que se encierre entre comillas (las comillas no se incluirán como parte del valor):

cscript script.vbs /a:Este es el parámetro con nombre a y este es el parámetro sin nombre 1

Daría como resultado un parámetro con nombre /a cuyo contenido sería Este y nada menos que 14 argumentos sin nombre (es, el, parámetro, con, nombre, a, y, este, es, el, parámetro, sin, nombre, 1). Como realmente sólo queríamos pasar un parámetro con nombre y uno sin nombre, la línea debe ser esta otra:

cscript script.vbs /a:"Este es el parámetro con nombre a" "y este es el parámetro sin nombre 1"

No sólo se debe encerrar entre comillas los valores, también se debe hacer con las etiquetas de los argumentos con nombres si estas incluyen espacios en medio (sí, se puede hacer :-)):

cscript script.vbs /primer argumento con nombre:"su valor"

Esta línea daría como resultado un modificador, /primer y tres argumentos sin nombre: argumento, con y nombre:su valor (nótese cómo se ha convertido en un sólo argumento nombre:"su valor" y cómo han desaparecido las comillas). La línea debería haberse escrito así:

cscript script.vbs /"primer argumento con nombre":"su valor"

Argumentos Con Nombre Vs Argumentos Sin Nombre

¿Cuándo es mejor un tipo de argumento frente a otro? De manera general, podemos decir que siempre son mejores los argumentos con nombre, pues nos permiten pasar modificadores y parámetros en cualquier orden, mientras que los argumentos sin nombre son interpretados en el script según el órden en que se pasen. Esto hace que con parámetros sin nombre sea más fácil que se produzcan confusiones (¿que parámetro debía poner antes?).

Generalmente se usan los parámetros sin nombre cuando se trata de pocos parámetros y todos del mismo tipo. No suele ser deseable mezclar ambos tipos de argumentos, siendo mejor usar sólo sin nombre o sólo con nombre. No obstante, hay un caso en el que si es interesante el mezclarlos: cuando tenemos modificadores y parámetros opcionales y uno dos parámetros requeridos, puede ser muy útil poner los modificadores y parámetros opcionales como argumentos con nombre y los parámetros requeridos como argumentos sin nombre. Por ejemplo, un script que copie un fichero a una carpeta no necesita que ambos parámetros tengan nombre:

cscript copiar-fichero.vbs c:listadosorcos.txt e:moria

Si este mismo script preguntase si debe sobreescribir el fichero en caso de que exista en el destino, podría llevar un modificador que así lo indicase, evitando el preguntarlo:

cscript copiar-fichero.vbs /s c:listadosorcos.txt e:moria

Verificación De Argumentos

Una vez recibe los argumentos un script, deberían ser siempre revisados, para comprobar que no se han pasado argumentos de más, que no se han pasado argumentos con nombre no contemplados en el script y que han sido pasados todos los argumentos requeridos .

Comprobación Del Número De Argumentos Pasados

El objeto wshArguments tiene una propiedad Count que devuelve el número de argumentos pasados. Esta cuenta es la suma de argumentos con y sin nombre. Si, por ejemplo, la suma de todos los parámetros es 5, podemos comprobar si se han pasado argumentos de más de la siguiente forma:


If WScript.Arguments.Count > 5 Then

    WScript.Echo "Error 1: se han pasado demasiados argumentos."
    WScript.Quit 1
	
End If

 

No obstante, esto tiene sus problemas ¿qué pasa si hay un argumento sin nombre requerido y se pasan cinco argumentos con nombre, aunque uno de ellos no sea propio del script? En estos casos podemos desear contar los argumentos sin nombre por un lado y los con nombre con otro. Esto se puede hacer gracias a dos propiedades del objeto wshArguments: la propiedad Unnamed y la propiedad Named. Ambas propiedades son objetos de tipo colección que tienen una propiedad Count, que devuelve el número de argumentos que contienen. Así, para controlar el ejemplo anterior, deberíamos hacer esto otro:


'Controlamos que el número de argumentos sin nombre no sea más de uno
If WScript.Arguments.Unnamed.Count > 1 Then

    WScript.Echo "Error 1: se han pasado demasiados argumentos sin nombre."
    WScript.Quit 1

'Controlamos que el número de argumentos sin nombre no sea inferior a uno
ElseIf WScript.Arguments.Unnamed.Count < 1 Then

    WScript.Echo "Error 2: no se ha pasado el argumento sin nombre requerido"
    WScript.Quit 2
	
End If

'Controlamos que el número de argumentos con nombre no sea superior a cuatro
If WScript.Arguments.Named.Count > 4 Then

    WScript.Echo "Error 3: se han pasado demasiados argumentos con nombre"
    WScript.Quit 3

End If

 

Obviamente, el control primero podría haber sido preguntando, sencillamente, si el número de argumentos sin nombre era distinto de uno, pero no habría tanta precisión en el informe del error.

Comprobación De Que Están Contemplados Todos Los Argumentos Con Nombre

Para hacer esta comprobación hay que relizar un enfoque un poco indirecto. Personalmente no suelo hacer esta comprobación, pues ¿qué más da? Si se pasa un parámetro con nombre que no es contemplado por el script, sencillamente será ignorado. No obstante, si queremos ser totalmente pulcros, se debería avisar al usuario de que ha pasado un argumento con nombre que no es contemplado por el script. Habrá tantas soluciones como desarrolladores. Por ejemplo, esta sería una manera de hacerlo.

Consiste en recorrer la colección completa de argumentos, no la colección de argumentos con nombre. Cuando hacemos esto, el objeto wshArguments devuelve como valor del argumento su etiqueta más valor. A base de trocear cadenas, podemos acabar obteniendo la etiqueta y por tanto sabiendo si el argumento con nombre es contemplado o no. Pongamos que tenemos un script que contempla los argumentos /A, /B, /C y /D.


'Array con los nombres de argumentos contemplados
Dim arr_Argumentos

arr_Argumentos = Array("A","B","C","D")

'Contador de elementos del array
Dim int_Elemento

'Almacenará dónde están los dos puntos en los parámetros
Dim int_Puntos

'Almacenará la etiqueta del argumento con nombre
Dim str_Etiqueta

'Contador de argumentos
Dim int_Argumento

'Se pondrá a True si el argumento se encontró
Dim bol_Encontrado

'Almacenará el mensaje en caso de encontrar un argumento no
'contemplado
Dim str_Mensaje

str_Mensaje = ""

'Recorremos todos los argumentos en un bucle For
For int_Argumento = 0 To WScript.Arguments.Count - 1

    'Revisamos si el argumento recibido es con nombre o sin él.
    'Para ello miramos si comienza por barra de dividir
    If Left(WScript.Arguments(int_Argumento),1) = "/" Then

        'Obtenemos la posición de los dos puntos que separan la
        'etiqueta del valor, en el caso de los parámetros
        int_Puntos = InStr(1,WScript.Arguments(int_Argumento),":")
		
        'Se ha encontrado el caracter de dos puntos, es un parámetro
        If int_Puntos > 0  Then
        
            'La etiqueta es, por tanto desde el segundo caracter 
            '(la barra de división la quitamos) hasta el anterior a 
            'los dos puntos
            str_Etiqueta = Mid(WScript.Arguments(int_Argumento), _
			                   2,int_Puntos - 2)		
                         
        'No se ha encontrado el caracter de dos puntos, es un
        'modificador
        Else
        
            'La etiqueta es todo el argumento menos la barra de
            'división inicial
            str_Etiqueta = _
                   Right(WScript.Arguments(int_Argumento), _
                      Len(WScript.Arguments(int_Argumento)) - 1)

        End If

        'Marcamos como no encontrado el argumento
        bol_Encontrado = False
		
        'Veremos ahora si está la etiqueta dentro del Array
        For int_Elemento = LBound(arr_Argumentos) To _
	                               UBound(arr_Argumentos)	
										
            If Ucase(arr_Argumentos(int_Elemento)) = _
	                           Ucase(str_Etiqueta) Then
			
                bol_Encontrado = True
                Exit For
				
            End If
			
        Next 'int_Elemento

        'Si no se ha encontrado el argumento, lo almacenmos
        'en el mensaje
        If Not bol_Encontrado Then
			
            str_Mensaje = str_Mensaje & "El argumento " & _
                          str_Etiqueta & " no está cont" & _
                          "emplado en este script." & vbCrLf
							  
        End If    
	
    End If

Next 'int_Argumento

'Si el mensaje tiene contenido...
If Len(str_Mensaje) > 0 Then

    'mostramos el mensaje y terminamos el script con error 1
    WScript.Echo "Error 1: Parámetro/s no contemplado/s " & _
                 "por este script. El/los parámetro/s no" & _
                 " contemplado/s es/son:" & vbCrLf & _
                 vbCrLf & str_Mensaje
    WScript.Quit 1
    
Else

    'Todos los argumentos pasados son contemplados por el script,
    'lo indicamos y salimos del script sin error
    WScript.Echo"Argumentos correctos"
    WScript.Quit 0

End If

 

Comprobación De Argumentos Requeridos

Para comprobar que están todos los argumentos requeridos, debemos tener en cuenta si los argumentos requeridos son con nombre o sin nombre.

Argumentos Requeridos Sin Nombre

Los argumentos sin nombre requeridos tan sólo pueden ser revisados contándolos. Para ello usamos la propiedad Count de la colección Unnamed. Supongamos que un script recibe dos argumentos sin nombre requeridos, el control a establecer sería algo así:


If WScript.Arguments.Unnamed.Count <> 2 Then

    WScript.Echo "Número de argumentos sin nombre erroneo." & _
	         " El número de argumentos sin nombre debe" & _
                 " ser dos."
    WScript.Quit 1
	
Else

    WScript.Echo "Número de argumentos sin nombre correcto"
    WScript.Quit 0 

End If

 

Esto es una limitación y hace que sea obvio que en el momento en que no todos los argumentos sin nombre sean requeridos, será necesario que pasemos los opcionales como argumentos con nombre, para así poder tener mejor control.

Argumentos Requeridos Con Nombre

Es muy fácil comprobar si ha sido pasado un argumento con nombre gracias al método Exists de la propiedad Named. A este método se le pasa como parámetro la etiqueta del argumento (sin la barra de división) y devuelve True en el caso de que el argumento haya sido pasado y False si no lo ha sido. Pongamos que se debe pasar el argumento con nombre /R:


If Not WScript.Arguments.Named.Exists("R") Then

    WScript.Echo "Error 1: El argumento /R es un argumento requerido"
    WScript.Quit 1
	
End If

 

Como se puede ver, el uso de argumentos con nombre es mucho mejor que el de argumentos sin él, pues permite preguntar por un argumento en concreto, independientemente del número de argumentos pasados y del orden en que lo hayan sido.

Obteniendo Los Valores De Los Parámetros

Vamos a ver ahora cómo se obtiene el valor de los parámetros que se han recibido.

La forma más básica es por medio de la propiedad Item del objeto wshArguments. Esta propiedad nos permite consultar el valor de un argumento según el órden en que ha sido pasado. Si lanzamos este script:

cscript //nologo script.vbs sin_nombre1 /R:con_nombre1 sin_nombre2 /L:con_Nombre2

Este bucle mostrará en pantalla los argumentos recibidos según el orden en que fueron pasados:


For i = 0 To WScript.Arguments.Count - 1

    WScript.Echo WScript.Arguments.Item(i)

Next 'i

 

La propiedad Item es la predeterminada del objeto wshArguments, con lo que se puede omitir y obtener lo mismo:


For i = 0 To WScript.Arguments.Count - 1

    WScript.Echo WScript.Arguments(i)

Next 'i

 

En ambos casos la devolución será la misma:


sin_nombre1
/R:con_nombre1
sin_nombre2
/L:con_nombre2

 

Como vemos, se mezcla todo, lo que hace que no sea una forma deseable de referirse a los argumentos. Por ello, es preferible recorrer los argumentos sin nombre, con Unnamed, y los con nombre por otro, con Named:


WScript.Echo "Argumentos sin nombre:"

For i = 0 To WScript.Arguments.Unnamed.Count - 1

    WScript.Echo WScript.Arguments.Unnamed(i)

Next 'i

WScript.Echo
WScript.Echo "Argumentos con nombre:"

For i = 0 To WScript.Arguments.Named.Count - 1

    WScript.Echo WScript.Arguments.Named(i)

Next 'i

 

La devolución de este script daría los parámetros ordenados:


Argumentos sin nombre:
sin_nombre1
sin_nombre2

Argumentos con nombre:
con_nombre1
con_nombre2

 

No obstante, en el caso de los argumentos con nombre no es necesario recorrerlos con un bucle, gracias al método Exists de Named, que nos permite preguntar diréctamente si un argumento con nombre ha sido o no pasado. Para referirse al argumento, tanto en el método Exists como a la hora de que Named nos devuelva su valor, se utiliza la etiqueta sin la barra de división:


'Comprobamos si ha sido pasado el argumento con nombre F
'y, en caso afirmativo, guardamos su valor en la variable
'str_Fichero
If WScript.Arguments.Named.Exists("F") Then

    str_Fichero = WScript.Arguments.Named("F")
	
End If

 

Script "Destripa" Argumentos

Para finalizar. este script que nos devuelve los argumentos pasados, indicando si son con nombre o sin él, y en el caso de tener nombre nos dice cuál es este nombre. Reune en sí varias de las técnicas que hemos visto a la hora de tratar con los argumentos:


Dim int_Argumento

'Recorremos todos los argumentos
For int_Argumento = 0 To WScript.Arguments.Count - 1

    'Mostramos el argumento tal y como lo devuelve
    'Arguments
    WScript.Echo "Argumento nº " & int_Argumento & _
                 ": """ & WScript.Arguments( _
                                int_Argumento) & """"

    'Como estamos refiriendonos a los argumentos
    'directamente con Arguments, los argumentos con nombre
    'son devueltos con la etiqueta incluída, por lo que
    'empiezan por barra de dividir. Con este If separamos
    'los argumentos con nombre de los sin nombre
    If Left(WScript.Arguments(int_Argumento),1) = "/" Then
    
        'Obtenemos la posición de los dos puntos en el
        'parámetro. En caso de que se trate de un
        'modificador, no serán encontrados y la devolución
        'de InStr será cero
        int_Puntos = InStr(1,WScript.Arguments(int_Argumento),":")
        
        'Si los dos puntos han sido encontrados...
        If int_Puntos > 0  Then

            'Extraemos el nombre del argumento usando Mid, en
            'lo devuelto por Arguments, como lo que hay entre
            'la barra de dividir inicial y los dos puntos, y
            'su contenido pasando lo anterior como identificador
            'a Named
            WScript.Echo """" & Mid(WScript.Arguments( _
                               int_Argumento),2,int_Puntos - 2) & _
                         """ es un parámetro con nombre, cuyo" & _
                         " valor es """ & WScript.Arguments.Named( _
                         Mid(WScript.Arguments( _
                         int_Argumento),2,int_Puntos - 2)) & """"

        
        'No hay dos puntos, es un modificador                 
        Else
        
            'Extraemos el nombre del argumento usando Mid, en
            'lo devuelto por Arguments, como lo que hay desde
            'la barra de dividir inicial hasta el final
            WScript.Echo """" & Right(WScript.Arguments( _
                                               int_Argumento), _
                                      Len(WScript.Arguments( _
                                        int_Argumento)) - 1) & _
                         """ es un modificador, por tanto " & _
                         "no tiene contenido."
                         
        End If

    'Como el argumento no comienza por barra de dividir se trata
    'de un argumento sin nombre        
    Else

        'Mostramos el valor del argumento sin nombre    
        WScript.Echo """" & WScript.Arguments(int_Argumento) & _
                     """ es un argumento sin nombre."
        
    End if
            
Next 'int_Argumento

WScript.Quit 0

 

4 comentarios to “Trabajar Con Argumentos En VBScript”

  1. Ramón Sola said

    Magnífico trabajo, enhorabuena. :-)

  2. Maxi said

    Hola urpiano necesito que me des una gran mano, estoy intentando realizar un gpupdate /force en una maquina remota dentro de una lan, si me pasas los pasos te lo voy a agradecer

    Un saludo y gracias

  3. Maxi said

    mi mail es magall2000@yahoo.com.ar

  4. urpiano said

    Mira si te ayuda este script:

    Script VBScript Para Ejecutar Un Comando En Un Equipo Remoto

    En concreto, si el equipo se llama equipo la línea que deberías ejecutar sería:

    cscript //nologo comando-remoto.vbs /e:equipo /u:tudominio\administrador /c:contraseña "cmd /c gpupdate /force /wait:0"

    De esta manera se ejecutaría y no pediría confirmación para cerrar sesión o reiniciar el equipo. Si deseas que se reinicie el equipo o cierre la sesión, tienes modificadores de GPUPDATE para ello; /Boot para reiniciar y /Logoff para cerrar sesión; deberías sustituir /wait:0 por ellos.

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: