Showing posts with label strings. Show all posts
Showing posts with label strings. Show all posts

Friday, May 13, 2011

Two Ways to Do String Matching in VBscript

The ugly but easier way (using InStr function)

Const strValue = "Microsoft Windows 7 Enterprise Edition"
If InStr(strValue, "Windows 7") > 0 Or InStr(strValue, "Windows XP") > 0 Then
wscript.echo "match found"
End If


The fancier but more irritating way (using the REGEX object):



Function MatchString(strToSearch, strPattern)
Dim objRegEx, colMatches, matchFound
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Global = True
objRegEx.Pattern = strPattern
Set colMatches = objRegEx.Execute(strToSearch)
If colMatches.Count > 0 Then
matchFound = True
End If
Set objRegEx = Nothing
MatchString = matchFound
End Function

If MatchString(strValue, "Windows XP|Windows 7") Then
wscript.echo "match found"
End If

Wednesday, September 8, 2010

Stupid-Simple, Yet Useful VBScript Functions

Ok, technically some of these are not functions, they're subs (or subroutines), but who cares.  I don't know who invented them, but I've been using these for years and years.  I hope they're helpful to you as well…

Sub Echo(category, caption)
    wscript.echo Now & vbTab category & vbTab & caption
End Sub

Examples…

Echo "info", "searching for wmi repository scope on remote computer…"

Echo "fail", "unable to connect to remote computer"

Function ScriptPath()
    ScriptPath = Replace(wscript.ScriptFullName, "\" & wscript.ScriptName, "")
End Function

Function IsWeekend(strDate)
    If Weekday(strDate)=1 Or Weekday(strDate)=2 Then
        IsWeekend = True
    End If
End Function

Function LeapYear(yr)
    Dim d1, d2
    d1 = FormatDateTime("1/1/" & yr)
    d2 = DateAdd("yyyy", 1, d1)
    If DateDiff("d", d1, d2) = 366 Then
        LeapYear = True
    End If
End Function

For i = 2004 to 2012
    If LeapYear(i) Then
        wscript.echo i & vbTab & "is a leap year"
    Else
        wscript.echo i & vbTab & "is not a leap year"
    End If
Next

Script Tip: Determine the Script File Path

With BAT/CMD scripts you can simply prefix any path references with %~dps0 to get to things in the same location (folder/UNC) where the script itself resides.  So if you run..

start /wait %~dps0setup.exe /silent /norestart

It runs setup.exe from the same folder location. (that is not a typo, there should be NO space between the zero and the rest of the file path)

It's just as easy with KiXtart using the @scriptdir macro, but with VBscript it's not that simple.  But it's not difficult either…

scriptPath = Replace(Wscript.ScriptFullName, "\" & Wscript.ScriptName, "")

An example of running setup.exe in the same folder with VBscript might be…

filePath = scriptPath & "\setup.exe"
result = objShell.Run(filePath & " /silent /norestart", 7, True)

However, be careful to wrap paths in double-quotes if they contain spaces…

filePath = Chr(34) & scriptPath & "\setup.exe" & Chr(34)
result = objShell.Run(filePath & " /silent /norestart", 7, True)

Tuesday, March 30, 2010

Splitting the Splitter

Here’s a cute little oafish trick that has helped me out more than a few times.  You run an inline Split/Array operation to mimic what the LISP cdr and cadr, etc. functions do, which is to pick out a logical subordinate within a string construct which represents a paired list (logically speaking).

myString = “1=Apple,2=Banana,3=Cherry,4=Grapes”

item2 = Split(Split(myString, “,”)(1), “=”)(1)


This will return “Banana”.  You can continue nesting (or un-nesting, if you will) obviously, but without error checking this can become quite dangerous.  But it is nice to see a use for something like this.  Now, if only there were a simple, easy way to mimic mapcar and apply as well.

Thursday, March 18, 2010

Query Scheduled Tasks The Hard Way

Because the CIM/WMI model is still an unfinished work in progress, I’ve once again had to resort to making some ugly crap code to work around a giant hole in the model. In this case it’s the lack of a model counterpart to the Scheduled Tasks collection.  This is NOT the same as the Win32_ScheduledJobs or the AT command output.  I’m talking about SCHTASKS.exe and the Windows Scheduled Tasks utility.  Anyhow, the klunky workaround here is to ride the SCHTASKS command like a whipping boy and make it dump a text file, then turn around and do a crude (but effective) string parsing and crank it out in XML form.  Enjoy.
'****************************************************************
' Filename..: xml_scheduled_tasks.vbs
' Author....: David M. Stein
' Date......: 03/18/2010
' Purpose...: query Scheduled Tasks (not WMI/Jobs/AT) --> XML out
'****************************************************************

Const tempfile = "c:\temp\schtasks.txt"
Const computer = ""

Const ForReading = 1
Const ForWriting = 2

Set objShell = CreateObject("Wscript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

If computer <> "" Then
cmdstr = "cmd /c schtasks /query /s \\" & computer & " /v /fo list >" & tempfile
Else
cmdstr = "cmd /c schtasks /query /v /fo list >" & tempfile
End If

retval = objShell.Run(cmdstr, 1, True)

If objFSO.FileExists(tempfile) Then
Dim linecount, objFSO, objFile, ln, strLine

linecount = 0
wscript.echo ""

Set objFile = objFSO.OpenTextFile(tempfile, ForReading)
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)

If Left(strLine, 9) = "HostName:" Then
hostname = Mid(strLine, 39)
wscript.echo vbTab & ""

ElseIf Left(strLine, 9) = "TaskName:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""
wscript.echo vbTab & vbTab & "" & hostname & ""

ElseIf Left(strLine, 15) = "Scheduled Type:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 9) = "Schedule:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Task To Run:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 8) = "Comment:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Run As User:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Time:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Date:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 17) = "Power Management:" Then
wscript.echo vbTab & "
"

End If
linecount = linecount + 1

Loop
objFile.Close
Set objFSO = Nothing

wscript.echo "
"

Else
wscript.echo "fail: file not found"
End If

Tuesday, March 2, 2010

Now vs Now: VBScript and KiXtart

Date values are a very common aspect to script writing and most any programming situation in general.  How dates are stored, presented and manipulated varies widely from one programming language to another.

Let’s look at the “Now” function included with Windows Scripting Host’s VBScript.  This function returns the current date and time in “mM/dD/YYYY hH:MM:SS XM” format.

In case you’re wondering what the hell “mM” and “hH” imply: they imply zero-trim numbers.  In other words 8:01:42 AM is not stored as 08:01:42 AM. The leading zero is omitted.  Same for month (“mM”), and day (“dD”) as well.

But KiXtart, one of my all-time favorite scripting languages, handles date values quite differently.  At first it may seem almost identical, but as you pick things apart you start to see the deltas.

(kixtart)
? @date+" "+@time
>> 2010/03/02 08:20:01

(vbscript)
Wscript.echo Now
>> 3/2/2010 8:20:01 AM


When you compare the output of each result above, not only are the order of YYYY/MM/DD flipped from M/D/YYYY, but the zero-trim is not used with KiXtart.  Is this “bad” or “wrong”?  No.  Just different.  There are times when this is actually a very handy benefit to have as the default.  But also notice that the time stamp is formatted differently.  And the AM/PM suffix is not shown.


So, how can we make KiXtart do it the way VBScript does it?  This is assuming you need to make it do that, of course, which you may not.  But this is for demonstration purposes, so cut me some slack - if you will.


Below are two examples for producing a VBScript formatted “Now” result.  The first one uses a rudimentary date->string parsing technique.  The second does a cop-out and simply knocks on the door of the ScriptControl COM interface to make VBScript do the work and hand back a result.  The performance overhead is about the same at this scalar load level.  If you start piling in a lot more, the results can shift the balance of performance in either direction, depending upon the nature of what your doing (math, string, date, or object management tasks).


------------------------------------------------
Break ON

Function Now1()
$today = ""+@monthno+"/"+@mdayno+"/"+@year
$arrTime = Split(@time, ":")
$hour = $arrTime[0]
$min = $arrTime[1]
$sec = $arrTime[2]
If Int($hour) < 12
$sfx = "AM"
Else
$sfx = "PM"
EndIf
$Now1 = $today+" "+Int($hour)+":"+$min+":"+$sec+" "+$sfx
EndFunction

Function Now2()
Dim $sc, $result
$sc = CreateObject("ScriptControl")
$sc.Language = "vbscript"
$result = $sc.Eval('Now()')
$sc = 0
$Now2 = $result
EndFunction

? "Kix: "+Now1()
? "VBs: "+Now2()


The results should be identical.  Could I/you refactor the Now1() function to nest statements and further compact the code?  Sure.  Does it buy any performance gains? Not really.



Consider this variation…



Function Now1()
$today = ""+@monthno+"/"+@mdayno+"/"+@year
$arrTime = Split(@time, ":")
If Int($arrTime[0]) < 12
$Now1 = $today+" "+Int($arrTime[0])+":"+$arrTime[1]+":"+
$arrTime[2]+" AM”
Else
$Now1 = $today+" "+Int($arrTime[0])+":"+$arrTime[1]+":"+
$arrTime[2]+" PM”
EndIf
EndFunction


More compact for sure.  But there’s a hidden, even if trivial price: The repeated use of an array index request.  There are other ways to compact/refactor this of course, but for such few lines of code the pay-offs are difficult to justify beyond elegant coding form (aesthetics).  Oh well, blah blah blah.  What do I know anyway.  I just finished a huge “breakfast-for-dinner” and was then told my car repairs would cost way too much, so I’m blabbering to let off steam.  I hope you enjoyed this.

Thursday, December 31, 2009

VBScript ADO with XML and CSV Data Files

I was poking around to find a way to read CSV, TXT (various delimiters) through VBScript for use in scripted data migrations, as well as to render the data in ASP, and found some interesting things.  I have to give credit to [http://www.mombu.com/microsoft/scripting-wsh/t-query-xml-file-with-ado-in-wsh-131431.html] for the XML example.  I only modified it slightly to fit in with how I tend to code ADO processes.  I also would like to applaud the efforts of Connection Strings.com for their fantastic reference site for connection information for almost anything that can possibly store information.

Reading XML Data

Const dsn = "Provider=MSDAOSP;Data Source=MSXML2.DSOControl;"
Const adChapter = 136

Dim conn, rs
Dim iLevel : iLevel = 0

Set conn = CreateObject( "ADODB.Connection" )
Set rs = CreateObject( "ADODB.Recordset" )

conn.Open dsn

rs.Open CreateObject( "WScript.Shell" ).CurrentDirectory + _
"\test.xml", conn

WalkHier iLevel, rs

rs.Close
conn.Close

Sub WalkHier(ByVal iLevel, ByVal rs)
iLevel = iLevel + 1
Dim PriorLevel : PriorLevel = iLevel
Dim i, adoChildRS
While Not rs.EOF
For i = 0 To rs.Fields.Count - 1
If rs.Fields(i).Name <> "$Text" Then
If rs.Fields(i).Type = adChapter Then
Set adoChildRS = rs.Fields(i).Value
WalkHier iLevel, adoChildRS
Else
wscript.echo iLevel & ": rs.Fields(" & i & ") = " & _
rs.Fields(i).Name & " = " & rs.Fields(i).Value
End If
End If
Next
rs.MoveNext
Wend
iLevel = PriorLevel
End Sub


Reading CSV Data



dsn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='s:\scripts\';Extended Properties=""text;HDR=Yes;FMT=Delimited(,);"""

query = "SELECT * FROM test.csv"

Set conn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
Set rs = CreateObject("ADODB.Recordset")

conn.Open dsn

rs.CursorLocation = adUseClient
rs.CursorType = adOpenStatic
rs.LockType = adLockReadOnly

Set cmd.ActiveConnection = conn

cmd.CommandType = adCmdText
cmd.CommandText = query
rs.Open cmd

If Not(rs.BOF And rs.EOF) Then
Do Until rs.EOF
For i = 0 to rs.Fields.Count - 1
wscript.echo rs(i).name & " = " & rs(i).value
Next
rs.MoveNext
Loop
Else
wscript.echo "error: no records found"
End If
rs.Close
conn.Close
Set rs = Nothing
Set cmd = Nothing
Set conn = Nothing

Friday, December 25, 2009

Convert INI to XML with KiXtart

Sometimes you may want/need to read a standard INI data file and output it to an XML format.  There are several ways to do this, but here is just one.  You’ll need KiXtart 4.61 in order to use the Replace() function. Enjoy (and Merry Christmas!)

KiXtart Code

Break ON
; requires KiXtart 4.61 or later!!!
If @kix <= "4.60"
? "this script requires 4.61 or later!"
Exit
EndIf

$strFileName = "s:\scripts\test.ini"

$quote = Chr(34)
$tab = Chr(9)

Dim $linecount, $fHandle, $strLine, $outer, $keyset, $subkeyformat
Dim $name, $value

$subkeyFormat = 1
$fHandle = FreeFileHandle()
$outer = ""

If Open($fHandle, $strFileName) = 0
$strLine = ReadLine($fHandle)
While @error = 0
Select
Case Left($strLine,1) = "["
$outer = Replace(Replace($strLine, "]", ""), "[", "")
? "<$outer>"
Case InStr($strLine, "=") <> 0
$keyset = Split($strLine, "=")
$name = $keyset[0]
$value = $keyset[1]
If $subkeyFormat == 1
? "$tab"
Else
? "$tab<$name>$value</$NAME>"
EndIf
Case 1
If $outer <> ""
? "</$OUTER>"
$outer = ""
EndIf
EndSelect
$strLine = ReadLine($fHandle)
Loop
$=Close($fHandle)
EndIf

Friday, September 25, 2009

Poor Mans Nested Array Splitting

Some will laugh.  Some will scoff.  Some will snort and then realize they accidentally blew a booger on their shirt and say “oh damn”.  Oh well, here goes…

<%
Const myList = "1=RED,2=YELLOW,3=GREEN,4=CYAN,5=BLUE,6=MAGENTA"

Sub ColorNumList(default)
For each pair in Split(myList, ",")
x = Split(pair, "=")
If Cstr(default) = x(0) Then
Response.Write "<option value=" & x(0) & _
" selected>" & x(1) & "</option>"
Else
Response.Write "<option value=" & x(0) & _
">" & x(1) & "</option>"
End If
Next
End Sub
%>

To use this, you simply insert it within a matching set of ASP code tags inside of a <select></select> form object tag set:

...
<select name="colornum" size="1">
<% ColorNumList 3 %>
</select>
...

Friday, July 3, 2009

VBScript / ASP String Validate

Check if string contains a value (not Null and not empty)


Function StringVal(strval)
If Not(IsNull(strval)) And Trim(strval) <> "" Then
StringVal = True
End If
End Function

VBScript / ASP String Padding


Function PadString(strval, delim, length, side)
Dim tmp : tmp = Trim(strval)
Select Case Ucase(Left(side,1))
Case "L":
Do While Len(tmp) < length
tmp = delim & tmp
Loop
Case "R":
Do While Len(tmp) < length
tmp = tmp & delim
Loop
End Select
PadString = tmp
End Function