mbt masai
 
Welcome !
         

                                
After experiencing a lot of down time, We decided to move this site to CrystalTech.com. CrystalTech.com is powered by only the finest Windows servers providing the best performance, reliability, and value anywhere.

 How to organize your script

Author Message
ebgreen

  • Total Posts : 8088
  • Scores: 95
  • Reward points : 0
  • Joined: 7/12/2005
  • Status: offline
How to organize your script Tuesday, March 30, 2010 6:31 AM (permalink)
0
This topic has the potential to create a bit of controversy. First, let me say that I am simply going to present the way I do things and feel free to take or leave as much of it as you want. I'll be happy to discuss my decisions (or yours) in the comments. Second, to be honest I don't care if everyone does things my way or not. What I do care about is that everyone at least make some attempt at organizing and formatting their scripts in some consistent way.

Overall Organization
Here is how I try to organize my scripts. Notice I say try since I am not always completely successful.

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''
''     File Name:     Something.vbs
''     Author:     EBGreen
''     Purpose:     Demonstrate script organization
''     Parameters:
''         /Param1 - Example parameter. Doesn't really do anything
''         /Param2 - Another example parameter that won't really do anything
''     Example Use:
''         CScript.exe Something.vbs /Param1
''         This would run the script passing in the param1 parameter
''     History:
''         03/30/2010 - RMD - v1.0     Initial creation of the script
''         03/30/2010 - RMD - v1.1     Changed nothing really
''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Explicit

'Global Constants
Const SCRIPTVERSION = "1.1"

'Global Variables
Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
Dim strTestVariable

'Main Code
strTestVariable = "This is where the main flow of the script goes"
WScript.Echo strTestVariable
Test "This is in one of the support subs"

'Functions and Subs
Sub Test(strIn)
    WScript.Echo strIn
End Sub

Details
So here is why I organize things the way that I do.

Header
Having a header is a maintenance issue. Knowing why the script exists, who to ask about it, how long ago they worked on it, and how to run the script can be a great time saver for a maintenance coder that needs to pickup and modify a script that you wrote 5 years ago. For that matter having that data has helped me when I've had to modify my own scripts five years later. This unfortunately is the portion of the script that I most often leave off. Often I'll do a quick script just to explore some possibility or to help someone out and I won't take the time to put the header on up front. Then I just never go back and add it.

Option Explicit
Use it. Always. Period.

Constant and Variable Declaration
Since you will always be using Option Explicit, you will always need to Dim your variables. I always declare at the top of a block of code. So global variables and constants (whose use should be as minimal as possible) always get declared at the very top of the script. Variables inside a sub/function get declared at the top of the sub/function. There is a competing methodology that says you should declare variables as close as possible to where you will be using them. To be honest, I have no problem with people doing it this way (as long as they are consistent). I do it at the top for two reasons. First, it is habit. It was the most common method when I started scripting, so I have simply always done it that way. Second, the primary reason for the "Declare it close to use" methodology is for strongly typed languages so that you never have to look very far to see the variable declaration and know it's type. VBScript is not strongly typed. I don't need to know the type of a variable since I can put whatever I want into it. As a matter of fact, the only reason that I bother to declare (Dim) the variables at all is because using Option Explicit makes it mandatory.

Main Code
After I have declared all the global variables and constants, I have the main logic of the script. There are two primary goals that I aim for when writing this section. One I always accomplish, the other, not so much. The first goal is that this section of code is the only place a global variable or constant should be used. Let me say that in another way. global variables and constants should never be used in subs and functions. This goal I pretty much always hit with no problem. The second goal that is usually more of a struggle is that this main code section should be as small and clear as possible. I try to make this section small enough that I can see the entire section on the monitor at one time. For very complex scripts, this is often a goal that I fail at, but I still try. The way to minimize this section is to refactor as much as possible so that this section is purely just the logic of the script. All the real work of the script is done in subs and functions. So for instance Let's say that I wanted to write a script that simply gave a specific message based on the machine's OS. Here is one way to do that (yes, I know I left the header off):

Option Explicit

Dim oWMI : Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Dim colItems
Dim oItem
Dim strCaption

Set colItems = oWMI.ExecQuery("Select * from Win32_OperatingSystem",,48)
For Each oItem In colItems
    strCaption = oItem.Caption
Next

if Instr(strCaption, "XP") > 0 Then
    WScript.Echo "This is an XP based OS"
Else
    WScript.Echo "This is not an XP based OS"
End If


There is nothing wrong with this code. As a matter of fact if I was writing a script to do just this, I would probably be fine with it just the way that it is. Now imagine however that this is just one of 53 different such similar tests that a script was doing. Having the code in there that gets the OS is just cluttering up the flow of reading and understanding what the script is doing. Instead, this is how I would really do this:

Option Explicit

'Main Code
if Instr(GetOSCaption, "XP") > 0 Then
    WScript.Echo "This is an XP based OS"
Else
    WScript.Echo "This is not an XP based OS"
End If

'Subs and Functions
Function GetOSCaption()
    Dim oWMI : Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Dim colItems
    Dim oItem

    Set colItems = oWMI.ExecQuery("Select * from Win32_OperatingSystem",,48)
    For Each oItem In colItems
        GetOSCaption = oItem.Caption
    Next
End Function


Now you can read the main code section and quickly understand what the script is trying to do overall. If you need to know how the script is doing one specific thing, you can certainly still go look at the code that determines the OS caption. With the first version of the script though, you had to wade through the WMI code every time you wanted to read the script. Note that putting as much of the functionality (not logic) of the script out in small subs and functions makes much more of your code reusable in the future as well.

Functions and Subs
Here is where I put all the subs and functions that do the real work of the script. Again I have two goals for all these subs and functions. First, no global variables are used in a sub or a function. I can't think of a time recently when I have not hit this goal and if I did miss it, it was simply an oversight. I have never seen a situation where it is necessary to use a global in a sub/function. The second goal I pretty much always hit although occasionally I won't for one reason or another. It is that every sub/function should be as small as possible. Again if possible I want to be able to see the entire contents of a sub/function in one monitor screen size.

Conclusion
Again, these are just my guidelines. They are however guidelines that I have come to over several years of writing scripts and trying to perfect my crafting of said scripts. With this tutorial I'm not trying to get people to implement my ideas so much as to get them thinking about the topic in general. It's not important that you do it my way, but it is important that you give thought to how you organize your scripts and try to do so consistently.
<message edited by ebgreen on Tuesday, March 30, 2010 7:08 AM>
"... when you are good and crazy, oooh, oooh, oooh, the sky is the limit!" - The Tick
Goog places to start:http://www.visualbasicscript.com/m_24727/tm.htm
http://www.visualbasicscript.com/m_47117/tm.htm
#1
    ehvbs

    • Total Posts : 3312
    • Scores: 110
    • Reward points : 0
    • Joined: 6/22/2005
    • Location: Germany
    • Status: offline
    Re:How to organize your script Tuesday, March 30, 2010 9:31 AM (permalink)
    0
    Thanks for this excellent tutorial! I agree that having some consistent way
    of structuring your code is most important - whether you follow ebgreen's
    well-considered rules or modify them to better fit your circumstances is
    secondary. To give you some ideas - not to criticize ebgreen's approach -
    here are some of my deviations/variations:

    Header:

    The first line of my script looks like this:

    '' filename.ext - the problem in a nutshell

    '' Something.vbs - Demonstrate script organization

    The benefit: I can use a grep tool to search for scripts:

        C:\wis\_vbs\0506\dev\forum
        tgrep -d "'' [^ ]+ - .*" .\vbstmplates\*.vbs
        File .\vbstmplates\demostructure.vbs:
        '' demostructure.vbs - Demonstrate script organization
        File .\vbstmplates\excelado.vbs:
        '' excelado.vbs - use ado for excel work
        File .\vbstmplates\something.vbs:
        '' something.vbs - Demonstrate script organization
        File .\vbstmplates\tinterleave.vbs:
        '' tinterleave.vbs - test interleave

        C:\wis\_vbs\0506\dev\forum
        tgrep -d "'' [^ ]+ - .*" .\vbstmplates\*.vbs | tgrep orga
        File STDIN:
        '' demostructure.vbs - Demonstrate script organization
        '' something.vbs - Demonstrate script organization

    Option Explict:

    As this is such an important part of any decent VBScript program, I will
    cite ebgreen

       Use it. Always. Period.

    to drive this rule home.

    Constant and Variable Declaration:

    I try to Dim my variables as close as possible to their first use, because
    that reduces the number of lines you have to check to understand a variable.
    What really causes me bad dreams (about programmers being nailed to doors by
    bosses or customers because their messy scripts made rockets or oxygenators
    explode) are lines like

      Dim objFSO, objTextfile, objNewTextFile, objXL, arrEmailLog, i, count, s, arrignore, arrdate, strdate, arrtime

    at the top of the script. I bet $100 that at least one item of the list isn't used
    in the code, so a maintainer will have to double check all of them and ponder for
    the unused ones whether they are missing by design or accident. (I win - see

      http://www.visualbasicscript.com/fb.ashx?m=80312

    - I stopped bothering after "objNewTextFile" and "arrignore")

    I'm more concerned about types and scopes as ebgreen is. So instead of

        'Global Variables
        Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
        Dim strTestVariable

    I have

        'Global Variables
        Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )

    see below why "Dim strTestVariable" got lost.

    Main Code:

    Decent programming languages like C, Java, or C# don't allow top level code out
    of the entrypoint function/method. Languages that started with the principle
    "First line of code not in a function/sub/class/method is executed immediately"
    were improved upon in later versions (VB -> VB.NET, to mention just one). I admit
    that such a change is often linked to a transition from a scripting language to
    compiled language, so you could argue that a main function is overkill for
    VBScript. I say: Put your 'real' code in a main function in any case, but exploit
    the immediate execution where it brings benefits (.hta resize, library includes).

    Instead of

        'Main Code
        strTestVariable = "This is where the main flow of the script goes"
        WScript.Echo strTestVariable

    I prefer

        'Main Code
        WScript.Quit TrivialMain() ' the one and only top level code line

        ' TrivialMain - just show we are living
        Function TrivialMain()
          TrivialMain = 1 ' assume error
          Dim sMsg : sMsg = "This is where it really starts."
          WScript.Echo sMsg
          ' ....
          TrivialMain = 0 ' came to here, so it seems ok
        End Function

    The benefits:

      (1) doing a botch job by creative use of globals will be more difficult
          (read/study
              http://www.visualbasicscript.com/fb.ashx?m=81456
          )

      (2) You can work with different (sub)problems and variations of their
          solution by writing and then selecting many 'main' functions in
          the same script:

        'Main Code (select function to call by re-ordering or commenting (out)
        'WScript.Quit TrivialMain() ' the one and only top level code line
        WScript.Quit createTestData()
        WScript.Quit reportWithExcel()
        WScript.Quit reportWithADO()
        ....

      (3) You can use a nearly global "On Error Resume Next" that can be 'switched
          off' at runtime

     '' oern.vbs - professional OERN
     
     Option Explicit
     
     ' Global Constants
     
     ' Global Variables
     Dim oWAN : Set oWAN = WScript.Arguments.Named
     
     ' Main Code
     If oWAN.Exists( "debug" ) Then
        WScript.Quit Main()
     Else
        Dim nErrorLevel : nErrorLevel = 2
     On Error Resume Next
        nErrorLevel = Main()
        If 0 <> Err.Number Then
           WScript.Echo Err.Number, Err.Description
           WScript.Echo "fatal error, but no abort - and no line # either"
        End If
        WScript.Quit nErrorLevel
     End If
     
     ' Main - cause an error
     Function Main()
       Main = 1 ' assume error
       Dim nRes : nRes = 15 / CInt( oWAN( "num" ) )
       WScript.Echo "The answer is", nRes
       Main = 0 ' came to here, so it seems ok
     End Function
     


    using it:

     C:\wis\_vbs\0506\dev\forum\vbstmplates
     cscript oern.vbs /num:0
     11 Division durch Null
     fatal error, but no abort - and no line # either
     
     C:\wis\_vbs\0506\dev\forum\vbstmplates
     cscript oern.vbs /num:3
     The answer is 5
     
     C:\wis\_vbs\0506\dev\forum\vbstmplates
     cscript oern.vbs /num:0
     11 Division durch Null
     fatal error, but no abort - and no line # either
     
     C:\wis\_vbs\0506\dev\forum\vbstmplates
     cscript oern.vbs /num:0 /debug
     C:\wis\_vbs\0506\dev\forum\vbstmplates\oern.vbs(27, 14) Laufzeitfehler in Microsoft VBScript: Division durch Null
     


    #2
      ebgreen

      • Total Posts : 8088
      • Scores: 95
      • Reward points : 0
      • Joined: 7/12/2005
      • Status: offline
      Re:How to organize your script Wednesday, March 31, 2010 2:24 AM (permalink)
      0
      Excellent additions ehvbs. I have use a Main() function in the past. I still do when working in a language that evaluates strictly in order so that I can have my main code at the top but still use functions defined further down. I had stopped using a Main() in VBS because I didn't see any real benefit. Your points regarding making it harder to use globals though may convince me to go back to using a Main().
      "... when you are good and crazy, oooh, oooh, oooh, the sky is the limit!" - The Tick
      Goog places to start:http://www.visualbasicscript.com/m_24727/tm.htm
      http://www.visualbasicscript.com/m_47117/tm.htm
      #3
        chant

        • Total Posts : 1
        • Scores: 0
        • Reward points : 0
        • Joined: 4/14/2010
        • Status: offline
        Re:How to organize your script Wednesday, April 14, 2010 2:14 AM (permalink)
        0
        Great Stuff guys,
              I have a template that i use to avoid having to remember everything and keep it clean. Here it is if anyone is interested in using it. I did add the script info from your first post ebgreen, i hope that is ok. It was neat and tidy and i thought it made a nice addition.  ^_^  Hope it helps  Now i know that it looks funny pasted in here but if you copy the template and paste it into your editor or notepad it should display fine. Tried to upload it but i have to register an AJAX control and i've been looking for the help on it as instructed but am not finding it here so have to look elsewhere.
         
        thanks,

        Chant
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' This section is used to put notes and To Do lists in
        ' ~~~~~ Notes ~~~~~
        ' ~~~~~ To Do ~~~~~
         
        '     File Name:     ScriptName.vbs
        '     Author:     
        '     Purpose:     
        '     Parameters:
        '         /Param1 - Add Parameters if any
        '         /Param2 - Add Secondary Parameters if any
        '     Example Use:
        '         ScriptName.vbs /Param1 /Param2
        '         run the script and pass parameters to it
        '     History:
        '         00/00/2010 - v1.0     Initial creation 
        '         00/00/2010 - v1.1     Revisions
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END NOTES SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONFIGURATION SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Option Explicit
        ' ~~~~~~~~~~GLOBAL CONSTANTS~~~~~~~~~~
         
        ' ~~~~~~~~~~GLOBAL VARIABLES~~~~~~~~~~
         
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END CONFIGURATION SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MAIN PROGRAM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
         
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END MAIN SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
        '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS AND SUB ROUTINES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
         
         
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END FUNCTION SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUB ROUTINE SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END SUB ROUTINE SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ERROR HANDLING SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
         
         
         
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END ERROR HANDLING SECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
        #4
          Fredledingue

          • Total Posts : 572
          • Scores: 0
          • Reward points : 0
          • Joined: 5/9/2005
          • Location: Europe
          • Status: offline
          Re:How to organize your script Sunday, May 09, 2010 2:24 AM (permalink)
          0
          Here is were I disgress:
          I'm using function and subs (preferably functions) only when what it does has to be repeated, otherwise the code is in the main script.
          I don't see the point in having my script scattered in multiple functions or subs.
          Yet I add a lot of comments, draw lines between parts of my codes etc
          "Option Explicit" is also a question of personal preference.
          I like my variables to be unexplicit. And I don't want to have to declare every variables I use since I add them while coding, not before coding. Before starting coding I have no idea what variables I'll have to use. So everytime I create a new variable I'll have to copy-paste its name to the top on the "Dim" line else it will crash. No thanks.
          I'm sure to make less mistake through bad typing variable names than by forgetting to declare them.
          To make sure, I always copy-paste variable names when their lenght exceeds 4 characters.
          Fred
          #5

            Online Bookmarks Sharing: Share/Bookmark

            Jump to:

            Current active users

            There are 0 members and 2 guests.

            Icon Legend and Permission

            • New Messages
            • No New Messages
            • Hot Topic w/ New Messages
            • Hot Topic w/o New Messages
            • Locked w/ New Messages
            • Locked w/o New Messages
            • Read Message
            • Post New Thread
            • Reply to message
            • Post New Poll
            • Submit Vote
            • Post reward post
            • Delete my own posts
            • Delete my own threads
            • Rate post

            2000-2012 ASPPlayground.NET Forum Version 3.8
            mbt shoes www.wileywilson.com