Skip navigation

Tag Archives: vbscript

I haven’t written a scripting post in a while, but I’ve wanted to.  So in keeping with the spirit of my stick to the script posts lets look at something that is common among all scripting languages (even if the syntax isn’t).

Let’s talk about strings…….

 kitty-yarn

Awwww, but no.  These kind of strings.  In the case of scripting, I think the best way to think about it is, text, what you are reading or able to read.  They aren’t used mathematically (usually), but can and will be a huge component in your scripting.  Especially when automating things around a desktop or server environment.

Oh really?  Yes, really.  General uses for strings in a script are:

  • User messages
  • Reporting or logging
  • Comparisons
  • Explicit paths
  • Application execution
  • Conditionals

Ok, so maybe that list doesn’t look that impressive, but when you consider how much of that is done within a script, it becomes obvious the importance of string values to scripting.  It’s also important to recognize that in certain scripting environments, it’s important to define a string value as such so that it can be properly used. 

(Powershell for instance, requires you to properly define a value type to use the relevant functions… but I’m getting ahead of myself.)

So wait?  There are more than strings in a script?  Yes; Strings, Integers, and Booleans are your standard value types. Integers are numbers (math!) and Booleans are True or False.  So given those value types, perhaps it is a bit more obvious how frequently you will use string values?

So lets get into some sample code and evaluate strings some shall we?


VBScript:

strTest = "Hey, I'm a string value"

wscript.echo strTest
'Shows the string value
wscript.echo strTest&", and I've been concatenated to the value."
'& operator joins values
wscript.echo lcase(strTest)
'Lower case
wscript.echo ucase(strTest)
'Upper case
wscript.echo strReverse(strTest)
'Reverses the string
wscript.echo len(strTest)
'Gives the total length of a string
wscript.echo mid(strTest,10,8)
'Returns fix number of characters in string
wscript.echo left(strTest,11)
'11 chars from the left
wscript.echo right(strTest,13)
'13 chars from the right
'----------------------------------------------------------------
wscript.echo inStr(strTest,"a")
'Returns position of string from left to right
wscript.echo inStrRev(strTest,"a")
'Returns position of string from right to left
'----------------------------------------------------------------
a = split(strTest)
'Splits strTest by it's spaces
for each item in a
    wscript.echo item
   'echoes each dimension from the split array
next

wscript.echo a(3)&" "&a(4)

'echoes the split arrays dimensions 3 and 4
'---------------------------------------------------------------

strReturn=inputbox("Here, you try!")

if strReturn = "" then
   wscript.echo "Fine, don't play along"
else
    wscript.echo "So you said: "&trim(ucase(strReturn))&vbcrlf _
    &"Sheesh, no need to shout!"
end if
'---------------------------------------------------------------


Running the above script will give you a better understanding of what I’m about to explain.  I wanted to show some common functions in vbscript (syntax is different but these will be universal functions you will use).  The above are common string manipulation tools

 

Code explained… line by line

First we are defining our string to a variable strTest.  Now “in the wild” as it were, this string could be pulled from an object property, read from a file, registry, user input, output from another application, etc.  It’s best to define a string to a variable though, no matter the method for input.  This of course is the most direct way to do it for our example

Now we begin with the simplest string usage, output.

Now we raise the stakes a bit by joining an additional string value to our current strTest.  This action is known as concatenation.  This is a very common thing with string usage and manipulation.  Building complex values/messages/logs from various predefined and/or dynamically pulled string values.

Our next two examples have to do with manipulating case between upper and lower.  This is fairly self explanatory, and in the interest of string comparisons it’s usually a good practice (and often necessary) to force a case set, especially if the comparison function is case sensitive.

String reversal, this may not seem important initially, but makes a huge difference when you are forced to chop strings up.  The ability to reverse a string can go a long way for string chopping.  Especially if you are dealing with filenames.

The length function is another that may seem arbitrary to some, but allows for great flexibility as well in chopping up strings such as file names.  If you have a fixed number of characters to remove it’s sometimes simpler then splitting the string.  (so I wasn’t completely honest about the math stuff and strings)

Mid, Left, and Right.  These 3 can be used in conjunction with length to return a fixed number of characters from the left right, or middle (specified) of a string.  Here’s a quick easy example:

test="I am 18 chars long"
wscript.echo test
count=len(test)-4
wscript.echo right(test,count)

Very simply, we take the total length of Test and subtract it by 4, then return the sum of remaining characters from right to left of the original string.  In this example we, had a fixed value to subtract, be mindful you could use the length value of multiple strings to achieve the same type of results.

Now, InStr and InStrRev, or “In String” and “In String Reverse”.  These two functions make for great conditionals.  They, along with strComp, are excellent for determining like strings and taking action.  Especially when parsing through files and directories looking for specific returns. 

One of my favorites, especially in PowerShell, split.  Split takes a string, looks for a delimiter (space by default) and breaks the string up into an array.  Why do I like it so much?  Put simply, it allows you to quickly whittle down long path names into a single filename.  It also allows you to quickly and efficiently modify lists of data into manageable formats.  And last but not least, it can easily turn files like csv’s into an array for manipulation.

Finally, user input.  This is pretty self explanatory.  Prompt for input, receive and control input, use input.


In PowerShell, string functions are called like this:

$a=”This is a string value”

$a.ToString()

$a.ToUpper()

$a.ToLower()

$a.Replace(“a “,”my “)

$a.split(“ “)

$a.contains(“string”)

$a.StartsWith(“t”)

$a.EndsWith(“e”)

$a.Length

$a.CompareTo(“this is a string value”)

$a.Length.Equals(22)

$a.CharArray()

$a.PadLeft(“30”)

$a.PadRight(“30”)

$a.Trim()

$a.TrimEnd()

$a.TrimStart()

Given the previous examples in vbscript, you should be able to easily adapt your knowledge to using these in PowerShell.  The idea and purpose is still the same, again, the syntax is just different.


String manipulation inside Bash is, admitedly, a bit more convoluted so I won’t be touching on it in this post.  However I’d highly recommend an online source like: Mendel Cooper’s guide.  Again, the methodology will still be fairly the same, but the syntax will differ.  The largest issue with Bash is the myriad of ways of performing the string manipulation.

 

Anyway, I hope this has been informative for you.  Good luck, and happy scripting!

Advertisements

I’ve honestly been trying to post my final part to the “stick to the script” series.  However those actions have been soundly thwarted by an abundance of work, and a new workout regiment.  I hope to have it up and syndicated to myitforum before the weekend is over.

I’ve also built a nice sccm client install script, and thanks to John Marcum, I’ve built a nice remote cm wmi repair tool in powershell as well.

So stay tuned as I plan to start releasing those scripts after scrubbing them.

Today we are going to examine VBScript. Now, a bit of fair warning before we start on this.  This scripting language is a departure from our standard shell scripting.  VBScript is an automation scripting language for the Windows Script Host (WSH)/Internet Explorer (IE)/Internet Information Services (IIS), in short, this is the primary Windows scripting language.

Not to get too carried away on the subject, but this language uses a Component Object Model that allows direct (or indirect) action on just about every object within the windows environment and does so natively via the windows script host interpreter ((which is extensible) (wscript.exe or cscript.exe)).  There are nuances to that statement, and I encourage you to investigate it more thoroughly, however I’m going to jump right into some of the basics of using this language, then discuss the code below as we’ve done in the previous 2 posts.

First off, what is a component object model?  Put as simply as possible, they are exposed objects that you can manipulate in the environment by invoking their methods and properties.  This scripting language brings you dangerously close to windows development at times, but at it’s heart, it’s still very much a script.  Controlling environment objects and properties, performing sequenced tasks, and no compile.

Now, I’m going to introduce 4 new things with this script, I will name them now and explain them after we’ve reviewed the code:

Arrays

WMI

Subroutines & Functions (They can be the same, but in WSH they are different)

Loops

Function VBscript (blog)

The overall activity of this script is the same as our drivemounter batch script we made.  Lets take a look at the code.


‘||========================================||
‘||Author Daniel Belcher                   ||
‘||Function drivemounter                   ||
‘||Date 5/4/2011                           ||
‘||========================================||
‘|Objects, Variables, and Arrays ***********
‘\==========================================/
‘|Set number of items in array             ‘|
‘|Example: 3 drives would be (3,1) and 3   ‘|

Dim ArrDrive(6,1)                          ‘|
DriveCount = 7                             ‘|
’|Define the Array to read                 ‘|
    arrDrive(0,0) = "h:"                   ‘|
    arrDrive(0,1) = “\\uncpath\1”          ‘|
    arrDrive(1,0) = "i:"                  
‘|
    arrDrive(1,1) = ”\\uncpath\2”          ‘|
    arrDrive(2,0) = "j:"                   ‘|
    arrDrive(2,1) = ”\\uncpath\3”          ‘|
    arrDrive(3,0) = "k:"                   ‘|
    arrDrive(3,1) = ”\\uncpath\4”          ‘|
    arrDrive(4,0) = "l:"                  
‘|
    arrDrive(4,1) = ”\\uncpath\5”          ‘|
    arrDrive(5,0) = "m:"                   ‘|
    arrDrive(5,1) = ”\\uncpath\6”         
‘|
    arrDrive(6,0) = "n:"                   ‘|
    arrDrive(6,1) = "\\uncpath\7"          ‘|
‘|Define the Server to Ping for Net Check  ‘|
Dim
strSvr                                 ‘|
    strSvr = "servertoping"               
‘|
‘==========================================================================

Const DEBUGMSG = True    ‘True = Debug Messages, False = No Messages
Dim oWShell
    Set oWShell = CreateObject("WScript.Shell")
Dim oWNet
    Set oWNet = CreateObject("WScript.Network")
Dim Target
    Target = "."
Dim oWMISvc
    Set oWMISvc = GetObject _
("winmgmts:{impersonationLevel=impersonate}!\\"&Target&"\root\cimv2")
Dim oPing
    Set oPing = oWMISvc.ExecQuery _
("Select StatusCode From Win32_PingStatus where Address = ‘"&strSvr&"’")

‘|Main Run =================================================================
DriveMount        ‘Perform Function DriveMount
Report            ‘Perform Function Report
Wscript.Quit(0)   ‘Close Script
‘SubRoutines and Procedures ================================================
Sub Mount(letter,path)
    oWNet.MapNetworkDrive letter,path
End Sub
‘*****************************************************
Sub Umount(letter)
    oWNet.RemoveNetworkDrive letter
End Sub
‘|Functions ================================================================
Function DriveMount
http://msdn.microsoft.com/en-us/library/aa394350(v=vs.85).aspx
    For Each item in oPing
        If IsNull(item.StatusCode) or item.StatusCode<>0 Then
‘**********Domain not reachable, unmount drives in arrDrive
        x = 0
          do until x = DriveCount
             On Error Resume Next
                Umount arrDrive(x,0)
                       If debugmsg then msgbox "Umount"& vbcrlf _
                       &"Drive Letter: "&arrDrive(x,0)& vbcrlf _
                       &     "Error Number: "&Err.Number& vbcrlf _
                       &     "Error: "&Err.Description
              Err.Clear
        x = x + 1
          loop
        else
‘**********Domain exists, mount drives from arrDrive

        x = 0
          do until x = DriveCount
             On Error Resume Next
                Mount arrDrive(x,0), arrDrive(x,1) 
                       If debugmsg then msgbox "Mount"& vbcrlf _
                       &"Drive Letter: "&arrDrive(x,0)& vbcrlf _
                       &     "Error Number: "&Err.Number& vbcrlf _
                       &     "Error: "&Err.Description
              Err.Clear
         x = x + 1
          loop 

        End if
   Next
End Function

‘*****************************************************
Function Report
      If Debugmsg then msgbox "Script completed"
End Function
‘End ======================================================================


Copy and paste the code and save as a .vbs file (unless you have a specific editor, I recommend notepad to insure formatting is properly translated.)

Lets start with our 4 areas of interest we’ve focused on with the previous posts.

  1. Sequence
  2. Command usage
  3. Output usage
  4. Conditional logic

Sequence:

Sequencing and Command usage will be the most interesting topics this time around.  Unless wscript is pointed towards a specific function or sub, it reads everything in line.  This point is rather large when you consider BASH and POWERSHELL and a lot of other script languages which will error out if something is called that hasn’t been previously declared (speaking about functions and subroutines, variables must always be declared before usage).  However, the rule remains that everything is read one after another, or AS the interpreter is directed to read.

As a habit when I write my vbscripts I will almost always write them in this format. Variables, Run sequence, subs, functions.  There is no real reason for this outside of the fact I prefer to immediately see variables and prescribed run order.

Now lets look at our variable declaration and focus on what’s new.  An array, and a multidimensional one at that (more than two columns of data).  An array is an assortment of data stored in memory, think of it like a spreadsheet.  Row 0,1,2,3,4,5,6 and Column 0,1,2,3,4,5,6.  This would be a multidimensional array.  A simple array would be 1 Column (column 0) and however many rows as you wanted.  In this script I declare this array to be limited to 7 rows and 2 columns.  That sounds weird right, cause the declare clearly says (6,1) ?  Remember that 0 counts so 6 = 7 and 1 = 2, but you declare it by the integer value of the last entry.

Dim ArrDrive(6,1)

I then declare my Array entries by defining ArrayName(row,column) = data

arrDrive(0,0) = "h:"          ‘|
arrDrive(0,1) = “\\uncpath\1” ‘|
arrDrive(1,0) = "i:"         
‘|
arrDrive(1,1) = ”\\uncpath\2” ‘|

From here on out when I need to utilize any of these pieces of data I can simply call them using their array name and position.  Another way to think of this is a shared variable name perhaps?

Now lets discuss our run sequence:

‘|Main Run =================================================================
DriveMount      ‘Perform Function DriveMount
Report          ‘Perform Function Report
Wscript.Quit(0) ‘Close Script

This block of code dictates the run order of my script.  The first 2 are Functions I have defined, and the last is a wscript method to insure a clean exit (more on this in command usage).

Sequence is important. For organizations sake, I will take a quick and easy VBScript and build it in this fashion.  For me, and for others, it allows for simpler review and additions to be made to the script that could and will improve it’s functionality.  It’s also far simpler to isolate bad sections of your script and to target a specific function for testing.

Now let’s discuss the iteration statements that are introduced in the DriveMount function.  I will touch on the code more specifically when we break down what the script is doing, but an iteration statement is just a loop that continually performs a task until a certain condition has been met.  That could be reaching a certain number, that could be reaching the end of a file, that could be reaching the end of an array, etc.  In this script (although not how I would naturally do it) I’ve offered 2 concrete examples of vbscript loop statements for your review.

Finally, subroutines and functions.  Similar to labels, identical to the function I showed with BASH.  They are, put succinctly, sections of code that can be called by name to perform a fixed task.  In VBScript specifically a sub routine passes back no data, a function does.  So if I need to perform mathematical operations and reuse it as a variable elsewhere, I’d use a function*.  If I just need to move a file from one location to the next, a sub.  As a safe bet inside of VBScript, declare them all as functions, there is really no benefit I’ve found one way or the other.  I declare them as Sub and Function only to offer them as an example. Syntax for this is:

 Function Name                              Sub Mount                         

        Code to use                             Code to use

End Function                                End Sub

If you wish to use arguments with these functions/subs you would use:

Function Name (arguement1, arguement2, etc)

                Code using arguments provided

End Function

Command Usage:

Unlike our other scripting languages so far, the WSH doesn’t really utilize commands per say.  Command usage is actually called through a COM.  So when you build a vbscript, you spend the first portion of the script defining what COMs will be utilized in the script.  This is all part of my initial variable declaration (DIM statements or Declare Into Memory)

Dim oWNet
    Set oWNet = CreateObject("WScript.Network")

This is essentially creating the callable object or “commandoWNet for me to use moving forward.  What’s actually happening is I am using the WScript object to instantiate (create an instance of) the WshNetwork object for later method or property usage (exposing the object for manipulation).

This is how an object based language works, call the object, use the object, (and ideally) release the object.  When I later use these objects methods I will do so by invoking them.  Syntax comes in to play in these cases.

             oWNet.MapNetworkDrive letter,path

That is the invocation of the WshNetwork MapNetworkDrive method which requires drive letter then path to map.  Hopefully that makes sense, it’s an extra step but allows for some amazing control and it remains rather light weight as it depends on existing objects for it’s control base as opposed to having them already built in.  However that’s not to say there aren’t commands built into the WSH but they are for conditional and iteration statements as well as integer, string, and date functions (w3schools.com has a nice breakdown as well) etc.

Output Usage and Conditional Logic:

For this script the output usage is in reading a ping response, mapping drives, and in exception handling (error catching).  We read the status code from the WMI Win32_PingStatus class object (list of WMI Classes) then use it as our condition.  We then loop through the array and perform the appropriate action while catching and clearing any potential errors.  We also redirect that error output to a popup message if DEBUGMSG Boolean is set to TRUE in our initial variable declaration.

Our conditional logic as stated before is in the form of IF statements.  I will demonstrate case statements in my PowerShell write up.  Case statements look for something (usually a specific string type) and respond in a defined way.  However a case statement is strictly defined where an IF statement is generally this or that, it will make more sense in the future I promise.


So what does this vbscript do?

In this script we open with our declarations.  We define our Array ArrDrive as a 7 row and 2 column array (0 counts, remember though declaration will be the last integer value so in this case: 6,1) and supply it with values.  We set a Boolean for debugging messages and we set our object instance for WScript.Network to oWNet. 

We also start an instance of the WMI Service, and define a WQL that reads the ping status to a targeted server (strSvr) for us (Target=”.” means the local machine, it can be changed for remote PC name, more on wmi scripting).  (WMI is Windows Management Instrumentation, similar to the WSH objects it contains a series of namespaces, classes, methods, and properties to control the windows platform.  Essentially if you can do it on the Windows machine, there is a WMI namespace/class/method involved in it.)

Dim Target
    Target = "."
Dim oWMISvc
    Set oWMISvc = GetObject _
("winmgmts:{impersonationLevel=impersonate}!\\"&Target&"\root\cimv2")
Dim oPing
    Set oPing = oWMISvc.ExecQuery _
("Select StatusCode From Win32_PingStatus where Address = ‘"&strSvr&"’")

Now that we have all that declared we move into our run sequence.  The Function DriveMount is first and it immediately performs a For Each statement through our oPing WQL and grabs the statuscode value and compares it with an IF statement.

For Each item in oPing
         If IsNull(item.StatusCode) or item.StatusCode<>0 Then

If there is no value, or the status code is anything but 0 (0 is a clean exit code, success, that’s what the status code is in its simplest form) then we aren’t in our appropriate network so we will begin a Dismount loop.  If the return value is 0 and is NOT null then we will perform a Mount loop.

Lets stop here for a second so I can explain this loop line for line, first the code sample:

‘**********Domain exists, mount drives from arrDrive

x = 0
  do until x = DriveCount
     On Error Resume Next
        Mount arrDrive(x,0)
, arrDrive(x,1)  
              If debugmsg then msgbox "Mount"& vbcrlf _
              &"Drive Letter: "&arrDrive(x,0)& vbcrlf _
              & "Error Number: "&Err.Number& vbcrlf _
              & "Error: "&Err.Description
     Err.Clear
x = x + 1
   loop

We declare x as 0, we will enumerate this integer value with each pass of our iteration (loop).  Word of warning here, if using this method make doubly sure that you set your enumerate value outside of the loop or it will be re-declared each loop and become an infinite loop.

We do until x = DriveCount, we declared DriveCount as 7 at the start of the script.  This loop will loop 7 times.

On Error Resume Next, we will not let error outputs break our function, we will perform the next in line.

We run the Mount subroutine passing the letter and path arguments which we pull from our arrDrive array.  We use x to select our row (remember we are enumerating x) and select the appropriate column for the data to pass.

Now as an extra step, we check for the DEBUGMSG Boolean, if it’s TRUE, we generate a popup window that tells us what Subroutine is being used, drive letter, error number, and error message. (if the drives are already mounted it WILL error, the error is that the drives are already mounted, so this is helpful if we are chasing something down)

We clear the errors that may or may not have been generated.

Now we take x and we add 1 to it, so 0 becomes 1, 1 becomes 2, 2 becomes 3, etc on each successive pass.

Finally we terminate the statement with loop so that the WSH knows to return to the start of the loop statement.

Easy huh?  There is a lot of power to learning how to use loops and for each statements effectively.

I would normally have just made another for each statement against the array which would read it to the end, but I felt this serves as a great learning opportunity.

At this point our DriveMount function is complete so we move to the next Function in the run sequence which is Report.  Report runs a debugmsg check and tells us the script completed if debugmsg is true.

Now back to our run sequence where we close our script with

Wscript.Quit(0)

This insures an exit code of 0 which is a universal “everything ran great, nothing to see here” output.

End Function

Next up we will be discussing PowerShell.  A very robust shell scripting language for the newer windows platforms (xp sp3+) that utilizes commands, .net, com, wmi, dcom, and the list goes on.  I’ll try to keep it lite.


Now for some bonus material, lets take a look at the Mount loop if I had used a For Each instead of a conditional loop:

x = 0
For Each object in arrDrive
    On Error Resume Next
       Mount arrDrive(x,0), arrDrive(x,1)
            If debugmsg then msgbox "Mount"& vbcrlf _
            &"Drive Letter: "&arrDrive(x,0)& vbcrlf _
            & "Error Number: "&Err.Number& vbcrlf _
            & "Error: "&Err.Description
     Err.Clear
x = x + 1 
Next

You are probably thinking “this looks the same, why is this better?”.

When you perform a conditional loop statement it needs a stop point which is another factor you have to manage.  In this case we had to declare a maximum loop count (our DriveCount variable which was 7).  A for each statement will go through a list till the end and then move on.  You can think of a for each statement as “For Each item in whatever until the end.”

If you have any questions or corrections, please leave a comment and I’ll try and get back with you about it. For an unaltered version of this script to copy and paste, go here.