How can I get file details in subfolders recursively? - vbscript

I'm trying to compile a list of specific details about the music files on my computer, but my knowledge of VBS is limited. (Actually, I've done some VBA, but no VBS before.) I found two scripts online: one gets the file details in a folder and the other lists the names of subfolders and files recursively. I'm trying to combine the two but I'm running into problems because the first script starts with CreateObject("Shell.Application") and the second starts with CreateObject("Scripting.FileSystemObject"). This (i.e., Shell vs. FSO) is one of the areas of VBS scripting about which my knowledge is lacking, to put it mildly.
The incompatibility in my script appears in the For Each objFile in colFiles loop, which I inserted from the "Shell script" I referred to above. What can I do to make this script work?
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim StartFolder, FileName, fso, MyFile, Tabs, arrDetails(4)
Tabs = ""
arrDetails(0) = 0
arrDetails(1) = 1
arrDetails(2) = 27
arrDetails(3) = 28
StartFolder = "C:\Users\user\Music\MP3s"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(StartFolder)
FileName = "C:\Users\user\Documents\MP3 File Details.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.OpenTextFile(FileName, ForAppending, True, True)
MyFile.WriteLine objFolder.Path
ShowSubfolders objFSO.GetFolder(StartFolder), Tabs, arrDetails
Sub ShowSubFolders(Folder, ByVal Tabs, arrDetails)
Dim TabsFolder, TabsFiles, FileLine, arrText(4), i, d
TabsFolder = Tabs & "" & vbtab & ""
For Each Subfolder in Folder.SubFolders
MyFile.WriteLine
MyFile.WriteLine TabsFolder & Subfolder.Name
TabsFiles = TabsFolder & "" & vbtab & ""
Set objSubFolder = objFSO.GetFolder(Subfolder.Path)
Set colFiles = objSubFolder.Files
'Original inserted code for getting file details
' For Each strFileName in objFolder.Items
' For i = 0 to 3
' d = arrDetails(i)
' arrText(i) = objFolder.GetDetailsOf(strFileName, d)
' Next
'
' FileLine = arrText(0)
' For i = 1 to 3
' FileLine = FileLine & vbtab & arrText(i)
' Next
' MyFile.WriteLine FileLine
' Next
'Attempt to make code compatible with rest of script
For Each objFile in colFiles
If LCase(InStr(1, objFile.Name, ".mp3")) > 1 then
For i = 0 to 3
d = arrDetails(i)
arrText(i) = colFiles.GetDetailsOf(objFile, d)
Next
FileLine = arrText(0)
For i = 1 to 3
FileLine = FileLine & vbtab & arrText(i)
Next
MyFile.WriteLine TabsFiles & FileLine
End If
Next
ShowSubFolders Subfolder, TabsFolder, arrDetails
Next
End Sub
MyFile.Close

You do need both the FileSystemObject and the Windows Shell object in this case. You use the FileSystemObject to loop through the folders. In each folder, you then use the Windows Shell object to get the file details.
Here's a modified ShowSubFolders Sub that will work as expected:
Sub ShowSubFolders(Folder, Tabs, arrDetails)
Dim TabsFolder, TabsFiles, FileLine, arrText(4), i, d
Dim objShell
Dim objFolder
Dim objSubfolder
Dim objFiles
Dim objFile
Dim sFileName
Set objShell = CreateObject("Shell.Application")
TabsFolder = Tabs & "" & vbTab & ""
For Each objSubfolder In Folder.SubFolders
' Write subfolder to file
MyFile.WriteLine
MyFile.WriteLine TabsFolder & objSubfolder.Name
' Increment tab position
TabsFiles = TabsFolder & "" & vbTab & ""
Set objFolder = objShell.Namespace(objSubfolder.Path)
Set objFiles = objSubfolder.Files
For Each sFileName In objFolder.Items
' Check if file is MP3
If InStr(1, LCase(sFileName), ".mp3") > 0 Then
' Get file details
For i = 0 To 3
d = arrDetails(i)
arrText(i) = objFolder.GetDetailsOf(sFileName, d)
Next
' Build file information line
FileLine = arrText(0)
For i = 1 To 3
FileLine = FileLine & vbTab & arrText(i)
Next
' Write file information to file
MyFile.WriteLine TabsFiles & FileLine
End If
Next
' Call recursively to handle subfolders
ShowSubFolders objSubfolder, TabsFolder, arrDetails
Next
End Sub
The code you had commented out was good and made accessing extended file properties (like length and bitrate in your case) possible using the arrDetails you have.
Also included in this revised sub is the fix Arno Van Boven mentioned in the comments regarding flipping InStr and LCase.

Related

Replace a specific string with the filename?

How to replace a specific string with the filename? Example: I have several files with different names (like: Test.asp, Constant.asp, Letter.asp, etc.) within a subfolder that contain the text "ABC123". I would like to replace the "ABC123" in each file with the filename.
Below is the code I have that finds string and replaces it with a specific string but it doesn't do the job that I listed above.
Option Explicit
Dim objFilesystem, objFolder, objFiles, objFile, tFile, objShell, objLogFile,objFSO, objStartFolder, colFiles
Dim SubFolder, FileText, bolWriteLog, strLogName, strLogPath, strCount, strCount2, strOldText, strNewText, strEXT
bolWriteLog = True
Const ForReading = 1
Const ForWriting = 2
Const TriStateUseDefault = -2
Set objFilesystem = WScript.CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
strLogName = "log.txt"
strLogPath = "C:\" & strLogName
strCount = 0
strCount2 = 0
strOldText = "ABC123"
strNewText = ""
strEXT = "asp"
'Initialize log file
If bolWriteLog Then
On Error Resume Next
Set objLogFile = objFileSystem.OpenTextFile(strLogPath, 2, True)
WriteLog "############### Start Log ##################"
If Not Err.Number = 0 Then
MsgBox "There was a problem opening the log file for writing." & Chr(10) & _
"Please check whether """ & strLogPath & """ is a valid file and can be openend for writing." & _
Chr(10) & Chr(10) & "If you're not sure what to do, please contact your support person.", vbCritical, "Script Error"
WScript.Quit
End If
On Error Goto 0
End If
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "D:\MyFolder"
Set objFolder = objFSO.GetFolder(objStartFolder)
WScript.Echo objFolder.Path
Set colFiles = objFolder.Files
For Each objFile In colFiles
'WScript.Echo objFile.Name
' Now we have an exception for all files that can not be opened in text modus: all extensions such as "exe" should be listed upfront.
ReplaceText(objFile)
Next
ShowSubfolders objFSO.GetFolder(objStartFolder)
Sub ReplaceText(objFile)
If InStr(1, strEXT, Right(LCase(objFile.Name), 3)) = 0 Or objFile.Size = 0 Then
Else
strCount = strCount + 1
WriteLog("Opening " & objFile.Name)
Set tFile = objFile.OpenAsTextStream(ForReading, TriStateUseDefault)
FileText = tFile.ReadAll
tFile.Close
If InStr(FileText, strOldText) Then
WriteLog("Replacing " & strOldText & " with " & strNewText & ".")
FileText = Replace(FileText, strOldText, strNewText)
WriteLog("Text replaced")
Else
WriteLog(strOldText & " was not found in the file.")
strCount2 = strCount2 + 1
End If
Set tFile = objFile.OpenAsTextStream(ForWriting, TriStateUseDefault)
tFile.Write FileText
tFile.Close
FileText = ""
strCount = 0
strCount2 = 0
End If
End Sub
Sub ShowSubFolders(Folder)
For Each Subfolder in Folder.SubFolders
'WScript.Echo Subfolder.Path
Set objFolder = objFSO.GetFolder(Subfolder.Path)
Set colFiles = objFolder.Files
For Each objFile in colFiles
'WScript.Echo objFile.Name
ReplaceText(objFile)
Next
ShowSubFolders Subfolder
Next
End Sub
WriteLog "############### EndLog ##################"
WScript.Echo "Script Complete"
objShell.Run "C:\" & strLogName
'Clear environment and exit
On Error Resume Next
Set tFile = Nothing
Set objFile = Nothing
Set objFiles = Nothing
Set objFolder = Nothing
Set objLogFile = Nothing
Set objFilesystem = Nothing
Set objShell = Nothing
WScript.Quit
'Subs and functions ********** DO NOT EDIT ***************
Sub WriteLog(sEntry)
If bolWriteLog Then objLogFile.WriteLine(Now() & ": Log: " & sEntry)
End Sub
I can give you a one line Ruby solution, should be not too difficult to translate that in Python but somewhat more extensive in VbScript I am afraid. First a generic search and replace version.
ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(ARGV[-2],ARGV[-1]))}
Save it in a script, eg replace.rb
You start in on the command line (here cmd.exe) with
replace.rb *.txt <string_to_replace> <replacement>
broken down so that I can explain what's happening but still executable
# ARGV is an array of the arguments passed to the script.
ARGV[0..-3].each do |f| # enumerate the arguments of this script from the first to the last (-1) minus 2
File.write(f, # open the argument (= filename) for writing
File.read(f) # open the argument (= filename) for reading
.gsub(ARGV[-2],ARGV[-1])) # and replace all occurances of the beforelast with the last argument (string)
end
And finally your request to replace ABC123 with the filename.
Of course tested and working
ARGV[0..-1].each{|f| File.write(f, File.read(f).gsub('ABC123', f))}
Contents of one of my testfiles (1.txt) after executing
test phrase
1.txt
EDIT
I see you want subfolder recursion on a fixed folder, no problem
Dir['**/*'].each{|f| File.write(f, File.read(f).gsub('ABC123', f)) unless File.directory?(f) }

read folder path and using the path to access the files and rename it

I want to write a VBScript that can access a config file which has the folder path. Once directed to the folder, there are documents with _DDMMYYYY. I want to remove the _ and the date stamp.
Can somebody help me please?
Option Explicit
Dim FSO: Set FSO = CreateObject("Scripting.FileSystemObject")
'Declare the variables to be used from the property file
Dim Folder
Dim objWMIService, objProcess, colProcess, obNetwork
Dim strComputer, WshShell, strComputerName
strComputer = "."
Set obNetwork = WScript.CreateObject("Wscript.Network")
strComputerName = obNetwork.ComputerName
Set obNetwork = Nothing
SetConfigFromFile("C:\Users\Lenovo\Desktop\RenameFile\ConfigPad.txt")
MsgBox "Folder = " & Folder
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run Folder
'---------- Get Variables from ConfigPad.txt ----------
Sub SetConfigFromFile(fileName)
Dim strConfigLine
Dim fConFile
Dim EqualSignPosition
Dim strLen
Dim VariableName
Dim VariableValue
Set fConFile = fso.OpenTextFile(fileName)
While Not fConFile.AtEndOfStream
strConfigLine = fConFile.ReadLine
strConfigLine = Trim(strConfigLine)
'MsgBox(strConfigLine)
If (InStr(1,strConfigLine,"#",1) <> 1 And Len(strConfigLine) <> 0) Then
EqualSignPosition = InStr(1, strConfigLine, "=", 1)
strLen = Len(strConfigLine)
VariableName = LCase(Trim(MID(strConfigLine, 1, EqualSignPosition-1))) 'line 34
VariableValue = Trim(Mid(strConfigLine, EqualSignPosition + 1, strLen - EqualSignPosition))
Select Case VariableName
'ADD EACH OCCURRENCE OF THE CONFIGURATION FILE VARIABLES(KEYS)
Case LCase("Folder")
If VariableValue <> "" Then Folder = VariableValue
End Select
End If
Wend
fConFile.Close
End Sub
'---------- Rename the documents ----------
Dim FLD
Dim fil
Dim strOldName
Dim strNewName
Dim strFileParts
'Set the folder you want to search.
Set FLD = FSO.GetFolder("C:\Users\Lenovo\Desktop\RenameFile\RenameFile.vbs")
'Loop through each file in the folder
For Each fil in FLD.Files
'Get complete file name with path
strOldName = fil.Path
'Check the file has an underscore in the name
If InStr(strOldName, "_") > 0 Then
'Split the file on the underscore so we can get everything before it
strFileParts = Split(strOldName, "_")
'Build the new file name with everything before the
'first under score plus the extension
strNewName = strFileParts(0) & ".txt"
'Use the MoveFile method to rename the file
FSO.MoveFile strOldName, strNewName
End If
Next
'Cleanup the objects
Set FLD = Nothing
Set FSO = Nothing
My config file only has this:
Folder = "C:\Users\Lenovo\Desktop\RenameFile\Test - Copy"
Set fso = CreateObject("Scripting.FileSystemObject")
Set TS = fso.OpenTextFile("C:\Users\Lenovo\Desktop\RenameFile\ConfigPad.txt")
SrcFolder = TS.ReadLine
Set fldr = fso.GetFolder(SrcFolder)
Set Fls = fldr.files
For Each thing in Fls
If Left(thing.name, 1) = "_" AND IsNumeric(Mid(thing.name, 2, 8)) Then
thing.name = mid(thing.name, 10)
End If
Next
This assumes the first line in the config file is a path. It renames any files starting with an underscore and followed by 8 digits.
Please Try This
configfile = "Config File Name Here" 'Example : C:\Documents\Config.txt
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set tf = objFSO.OpenTextFile(configfile, 1)
Do Until tf.AtEndOfStream
cl = tf.ReadLine
If InStr(cl, "Folder = ") > 0 Then
Folder = Replace(Replace(cl,"Folder = ",""),chr(34),"")
tf.Close
Exit Do
End If
Loop
For Each File in objFSO.GetFolder(Folder).Files
If InStr(File.Name, "_") > 0 And IsNumeric(Mid(File.Name,InStr(File.Name, "_") + 1,8)) Then
NewName = Replace(File.Name,Mid(File.Name,InStr(File.Name, "_"),9),"")
objFSO.MoveFile File.Path, objFSO.GetParentFolderName(File.Path) & "\" & NewName
End If
Next
MsgBox "Task Complete", vbOKOnly, "Remove Time Stamp"

VBAScript to delete items from folder

I'm new to VBScripting and have completely no knowledge on how to code but however i understand the basics of VBScripting.
I tried using the search function to find similar cases to mine but it doesn't have what i need.
I would really appreciate any help as my project is due soon.
Scenario:
I need to delete jpeg files that are more than 3months old that is in a directory with lots and lots of subfolders within each other. Furthermore there are 4 folders in the directory that i must not delete or modify.
How i manually did it was to navigate to the mapped drive, to the folder, use the "Search 'Folder'" from the window and type in this "datemodified:‎2006-‎01-‎01 .. ‎2013-‎08-‎31".
It will then show all the folders and subfolders and excel sheets within that folder, i'll then filter the shown list by ticking jpeg only from Type.
Code:
'**** Start of Code **********
Option Explicit
On Error Resume Next
Dim oFSO, oFolder, sDirectoryPath
Dim oFileCollection, oFile, sDir
Dim iDaysOld
' Specify Directory Path From Where You want to clear the old files
sDirectoryPath = "C:\MyFolder"
' Specify Number of Days Old File to Delete
iDaysOld = 15
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sDirectoryPath)
Set oFileCollection = oFolder.Files
For each oFile in oFileCollection
'This section will filter the log file as I have used for for test case
'Specify the Extension of file that you want to delete
'and the number with Number of character in the file extension
If LCase(Right(Cstr(oFile.Name), 4)) = "jpeg" Then
If oFile.DateLastModified < (Date() - iDaysOld) Then
oFile.Delete(True)
End If
End If
Next
Set oFSO = Nothing
enter code here`Set oFolder = Nothing
enter code here`Set oFileCollection = Nothing
enter code here`Set oFile = Nothing
'******* End of Code **********
I need to set an path that must be excluded + go through sub folders.
I'd like to thank you in advance for helping me out.
Thanks,
Working solution (Jobbo almost got it to work in generic form):
UPDATE: includes log file writing with number of folders skipped and files deleted.
Option Explicit
'set these constants to your requirements
Const DIR = "C:\Test"
Const LOGFILE = "C:\Log.txt" ' Location of Log file
Const MAX_AGE = 3 ' Unit: Months
Const FILEEXT = "jpeg"
Dim oFSO
Dim oLogFile
Dim aExclude
Dim lngDeletes, lngSkips
'add to this array to exclude paths
aExclude = Array("c:\Test\test 1", "c:\Test\test 2\test")
Set oFSO = CreateObject("Scripting.FilesystemObject")
Set oLogFile = oFSO.createtextfile(LOGFILE)
lngDeletes = 0
lngSkips = 0
LOGG "Script Start time: " & Now
LOGG "Root Folder: " & DIR
LOGG String(50, "-")
deleteFiles oFSO.GetFolder(DIR)
LOGG String(50, "-")
LOGG lngDeletes & " files are deleted"
LOGG lngSkips & " folders skipped"
LOGG "Script End time: " & Now
oLogFile.Close
Set oLogFile = Nothing
Set oFSO = Nothing
MsgBox "Logfile: """ & LOGFILE & """", vbInformation, wscript.scriptName & " Completed at " & Now
wscript.Quit
'=================================
Sub LOGG(sText)
oLogFile.writeline sText
End Sub
'=================================
Function isExclude(sPath)
Dim s, bAns
bAns = False
For Each s In aExclude
If InStr(1, sPath, s, vbTextCompare) = 1 Then
bAns = True
Exit For
End If
Next
isExclude = bAns
End Function
'=================================
Function isOldFile(fFile)
' Old file if "MAX_AGE" months before today is greater than the file modification time
isOldFile = (DateAdd("m", -MAX_AGE, Date) > fFile.DateLastModified)
End Function
'==================================
Function isFileJPEG(fFile)
Dim sFileName
sFileName = fFile.Name
' Mid(sFileName, InStrRev(sFileName, ".")) gives you the extension with the "."
isFileJPEG = (LCase(Mid(sFileName, InStrRev(sFileName, ".") + 1)) = FILEEXT)
End Function
'==================================
Sub deleteFiles(fFolder)
Dim fFile, fSubFolder
If Not isExclude(fFolder.Path) Then
'WScript.echo "==>> """ & fFolder.Path & """" ' Comment for no output
For Each fFile In fFolder.Files
If isFileJPEG(fFile) And isOldFile(fFile) Then
lngDeletes = lngDeletes + 1
LOGG lngDeletes & vbTab & fFile.Path
'WScript.echo vbTab & "DELETE: """ & fFile.Path & """" ' Comment for no output
fFile.Delete True ' Uncomment to really delete the file
End If
Next
' Only Process sub folders if current folder is not excluded
For Each fSubFolder In fFolder.SubFolders
deleteFiles fSubFolder
Next
Else
lngSkips = lngSkips + 1
'WScript.echo "<<-- """ & fFolder.Path & """" ' Comment for no output
End If
End Sub
Never ever use On Error Resume Next unless it absolutely cannot be avoided.
This problem needs a recursive function. Here's how I would do it:
Option Explicit
'set these constants to your requirements
Const DIR = "C:\MyFolder"
Const AGE = 15
Dim oFSO
Dim aExclude
'add to this array to exclude paths
aExclude = Array("c:\folder\exclude1", "c:\folder\another\exclude2")
Set oFSO = CreateObject("Scripting.FilesystemObject")
Call deleteFiles(oFSO.GetFolder(DIR))
Set oFSO = Nothing
WScript.Quit
'=================================
Function isExclude(sPath)
Dim s
For Each s in aExclude
If LCase(s) = LCase(sPath) Then
isExclude = True
Exit Function
End If
Next
isExclude = False
End Function
'==================================
Sub deleteFiles(fFolder)
Dim fFile, fSubFolder
If Not isExclude(fFolder.Path) Then
For Each fFile in fFolder.Files
If (LCase(Right(Cstr(fFile.Name),4)) = "jpeg") And (fFile.DateLastModified < (Date() - AGE)) Then
'WScript.echo fFile.Path 'I put this in for testing, uncomment to do the same
Call fFile.Delete(true)
End If
Next
End If
For Each fSubFolder in fFolder.SubFolders
Call deleteFiles(fSubFolder)
Next
End Sub
I'm not really able to fully test it out because I don't have an example data set, but really all you need to do is set DIR and change the aExclude array. Make sure you know what its going to delete before you run it though...
Also, it will only delete jpeg extensions, not jpg but I imagine you already know that

VBScript to Move files with particular extension

I currently have a VBscript that scans a folder for files and moves the files to particular folders depending on key words in the file name.
I need currently the script only scans the one level (ie. doesn't scan recursively) and I need to to search all sub folders too.
Can someone give me a hand with this?
EDIT: Since writing this script I have realized that I need to have this only move files with particular extensions from a particular folder and sub folders to other directories based on the file name.
For example I need only .mp4 and .avi files to be moved.
Can someone help me with this please? I have tried multiple things but still can't get the recursive scanning and moving or the extension specific moving working.
Below is my current script.
'========================================================
' Script to Move Downloaded TV Shows and Movies to
' correct folders based on wildcards in File Name
'========================================================
On Error Resume Next
Dim sTorrents, sTV, sMovie, sFile, oFSO
' create the filesystem object
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
' Create Log File
Set objLog = oFSO.OpenTextFile("c:\temp\log.txt", 8, True)
' Set Variables
sTorrents = "C:\Temp\torrents\"
sTV = "C:\Temp\TV Shows\"
sMovie = "C:\Temp\Movies\"
' Scan each file in the folder
For Each sFile In oFSO.GetFolder(sTorrents).Files
' check if the file name contains TV Show Parameters
If InStr(1, sFile.Name, "hdtv", 1) OR InStr(1, sFile.Name, "s0", 1) <> 0 Then
' TV Show Detected - Move File
objLog.WriteLine Now() & " - " & sFile.Name & " Detected as TV Show - Moving to " & sTV
oFSO.MoveFile sTorrents & sFile.Name, sTV & sFile.Name
' Move all other Files to Movies Directory
Else objLog.WriteLine Now() & " - " & sFile.Name & " Detected as Movie - Moving to " & sMovie
oFSO.MoveFile sTorrents & sFile.Name, sMovie & sFile.Name
End If
Next
If sTorrents.File.Count = 0 And sTorrents.SubFolders.Count = 0 Then
objLog.WriteLine Now() & " - There is nothing left to Process..."
objLog.Close
End If
Some notes:
Sub listfolders(startfolder)
Dim fs
Dim fl1
Dim fl2
Set fs = CreateObject("Scripting.FileSystemObject")
Set fl1 = fs.GetFolder(startfolder)
For Each fl2 In fl1.SubFolders
Debug.Print fl2.Path
''process the files
ProcessFiles fl2.Path
'Recursion: lists folders for each subfolder
listfolders fl2.Path
Next
End Sub
''Code copied from question
Sub ProcessFiles(sPath)
' Scan each file in the folder
For Each sFile In oFSO.GetFolder(sPath).Files
' check if the file name contains TV Show Parameters
If InStr(1, sFile.Name, "hdtv", 1) OR InStr(1, sFile.Name, "s0", 1) <> 0 Then
' TV Show Detected - Move File
objLog.WriteLine Now() & " - " _
& sFile.Name & " Detected as TV Show - Moving to " & sTV
oFSO.MoveFile sTorrents & sFile.Name, sTV & sFile.Name
' Move all other Files to Movies Directory
Else
objLog.WriteLine Now() & " - " _
& sFile.Name & " Detected as Movie - Moving to " & sMovie
oFSO.MoveFile sTorrents & sFile.Name, sMovie & sFile.Name
End If
Next
End Sub
before the extension put a * that will find all files with that externsion.
Example: oFSO.MoveFile (PATH\*.EXTERNSION)
here is a recusive function to list files in folders and sub folders
it's tested and working, but you'll probably need some adaptation to your own forkflow. And it's not the most optimized, but it's simple to read
Sub test()
aFiles = F_ListFilesInDirAndSubDir("C:\foo\folder")
'then, add some code to parse the array:
For i = 0 to UBound(aFiles)
'Move or not to move, that is what your code should tell
Next
End Sub
Public Function F_ListFilesInDirAndSubDir(ByVal sDir)
'===============================================================================
'Get the list of files in a directory and in all its sub directories With the full path
'===============================================================================
Dim sChild As String
Dim aFolders As Variant
Dim aFiles As Variant
Dim aChildFiles As Variant
Dim i As Long
Dim j As Long
F_ListFilesInDirAndSubDir = aFiles
Set fs = CreateObject("Scripting.FileSystemObject")
If Not fs.FolderExists(sDir) Then Exit Function
'Get the files in the directory
aFiles = F_ListFilesInDir(sDir)
'Add the fullpath
For i = 0 To UBound(aFiles)
If aFiles(i) <> "" Then
aFiles(i) = sDir & "\" & CStr(aFiles(i))
End If
Next
'get the folders
aFolders = F_ListFoldersInDir(sDir)
'for each folders, push the files in the file list
For i = 0 To UBound(aFolders)
If aFolders(i) <> "" Then
sChild = sDir & "\" & CStr(aFolders(i))
'Recursive call on each folders
aChildFiles = F_ListFilesInDirAndSubDir(sChild)
'Push new items
For j = 0 To UBound(aChildFiles)
If aChildFiles(j) <> "" Then
ReDim Preserve aFiles(UBound(aFiles) + 1)
aFiles(UBound(aFiles)) = aChildFiles(j)
End If
Next
End If
Next
F_ListFilesInDirAndSubDir = aFiles
End Function
Public Function F_ListFilesInDir(ByVal sDir)
'===============================================================================
'Get the list of files in a directory
'===============================================================================
Dim aList As Variant
Dim i As Long
Dim iChild As Long
Dim oFile
Dim oFolder
Dim oChildren
ReDim aList(0)
F_ListFilesInDir = aList
Set fs = CreateObject("Scripting.FileSystemObject")
If Not fs.FolderExists(sDir) Then Exit Function
Set oFolder = fs.GetFolder(sDir)
Set oChildren = oFolder.Files
iChild = CDbl(oChildren.Count) - 1
If iChild = -1 Then Exit Function
ReDim aList(iChild)
i = 0
For Each oFile In oChildren
aList(i) = oFile.Name
i = i + 1
Next
F_ListFilesInDir = aList
End Function
Public Function F_ListFoldersInDir(ByVal sDir As String) As Variant
'===============================================================================
'Get the list of folders in a directory
'===============================================================================
Dim aList As Variant
Dim i As Long
Dim oDir
Dim oFolder
Dim oChildren
ReDim aList(0)
F_ListFoldersInDir = aList
Set fs = CreateObject("Scripting.FileSystemObject")
If Not fs.FolderExists(sDir) Then Exit Function
Set oFolder = fs.GetFolder(sDir)
Set oChildren = oFolder.SubFolders
If oChildren.Count = 0 Then Exit Function
ReDim aList(oChildren.Count - 1)
i = 0
For Each oDir In oChildren
aList(i) = oDir.Name
i = i + 1
Next
F_ListFoldersInDir = aList
End Function

VBS rename file to the same as a folder name

Is it possible to rename a file in a folder to its folder name using vbs? I have the following script which I am just using MsgBox at this time for debugging before I implement the renaming. for some reason tho ObjFolder doesnt change.
Option Explicit
Dim strFolderToSearch, objFSO, objRootFolder, objFolder, colSubfolders, strOutput, objStartFolder, colFiles, objFile
strFolderToSearch = "D:\Shared\Films"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objRootFolder = objFSO.GetFolder(strFolderToSearch)
Set colSubfolders = objRootFolder.SubFolders
For Each objFolder in colSubfolders
objStartFolder = objFolder
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colSubfolders
MsgBox objFile.name & "," & objFolder.name
Next
Next
I admit that I can't follow the tangle of your folders, subfolders, and files. But if you want to rename files in a folder, use this stratege:
Dim sDName : sDName = "FancyRename"
Dim sDName2 : sDName2 = "," & sDName
Dim oFile, sNewName
For Each oFile In goFS.GetFolder(goFS.BuildPath("..\testdata", sDName)).Files
If 0 = Instr(oFile.Name, sDName2) Then
sNewName = Replace(oFile.Name, ".", sDName2 & ".")
Else
sNewName = Replace(oFile.Name, sDName2, "")
End If
WScript.Echo oFile.Name, "=>", sNewName
oFile.Name = sNewName
Next
output of running this three times:
that.txt => that,FancyRename.txt
this.txt => this,FancyRename.txt
that,FancyRename.txt => that.txt
this,FancyRename.txt => this.txt
that.txt => that,FancyRename.txt
this.txt => this,FancyRename.txt
UPDATE
How about: Given a folder D and a file name F (e.g. someavi.avi), rename all (existing) Fs in D and its sub folders to "subfoldername.avi", unless such a file already exists:
recursiveRename goFS.GetFolder("..\testdata\FancyRename"), "someavi", "avi"
Sub recursiveRename(oDir, sFiNa, sExt)
WScript.Echo "Looking into", oDir.Path
Dim sOFiNa : sOFiNa = sFiNa & "." & sExt
Dim sOFSpec : sOFSpec = goFS.BuildPath(oDir.Path, sOFiNa)
Dim sNFSpec
If goFS.FileExists(sOFSpec) Then
WScript.Echo "found ", sOFSpec
sNFSpec = goFS.BuildPath(oDir.Path, oDir.Name & "." & sExt)
If goFS.FileExists(sNFSpec) Then
WScript.Echo "found ", sNFSpec, "- can't rename"
Else
WScript.Echo "found no", sNFSpec, "- will rename"
goFS.MoveFile sOFSpec, sNFSpec
End If
Else
WScript.Echo "found no", sOFSpec
End If
Dim oSubF
For Each oSubF In oDir.SubFolders
recursiveRename oSubF, sFiNa, sExt
Next
End Sub
sample output:
Looking into M:\lib\kurs0705\testdata\FancyRename
found no M:\lib\kurs0705\testdata\FancyRename\someavi.avi
Looking into M:\lib\kurs0705\testdata\FancyRename\subfa
found no M:\lib\kurs0705\testdata\FancyRename\subfa\someavi.avi
Looking into M:\lib\kurs0705\testdata\FancyRename\subfc
found M:\lib\kurs0705\testdata\FancyRename\subfc\someavi.avi
found no M:\lib\kurs0705\testdata\FancyRename\subfc\subfc.avi - will rename
Looking into M:\lib\kurs0705\testdata\FancyRename\subfb
found M:\lib\kurs0705\testdata\FancyRename\subfb\someavi.avi
found M:\lib\kurs0705\testdata\FancyRename\subfb\subfb.avi - can't rename
UPDATE II
Changed specs: rename .avi to folder name, if there is exactly one .avi
recursiveRename03 goFS.GetFolder("..\testdata\FancyRename")
Sub recursiveRename03(oDir)
WScript.Echo "Looking into", oDir.Path
Dim sNFSpec : sNFSpec = goFS.BuildPath(oDir.Path, oDir.Name & ".avi")
If goFS.FileExists(sNFSpec) Then
WScript.Echo "found ", sNFSpec, "- can't rename"
Else
Dim oOFile : Set oOFile = Nothing
Dim oFile
For Each oFile In oDir.Files
If "avi" = goFS.GetExtensionName(oFile.Name) Then
If oOFile Is Nothing Then
Set oOFile = oFile
Else
WScript.Echo "Found second avi", oFile.Name
Set oOFile = Nothing
Exit For
End If
End If
Next
If oOFile Is Nothing Then
WScript.Echo "not exactly one avi found"
Else
WScript.Echo "found ", oOFile.Name, "- will rename"
oOFile.Name = oDir.Name & ".avi"
End If
End If
Dim oSubF
For Each oSubF In oDir.SubFolders
recursiveRename03 oSubF
Next
End Sub
UPDATE III
If you use a global FSO or pass an FSO to the Subs/Functions needing
it, you avoid its repetitive re-creation.
If you pass a folder/file object instead of a string to the
Subs/Functions dealing with such objects, you can access their
properties/methods immediately/for free (no need to reclaim/get back
info by string operations).
If you rename a file, you must check whether there is a file having
the new name (it's not sufficient to check whether the file you work
with doesn't have the new name).
Idealistically, your script should have the following features:
Recursion - For traversing folders that are 1-n deep from D:\Shared\Films
Rename file function - For renaming match files according to your rule.
I wrote the following script that features the following routines:
RenameAllVideos(strFolder) - this will recursively search subfolders
RenameVideo(strFileName) - will rename a match video file using your rule
Here's my script:
Option Explicit
Call RenameAllVideos("D:\Shared\Films")
Sub RenameAllVideos(strFolder)
Dim fso, file, folder
Set fso = CreateObject("Scripting.FileSystemObject")
' Check for AVIs to rename.
For Each file in fso.GetFolder(strFolder).Files
If Right(file.Name, 4) = ".avi" Then
Call RenameVideo(strFolder & "\" & file.Name)
End If
Next
' Check for SubFolders to recurse into.
For Each folder in fso.GetFolder(strFolder).SubFolders
Call RenameAllVideos(strFolder & "\" & folder.Name)
Next
End Sub
Sub RenameVideo(strFileName)
Dim fso, strExt, strFolder, strNewFileName
Set fso = CreateObject("Scripting.FileSystemobject")
' Note the extension (should be avi)
strExt = fso.GetExtensionName(strFileName)
' Derive the full path to the folder.
strFolder = fso.GetParentFolderName(strFileName)
' Derive the new filename.
strNewFileName = strFolder & "\" & fso.GetBaseName(strFolder) & "." & strExt
' Do the rename.
If strFileName <> strNewFileName Then
WScript.Echo "Renaming " & strFileName & " to " & strNewFileName
fso.MoveFile strFileName, strNewFileName
End If
End Sub

Resources