Select file by index from Files Collection - random

I'm trying to access a file by index using vbs but Item does not work as I expected. I would rather not have to loop all files as I'm trying to avoid a treewalk. I recieve the error "Error: Invalid procedure call or argument" on the line with colFiles.Item().
Randomize
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(fFolder.Path)
Set colFiles = objFolder.Files
Set objFile = colFiles.Item(Int(colFiles.Count * Rnd))
I'm sure it's obvious, but my searching only shows example using loops.

VBScript does not support random/index access to the elements of the .Files collection. You'll have to For Each loop, pick a random file, and Exit the loop.
Update:
According to the docs, you can use a 'name' (file name, file spec(?)) as parameter to .Item(), so you could keep an array of file names/specs, pick one randomly, and access the file. Whether that would be an improvement in your case, remains to be seen.

Related

Closing Word with VBScript leaves temporary word documents behind

I am having trouble closing a Word document with VBScript. When the Word document is opened (by the script) a temporary ~$ file is created by Word. For example, opening test.docx also creates a temporary file called ~$test.docx. I understand this is normal. But the problem is that when I close test.docx, the main document test.docx closes properly but ~$test.docx is left behind still open. With many files to process there is soon a large number of these temporary files. They show up in task manager as a background process. What am I doing wrong in closing the files? The code I am using is:
Set objWord = CreateObject("Word.Application")
objWord.Visible = False
objWord.DisplayAlerts = 0
objWord.Documents.Open FilePath 'FilePath previously set
'Do stuff (reading properties)
objWord.Documents.Close 0 'Close opened documents without saving
objWord.Quit
Set objWord = Nothing
It could be that the objWord variable is a 'global' reference to the Word application, defined somewhere at the top of the script.
This global reference remains in place as long as the calling program is active because the operating system will not end the automated application while the caller is active.
If that is the case here, wrapping the code in a function and defining the word object in there should solve it, because then the object has local scope and does not exist outside the function.
Something like this:
Function DoWordThings(FilePath)
Dim oWord
Set oWord = CreateObject("Word.Application")
oWord.Visible = False
oWord.DisplayAlerts = 0
oWord.Documents.Open FilePath 'FilePath now used as parameter to the function
'Do stuff (reading properties and returning them to the caller of this function)
oWord.Documents.Close 0 'Close opened documents without saving
oWord.Quit
Set oWord = Nothing
End Function

Error Saving File in Document Folder of Library

I am writing an HTA file with VBScript as the scripting language. I have a function where the user is prompted to choose the folder in which they would like to save a document. I didn't write this code myself, but instead borrowed it from here.
Function SelectFolder(myStartFolder)
Dim objFolder, objItem, objShell
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Select Folder to Save New File", 0, myStartFolder)
If IsObject(objFolder) Then SelectFolder = objFolder.Self.Path
End Function
I call this function in another one in order when I make the file and prompt the user to choose where to save it:
Sub Example()
Dim destPath, destFile, objWorkbook
destPath = SelectFolder(libPath)
destPath = destPath & "\Sample Export"
Set destFile = CreateObject("Excel.Application")
Set objWorkbook = destFile.Workbooks.Add()
objWorkbook.SaveAs(destPath)
(code to edit excel file)
End Sub
Example() works fine except when someone chooses to save their document in one of the four default libraries in Windows (Documents, Music, Pictures, Videos). In that case, I receive an error saying "The file could not be accessed" and indicating the error is at the line that says "objWorkbook.SaveAs(destPath)". The error box then gives me the following suggestions:
Make sure the specified folder exists
Make sure the folder that contains the file is not read-only
Make sure the file name does not contain any of the following characters: < > ? { } : | or *
Make sure the file/path name doesn't contain more than 218 characters.
The error occurs when I open the HTA file and click a button calling Example(), which then opens a dialog box to ask the user to choose the file location. When Documents, Music, Pictures, or Videos is chosen, a "Script Error" box pops up with the error message listed above. I am not familiar enough with VBScript to know what the problem is exactly. I would appreciate any suggestions as to what to do.
I don't know exactly what the solution to the above issue was. However, I noticed that the path I pass to SelectFolder had a typo in it. libPath was supposed to be to the %userprofile% from the environment variable. However, I had pluralized "userprofiles" so that it was %userprofiles% instead. This took me to somewhere that looked right but wasn't. I fixed the typo and now BrowseForFolder takes me to C:/Users/*username* like it's supposed to. It turns out that I was being sent to the Desktop location because of the fourth argument in BrowseForFolder, instead of the user profile like I wanted.

Transposing a text file row into columns using VBScripting

I currently have a text file that looks like this
I need to be able to create a VBScript file that will use FileSystemObject to change the rows into columns and output the data into an html table like below
I am having a difficult time finding a method for transposing. I am new to VBscripting, I assume that I can still use the CreateTextFile method for HTML?
Dim fso, MyFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.CreateTextFile("C:\Users\User.mdm\Desktop\PracticeTest\table.html", True)
MyFile.WriteLine(?)
MyFile.Close

Iterate over pre-filtered list of folders

I'm working with a client's flat folder structure that has a single folder containing 45k subfolders with 8-digit folder names, e.g. 51023231. I have a small script that ripples through them and copies them into a bin-sorted set of subfolders elsewhere on the network (for use with SharePoint), such that the first 5 digits are used as a parent folder, i.e. the contents of 51023231 are copied into 51023\51023231. It works perfectly well, and I've managed to some modest optimisation when dealing with folders new to the destination.
However, it can take an hour or so to run over the entire 45k set of folders doing folder by folder comparisons, I was wondering if it was possible to run a system-level query to return only an initial list of folders whose modification dates were after a given point, and then run the existing script over that. I've done the usual Google-is-your-friend type trawl, and keep hitting the idea of using WMI to do this, but I don't get much further. Is this because it simply isn't possible with VBScript?
Any pointers gratefully received.
It's possible with VBScript using WMI. It's not something you'd be able to do using the FileSystemObject, if that's what you're implying.
You can query WMI's Win32_Directory class to filter folders by modified date. The only tricky part is the datetime format used by WMI. But the SWbemDateTime class can convert a VBScript date to a datetime value.
Here's an example:
' Create a datetime value for use in our WMI query...
Dim dt
Set dt = CreateObject("WbemScripting.SWbemDateTime")
dt.SetVarDate DateSerial(2015, 8, 31)
Dim objWMI
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
' Find all subfolders of 'c:\some\path' that were modified > 2015/08/31
Dim objFolders
Set objFolders = objWMI.ExecQuery("select * from Win32_Directory" _
& " where Drive='C:' and Path='\\some\\path\\' and LastModified>'" & dt & "'")
Dim objFolder
For Each objFolder in objFolders
WScript.Echo objFolder.Name
Next

VB script will not traverse every file in a given folder

I am new to VBscript and am looking to write a simple script that changes a couple cells in a few thousand csv files in a given folder location. I have a good start, and it all seems to be working, except for the fact that when I run the script (from a .bat file that just calls the script) it only changes and moves 3-8 files at a time. The number of files it changes is random, its not like it always changes 5 files or something. I am not sure what is wrong in the code as to why it will not edit and move every single file and only does a couple at a time, here is what I have so far, thanks in advance for any help:
Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")
Set colFiles = ObjFSO.GetFolder("C:\Users\xxx\BadCSVs").Files
Set xl = CreateObject("Excel.Application")
For Each objFile in colFiles
If LCase(objFSO.GetExtensionName(objFile)) = "csv" Then
Set wb = xl.Workbooks.Open(objFile)
Set sht = xl.ActiveSheet
If(sht.Cells(1,11) <> "") Then
sht.Cells(1,8) = sht.Cells(1,8) & sht.Cells(1,9)
sht.Cells(1,9) = sht.Cells(1,10)
sht.Cells(1,10) = sht.Cells(1,11)
sht.Cells(1,11) = Null
wb.Save
wb.Close True
Else
'if file is opened up and has only 10 columns of data, then it makes no changes, then closes it.
wb.Close
End If
End If
Next
xl.Quit
Your EVIL global
On Error Resume Next
hides errors. Disable/Remove it and test again.
Your
wb.Close SaveChanges=True
passes the boolean result of comparing SaveChanges (undefined/empty) vs. the boolean literal True. Perhaps you copied VBA code
wb.Close SaveChanges:=True
(mark the colon) that is not legal in VBScript?
And
Set xl = CreateObject("Excel.Application")
should be paired with an
xl.Quit
If you invoke Excel in the loop, terminate it there. I would try to start/quit Excel out of the loop, but you should test that approach carefully.

Resources