VBscript error input past end of file - vbscript

I have 3 scripts wherein they all must be run in the right order repeatedly.
1st script - performs a process on a list of PCs (listed on a textfile input) depending if they are online/offline. It outputs a list of the PCs which were online and another list of the offline ones
2nd script - gets the PC difference from the original list and the output of the 1st script to know which machines have run the process from the 1st script
3rd script - using the differences, updates the input list
The script below is the 3rd script. Whenever I run it, it ends with an error "input past end of file". I've tried several modifications and it always ends that way.
My idea for the 3rd script is that the Differences.txt output from the 2nd file are the ones that still need to run the process form the first script, so I simply delete the original input file and rename this one into the new output file. However, I have to also keep track of the ones that were already done with the process so I have to list/append them to another text file.
Thanks in advance for any help.
Option Explicit
Dim objFso
Dim Fso
Dim firstfile,secondfile,file,fileText
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists("Machines.ini") Then objFSO.DeleteFile("Machines.ini")
Set Fso = WScript.CreateObject("Scripting.FileSystemObject")
Fso.MoveFile "Differences.txt", "Machines.ini"
firstfile="Notified.txt"
secondfile="Notified-all.txt"
Set fso=CreateObject("Scripting.FileSystemObject")
Set file=fso.OpenTextFile(firstfile)
fileText = fileText & file.ReadAll() & vbCrLf
file.Close
Set file=fso.OpenTextFile(secondfile)
fileText=filetext & file.ReadAll()
file.Close
set file=fso.CreateTextFile(secondfile,true)
file.Write fileText
file.close

You get that error when you call ReadAll on an empty file. Check the AtEndOfStream property and read the content only if it's false:
If Not file.AtEndOfStream Then fileText = fileText & file.ReadAll

Related

Why is my readall function popping up a error? [duplicate]

I have 3 scripts wherein they all must be run in the right order repeatedly.
1st script - performs a process on a list of PCs (listed on a textfile input) depending if they are online/offline. It outputs a list of the PCs which were online and another list of the offline ones
2nd script - gets the PC difference from the original list and the output of the 1st script to know which machines have run the process from the 1st script
3rd script - using the differences, updates the input list
The script below is the 3rd script. Whenever I run it, it ends with an error "input past end of file". I've tried several modifications and it always ends that way.
My idea for the 3rd script is that the Differences.txt output from the 2nd file are the ones that still need to run the process form the first script, so I simply delete the original input file and rename this one into the new output file. However, I have to also keep track of the ones that were already done with the process so I have to list/append them to another text file.
Thanks in advance for any help.
Option Explicit
Dim objFso
Dim Fso
Dim firstfile,secondfile,file,fileText
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists("Machines.ini") Then objFSO.DeleteFile("Machines.ini")
Set Fso = WScript.CreateObject("Scripting.FileSystemObject")
Fso.MoveFile "Differences.txt", "Machines.ini"
firstfile="Notified.txt"
secondfile="Notified-all.txt"
Set fso=CreateObject("Scripting.FileSystemObject")
Set file=fso.OpenTextFile(firstfile)
fileText = fileText & file.ReadAll() & vbCrLf
file.Close
Set file=fso.OpenTextFile(secondfile)
fileText=filetext & file.ReadAll()
file.Close
set file=fso.CreateTextFile(secondfile,true)
file.Write fileText
file.close
You get that error when you call ReadAll on an empty file. Check the AtEndOfStream property and read the content only if it's false:
If Not file.AtEndOfStream Then fileText = fileText & file.ReadAll

pasting a value to xlsx using shell

I have a template file in xlsx format and I want to paste a dynamic value in one particular cell i.e based on the flow of program the value in that cell will change which in turn changes conditions in xlsx file for a different process.
I have tried codes like
awk -v value=$value -v row=$row -v col=$col 'BEGIN{FS=OFS="#"} NR==row {$col=value}1' file.csv
but the issue is I cant use this code for xlsx file format. is there any way to do this for xlsx file format, since it's a template file I need to retain xlsx file format.
When I have to extract values from an Excel workbook on my Windows PC I install cygwin and then write a small shell script that does:
cygstart "/path/to/xls2csv.vbs" 'C:/cygwin64/path/to/bookName.xlsx'
awk 'whatever' '/path/to/bookName/sheetName.csv'
and the work of extracting every sheet from the workbook as a separate CSV named based on the sheet name suffixed with ".csv" under a common directory named after the workbook is done by this visual basic script:
$ cat xls2csv.vbs
csv_format = 6
Dim strFilename
Dim objFSO
Set objFSO = CreateObject("scripting.filesystemobject")
strFilename = objFSO.GetAbsolutePathName(WScript.Arguments(0))
If objFSO.fileexists(strFilename) Then
Call Writefile(strFilename)
Else
wscript.echo "no such file!"
wscript.echo strFilename
End If
Set objFSO = Nothing
Sub Writefile(ByVal strFilename)
Dim objExcel
Dim objWB
Dim objws
Set objExcel = CreateObject("Excel.Application")
Set objWB = objExcel.Workbooks.Open(strFilename)
For Each objws In objWB.Sheets
objws.Copy
objExcel.ActiveWorkbook.SaveAs objWB.Path & "\" & objws.Name & ".csv", csv_format
objExcel.ActiveWorkbook.Close False
Next
objWB.Close False
objExcel.Quit
Set objExcel = Nothing
End Sub
That command would fail given blanks in file or directory names so we need to replace those with, say, underscores. In reality I usually copy the Xls file to a temp directory and give it a temp name before running the above on it so I can run the above on it without affecting the original file and without having to care about the path to the original file. It requires an absolute path to the input Excel workbook.
You might need to throw a wait and/or sleep in before the awk command to ensure the VB script is done before the awk command runs. My not shown shell code is kinda convoluted testing for the VB script creating then removing tmp files to ensure the VB script is done and looping trying and then killing Excel if it doesn't start or hangs before calling awk - I wrote it a long time ago, it's a mess, and I doubt if it's really necessary or a good approach which is why I'm not including it here.
To get those values back INTO a multi-sheet workbook you'd have to open any updated/generated CSV with Excel (or copy/paste). There's probably some other VB script could be written to import the CSVs for you just like I export them above but I've never needed that functionality so idk what that'd look like.
I don't know if you need that though - if your awk script writes CSV then you can just double click on the output .csv and Excel will happily open and display it just like it would any .xls or .xlsx Excel file.
So, to do what you want, assuming your original content is in "Sheet1" of single-sheet Excel workbook "MyStuff.xlsx" you'd do this from cygwin:
cygstart "/path/to/xls2csv.vbs" 'C:/cygwin64/path/to/MyStuff.xlsx'
wait; sleep 10 # or similar
awk -v value="$value" -v row="$row" -v col="$col" 'BEGIN{FS=OFS=","} NR==row {$col=value}1' '/path/to/MyStuff/Sheet1.csv' > "/tmp/tmp$$" &&
mv "/tmp/tmp$$" '/path/to/MyStuff/Sheet1.csv'
and then in Windows just double-click on /path/to/MyStuff/Sheet1.csv to open it in Excel (you may need to associate the .csv file suffix with Excel the first time you do that).
Note that the above will only handle simple CSVs, see What's the most robust way to efficiently parse CSV using awk? for how to robustly handle CSVs with awk in general.

VBScript While file exists

This thing is going to kill me, or I'll kill it. I can't tell what I'm doing but I keep getting a file not found after I delete the file in a while statement.
MsgBox FSO.FileExists(file.path)'Returns True as a test
While (FSO.FileExists(file.path))
If objZip.Items.Item(0).Name = FSO.getfilename(file.path) Then
FSO.DeleteFile (file.path)
MsgBox FSO.FileExists(file.path)'Returns False as a test
End If
WScript.Sleep 100
Wend
Can someone point me to what I'm doing wrong? I have similar code in another working script.
When you delete the disk file the reference to it that is stored in the file variable is no longer valid. Store the file.Path value in a variable and change your code to use it.
Dim filePath
filePath = file.Path
While FSO.FileExists( filePath )
FSO.DeleteFile filePath
Wend
Note - Previous code just exposes the approach about how to reference the file. If DeleteFile fails (we are looping to remove the file) both error handling and loop wait are needed.

open and write 2 files

I need create one script for open one file (Server.txt → content all servers names) and create logfile with ServerName (example: Server1.txt). After that I need WriteLine in this logfile result of the script retrieve registry values.
I have one script working retrieve all registry values but I need to create each FileLog with ServerName.
I think cannot use two Opentextfile before close one.
Can we help me?
This is code I'm using for test:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("Servers.txt")
Do Until objFile.AtEndOfStream
strComputer = objFile.ReadLine
Set objFile2 = objFSO.CreateTextFile(strComputer & ".txt",True)
set objHtml=objFSO.OpenTextFile(objFile2,8,true)
objHtml.WriteLine Now() & VbTab & RegResultQuery
objHtml.Close
Loop
You can call OpenTextFile twice, but you can't open the same file twice without closing it first. From what I see you don't need to open the file twice, though. CreateTextFile already returns a handle to the file, so you can simply use objFile2 throughout the loops.

Output content of text file to computer voice via batch file

I have this batch file:
#echo off
echo StrText="Application created Successfully" > spk.vbs
echo set ObjVoice=CreateObject("SAPI.SpVoice") >> spk.vbs
echo ObjVoice.Speak StrText >> spk.vbs
start spk.vbs
This batch file creates spk.vbs in the same directory and outputs the text "Application created Successfully" with the computer voice.
Now I want the batch file to speak out the content of a text file given to it on the command line instead (%1). And the spk.vbs file should be created in the default Windows temporary directory instead. How can I do this?
***Edit 06.11.2012 20:24
Meanwhile I've discarded the idea of using a batch file script to generate a vbs script file and want to use the vbs script directly. Although I am an absolute beginner with VBS I created this one:
Set objFSO = CreateObject("Scripting.FileSystemObject")
strAFile = Wscript.Arguments(0)
Set objFile = objFSO.GetFile(strAFile)
If objFile.Size > 0 Then
Set objReadFile = objFSO.OpenTextFile(Wscript.Arguments(0), 1)
strContents = objReadFile.ReadAll
objReadFile.Close
set ObjVoice=CreateObject("SAPI.SpVoice")
ObjVoice.Speak strContents
Else
Wscript.Echo "The file is empty."
End If
It works, but probaly I've made a lot of mistakes. Can someone tell me how the vbs script can be optimized? Thank you!
***Edit 06.11.2012 22:19
After this worked a few times, now it does not work anymore: Now the computer speaker outputs only "Y" and the first character of the text file! Has this something to do with an error in my script?
***Edit 10.11.2012 19:32
Found the bug: The above script work only with ANSI-coded text-files. It does not work with UNICODE text-files! Why? How can I make it work with UNICODE text-files too?
Use the 4th parameter of the .OpenTextFile (or the 2nd parameter of the .OpenAsTextStream) method to specify whether to open the file as ASCII or Unicode (16).
I don't find any serious mistakes in your code snippet, but perhaps you want to consider:
using "Option Explicit" (explicitly)
checking whether the user passed at least one argument to the script
avoiding to refer to the same 'object' via different names/variables (strAFile, WScript.Arguments(0))
using .OpenAsTextStream as you have a File object already
avoiding 'magic numbers' (e.g. 1) by defining the appropriate constants (e.g. ForReading)
avoiding unnecessary variables (code you don't write can't be wrong)
E.g:
Set objReadFile = objFSO.OpenTextFile(WScript.Arguments(0), 1)
strContents = objReadFile.ReadAll
objReadFile.Close
==>
Const cnUnicode = -1
...
strContents = objFile.OpenAsTextStream(ForReading, cnUnicode).ReadAll()

Resources