Searching C Drive for a file with VBScript - recursion

I am very new to VBScript, and I am trying to write a simple script that will extract a file in a directory to a new directory. So far this is what I have (and it works well):
'USER VAR REPRESENTS WINDOWS USERNAME
Set oShell = CreateObject( "WScript.Shell" )
user=oShell.ExpandEnvironmentStrings("%UserName%")
'FOLDER TO BE EXTRACTED
ZipFile="C:\Users\"&user&"\Downloads\Test.zip"
'LOCATION TO EXTRACT FILES
ExtractTo="C:\Users\"&user&"\desktop"
'EXTRACT ZIP FILE
Set objShell = CreateObject("Shell.Application")
Set FilesInZip=objShell.NameSpace(ZipFile).items
objShell.NameSpace(ExtractTo).CopyHere(FilesInZip)
Set fso = Nothing
Set objShell = Nothing
Set oShell = Nothing
Now, if possible, if the "Desktop" folder cannot be found, or the "Test.zip" file cannot be found, I would like to search the C Drive for them, and then proceed with extracting, etc. I have seen some examples, but I cannot understand how to replicate them. How can I search the entire C drive and sub folders for these files?
Help would be appreciated, thanks in advance!

In general a recursive search can be done like this:
Function SearchFolder(fldr, name)
Set SearchFolder = Nothing
For Each f In fldr.Files
If LCase(f.Name) = LCase(name) Then
Set SearchFolder = f
Exit Function
End If
Next
For Each sf In fldr.SubFolders
Set result = SearchFolder(sf, name)
If Not result Is Nothing Then
Set SearchFolder = result
Exit Function
End If
Next
End Function
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = SearchFolder(fso.GetFolder("C:\"), "Test.zip")
However, searching a whole drive that way will take quite some time. Also there are several folders that users don't have access to, so you'll have to account for that if you want to implement a search like this.

Related

Count all files in folder and subfolder with VB6

In VB6, I am using a Webbrowser form to display all files and subfolders as icons in the style of Windows Explorer. On the form, I display a count of all files in the main folder and all subfolders. This is my code so far, though haven't been able to find any information about counting subfolders.
Private Sub Load_Form()
Dim myPathName as String
Dim iTotalCount as Long
some stuff here ....
WebBrowser1.Navigate myPathName
WebBrowser1.Document.CurrentViewMode = 5 'medium icons
iTotalCount = FileCount(myPathName)
lblLabel.Caption = "Total Files = " & iTotalCount
more stuff here ....
End Sub
Public Function FileCount(myPathName as String) as Long
Dim FSO as New FileSystemObject
Dim fld as Folder
If FSO.FolderExists(myPathName) Then
Set fld = FSO.GetFolder(myPathName)
FileCount = fld.Files.Count
End If
End Function
This StackOverFlow question is similar, though for vb.net (which I don't know). I'd appreciate someone pointing me in the right direction. Many thanks.

How to test whether an uploaded Excel file meets requirements

Background
Suppose I have a shiny app where the user can upload an Excel file. The users will have access to a certain Excel template and I want to make sure that only copies of this template are uploaded.
My current approach
My current approach is now as follows:
Check if sheet name xyz is present -> if not throw an error
Read data from sheet xyz, compare column names with requirements -> if missing columns throw an error
Repeat for all necessary sheets
Problem with the current approach
This requires a lot of hard coding required sheet names and required column names and becomes tedious.
Question
So my question: how can I assure that the user provides a valid file? What strategies do you usually use to make sure that the uploaded file can be properly processed by your apps?
Pseudo Code
library(shiny)
library(tidyverse)
ui <- fluidPage(fileInput("file", "Upload Excel"))
server <- function(input, output, session) {
observe({
req(input$file)
sheet1 <- tryCatch(read_xlsx(input$file$datapath, sheet = "xyz"),
error = function(e) {
## do some sort of error handling, e.g. write to a reactiveValue list
})
if (!all(.REQUIRED_FIELDS_FOR_XYZ %in% names(sheet1))) {
## signal error
}
})
}
If you are already using Excel, why not use a Macro to do the work for you. Consider listing file paths, checking format types, cell addresses, cell values, etc. The Macro below will do most of the heavy lifting for you.
Sub GetFolder_Data_Collection()
Dim colFiles As Collection, c As Range
Dim strPath As String, f, sht As Worksheet
Dim wbSrc As Workbook, wsSrc As Worksheet
Dim rw As Range
Dim sh As Worksheet, flg As Boolean
Set sht = ActiveSheet
strPath = ThisWorkbook.Path
Set colFiles = GetFileMatches(strPath, "*.xlsx", True)
With sht
.Range("A:I").ClearContents
.Range("A1").Resize(1, 5).Value = Array("Name", "Path", "Cell", "Value", "Numberformat")
Set rw = .Rows(2)
End With
For Each f In colFiles
Set wbSrc = Workbooks.Open(f)
Set wsSrc = wbSrc.Sheets(1)
For Each c In wsSrc.Range(wsSrc.Range("A1"), _
wsSrc.Cells(1, Columns.Count).End(xlToLeft)).Cells
rw.Cells(2).Value = wbSrc.Path
sht.Hyperlinks.Add Anchor:=rw.Cells(1), Address:=wbSrc.Path, TextToDisplay:=wbSrc.Name
rw.Cells(3).Value = c.Address(False, False)
rw.Cells(4).Value = c.Value
rw.Cells(5).Value = c.NumberFormat
i = 6
For Each sh In Worksheets
If sh.Name Like "Sheet1*" Or sh.Name Like "*Sheet2*" Then rw.Cells(i).Value = sh.Name & " Exists"
i = i + 1
Next
Set rw = rw.Offset(1, 0)
Next c
wbSrc.Close False
Next f
End Sub
'Return a collection of file objects given a starting folder and a file pattern
' e.g. "*.txt"
'Pass False for last parameter if don't want to check subfolders
Function GetFileMatches(startFolder As String, filePattern As String, _
Optional subFolders As Boolean = True) As Collection
Dim fso, fldr, f, subFldr
Dim colFiles As New Collection
Dim colSub As New Collection
Set fso = CreateObject("scripting.filesystemobject")
colSub.Add startFolder
Do While colSub.Count > 0
Set fldr = fso.GetFolder(colSub(1))
colSub.Remove 1
For Each f In fldr.Files
If UCase(f.Name) Like UCase(filePattern) Then colFiles.Add f
Next f
If subFolders Then
For Each subFldr In fldr.subFolders
colSub.Add subFldr.Path
Next subFldr
End If
Loop
Set GetFileMatches = colFiles
End Function
PUT THIS CODE IN AN XLSB OR XLSM EXCEL FILE IN THE SAME FOLDER AS YOUR EXCEL FILES.
It's probably just easier to do this kind of thing with Excel, and I'm a huge proponent of using the right tool for the job.

VBS: FileSystemObject use in Recursion

Currently I'm working on a script that will go through a given folder and search for all files with a specific extension. It will then print out the name and sum the file size. I believe i have most of the issues sorted out, so this question isn't about how to do this.
Instead, I want to know what would be the best practice for using FileSystemObject streams in a recursive function. Should I be using a single stream for all calls (either global, or passed), or should I be creating a new stream for each recursive step?
For extra fun, I'm planning on having this access multiple PCs, and over UNC path. And yes, I expect there's a better way of doing this, but I'm relatively new with VBS.
Current code:
'Recursive Function handles search of files in folder and subfolders.
Function UNCSearchFolder(strUNCRootPath, strUNCNextFolder)
Dim objFSOUNCSearchFolder, objFSOUNCSearchFolder2, colFolderList, objFolder, strCurrentFolder, strSubFolder
'Get list of Subfolders in folder: <Rootpath>\<Nextfolder>
strCurrentFolder = strUNCRootPath & "\" & strUNCNextFolder & "\"
Set objFSOUNCSearchFolder = CreateObject("Scripting.FileSystemObject")
Set objFSOUNCSearchFolder2 = objFSOUNCSearchFolder.GetFolder(strCurrentFolder)
Set colFolderList = objFSOUNCSearchFolder2.SubFolders
'Subfolder dive
For Each objFolder in colFolderList
strSubFolder = objFolder.name
'REMOVE THIS ECHO LATER
wscript.echo strSubFolder
UNCSearchFolder(strCurrentFolder, strSubFolder)
Next
'Search for files here
'GC on File Streams
Set objFSOUNCSearchFolder2 = Nothing
Set objFSOUNCSearchFolder = Nothing
End Function
So, should one filestream be used for all accesses or should each step use one separately? Is it a moot point? Will this cause multiple connections to each system or should it only use one? Basically I want the script to work without disrupting users, or causing weird responses (ie, running out of active connections). The script will only be used a couple times for an audit we're doing, but may eventually be repurposed for future audits.
Let me know what you think. Thanks for any help,
If you choose to set a reference to FSO inside your function,
then in each recursion will be used new FSO object.
Using single FSO object (either global, or passed) is quite enough.
At least I don't know any benefit of using multiple FSO instances.
[EDIT] I appreciate #AnsgarWiechers comment, and to make the code ready for re-using, while kept the FSO out of the function, we can wrap our function in a class.
With New FileInfo
WScript.Echo .FileSize("C:\temp", "txt", True)
End With
Class FileInfo
Private m_oFSO
Public Function FileSize(sRootDir, sExtension, bRecursive)
Dim oFolder, oFile, sFExt
sFExt = LCase(sExtension)
Set oFolder = m_oFSO.GetFolder(sRootDir)
For Each oFile In oFolder.Files
If LCase(m_oFSO.GetExtensionName(oFile.Name)) = sFExt Then
FileSize = FileSize + oFile.Size
End If
Next
If bRecursive Then
Dim oSubFolder
For Each oSubFolder In oFolder.SubFolders
FileSize = FileSize + FileSize(oSubFolder, sExtension, True)
Next
End If
End Function
Private Sub Class_Initialize
Set m_oFSO = CreateObject("Scripting.FileSystemObject")
End Sub
Private Sub Class_Terminate
Set m_oFSO = Nothing
End Sub
End Class

asp fileExists always returning false

Trying to use a loop to check if images exists however it is always returning false. I am sure I am doing something simple and stupid but here is the code:
dim fs, sql_except
set fs=Server.CreateObject("Scripting.FileSystemObject")
if Not rs.eof then
arrRS = rs.GetRows(30,0)
set rs = nothing
If IsArray(arrRS) Then
For i = LBound(arrRS, 2) to UBound(arrRS, 2)
sku = arrRS(0, i)
if (fs.FileExists("../i/"&sku&".gif")=false) Then
response.write sku&"does not exist<br>"
end if
next
end if
erase arrRS
end if
set fs=nothing
You appear to be operating under the impression that the current folder context the your call to FileExists will assume is the physical folder containing the ASP script being executed. This is not so, it most likely will be "C:\windows\system32\inetsrv". You are also using URL path element separator / where FileExists is expecting windows physical path folder separator \.
You need to use Server.MapPath to resolve the path. This may work:
if Not fs.FileExists(Server.MapPath("../i/"&sku&".gif")) then
However you may run in to trouble with the parent path "..", this may not be allowed for security reasons. This might be a better approach:
Dim path : path = Server.MapPath("/parentFolder/i") & "\"
For i = LBound(arrRS, 2) to UBound(arrRS, 2)
sku = arrRS(0, i)
if Not fs.FileExists(path & sku & ".gif") Then
response.write Server.HTMLEncode(sku) & " does not exist<br>"
end if
next
Where "parentFolder" is the absolute path from the site root.

What's the correct way to specify file path in VBscript?

New to VBscript and spending way too much time trying to find the right way to open a file for reading. Whatever I've tried I always get "Path not found" error.
This is the real path to my files:
D:\InetPub\vhosts\lamardesigngroup.com\httpdocs\
The file that I am trying to run is:
D:\InetPub\vhosts\lamardesigngroup.com\httpdocs\ifp\files.asp
and I want to read this file:
D:\InetPub\vhosts\lamardesigngroup.com\httpdocs\ifp\css\style.css
Here is the code:
Dim objFSO, strTextFile, strData, strLine, arrLines
CONST ForReading = 1
'name of the text file
strTextFile = "//css/style.css"
'Create a File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Open the text file - strData now contains the whole file
strData = objFSO.OpenTextFile(strTextFile,ForReading).ReadAll
'Split the text file into lines
arrLines = Split(strData,vbCrLf)
'Step through the lines
For Each strLine in arrLines
response.write(strLine & "<br>")
Next
'Cleanup
Set objFSO = Nothing
and I get "12|800a004c|Path_not_found 80"
I've also tried
strTextFile = "D:\InetPub\vhosts\lamardesigngroup.com\httpdocs\ifp\css\style.css"
' and
strTextFile = "\\css\style.css"
strTextFile = "css\style.css"
strTextFile = "css/style.css"
' and many other combinations
I'm obviously lost...
Morning Harley,
Give this a try:
strTextFile = server.MapPath("css/style.css")
It should result in recognizing your specific server location. I ran into this problem trying to get some vbscript file upload code to work. It should start from the folder your page is working in and go from there.

Resources