VBscript with lists - vbscript

I am trying to write a VBScript which will read a text file and build a dictionary which contains lists. Let me explain with an example:
The input file would be a simple text file of the sort:
Male,Peter
Male,Chris
Male,Stewie
Male,Brian
Female,Lois
Female,Meg
When I run my script, I would like a dictionary with the first column as the key, and the second column as the values
{'Male':['Peter,Chris,Stewie,Brian']}
{'Female':['Lois,Meg']}
The lack of dynamic arrays or lists in VBScript is making this a real pain. Any suggestion how I might tackle this?
Cheers

VBScript can use the System.Collections.ArrayList class provided by the .NET framework.
Set d = CreateObject("Scripting.Dictionary")
d.Add "Male", CreateObject("System.Collections.ArrayList")
d.Add "Female", CreateObject("System.Collections.ArrayList")
d("Male").Add "Peter"
d("Male").Add "Chris"
'...
d("Female").Add "Lois"
d("Female").Add "Meg"
'...
For processing the input file take a look at the code provided by #Rich.

Just to say, I'm not compete with posted answers for repo-point ;)
If you can convert my post to comment, feel free to do that.
I like Ansgar's idea (+1) as it based on single Dictionary and that seems to me quite enough to get back easy what is stored inside.
The need of .Exists may come in use in 2 cases - (a) if we don't know how many genders we have, and (b) if we don't know how they looks like (pronunciation). The rest is similar to Ansgar's idea.
Option Explicit
Const cGender = 0
Const cName = 1
Dim sGender, sName, sLine
Dim oFSO, oFile, oDict
Dim arrLine
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oDict = CreateObject("Scripting.Dictionary")
Set oFile = oFSO.OpenTextFile("persons_list.txt")
Do Until oFile.AtEndOfStream
sLine = oFile.ReadLine
If Len(sLine) Then
arrLine = Split(sLine, ",")
sGender = arrLine(cGender)
sName = arrLine(cName)
If Not oDict.Exists(sGender) Then
oDict.Add sGender, CreateObject("System.Collections.ArrayList")
End If
oDict(sGender).Add sName
End If
Loop
oFile.Close
Set oFile = Nothing
Set oFSO = Nothing
WScript.Echo "Genders:" & oDict.Count, vbNewLine & Join(oDict.Keys)
Dim sKey
For Each sKey In oDict
WScript.Echo sKey, oDict(sKey).Count, vbNewLine & Join(oDict(sKey).ToArray())
Next

I'm not too familiar with the dictionary object, but this might suffice?
Set oFso = CreateObject("Scripting.FileSystemObject")
Set oDictionary = CreateObject("Scripting.Dictionary")
Const cGender = 0
Const cName = 1
Set oFile = oFso.OpenTextFile ("yourfile.txt", 1)
Do Until oFile.AtEndOfStream
sLine = oFile.Readline
If sLine <> "" Then
arrLine = split(sLine,",")
oDictionary.Add arrLine(cGender,0), arrLine(cName,0) 'hope i got these indexes the right way round
'or
oDictionary.Add arrLine(cGender), arrLine(cName) 'if its one dimentional
End If
Loop

As #Rich approach is faulty (-1) - you can't .Add a key twice and if you could, the names would be overwritten, not appended - and Ansgar's good idea (+1) is not really production ready without a hint wrt its practical use:
Const cGender = 0
Const cName = 1
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim dicDic : Set dicDic = CreateObject("Scripting.Dictionary")
Dim dicAl : Set dicAl = CreateObject("Scripting.Dictionary")
Dim dicCnt : Set dicCnt = CreateObject("Scripting.Dictionary")
Dim oFile, sLine, arrLine
Set oFile = oFS.OpenTextFile ("so14479571.txt")
Do Until oFile.AtEndOfStream
sLine = oFile.Readline()
If sLine <> "" Then
arrLine = Split(sLine,",")
dicCnt(arrLine(cGender)) = dicCnt(arrLine(cGender)) + 1
If Not dicDic.Exists(arrLine(cGender)) Then
Set dicDic(arrLine(cGender)) = CreateObject("Scripting.Dictionary")
End If
dicDic(arrLine(cGender))(arrLine(cName)) = Empty
If Not dicAl.Exists(arrLine(cGender)) Then
Set dicAl(arrLine(cGender)) = CreateObject("System.Collections.ArrayList")
End If
dicAl(arrLine(cGender)).Add arrLine(cName)
End If
Loop
Dim sKey, sKey2
WScript.Echo "genders:"
For Each sKey In dicCnt
WScript.Echo "", sKey, dicCnt(sKey)
Next
WScript.Echo "dic:"
For Each sKey In dicDic
WScript.Echo "", sKey
For Each sKey2 In dicDic(sKey)
WScript.Echo " ", sKey2
Next
Next
WScript.Echo "AL:"
For Each sKey In dicAl
WScript.Echo "", sKey & ":", Join(dicAl(sKey).ToArray())
Next
output:
genders:
Male 4
Female 2
dic:
Male
Peter
Chris
Stewie
Brian
Female
Lois
Meg
AL:
Male: Peter Chris Stewie Brian
Female: Lois Meg
The script should show:
How you can use assignment without .Exists for 'simple' values that can be autovivified (here a number)
That you need an .Exists check for values like Arrays, ArrayLists, or Dictionaries

Related

How to save all Excel files in a folder as pipe delimited files

I'm writing a process that needs to loop through all Excel files in a folder and save each one as a pipe delimited value.
I've done a lot of hunting on how to do this and most of them say to change the delimiter value in Region settings. This isn't an option for me as this will be implemented on a customer's system and I cannot change these settings.
I've got some code to work as a vba macro in each file, and I have a vbs script that loops through the files in a folder and converts them to tab delimited files, both of these were found from this site and adapted to do what I need.
This is the code i have so far:
WorkingDir = "C:\Test\Temp"
savedir="C:\Test\Temp\"
Dim fso, myFolder, fileColl, aFile, FileName, SaveName
Dim objExcel, objWorkbook
Dim lastColumn
Dim lastRow
Dim strString
Dim i
Dim j
Dim outputFile
Dim objectSheet
Dim objectCells
Set fso = CreateObject("Scripting.FilesystemObject")
Set myFolder = fso.GetFolder(WorkingDir)
Set fileColl = myFolder.Files
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
For Each aFile In fileColl
name= Left(aFile.Name,Len(aFile.Name)-Len(Extension))
Set objWorkbook = objExcel.Workbooks.Open(aFile)
Set objectSheet = objExcel.ActiveWorkbook.Worksheets(1)
Set objectCells = objectSheet.Cells
lastColumn = objectSheet.UsedRange.Column - 1 + objectSheet.UsedRange.Columns.Count
lastRow = objectSheet.UsedRange.Rows(objectSheet.UsedRange.Rows.Count).Row
SaveName = savedir & name & ".txt"
Set outputFile = CreateObject("Scripting.FileSystemObject").OpenTextFile(SaveName, 2, true)
For i = 1 To lastRow
objectSheet.Cells(i, 1).Select '<-- this is the line currently causing problems
strString = ""
For j = 1 To lastColumn
If j <> lastColumn Then
strString = strString & objectCells(i, j).Value & "|"
Else
strString = strString & objectCells(i, j).Value
End If
Next
outputFile.WriteLine(strString)
Next
objFileToWrite.Close
Set objFileToWrite = Nothing
Next
Set objWorkbook = Nothing
Set objExcel = Nothing
Set myFolder = Nothing
Set fileColl = Nothing
Set fso = Nothing
I don't really use vb that often, so I'm basically changing a line until it stops throwing errors then moving on to the next one.
I just cannot get this over the commented line. It is currently giving me the error "Select method of Range class failed" with code 800A03EC. Searching this has given me no real results...
The file pretty much has to be pipe delimited as the file contains a lot of the common delimiters (commas, tabs etc.).
Any help to get this to work is greatly appreciated. This is my first post here so apologies if I've given too much or too little info, just let me know and I'll update as required
Update
Have managed to get it working, my working code in answer below. If anyone has suggestions on how to make this faster it'd be appreciated :)
I managed to crack it, I had to activate the sheet I wanted before I could use it and also call the sheet by name instead of using "1". Working code is below in case it helps anyone else in the future. I know it's ugly and could probably be done better but it works :)
WorkingDir = "C:\Test\Temp"
savedir="C:\Test\Temp\"
Extension = ".xls"
neededextension= ".txt"
Dim fso, myFolder, fileColl, aFile, FileName, SaveName
Dim objExcel, objWorkbook
Dim lastColumn
Dim lastRow
Dim strString
Dim i
Dim j
Dim outputFile
Dim objectSheet
Dim objectCells
Set fso = CreateObject("Scripting.FilesystemObject")
Set myFolder = fso.GetFolder(WorkingDir)
Set fileColl = myFolder.Files
Set objExcel = CreateObject("Excel.Application")
objExcel.EnableEvents = false
objExcel.Visible = False
objExcel.DisplayAlerts = False
For Each aFile In fileColl
ext = Right(aFile.Name,Len(Extension))
name= Left(aFile.Name,Len(aFile.Name)-Len(Extension))
Set objWorkbook = objExcel.Workbooks.Open(aFile)
Set objectSheet = objExcel.ActiveWorkbook.Worksheets("MICE BOB")
Set objectCells = objectSheet.Cells
lastColumn = objectSheet.UsedRange.Column - 1 + objectSheet.UsedRange.Columns.Count
lastRow = objectSheet.UsedRange.Rows(objectSheet.UsedRange.Rows.Count).Row
SaveName = savedir & name & ".txt"
Set outputFile = CreateObject("Scripting.FileSystemObject").OpenTextFile(SaveName, 2, true)
For i = 1 To lastRow
objectSheet.Activate
objectSheet.Cells(i, 1).Select
strString = ""
For j = 1 To lastColumn
If j <> lastColumn Then
strString = strString & objectCells(i, j).Value & "|" ' Use ^ instead of pipe.
Else
strString = strString & objectCells(i, j).Value
End If
Next
outputFile.WriteLine(strString)
Next
objFileToWrite.Close
Set objFileToWrite = Nothing
Next
Set objWorkbook = Nothing
Set objExcel = Nothing
Set myFolder = Nothing
Set fileColl = Nothing
Set fso = Nothing
The only issue I have now is that the conversion takes a very long time. Does anyone have a suggestion on how to speed this up, or does the nature of this just mean it's going to be slow?

VBScript: I want to take the contents of a file and run an UPDATE statement using the contents of each line

I have made a connection to a database. I want to take the contents of a file and run an UPDATE statement using the contents of each line.
Database Connection
Option Explicit
Dim sDir : sDir = "\\Server1\Data"
Dim sCS : sCS = Join(Array( _
"Provider=vfpoledb" _
, "Data Source=" & sDir _
, "Collating Sequence=general" _
), ";")
Dim oCN : Set oCN = CreateObject("ADODB.CONNECTION")
oCN.Open sCS
oCN.Close
File
STAD 1
SECA 2
..
UPDATE Statement
For this line:
STAD 1
It would run:
UPDATE B_SNAME.DBF SET SN_ANALSYS = 1 WHERE SN_ACCOUNT = STAD
I am extremely new to VBScript and DBF. I would have no problem writing a little Bash script to do this on our Linux side but here I am lost.
Please can someone provide some information on how I could do it, or even an example (that would be awesome)? :-)
If you separate the fields with one space or any single character (called a delimiter) you can use the split function to separate the fields. You will end up with something like this (I have not tested this)
Dim strSQL
Dim strFilename
Dim sConnString
Dim scs
Dim oCN
Dim oCmd
Dim fso
Dim f
strFilename = "C:\Temp\MyFile.txt"
sConnString = "Provider=vfpoledb;Data Source=\\Server1\Data;Collating Sequence=general;"
strSQL = "UPDATE B_SNAME.DBF SET SN_ANALSYS = p1 WHERE SN_ACCOUNT = p2"
Set oCN = CreateObject("ADODB.CONNECTION")
oCN.Open sConnString
Dim oCmd
Set oCmd = CreateObject("ADODB.Command")
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(strFilename)
Do Until f.AtEndOfStream
sArray = Split(f.ReadLine, " ")
oCmd.Parameters.Append oCmd.CreateParameter("p1", adChar, adParamInput, 4, sArray(1))
oCmd.Parameters.Append oCmd.CreateParameter("p2", adChar, adParamInput, 8, sArray(0))
oCmd.CommandText = strSQL
oCmd.Execute
Loop
f.Close
If oCN.State = 1 Then oCN.Close
Set oCmd = Nothing
Set oCN = Nothing
Most lines are delimited with either tabs or commas but there is no reason why you cannot use a space as long as it does not appear in your data.
Here is a simple example to read the data file and get each field into a variable. This assumes your data file contains a four character account name followed by five spaces and then a number.
Option Explicit
Const ForReading = 1
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
Dim line
Dim sn_analsys
Dim sn_account
Dim dataFile
Set dataFile = fso.OpenTextFile("C:\SomeFolder\data.txt")
Do Until dataFile.AtEndOfStream
line = dataFile.ReadLine
sn_account = Left(line, 4)
sn_analsys = Mid(line, 10)
WScript.Echo "sn_account = " & sn_account
WScript.Echo "sn_analsys = " & sn_analsys
'
' Do whatever processing you need to do...
'
Loop
dataFile.Close
If you change the data file to separate the fields by one space, you can use Split to get each field.
Dim line
Dim fields
Dim dataFile
Set dataFile = fso.OpenTextFile("C:\SomeFolder\data.txt")
Do Until dataFile.AtEndOfStream
line = dataFile.ReadLine
fields = Split(line)
WScript.Echo "sn_account = " & fields(0)
WScript.Echo "sn_analsys = " & fields(1)
WScript.Echo
'
' Do whatever processing you need to do...
'
Loop

VBScript for moving like files

I need a script to be able to move files with like names once there are 4 like files.
Example:
Cust-12345.txt
Addr-12345.txt
Ship-12345.txt
Price-12345.txt
The files will always start with those for names, the numbers after the "-" will always be different. I need to be able to search a folder and when all 4 files are there move them into a completed folder.
option explicit
dim objFS : dim strShareDirectory : dim strDumpStorageDir : dim objFolder : dim colFiles : dim re : dim objFile
dim dictResults ' dictionary of [filename] -> [matching substring]
dim dictResultsCount ' dictionary of [matching substring] -> [count]
dim dictResultsFinal ' only the valid entries from dictResults
dim keyItem
dim strMatch
dim message
message = "Yes"
set dictResultsFinal = CreateObject("Scripting.Dictionary")
set dictResults = CreateObject("Scripting.Dictionary")
set dictResultsCount = CreateObject("Scripting.Dictionary")
Set objFS = CreateObject("Scripting.FileSystemObject")
strShareDirectory = "c:\Test"
strDumpStorageDir = "c\Test\Out"
Set objFolder = objFS.GetFolder(strShareDirectory)
Set colFiles = objFolder.Files
Set re = New RegExp
re.Global = True
re.IgnoreCase = False
re.Pattern = "-\d"
Dim curFile, matchValue
Dim i: i = 0
For Each objFile in colFiles
' test if the filename matches the pattern
if re.test(objFile.Name) then
' for now, collect all matches without further checks
strMatch = re.execute(objFile.Name)(0)
dictResults(objFile.Name) = strMatch
' and count
if not dictResultsCount.Exists(strMatch) then
dictResultsCount(strMatch) = 1
else
dictResultsCount(strMatch) = dictResultsCount(strMatch) +1
end if
end if
next
' for testing: output all filenames that match the pattern
msgbox join(dictResults.keys(), vblf)
' now copy only the valid entries into a new dictionary
for each keyItem in dictResults.keys()
if dictResultsCount.Exists( dictResults(keyItem) ) then
if dictResultsCount( dictResults(keyItem) ) = 4 then
dictResultsFinal(keyItem) = 1
end if
end if
next
I had an answer here that involved using an array but, come to think of it, I don't think you even need an array. Just iterate each file and check for the existence of the others.
Set re = New RegExp
re.Global = True
re.IgnoreCase = True
re.Pattern = "\\(Cust|Addr|Ship|Price)-(\d+)\.txt"
For Each File In objFS.GetFolder(strShareDirectory).Files
' Test to make sure the file matches our pattern...
If re.Test(File.Path) Then
' It's a match. Get the number...
strNumber = re.Execute(File.Path)(0).SubMatches(1)
' If all four exist, move them...
If AllFourExist(strNumber) Then
For Each strPrefix In Array("Cust-", "Addr-", "Ship-", "Price-")
objFS.MoveFile strShareDirectory & "\" & strPrefix & strNumber & ".txt", _
strDumpStorageDir & "\" & strPrefix & strNumber & ".txt"
Next
End If
End If
Next
And here's the AllFourExist function (I'm assuming objFS is global):
Function AllFourExist(strNumber)
For Each strPrefix In Array("Cust-", "Addr-", "Ship-", "Price-")
If Not objFS.FileExists(strShareDirectory & "\" & strPrefix & strNumber & ".txt") Then Exit Function
Next
AllFourExist = True
End Function
I'm not sure how the FSO will handle the fact that you're moving files out of a folder that you're currently iterating. If it complains, you may need to resort to an array after all. Something to keep in mind.

Return line number or subsequent text of a text file string search

I have a several text files that have thousands of lines each with this being an example of a typical line:
PCI\VEN_10EC&DEV_8168&REV_09 Realtek\5x64\FORCED\PCIe_5.810.1218.2012\ Netrtle.inf Realtek 1 12/18/2012,5.810.1218.2012 Realtek PCIe GBE Family Controller
The script I'm working on does a string search for that first segment of text:
PCI\VEN_10EC&DEV_8168&REV_09
My script narrows down which files have this string, but what I really need is for it then to return the next string on that same line:
Realtek\5x64\FORCED\PCIe_5.810.1218.2012\
Once I have this string I can continue on with the rest of the script which is just extracting the Realtek folder from a 7zip.
I've seen this has been done with other languages on Stack but I can't find anything for VBS. I could probably find an answer if I knew how to phrase the task better. I'd really appreciate some advise on grabbing that second string.
For background, this is the script I'm working on. It looks through all the text files in C:\scripts\ for a string returned by a WMI query for CompatibleID of device drivers with code 28 (no driver installed):
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("Wscript.Shell")
Set objNet = CreateObject("WScript.Network")
Set objWMIService = GetObject("winmgmts:\\" & "." & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery _
("Select * from Win32_PnPEntity " _
& "WHERE ConfigManagerErrorCode = 28")
For Each objItem in colItems
Dim arrCompatibleIDs
aarCompatibleIDs = objItem.CompatibleID
for each objComp in aarCompatibleIDs
Dim FirstID
FirstID = objComp
Exit For
Next
Next
strSearchFor = firstID
objStartFolder = "C:\scripts"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colFiles
'Wscript.Echo objFile.Name
strFile = "C:\scripts\" & objFile.Name
set objFile = objFSO.getFile(strFile)
if objFile.size > 0 then
If InStr(objFSO.OpenTextFile(strFile).ReadAll, strSearchFor) > 0 Then
msgbox(objfile.name)
Else
WScript.Sleep (100)
End If
End If
Next
If you need to search for a fixed needle and a variable thread in a haystack, you can use some InStr()s or a RegExp. To get you started:
Dim sHaystack : sHaystack = Join(Array( _
"hay hay" _
, "fixed_needle variable_thread hay" _
, "hay hay" _
), vbCrLf)
Dim sNeedle : sNeedle = "fixed_needle" & " "
Dim nPosN : nPosN = Instr(sHaystack, sNeedle)
If 0 < nPosN Then
nPosN = nPosN + Len(sNeedle)
Dim nPosT : nPosT = Instr(nPosN, sHaystack, " ")
If 0 < nPosN Then
WScript.Echo "Instr()", qq(Mid(sHaystack, nPosN, nPosT - nPosN))
Else
WScript.Echo "no thread"
End If
Else
WScript.Echo "no needle"
End If
Dim reNT : Set reNT = New RegExp
reNT.Pattern = sNeedle & "(\S+) "
Dim oMTS : Set oMTS = reNT.Execute(sHayStack)
If 1 = oMTS.Count Then
WScript.Echo "RegExp ", qq(oMTS(0).SubMatches(0))
Else
WScript.Echo "no match"
End If
output:
Instr() "variable_thread"
RegExp "variable_thread"
If you change the haystack to
Dim sHaystack : sHaystack = Join(Array( _
"hay hay" _
, "fixed_needle no_variable_thread_hay" _
, "hay hay" _
), vbCrLf)
output:
Instr() "no_variable_thread_hay
hay"
no match
you see that there is more work needed to make the Instr() approach bulletproof.
Since your input file seems to be tab-separated, you could do something like this:
Set wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 28"
For Each entity In wmi.ExecQuery(qry)
For Each cid In entity.CompatibleID
firstID = cid
Exit For
Next
Next
Set fso = CreateObject("Scripting.FileSystemObject")
For Each f In objFSO.GetFolder(objStartFolder).Files
If f.Size > 0 Then
For line In Split(f.OpenAsTextStream.ReadAll, vbNewLine)
arr = Split(line, vbTab)
If arr(0) = firstID Then MsgBox arr(1)
Next
End If
Next
On a more general note, you shouldn't do stuff like this:
Set colFiles = objFolder.Files
For Each objFile in colFiles
strFile = "C:\scripts\" & objFile.Name
set objFile = objFSO.getFile(strFile)
if objFile.size > 0 then
If InStr(objFSO.OpenTextFile(strFile).ReadAll, strSearchFor) > 0 Then
...
The Files collection already contains File objects, so it's utterly pointless to build a pathname from the object's properties (which BTW include a Path property that gives you the full path) only to obtain the exact same object you already have. Plus, file objects have a method OpenAsTextStream, so you can directly open them as text files without taking a detour like objFSO.OpenTextFile(f.Path).

Modifying multiple text files with VBScript

i need help with this VBScript
What I'm trying to do here is modify the logfile to remove the extra spaces inside. (I just got this script actually somewhere on the net.)
It works if i specify just a single file but I'm trying to modify multiple files. Using the wildcard character as i did below did not work either (sorry I'm not so good with vbs)
Also does anyone know how we can do this without creating a new output file? just modify the original file. Thanks in advance..
Set objFSO = CreateObject("Scripting.FileSystemObject")
'change this line to wherever you want to read the input from.
Set objTextFile = objFSO.OpenTextFile("D:\access*.log",1)
Set objNewFile = objFSO.CreateTextFile("D:\access*_new.log")
Do Until objTextFile.AtEndOfStream
myString = objTextFile.Readline
objNewFile.WriteLine(Replace (myString, " ", " "))
Loop
In addition to my comment: The Scripting Guy explains exactly your replacement case: multiple spaces by one, with a regular expression:
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Global = True
objRegEx.Pattern = " {2,}"
strSearchString = _
"Myer Ken, Vice President, Sales and Services"
strNewString = objRegEx.Replace(strSearchString," ")
Wscript.Echo strNewString
The Scripting Guy also explains how you can change a text file:
Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Text.txt", ForReading)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "Jim ", "James ")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Text.txt", ForWriting)
objFile.WriteLine strNewText
objFile.Close
And on the same technet.microsoft you can find how you can easily iterate over all files. You can use a regular expression again to see if the file is matching your (wildcard) pattern, in your case ^access.*\.log$:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\FSO")
Set colFiles = objFolder.Files
For Each objFile in colFiles
Wscript.Echo objFile.Name, objFile.Size
Next
This should give you all the ingredients to create your script.
The freeze-dried version:
Const ForReading = 1
Const ForWriting = 2
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject")
Dim reZap : Set reZap = New RegExp
reZap.Global = True
reZap.Pattern = " +"
Dim oFile
For Each oFile In goFS.GetFolder("..\testdata\14620676").Files
WScript.Echo "----", oFile.Name
Dim sAll : sAll = oFile.OpenAsTextStream(ForReading).ReadAll()
WScript.Echo sAll
oFile.OpenAsTextStream(ForWriting).Write reZap.Replace(sAll, " ")
WScript.Echo oFile.OpenAsTextStream(ForReading).ReadAll()
Next
that makes no sense at all without #AutomatedChaos' admirable contribution (+1), but avoids growing the file's tail by using .Write instead of .WriteLine.

Resources