Output content of text file to computer voice via batch file - vbscript

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()

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.

Read path from file and check if file exists in a specified path

I am trying to read a PATH from a text file and check whether the file exists in the PATH specified in the "input.txt" file. Though the file is present in the specified location. The loop continues to run.Please help
Below is my VBScript
Set oReadObj = CreateObject("Scripting.FileSystemObject")
set oRead = oReadObj.OpenTextFile("C:\input.txt", 1)
loc = oRead.ReadAll()
Do Until oReadObj.FileExists(loc)
wscript.sleep 5000
Loop
msgbox "file found"
you don't need a loop to check if the file exists (if you have the full path of it), here is the code you need.
Set oReadObj = CreateObject("Scripting.FileSystemObject")
set oRead = oReadObj.OpenTextFile("C:\input.txt", 1)
loc = oRead.ReadAll()
If oReadObj.FileExists(loc) Then msgbox "file found" else msgbox "file not found"
.ReadAll() may include a EOL from the file, which surely isn't part of the path; use .ReadLine(), as you just want to get one path.
On second thought:
There may be other junk (spaces, BOM, ...) in your file. Did you try something like
WScript.Echo ">" & loc & "<"
to check for those or typos?
Reboot:
Based your comments:
If I specify the "path(location of installer)" instead of variable
"loc", I am getting expected result
This is the content of my " input.txt" file
"C:\Users\Administrator\Downloads\Storage_Manager_Server-windows-x86_64-6.0.0.ex‌​e"
we can
rule out permission problems (usual suspects if "Administrator" pops up)
conclude that loc - i.e. the file's content - is to blame
If we are sure that EOL's, blanks, typos are not the cause of .FileExists' failure, then the most likely hypothesis is: The file contains the " (quoted path), which is good for the shell, but fatal for FileSystemObject methods.

VBscript error input past end of file

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

Modify "C:\Windows\System32\drivers\etc\hosts" file using VBScript

I want to append a line to C:\Windows\System32\drivers\etc\hosts using VBScript. I tried to read this file first using this code:
Set filestreamIN = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Windows\System32\drivers\etc\hosts",2,true)
file = Split(filestreamIN.ReadAll(), vbCrLf)
for i = LBound(file) to UBound(file)
msgbox file(i)
Next
filestreamIN.Close()
Set filestreamIN = Nothing
But I got an error in the second line: Bad file mode. I ran it using this command:
cscript "D:\Project\AXA\AXADEPROJ-867\add host.vbs"
with cmd being run as an administrator. Any help would be great.
Open the file for appending, and simply output what you want. It will automatically be appended.
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oHosts = oFSO.GetFile("C:\Windows\System32\drivers\etc\hosts")
WScript.Echo oHosts.attributes
Set fileAPPEND = _
oFSO.OpenTextFile("C:\Windows\System32\drivers\etc\hosts", 8, true)
fileAPPEND.Write("192.168.0.1 MyMachine")
fileAPPEND.Close()
Set fileAPPEND = Nothing
Set oHosts = Nothing
Set oFSO = Nothing
Of course that does not address a potential issue of appending data that is already in the file.
If you want to read the file first, open it for reading, read the data, close it, then re-open it for appending and make your changes. There is no need to open it for writing.
If you want to edit the file, read it in, close it, reopen it for writing, and write out the edited data.
C:\Windows\System32\drivers\etc is a directory.
here is the bat file inc case you need
type "%windir%\system32\drivers\etc\hosts" | find /i "WEBSITE1" || echo 10.0.0.0 WEBSITE1 >> "%windir%\system32\drivers\etc\hosts"
type "%windir%\system32\drivers\etc\hosts" | find /i "SERVER1" || echo 10.0.0.0 SERVER1 >> "%windir%\system32\drivers\etc\hosts"

Resources