Jerry Dausman's profileThere's an answer to you...BlogLists Tools Help

Blog


    January 24

    Searching for Answers

    I can't believe I haven't added anything to this blog in 11 months!  Somebody wake me up!
     
    On my new job I wrote a script to help me find specific text in files.  I know what you're going to say: there's a built in feature in Windows that will do the same thing.  True, but it only gives me a list of files.  I want more!  And I got more.  The script below does the following:
    • uses an specific list of files to search (editable),
    • lists the line number where the text was found in the file,
    • puts the output in .csv format so I can play with it in another program, and
    • can be adapted to display any information about the file.
    The script uses a list (Reports.txt) as an input list of files to scan.  You can create this list by using the directory command at the "C:>" prompt as follows:
     
      dir *.* /B /S >Reports.txt
     
    Here's the code for the script that does the work:
     
      '  ************************************
    '  **                                **
    '  **  Scan for Particular Commands  **
    '  **                                **
    '  **        Scan4Commands.vbs       **
    '  **                                **
    '  ************************************
    '
    '  Copyright (C) 2007 Jerome F. Dausman
    '
    '  Purpose:
    '
    '    This program takes a list of reports
    '  and scans the list for particular text.
    '  The user inputs the path and filename
    '  of the text file listing the reports.
    '  The user also inputs the text that is
    '  being searched for.
    '  An output file is created with the
    '  cross-reference information.
    '
    '=== DECLARATIONS =========================================
    Option Explicit
    '--- Objects
    Dim objFSO        'file system object
    Dim objRepts      'the list of report files
    Dim objRpt        'the report file being scanned
    Dim objOut        'the output report generated
    '--- string variables
    Dim str           'useful string variable
    Dim strScript     'this script
    Dim strLocation   'this script's location
    Dim strRepts      'the name of the listing file
    Dim strRpt        'the name of individual report files
    Dim strOut        'the name of the output file
    Dim strSearch     'the search string
    '--- numeric variables
    Dim intLine       'line count
    Dim intX          'useful integer
    '--- constants
    Const ForReading = 1
    Const ForAppending = 8
    Const strQ = """"
    Const strC = ","
    'CONST vbOKOnly = 0
    'CONST vbOKCancel = 1  'Display OK and Cancel buttons.
    'CONST vbAbortRetryIgnore = 2 'Display Abort, Retry, and Ignore buttons.
    'CONST vbYesNoCancel = 3 'Display Yes, No, and Cancel buttons.
    'CONST vbYesNo = 4      'Display Yes and No buttons.
    'CONST vbRetryCancel = 5 'Display Retry and Cancel buttons.
    'CONST vbCritical = 16  'Display Critical Message icon.
    'CONST vbQuestion = 32  'Display Warning Query icon.
    'CONST vbExclamation = 48 'Display Warning Message icon.
    'CONST vbInformation = 64 'Display Information Message icon.
    'CONST vbDefaultButton1 = 0 'First button is the default.
    'CONST vbDefaultButton2 = 256 'Second button is the default.
    'CONST vbDefaultButton3 = 512 'Third button is the default.
    'CONST vbDefaultButton4 = 768 'Fourth button is the default.
    'CONST vbApplicationModal = 0 'Application modal.
    'CONST vbSystemModal = 4096 'System modal.
    '=== MAIN PROGRAM =========================================
    '--- get the script name and location --------
    strScript = WScript.ScriptName
    strLocation = WScript.ScriptFullName
    intX = Instr(strLocation, strScript) - 1
    strLocation = Left(strLocation, intX)
    MsgBox strLocation
    '-- get the name of the textfile list of reports to scan
    str = "What is the name of the list of report files to scan?"
    strRepts = InputBox(str,"List of Reports", "Reports.txt")
    '--- check file validity ---------------------
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    If Not (objFSO.FileExists(strRepts)) Then
      MsgBox "The file '" & strRepts & "' does not exist.", vbCritical, "No Scan"
      WScript.Quit
    End If
    '--- create an output file -------------------
    str = "What is the name of the report file you will create?"
    strOut = InputBox(str, "Output File", "Search.csv")
    On Error Resume Next
    Set objOut = objFSO.OpenTextFile(strOut, ForAppending, True)
    If (Err.Number <> 0) Then
      str = strOut & vbCrLf
      str = str & "is not a valid file for reporting."
      Msgbox str, vbCritical, "No Output"
      WScript.Quit
    End If
    On Error Goto 0
    '--- get input search string -----------------
    str = "What is the string you are looking for?"
    strSearch = InputBox(str, "Search String", ".CommandText")
    '--- write output header ---------------------
    objOut.WriteLine(" ")
    str = strQ & "===============================================" & strQ
    objOut.WriteLine(str)
    str = strQ & "Scan4Command Output Report" & strQ & strC
    str = str & strQ & Date() & strQ
    objOut.WriteLine(str)
    str = strQ & "-----------------------------------------------" & strQ
    objOut.WriteLine(str)
    str = "Search Text: " & strSearch
    objOut.WriteLine(str)
    str = strQ & "===============================================" & strQ
    objOut.WriteLine(str)
    objOut.WriteLine(" ")
    str = strQ & "Report" & strQ & strC
    str = str & strQ & "Line" & strQ & strC
    str = str & strQ & "Text" & strQ
    objOut.WriteLine(str)
    str = strQ & "-------" & strQ & strC
    str = str & strQ & "-----" & strQ & strC
    str = str & strQ & "-----------------------" & strQ
    objOut.WriteLine(str)
    '--- read from list and loop -----------------
    Set objRepts = objFSO.OpenTextFile(strRepts, ForReading)
    Do While objRepts.AtEndOfStream <> True
        '--- test a file name --------------------
        strRpt = objRepts.ReadLine
        If (objFSO.FileExists(strRpt)) Then
            '--- open the file -------------------
            intLine = 0
    on error resume next
            Set objRpt = objFSO.OpenTextFile(strRpt, ForReading)
    If Err.Number <> 0 Then
        msgbox "bad file = " & str
    End If
    on error goto 0
            '--- look for the search string ------
            Do While objRpt.AtEndOfStream <> True
                str = objRpt.ReadLine
                intLine = intLine + 1
                intX = Instr(str, strSearch)
                If (intX > 0) Then
                   str = mid(str, intX)
                   '--- output info --------------
                   objOut.Write(strQ & strRpt & strQ)
                   objOut.Write(strC & CStr(intLine) & strC)
                   objOut.WriteLine(strQ & str & strQ)
                End If
            Loop
        End If
    Loop
    '--- write end of output ---------------------
    str = strQ & "===============================================" & strQ
    objOut.WriteLine(str)
    '--- down and out ----------------------------
    objRepts.Close
    objOut.Close
    str = "Done!"
    MsgBox str, vbInformation, "Scan4Commands"
    WScript.Quit
     
    Hope this is helpful for you!
     
    April 26

    User Account Expiration Dates

    I can't believe I haven't entered anything since March 8!  My bad.
     
    Today's entry is from a week of scripting I taught a few weeks back.  We wanted to develop a script to show Windows user account expiration dates.  We would have liked to use ADSI objects, but they don't give you the object properties that you can use.  Using LDAP is the easiest way.  Below is the code I came up with.
     
    '  Display User Account Expiration Dates
    '  Jerome F. Dausman
    '  April 2006
    Option Explicit
     
    Dim objSvc  'server
    Dim objCon  'container
    Dim objUser 'user
    Dim strDate 'expire date
    Dim strOut  'output string

    Set objSvc = GetObject("LDAP://London/DC=nwtraders,DC=msft")
    For Each objCon in objSvc
        If objCon.class = "organizationalUnit" Then
            strOut = strOut & objCon.name & vbcrlf
            GetAllUsers(objCon)
        ElseIf objCon.class = "container" AND objCon.name = "CN=Users" Then
            strOut = strOut & objCon.name & vbcrlf
            GetAllUsers(objCon)
        End If
    Next
    WScript.Echo strOut
    WScript.Quit

    Sub GetAllUsers(objX)
        For Each objUser in objX
            If objUser.class = "user" Then
               strOut = strOut & "  " & objUser.name & vbTab
               If objUser.accountExpires.HighPart =  0 Then
                   strOut = strOut & "NEVER" & vbcrlf
               Else
                   strDate = objUser.accountExpirationDate
                   if strDate = "1/1/1970" Then
                       strOut = strOut & "NEVER" & vbcrlf
                   else
                       strOut = strOut & strDate & vbcrlf
                   end if
               End If
            End If
        Next
    End Sub
     
     There's a couple of things you may want to change in the above script.  The first is, of course, the line where we "Set objSvc" to the nwtraders.msft domain.  You might want to use an input box to take in any domain you're interested in.
     
    The second thing you'll probably want to change is the output.  Instead of using WScript.Echo you will probably want to write the output to a file.
     
    Finally, my script only checks the Users and organizational units 'folders' for user accounts.  If you have a more complex organizational structure, such as subdomains or a forest, you will have to modify the script accordingly.
    [ms2433, module 5, page 26]
    February 13

    Your Next Available Drive

    We're taking a short break from the list of things a new DBA ought to keep in mind to cover a script we put together in our ms2433 class last week.
     
    It's nice to know what the next available drive letter is, especially if you're going to use it for a network mapping.  The example in our 2433 class looks through the current drive mappings to find the highest drive letter, and then chooses the next letter in the alphabet as the next available letter.  All well and good ... except if the last drive letter currently is 'Z'.  People (and programs) can map drives in any order they wish, so I wrote a short script to show the first and last available drive letters.
     
    '  NextDrive.vbs
    '  Jerome Dausman    February 8, 2006
    Option Explicit
    Dim objFSO              'file system object
    Dim objDrive            'placeholder drive object
    Dim strDrive            'drive letter
    Dim intDrive            'the ASCII value of the drive - 64
    Dim strAvailables       'list of available drives
    Dim strOutput           'output string
    'initialize strings
    strAvailables = "   DEFGHIJKLMNOPQRSTUVWXYZ "
    strOutput = "Available Drives:" & vbCrLf
    'get a file system object
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    'scroll through the list of drives
    For Each objDrive in objFSO.Drives
        strDrive = objDrive.DriveLetter
        intDrive = ASC(strDrive) - 64
        'knock the drive letter out of the list
        If (intDrive = 1) Then
            strAvailables = " " & Mid(strAvailables, 2)
        Else
            strAvailables = Left(strAvailables, intDrive - 1) & " " _
                & Mid(strAvailables, intDrive + 1)
        End If
    Next
    'show the available drives, first and last
    strOutput = strOutput & "     " & strAvailables & vbCrLf & vbCrLf
    strOutput = strOutput & "First Available Drive: " _
        & Left(LTrim(strAvailables), 1) & vbCrLf
    strOutput = strOutput & " Last Available Drive: " _
        & Right(RTrim(strAvailables), 1)
    msgbox strOutput, vbInformation, "Drives for Mapping"
     
    So, the idea is to get a drive letter and knock it out of the list (strAvailables).  I started by knocking out drives A, B and C, since I always have those drives on all my systems.  You can taylor the script for your own needs, such as knocking out a drive everyone always uses as the departmental file server.
     

    [ms2433: Module 6, page 22]

     

    July 21

    Reinventing the Wheel

    A recent question from a student concerning a script had me using a little free time hacking script code.  That is until I remembered I was probably trying to reinvent the wheel.  So I went to one of my favorite scripting places http://www.microsoft.com/technet/scriptcenter/default.mspx .  The Script Repository there had just what we wanted.  Next time I'll remember ... there's a world of stuff out there already.
    July 08

    Code is a four-letter word, even in scripting.

    I work with a fellow MCT, Darwyn, who is also an MCSE.  A couple weeks ago he wandered into my class full of MCSEs and wanted to know why I was teaching them. When I showed him the MS2439 book Scripting Microsoft Windows Management Instrumentation he promptly held up his crucifix and string of garlic and slowly backed out of the room hissing at me. You see, to Darwyn, 'code' is a four-letter word. To him, what we do on the coding side of the fence is the same as witchcraft and divination. To make him feel better the class worked up a useful little script for him.
     
    The following script lists all services on the local computer, and their state.
     
    '  This script lists all services on the local comptuer
    '  Based on a simple script found on the Microsoft site.
     
    Dim str1, str2          'strings for formatting output
    Dim strComputer         'the local computer, can be changed
    Dim objWMIService       'the WMI service object
    Dim colServices         'a collection of service objects
    Dim i                   'a counter variable
     
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & strComputer _
        & "\root\cimv2")
     
    Set colServices = _
        objWMIService.ExecQuery("Select * from Win32_Service")
     
    str1 = "Service and State" & vbCrLf & vbCrLf
     
    If (colServices.Count > 0) Then
        For Each objService in colServices
            'format the service and state for output
            str2 = objService.Name & "........................."
            str2 = Left(str2, 25)
            str1 = str1 & str2 & " " & vbTab _
                & UCase(objService.State)
     
            'count to see if we start another line
            i = i + 1
            If (i mod 3 = 0) Then
                str1 = str1 & vbCrLf
            Else
                str1 = str1 & vbTab & vbTab
            End If
        Next
        WScript.Echo str1
    Else
        WScript.Echo "There are no services on this machine."
    End If
    [MS2439; Module 3; Page 5]