compare wscript.arguments and string - vbscript

I want to compare an wscript.argument that I got to the vbs to a string, so depending in that comparation one action or another is performed. I have tried this, but I get an error. How can I solve it? How can I make the type comparation?
Set args = Wscript.Arguments
Set accessPath = args.Item(5)
If accessPath = "-" Then
objExcel.Cells(15, 3).Value = " "
Else
objExcel.Cells(15, 3).Value = accessPath
End If

Use this instead:
Dim accessPath : accessPath = Wscript.Arguments(5)
If accessPath = "-" Then
objExcel.Cells(15, 3).Value = " "
Else
objExcel.Cells(15, 3).Value = accessPath
End If
Bear in mind that arguments start at 0, so by looking at Wscript.Arguments(5) you're actually looking at the sixth entry on the command line.
Finally you may want to also check the value of Wscript.Arguments.Count to ensure you have had enough arguments passed, otherwise an error will be thrown.

Related

VBScript Error: "Entry not found in index..." when opening documents Lotus Notes

Here is a working script for extract attachments from Lotus Notes letters:
Dim s
s = 1
Do
s = s + 1
Dim Session
Dim Maildb
Dim view
Dim vc
Dim doc
Dim Item
Dim coll
Dim x
Dim Sender
Dim sentTo
Dim viewTimer
Dim ws
Dim Source
Set Session = CreateObject("Lotus.NotesSession")
Call Session.Initialize("password")
Set Maildb = Session.GetDatabase("DOMAIN/Servers/Server-Name/RU", "GroupMail\mailbox.nsf")
Set view = Maildb.GetView("($inbox)")
If Not Maildb.IsOpen = True Then
Call Maildb.Open
End If
With view
x = 0
ReDim LmailID(x)
ReDim HasAttach(x)
Set doc = .GetFirstDocument
If doc Is Nothing Then
else
Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)")
Do
fileNames = Session.Evaluate("#AttachmentNames", doc)
For Each Filename In fileNames
Sender = doc.GETITEMVALUE("From")(0)
strSearchForSpecificName = "SpecificName"
If InStr(1, Sender, strSearchForSpecificName) > 0 then
sentTo = "SpecificName#mail.ru"
else
sentTo = Sender
End If
If Filename <> "" Then
Call doc.Save( False, False, True )
Set NotesEmbeddedObject = doc.GetAttachment(FileName)
NotesEmbeddedObject.ExtractFile ("d:\#files\" + Right("0" & Month(Now), 2) & "-" & Right("0" & Day(Now), 2) & "-" & Year(Now) & "-" & Hour(Time) & Minute(time) & Second(time) & "_" & Filename)
Set reply = doc.CreateReplyMessage( False )
Call reply.replaceItemValue("SendTo", sentTo)
Call reply.replaceItemValue("CopyTo", "copy#mail.ru")
Call reply.replaceItemValue("Subject", "Re: " & "файл " + Filename + " передан в обработку " + Right("0" & Month(Now), 2) & "-" & Right("0" & Day(Now), 2) & "-" & Year(Now) & Hour(Time) & ":" & Minute(time) & ":" & Second(time))
doc.SaveMessageOnSend = True
Call reply.Send( False )
End If
Next
x = x + 1
ReDim Preserve LmailID(x)
Set doc = .GetNextDocument(doc)
Loop Until doc Is Nothing
End If
End With
Wscript.Sleep (30 * 1000)
Set Session = Nothing
Set Maildb = Nothing
Set view = Nothing
Set vc = Nothing
Set doc = Nothing
Set Item = Nothing
Set coll = Nothing
Set x = Nothing
s = s - 1
Loop While s > 0
The problem is that sometimes I'm getting an error: Error: "Entry not found in index..." and program stopped at Set doc = .GetNextDocument(doc) line.
Is there there solution for resolve this error?
Your code is removing the first doc from the $Inbox, therefore it cannot be used as the anchor for getting the next document in $Inbox. The solution would normally be to make sure that you get the next document before you remove the current document. I.e., change
Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)")
to
Call doc.PutInFolder("Processed")
set nextDoc = .getNextDocument(doc)
Call doc.Removefromfolder("($inbox)")
and change
Set doc = .GetNextDocument(doc)
to
set doc = nextDoc
However, your code with the putInFolder and RemoveFromFolder calls is not actually inside the loop, therefore only the first doc that you process will be moved to the Processed folder and nextDoc will not be properly set after the first iteration of the loop. If you really only want to move the first document to the Processed folder, then the above solution still isn't right because you'll only be setting nextDoc once, outside the loop and you will have an infinite loop since you'll always be setting doc to the same nextDoc value. You'll need another instance of nextDoc = getNextDocument(doc) inside the loop. If you really want all documents to be moved to the Processed folder, then you just need to move the entire block of code dealing with the folders and assigning nextDoc into the inside of the loop.
The problem is simple: The document is removed from Inbox and therefor is not in the index anymore. This happens if one of two conditions are true:
The NotesView- Property "AutoUpdate" is set to true
Your timer- triggered "refreshView"- sub (that is not in your example code) does a view.Refresh.
Despite of the fact, that in your code there is a lot of "nonsense" (sorry to say), it is easy to fix this code:
Just use the fact, that the view- object can be updated as advantage and change to "getfirstdocument" all the time:
Change this line:
Set doc = .GetNextDocument(doc)
to these lines:
Call .Refresh()
Set doc = .GetFirstDocument
What does this do: The Refresh removes the currently processed document from the view. The "next" document will be the first in view. And that one you get until there is no more "first" document...
And: Richard is right. You need to move the two rows Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)") below the Do in order to move ALL documents to the folder and not only the first one.

Script won't split line at "=" Delimeter

The script below works in finding duplicates.
But most of the files i'm reading follow this format:
ServerName(1) = "Example1"
ServerName(2) = "Example1"
ServerName(3) = "Example3"
ServerName(4) = "Example4"
ServerName(5) = "Example5"
The 'cut' variable in the code below is supposed to cut the string at the "=" delimiter and return the value that comes after the "=" delimeter.
It should write to the duplicate file "Example1" but instead writes nothing. How would I make it so that the script below reads a file and only finds the duplicate in values after the "=" delimeter.
Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
FileName = "Test.txt"
PathToSave = "C:"
Path = (PathToSave & FileName)
Set objFile = objFSO.OpenTextFile(Path, ForReading)
Set objOutputFile = objFSO.OpenTextFile(PathToSave & "Noduplicates.txt", 2, True)
Set objOutputFile2 = objFSO.OpenTextFile(PathToSave & "Duplicates.txt", 2, True)
objOutputFile.WriteLine ("This document contains the " & path & " file without duplicates" & vbcrlf)
objOutputFile2.WriteLine ("This document contains the duplicates found. Each line listed below had a duplicate in " & Path & vbcrlf)
Dim DuplicateCount
DuplicateCount = 0
Set Dict = CreateObject("Scripting.Dictionary")
Do until objFile.atEndOfStream
strCurrentLine = LCase(Trim(objFile.ReadLine))
Cut = Split(strCurrentline,"=")
If not Dict.Exists(LCase(Trim(cut(strCurrentLine)))) then
objOutputFile.WriteLine strCurrentLine
Dict.Add strCurrentLine,strCurrentLine
Else Dict.Exists(LCase(Trim(cut(strCurrentLine))))
objOutputFile2.WriteLine strCurrentLine
DuplicateCount = DuplicateCount + 1
End if
Loop
If DuplicateCount > 0 then
wscript.echo ("Number of Duplicates Found: " & DuplicateCount)
Else
wscript.echo "No Duplicates found"
End if
Cut is your array, so Cut(1) is the portion after the =. So that's what you should test for in your dictionary.
If InStr(strCurrentline, "=") > 0 Then
Cut = Split(strCurrentline,"=")
If Not Dict.Exists(Cut(1)) then
objOutputFile.WriteLine strCurrentLine
Dict.Add Cut(1), Cut(1)
Else
objOutputFile2.WriteLine strCurrentLine
DuplicateCount = DuplicateCount + 1
End if
End If
I makes no sense at all to ask Split to return an array with one element by setting the 3rd parameter to 1, as in
Cut = Split(strCurrentline,"=",1)
Evidence:
>> WScript.Echo Join(Split("a=b", "=", 1), "*")
>>
a=b
>> WScript.Echo Join(Split("a=b", "="), "*")
>>
a*b
BTW: ServerName(5) = "Example5" should be splitted on " = "; further thought about the quotes may be advisable.
Update wrt comments (and downvotes):
The semantics of the count parameter according to the docs:
count
Optional. Number of substrings to be returned; -1 indicates that all substrings are returned. If omitted, all substrings are returned.
Asking for one element (not an UBound!) results in one element containing the input.
Evidence wrt the type mismatch error:
>> cut = Split("a=b", "=", 1)
>> WScript.Echo cut
>>
Error Number: 13
Error Description: Type mismatch
>>
So please think twice.

VB script run time error input past end of file

I'm taking a scripting class and im having some issues with my script. According to the lab assignment all my syntax is correct. However i keep getting a input past end of file error on line 60,1. I've starred at the program forever and checked all lines letter for letter for quite some time with no luck. Any help would be greatly appreciated. Here is the script.
dim ipAddress(5,3)
ipAddress(0,0)="192.168.10.11"
ipAddress(0,1)="192.168.10.12"
ipAddress(0,2)="192.168.10.13"
ipAddress(0,3)="192.168.10.14"
ipAddress(1,0)="192.168.10.19"
ipAddress(1,1)="192.168.10.20"
ipAddress(1,2)="192.168.10.21"
ipAddress(1,3)="192.168.10.22"
ipAddress(2,0)="192.168.10.27"
ipAddress(2,1)="192.168.10.28"
ipAddress(2,2)="192.168.10.29"
ipAddress(2,3)="192.168.10.30"
ipAddress(3,0)="192.168.10.35"
ipAddress(3,1)="192.168.10.36"
ipAddress(3,2)="192.168.10.37"
ipAddress(3,3)="192.168.10.38"
ipAddress(4,0)="192.168.10.43"
ipAddress(4,1)="192.168.10.44"
ipAddress(4,2)="192.168.10.45"
ipAddress(4,3)="192.168.10.46"
ipAddress(5,0)="192.168.10.51"
ipAddress(5,1)="192.168.10.52"
ipAddress(5,2)="192.168.10.53"
ipAddress(5,3)="192.168.10.54"
const READ = 1
const WRITE = 2
const APPEND = 8
const ASCII = 0
dim fileName
fileName = "IP_Addresses.csv"
dim ipAddrStr
ipAddrStr = ""
dim fso
Set fso = Wscript.CreateObject("Scripting.FileSystemObject")
Set ipFileObj = fso.CreateTextFile(fileName,True,ASCII)
For room = 0 to 5
For computer = 0 to 3
ipAddrSr = CStr(room+100) & "," & CStr(computer+1) & "," ipAddress(room,computer)
& vbCrlf
ipFileObj.write(ipAddrStr)
Next
Next
ipFileObj.close
Set ipFileObj = fso.OpenTextFile(fileName,READ,ASCII)
WScript.Echo ipFileObj.ReadAll **' this is line 60**
ipFileObj.Close
As you don't use "Option Explicit", you get what you deserve: You (try to) concatenate the lines into ipAddrSr but write ipAddrStr to the file. So nothing gets written to the file.
Fix the syntax error and the bad name to:
ipAddrStr = CStr(room+100) & "," & CStr(computer+1) & "," & ipAddress(room,computer) & vbCrlf
Assuming that the file isn't empty, perhaps you need to specify the directory the file is in? I think this can be done either in your script:
fileName = "c:\your_directory\IP_Addresses.csv"
Or if you run it in the command line via cscript...
cscript.exe your.vbs "c:\your_directory\IP_Addresses.csv"
You can check the file size before executing your Echo if you like...
if fileName.size > 0 then
Set ipFileObj = fso.OpenTextFile(fileName,READ,ASCII)
WScript.Echo ipFileObj.ReadAll **' this is line 60**
ipFileObj.Close
else
WScript.Echo = "File was empty"
end if
See details of passing an argument to your script here.

Remove parts of a string and copy the rest back to a file with vbscript

I would like to remove the unwanted text from each string in a file.
the input string looks like this
username^time stamp^don't need this printed on printer name more useless info pages printed:some number
I want to remove everything else but keep the username,time stamp,printer name and some number.Then write each line to a file so the output looks like this
username timestamp printername some number
This is the code I'm working with
Set fs = CreateObject("Scripting.FileSystemObject")
sf = "C:\test.txt"
Set f = fs.OpenTextFile(sf, 1) ''1=for reading
s = f.ReadAll
segments = Split(s,"^",-1)
s= segments(1,)
f.Close
Set f = fs.OpenTextFile(sf, 2) ''2=ForWriting
f.Write s
f.Close
There's always a moment that somebody asks "Why not use a regular expression?". This is that moment.
Try this:
Dim re, s, match, matches
s = "Chuck Norris^12-12-2012^don't need this printed on HAL9000 more useless info pages printed:42 "
Set re = new regexp
re.pattern = "(.*)\^(.*)\^.*printed on (\w+).*pages printed:(\d+).*"
re.Global = True
Set matches = re.Execute(s)
Set match = matches(0)
msgbox "username=" & match.submatches(0)
msgbox "time stamp=" & match.submatches(1)
msgbox "printer=" & match.submatches(2)
msgbox "pages printed=" & match.submatches(3)
Neat huh? And I bet you'll figure out how to implement it in your existing code.
Code:
Const csSep = "^"
'username^time^(other arbitrary junk)^printer name^(other arbitrary junk)^page count
Dim sJunk : sJunk = "kurt^01:02:03^some junk^nec p7^nix^123"
WScript.Echo sJunk
Dim aParts : aParts = Split(sJunk, csSep)
Dim sNetto : sNetto = Join(Array(aParts(0),aParts(1),aParts(3),aParts(5)), csSep)
WScript.Echo sNetto
output:
kurt^01:02:03^some junk^nec p7^nix^123
kurt^01:02:03^nec p7^123

Vbscript - Read ini or text file for specific section

I want to store some addresses in a text file and then read specific portions of the file, based on group membership. I've done all of the group membership stuff so I don't need any help for that.
But I'm not sure if I should use a plain text file or an INI file?
The thing is, the post addresses are in two or three lines and I need line break.
I tried using a plain text file, but I couldn't manage to get a line break correctly.
So INI files would be preferable?
The INI file could look like this:
[London]
Address 1
Postbox 3245
58348 London
[Copenhagen]
Address 2
Postbox 2455
5478347 Copenhagen
I'm not quite sure if this is possible in an INI file though, perhaps I need to name each line as well. OR, I could possibly use a plain text file and search for the word [london] and then read each line until there's a line break. Then store all of those lines in a variable that I'll pass along?
How would you guys solve this?
I have written a small VBScript Class that handles "real' ini files written with such format:
[section_name]
key1 = value1
key2 = value2
The code for the class is:
Class IniFileObject
Private m_Data
Private Sub Class_Initialize
Set m_Data = Server.CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate
Dim key
If IsObject(m_Data) Then
For Each key In m_Data
m_Data(key).RemoveAll
Set m_Data(key) = Nothing
Next
m_Data.RemoveAll
Set m_Data = Nothing
End If
End Sub
Public Function Init(sFilePath)
Dim arrLines, sLine, x
Dim sCurSection, oSectionDict
Set Init = Me
arrLines = GetFileLines(sFilePath)
If Not(IsArray(arrLines)) Then Exit Function
sCurSection = ""
For x = 0 To UBound(arrLines)
sLine = Trim(arrLines(x))
If Len(sLine)>0 Then
If Left(sLine, 1)="[" Then
If Not(HandleSectionLine(sLine, sCurSection)) Then Exit Function
Else
If Len(sCurSection)=0 Then
Err.Raise 1005, "IniFileObject init", "Found value outside any section (" & Server.HTMLEncode(sLine) & ")"
Exit Function
End If
Set oSectionDict = m_Data(sCurSection)
If Not(ParseOneLine(sLine, oSectionDict)) Then Exit Function
Set m_Data(sCurSection) = oSectionDict
End If
End If
Next
End Function
Public Property Get ReadValue(section, key)
Dim oSectionDict
ReadValue = ""
If m_Data.Exists(section) Then
Set oSectionDict = m_Data(section)
If oSectionDict.Exists(key) Then ReadValue = oSectionDict(key)
End If
End Property
Private Function ParseOneLine(ByVal sLine, ByRef oSectionDict)
Dim arrTemp, sErrorMsg, sKey
sErrorMsg = ""
ParseOneLine = True
If Left(sLine, 2)="//" Or Left(sLine, 1)="'" Or Left(sLine, 1)="{" Then Exit Function
arrTemp = Split(sLine, "=")
If UBound(arrTemp)=1 Then
sKey = Trim(arrTemp(0))
If (Len(sKey)>0) And (Len(arrTemp(1))>0) Then
If Not(oSectionDict.Exists(sKey)) Then
oSectionDict.Add sKey, Trim(arrTemp(1))
Else
sErrorMsg = "Key already exists"
End If
Else
sErrorMsg = "Empty key or value"
End If
Else
sErrorMsg = "Missing or too much '=' characters"
End If
Erase arrTemp
If Len(sErrorMsg)>0 Then
ParseOneLine = False
Err.Raise 1006, "IniFileObject Init", "Failed to parse single line (" & Server.HTMLEncode(sLine) & "): " & sErrorMsg
End If
End Function
Private Function HandleSectionLine(ByVal sLine, ByRef sCurSection)
HandleSectionLine = False
If (Len(sLine)<3) Or (Right(sLine, 1)<>"]") Then
Err.Raise 1002, "IniFileObject init", "Invalid line found: " & Server.HTMLEncode(sLine)
Exit Function
End If
sCurSection = Mid(sLine, 2, Len(sLine) - 2)
If m_Data.Exists(sCurSection) Then
Err.Raise 1003, "IniFileObject init", "Section exists more than once: " & Server.HTMLEncode(sCurSection)
Exit Function
End If
m_Data.Add sCurSection, Server.CreateObject("Scripting.Dictionary")
HandleSectionLine = True
End Function
Private Function GetFileLines(sFilePath)
Dim objFSO, oFile
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
If Not(objFSO.FileExists(sFilePath)) Then
Set objFSO = Nothing
Err.Raise 1001, "IniFileObject init", "file path '" & Server.HTMLEncode(sFilePath) & "' does not exist, check permissions"
Exit Function
End If
Set oFile = objFSO.OpenTextFile(sFilePath)
GetFileLines = Split(oFile.ReadAll, VBCrLf)
oFile.Close
Set oFile = Nothing
Set objFSO = Nothing
End Function
End Class
Usage example:
Dim filePath, ini
filePath = Server.MapPath("config.ini")
Set ini = New IniFileObject.Init(filePath)
Response.Write("Value for 'Key001': " & ini.ReadValue("MySection", "Key001") & "<br />")
Set ini = Nothing
The code throw various errors when the file does not exist or contains invalid lines, the errors are pretty much clear. It's possible to "suppress" the errors and not display error page by using such code when consuming:
On Error Resume Next
Set ini = New IniFileObject.Init(filePath)
If Err.Number<>0 Then
Response.Write("Error reading ini file")
End If
On Error Goto 0
If IsObject(ini) Then
Response.Write("Value for 'IP001': " & ini.ReadValue("IPaddress", "IP001") & "<br />")
Set ini = Nothing
End If
I would probably use CSV file instead where each row will represent a country.
Country,Address1,Address2,Address3,Address4
London,Address 1,Postbox 3245,58348 London
Copenhagen,Address 2,Postbox 2455,5478347,Copenhagen
If you can easily identify your data then you could probably have more descriptive column names (i.e. Street1, Street2, Town, Postcode, etc.).
This file format is also easy to read since you only read one line of the input file at a time and split it using something like
aAddress = split(sLine, ",")
To make it even easier to work with you could use dictionary object and use country as a key and array as a value
'sLine should be read from input file'
sLine = "Copenhagen,Address 2,Postbox 2455,5478347,Copenhagen"
'Create dictionary for addresses'
Set dic = CreateObject("Scripting.Dictionary")
'Split line into array'
aAddressParts = Split(sLine, ",")
'Remove the first element of the array'
sValues = Mid(sLine, InStr(sLine, ",")+1)
aValues = Split(sValues, ",")
'Add new entry into dictionary'
dic.Add aAddressParts(0), aValues
'Usage'
MsgBox "Address for Copenhagen: " & vbNewLine & _
Join(dic("Copenhagen"), "," & vbNewLine)
Thanks,
Maciej
You could store the addresses in one line and use a special character, for example an underscore, to indicate a line break. When you read the address, you just need to replace the special character with a line break.
[London]
Address = "Postbox 3245_58348
London"
[Copenhagen]
Address = "Postbox
2455_5478347 Copenhagen"
That allows you to store addresses with more lines or without a postbox line, as well. In my experience, information like "our addresses always have exactly two lines and the first one is always a postbox" is very often incorrect...
I use a small executable that launches native api for that: GetPrivateProfileString and WritePrivateProfileString.
The executable is called like that:
Set sh = CreateObject("WScript.Shell")
Set exec = sh.Exec("ini.exe get %APPDATA%\sth\file.ini ""Section name"" key")
sFirma1 = exec.StdOut.ReadLine
Call sh.Run("ini.exe set %APPDATA%\sth\file.ini ""Section name"" key set_value", 0)
See also Running command line silently with VbScript and getting output?.
This is the code of the executable:
#include <stdio.h>
#include <windows.h>
void usage()
{
puts("ini <get>/<set> <file> <section> <key> <value>");
exit(1);
}
int main(int cArg, char **aszArg)
{
int iFile = 2;
int iSection = 3;
int iKey = 4;
int iValue = 5;
if (cArg < 5) usage();
if (strcmp(aszArg[1], "get") != 0 && strcmp(aszArg[1], "set") != 0) usage();
if (strcmp(aszArg[1], "set") == 0 && cArg < iValue + 1) usage();
if (strcmp(aszArg[1], "set") == 0) {
if (!WritePrivateProfileString(aszArg[iSection], aszArg[iKey],
aszArg[iValue], aszArg[iFile]))
puts("Failure in WriteProfileString.");
} else {
char buf[1000];
buf[0] = 0;
GetPrivateProfileString(
aszArg[iSection], aszArg[iKey], "", buf, 999, aszArg[iFile]);
puts(buf);
}
return 0;
}
You need to compile it using a c compiler for Windows. I did it with gcc, but a free compiler from ms should also work. If this page with a 32-bit executable is still available, you may give it a try, but on your own responsibility. Hackers already visited my site once.

Resources