VBscript output not writing correctly - scripting

Hello Scripting Experts,
I have a log file on remote servers..
in remote servers c:\vb\text.log
I have included my remote systems in list.Txt like
server1
server2
below is the sample of log..
application working
[10/23/2012 working
[10/24/2012 nos appdown
error found you need to check this
Below is my Script.
Set Fso = CreateObject("Scripting.FileSystemObject")
Set InFile = fso.OpenTextFile("list.Txt")
Set out = fso.CreateTextFile("error.log")
Const ForReading = 1
Do While Not (InFile.atEndOfStream)
strComputer = InFile.ReadLine
today = Date()
Set fso = CreateObject("Scripting.FileSystemObject")
strFilePath = "\\" & strComputer & "\c$\vb\"
Set InputFile = fso.OpenTextFile(strFilePath & "text.log", 1)
Do While Not (InputFile.AtEndOfStream)
strLine = InputFile.ReadLine
If Left(line, Len(today)+1) = "[" & today Then
' line timestamped with today's date
If InStr(line, "nos") > 0 Then
' line contains "error"
out.WriteLine InStr & vbTab & strComputer
End If
End If
Loop
InputFile.close
Loop
out.Close
InFile.Close
Basically the above script should search from current date line only from the text.log file that is [10/24/2012 nos appdown. Then if found as "Nos" in the current date line.. then it should write to the error.log with computer Name.
In my case the output is not coming , however looks like it is searching for the string "Nos".
Kindly gail break me from this situation....

The bug is that you don't specify the explicit option. Like so,
option explicit
This will force VBScript to complain about nondeclared variables. By doing this, you easily can spot misspelled variable names. Delcare variables with dim statement, like so
dim Fso, out
Run the script again and see that you are using a non-existing and non-initialized variable in comparision:
strLine = InputFile.ReadLine ' Read stuff to strLine
If Left(line, Len(today)+1) = "[" & today Then ' ERROR. line has no value!

There are several issues with your adaptation of my script:
As was already pointed out by vonPryz this is the cause of the problem:
strLine = InputFile.ReadLine
If Left(line, Len(today)+1) = "[" & today Then
When you change a variable name from file to strFile you have to change every occurrence of that variable, not just the line where it's assigned.
out.WriteLine InStr & vbTab & strComputer
This line will also fail, because InStr is a function and you don't call it with the correct number of arguments.
today = Date()
This should not be inside a loop unless you expect the date to change during the script run and need to have the current date in every loop cycle.
Set fso = CreateObject("Scripting.FileSystemObject")
fso is instantiated at the beginning of the script. There's no need to re-instantiate it, especially not in each loop cycle. That's just a waste of resources.
Const ForReading = 1
There's no point in defining a constant when you're never using it.
Do While Not ...
Using Do Until ... would be easier to read and to understand.

Related

Stop Access writing two sets of double quotes to csv

So, I'm using the output from a record set and writing out to a csv file. But I'm getting an issue with Quotation marks. Ideally I'd like to include them as text markers. But if I include them in my line of text they get printed as two sets of quotation marks.
I want this as the output (delimited by tabs):
"Header1" "header2" "......[]...."headerX"
I tried this
Sub Write_Tbl(Filename, StrSQL)
Dim unicode, UTF, i As Long , Fileout As Object, forwriting, TristateUseDefault, TxtStr As String, TextHolder As String, rs As Recordset
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim File_out As Object
Set File_out = fso.CreateTextFile(Filename, True, unicode = UTF - 8)
File_out.Close
Open Filename For Output As #1
Set rs = CurrentDb.OpenRecordset(StrSQL)
rs.MoveFirst
'for headers
TxtStr = rs.Fields.Item(0).Name 'so that there isn't a tab at the start of the string
For i = 1 To rs.Fields.Count - 1
TxtStr = TxtStr & chr(34) & vbTab & chr(34) & rs.Fields.Item(i).Name
Next i
Write #1, TxtStr & chr(34) 'write headers to file
and got this as the output
""Header1"" ""header2"" ""......[]....""headerX""
So I removed the quotation marks and got this:
'for headers
TxtStr = rs.Fields.Item(0).Name 'so that there isn't a tab at the start of the string
For i = 1 To rs.Fields.Count - 1
TxtStr = TxtStr & vbTab & rs.Fields.Item(i).Name
Next i
Write #1, TxtStr 'write headers to file
and what I'm getting is
"Header1 header2 ......[]....headerX"
If I monitor the variables in the locals window, there's only one set of quotes so it must be something to do with printing? It doesn't happen if I use single quotation marks (ascii no 39). I also tried just using write to file, rather than as a text stream, but I got memory issues and ERROR 5 issues. STUMPED. Please help.
If you have prepared your text string in VBA, you should use the Print # statement instead of Write # .
Documentation: Print # vs. Write #
Unlike the Print # statement, the Write # statement inserts commas between items and quotation marks around strings as they are written to the file.
Note:
I'm not sure if these functions write Unicode at all, or care how the file was created.
Open Filename For Output As #1
will create the file if it doesn't exist, so you can probably omit the whole CreateTextFile part.
Or use File_out.WriteLine() instead, it seems odd to mix both methods (FSO and the ancient Print/Write statements).
Edit: see How to create and write to a txt file using VBA

Finding txt File path dynamically

I need to read a txt file but I don't have the path. The text file is two directories before the path of the script I'm running. I thought I could use "WScript.ScriptFullName" and then just use an instrRev and make it split the str at "/". But It doesn't work Could you guys help me with that. I have to run this on multiple computers so the path changes but the text file will always be two derictories above the script path
My code so far
Dim strScriptPath
strScriptPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
WScript.Echo strScriptPath
WScript.Echo(WScript.ScriptFullName)
Dim DashRev
DashRev = instrRev(WScript.ScriptFullName, "/")
wscript.echo DashRev
First replace the "/" with "\"
Then try the following. This seems to work for me:
Dim strScriptPath
strScriptPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
WScript.Echo strScriptPath
WScript.Echo(WScript.ScriptFullName)
Dim first, sec
first = instrRev(strScriptPath, "\",Len(strScriptPath)-1)
sec = instrRev(WScript.ScriptFullName, "\",first-1)
wscript.Echo "parent = " & Left(strScriptPath,sec)
The idea being that strScriptPath is always going to end in "\" and first is going to exclude that from the instrrev by using the starting position of one less than the length of the path. Same thing essentially with sec.
Set FSO = WScript.CreateObject("Scripting.FileSystemObject")
WScript.Echo FSO.GetFile(WScript.ScriptFullName).ParentFolder.ParentFolder.ParentFolder.Path

Excel macro to read input from files created today only

I have an application that exports daily reports in txt format.
I have a macro that extracts certain lines of data from those reports and puts them in an output xls file. my macro's input directory is curently a separate folder that i manually move today's reports into.
I'd like for my macro to be able to just read from the default report folder and only read files created with today's date.
the naming convention of the report files is as follows:
1101_16_16_AppServiceUser_YYYYMMDDhhmmssXXX.txt
not sure what the last 3 digits on the file name represents, but they're always numbers.
Help?
WOW that was fast! thanks... fist time using stackoverflow.
I guess i should include the code that pulls data and dumps it to excel... here it is:
Sub PullLinesFromEPremisReport()
Dim FileName, PathN, InputLn As String
Dim SearchFor1, SearchFor2, OutpFile As String
Dim StringLen1, StringLen2 As Integer
Dim colFiles As New Collection
Dim bridgekey As String
PathO = "C:\Documents and Settings\GROMERO\Desktop\CM reconciliation\output\"
PathN = "C:\Documents and Settings\GROMERO\Desktop\CM reconciliation\input\"
FileName = Dir(PathN)
While FileName <> ""
colFiles.Add (FileName)
FileName = Dir
Wend
SearchFor1 = "BRIDGE KEY"
StringLen1 = Len(SearchFor1)
OutpFile = "RESULTS.xls"
Open PathO & OutpFile For Output As #2
For Each Item In colFiles
Open PathN & Item For Input As #1
Do Until EOF(1) = True
Line Input #1, InputLn
If (Left(LTrim$(InputLn), StringLen1) = SearchFor1) Then
bridgekey = InputLn
End If
Loop
Close #1
Next Item
Close #2
End Sub
Daniel's answer is correct, but using the FileSystemObject requires a couple of steps:
Make sure you have a reference to "Microsoft Scripting Runtime":
Then, to iterate through the files in the directory:
Sub WorkOnTodaysReports()
'the vars you'll need
Dim fso As New FileSystemObject
Dim fldr As Folder
Dim fls As Files
Dim fl As File
Set fldr = fso.GetFolder("C:\Reports")
Set fls = fldr.Files
For Each fl In fls
'InStr returns the position of the substring, or 0 if not found
' EDIT: you can explicitly use the reliable parts of your file name
' to avoid false positives
If InStr(1, fl.Name, "AppServiceUser_" & Format(Now, "YYYYMMDD")) > 0 Then
'Do your processing
End If
Next fl
End Sub
EDIT: So I think, from the code you posted, you could send PathN to the main Reports folder like you desire, then just modify your While statement like so:
While FileName <> ""
If InStr(1, FileName, "AppServiceUser_" & Format(Now, "YYYYMMDD")) > 0 Then
colFiles.Add (FileName)
End If
FileName = Dir
Wend
Two ways you can do this off the top of my head. Assuming you are using a File via the FileSystemObject.
Do an Instr on the file.Name looking for Format(Date, "YYYYMMDD") within the string.
Or use a far simpler approach loop through the files and within your loop do this:
If File.DateCreate >= Date Then
'Do something
end if
Where File is the actual variable used to for looping through the files.
If fileName like "*AppServiceUser_" & Format(Now, "YYYYMMDD") & _
"#########.txt" Then
'good to go
End If

VBScript - How to make program wait until process has finished?

I have a problem in a VBScript that I am using with a VBA/Excel macro and a HTA. The problem is just the VBScript, I have the other two components, i.e. the VBA macro and HTA front-end working perfectly. But before I explain the problem, I think for you to help me I must help you understand the context of the VBScript.
So, basically all components (VBScript, VBA macro and HTA) are parts of a tool that I am building to automate some manual chores. It pretty much goes like this:
A - HTA
~~~~~~~~~~~~
User selects some files from the HTA/GUI.
Within the HTML of the HTA there is some VBScript within the "SCRIPT" tags which passes the users 4 input files as arguments to a VBScript (executed by WScript.exe - you may refer to note #1 for clarity here)
The script, lets call it myScript.vbs from now on then handles the 4 arguments, 3 of which are specific files and the 4th is a path/folder location that has multiple files in it - (also see note #2 for clarity)
B - myScript.vbs
~~~~~~~~~~~~
myScript.vbs opens up the first 3 arguments which are Excel files. One of them is a *.xlsm file that has my VBA macro.
myScript.vbs then uses the 4th argument which is a PATH to a folder that contains multiple files and assigns that to a variable for passing to a FileSystemObject object when calling GetFolder, i.e.
... 'Other code here, irrelevant for this post
Dim FSO, FLD, strFolder
... 'Other code here, irrelevant for this post
arg4 = args.Item(3)
strFolder = arg4
Set FSO = CreateObject("Scripting.FileSystemObject"
'Get a reference to the folder you want to search
Set FLD = FSO.GetFolder(strFolder)
...
From here I create a loop so that I can sequentially open the files within the folder
and then run my macro, i.e.
...
Dim strWB4, strMyMacro
strMyMacro = "Sheet1.my_macro_name"
'loop through the folder and get the file names
For Each Fil In FLD.Files
Set x4WB = x1.Workbooks.Open(Fil)
x4WB.Application.Visible = True
x1.Run strMyMacro
x4WB.close
Next
...
Please note that when the first 3 Excel files have opened (controlled by code prior to the loop, and not shown here as I am having no problem with that part) I must keep them open.
It is the files in the folder (that was passed as the 4th argument) which must sequentially open and close. But inbetween opening and closing, I require the VBA/macro (wrote in one of the 3 Excel files previously opened) to run each time the loop iterates and opens a new file from the folder (I hope you follow - if not please let me know :) ).
The problem I am having is that the files in the folder open and close, open and close, n number of times (n = # of files in folder, naturally) without waiting for the macro to run. This is not what I want. I have tried the WScript.sleep statement with a 10 second delay after the 'x1.Run strMyMacro' statement, but to no avail.
Any ideas?
Thanks,
QF.
NOTES:
1 - For simplicity/clarity this is how:
strCMD = cmd /c C:\windows\system32\wscript.exe myScript.vbs <arg1> <arg2> <arg3> <arg4>
'FYI - This is run by creating a WShell object, wsObj, and using the .run method, i.e. WShell.run(strCMD)
2 The HTA employs a piece of JavaScript that strips the users 4th input file (HTML: INPUT TYPE="file") and passes that to the the VBScript within the HTA. This gets me round the problem of not being able to exclusively select a FOLDER in HTML.
You need to tell the run to wait until the process is finished. Something like:
const DontWaitUntilFinished = false, ShowWindow = 1, DontShowWindow = 0, WaitUntilFinished = true
set oShell = WScript.CreateObject("WScript.Shell")
command = "cmd /c C:\windows\system32\wscript.exe <path>\myScript.vbs " & args
oShell.Run command, DontShowWindow, WaitUntilFinished
In the script itself, start Excel like so. While debugging start visible:
File = "c:\test\myfile.xls"
oShell.run """C:\Program Files\Microsoft Office\Office14\EXCEL.EXE"" " & File, 1, true
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objWMIService.Create "notepad.exe", null, null, intProcessID
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
Do Until i = 1
Set objLatestProcess = colMonitoredProcesses.NextEvent
If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
i = 1
End If
Loop
Wscript.Echo "Notepad has been terminated."
This may not specifically answer your long 3 part question but this thread is old and I found this while searching today. Here is one shorter way to: "Wait until a process has finished." If you know the name of the process such as "EXCEL.EXE"
strProcess = "EXCEL.EXE"
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcesses = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = '"& strProcess &"'")
Do While colProcesses.Count > 0
Set colProcesses = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = '"& strProcess &"'")
Wscript.Sleep(1000) 'Sleep 1 second
'msgbox colProcesses.count 'optional to show the loop works
Loop
Credit to: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/
Probably something like this? (UNTESTED)
Sub Sample()
Dim strWB4, strMyMacro
strMyMacro = "Sheet1.my_macro_name"
'
'~~> Rest of Code
'
'loop through the folder and get the file names
For Each Fil In FLD.Files
Set x4WB = x1.Workbooks.Open(Fil)
x4WB.Application.Visible = True
x1.Run strMyMacro
x4WB.Close
Do Until IsWorkBookOpen(Fil) = False
DoEvents
Loop
Next
'
'~~> Rest of Code
'
End Sub
'~~> Function to check if the file is open
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function

Unzipping a file to a remote directory in VBA

I have a project where I need to extract a file from a zip, and then open that file. I had it working last week with the code:
With CreateObject("Shell.Application")
.Namespace("" & UnZippedFolder).copyhere .Namespace("" & ZipFolder & _
ZipFile).Items
End With
When I tried to run it this week, I got a bunch of errors as I tried to debug it.
I've moved from 'simple' (above) to 'as explicit as I can figure out' (below). I'm currently getting the error, "Object variable or With block variable not set." with the line selected that has '*' at the end. I can't figure out why this error is being thrown, or how to fix it.
Dim WeekNum As Integer
Dim ZipFolder As String
Dim ZipFile As String
Dim UnZippedFile As String
Dim UnZippedFolder As String
Dim objShell
Dim UZipFold
Dim ZipFoldAndFile
If Proceed = False Then Exit Sub
WeekNum = Workbooks("personal.xlsb").Sheets("Dates").Range("WeekNum").Value
ZipFolder = "\\server\path\" ' obfuscated because I must, sorry
ZipFile = "Prefix" & "Week" & WeekNum & " (xlsx 07 format).zip" ' change the 11 to the last 2 digits of the year!
UnZippedFolder = "\\server\path\" ' obfuscated, again, because I must
UnZippedFile = "Logging_11" & "Week" & WeekNum & " (xlsx 07 format).xlsx"
Set objShell = New Shell
UZipFold = objShell.Namespace("" & UnZippedFolder)
ZipFoldAndFile = objShell.Namespace("" & ZipFolder & ZipFile)
UZipFold.copyhere (objShell.Namespace("" & ZipFolder & ZipFile).Items) '*'
You must declare your paths or anything passed to the shell object as variants, not strings.
See here: http://www.rondebruin.nl/windowsxpunzip.htm