move subfolders based on date last modified - excel

Trying to find MS Excel/VBA code to move all subfolders with lastdatemodified < date -30 to a different folder.
Like this (but obviously not this)
foldertomove = subfolder
folder = main
newfolder = archive
for each subfolder in main
if subfolder.datelastmodified < date - 30 then
move subfolder to archive
end if
next
Any help is greatly appreciated! Thanks!

Objective of this program is to Copy Folders, Sub-Folders and Folders
within Folders along with files contained in them. It could be any type of the file PDF, Text, Word, Excel etc.
This program will only copy Files which are 30 days older from
Current Time. User can adjust this date or between two dates as per
his requirements.
When program is run File Picker Dialog will open and allow user to
chose the folder to be archived.
It is very important that an Empty Directory Structure with same
folder structure as parent folder to be archived has is created.
Presently VBA code for this step has not been incorporated in this
program. Simplest way is to copy paste folder and then delete files
in various folders and sub-folders manually. It is one time exercise
so long as parent directory structure remains the same. Any changes
in the parent directory structure are also to be incorporated in the
Archive folder also.
Program will also output Directory and File Paths on a separate
workbook of the parent directory being archived. If it is not
required then relevant portions of the program can be commented out.
Snapshot of output is placed below.
Further improvements in this program shall be endeavoured based on feedback and help of experts.
Code is placed below.
Sub CopyFolders_Recursively()
Dim strFolder As String
Dim objFSO As Object
Dim objFolder As Object
Dim myResults As Variant
Dim lCount As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Get the directory from the user
With Application.FileDialog(msoFileDialogFolderPicker)
.Show
If .SelectedItems.Count = 0 Then Exit Sub
'user cancelled
strFolder = .SelectedItems(1)
End With
Set objFolder = objFSO.GetFolder(strFolder)
'the variable dimension has to be the second one
ReDim myResults(0 To 5, 0 To 0)
' place make some headers in the array
myResults(0, 0) = "Filename"
myResults(1, 0) = "Size"
myResults(2, 0) = "Created"
myResults(3, 0) = "Modified"
myResults(4, 0) = "Accessed"
myResults(5, 0) = "Full path"
'Send the folder to the recursive function
FillFileList objFolder, myResults, lCount
' Dump these to a worksheet
fcnDumpToWorksheet myResults
'tidy up
Set objFSO = Nothing
End Sub
Private Sub FillFileList(objFolder As Object, ByRef myResults As Variant, ByRef lCount As Long, Optional strFilter As String)
Dim i As Integer
Dim objFile As Object
Dim fsoSubFolder As Object
Dim fsoSubFolders As Object
Dim ToPath As String
Dim lpath As String
ToPath = "C:\Archive\"
Dim Fdtdiff As Integer
'load the array with all the files
For Each objFile In objFolder.Files
lCount = lCount + 1
ReDim Preserve myResults(0 To 5, 0 To lCount)
myResults(0, lCount) = objFile.Name
myResults(1, lCount) = objFile.Size
myResults(2, lCount) = objFile.DateCreated
myResults(3, lCount) = objFile.DateLastModified
myResults(4, lCount) = objFile.DateLastAccessed
myResults(5, lCount) = objFile.Path
Fdtdiff = DateValue(Now) - DateValue(myResults(3, lCount))
If Fdtdiff > 30 Then
lpath = Replace(objFile.Path, "my_dir", "Archive")
objFile.Copy lpath
End If
Next objFile
'recursively call this function with any subfolders
Set fsoSubFolders = objFolder.SubFolders
For Each fsoSubFolder In fsoSubFolders
FillFileList fsoSubFolder, myResults, lCount
Next fsoSubFolder
End Sub
Private Sub fcnDumpToWorksheet(varData As Variant, Optional mySh As Worksheet)
Dim iSheetsInNew As Integer
Dim sh As Worksheet, wb As Workbook
Dim myColumnHeaders() As String
Dim l As Long, NoOfRows As Long
If mySh Is Nothing Then
'make a workbook if we didn't get a worksheet
iSheetsInNew = Application.SheetsInNewWorkbook
Application.SheetsInNewWorkbook = 1
Set wb = Application.Workbooks.Add
Application.SheetsInNewWorkbook = iSheetsInNew
Set sh = wb.Sheets(1)
Else
Set mySh = sh
End If
'since we switched the array dimensions, have to transpose
With sh
Range(.Cells(1, 1), .Cells(UBound(varData, 2) + 1, UBound(varData, 1) + 1)) = _
Application.WorksheetFunction.Transpose(varData)
.UsedRange.Columns.AutoFit
End With
Set sh = Nothing
Set wb = Nothing
End Sub

Private Sub CopyFolders_Recursively()
Dim strFolder As String
Dim objFSO As Object
Dim objFolder As Object
Dim myResults As Variant
Dim lCount As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Get the directory from the user
'With Application.FileDialog(msoFileDialogFolderPicker)
'.Show
'If .SelectedItems.Count = 0 Then Exit Sub
'user cancelled
'strFolder = .SelectedItems(1)
'End With
strFolder = "D:\testing\" '<<change
Set objFolder = objFSO.GetFolder(strFolder)
'the variable dimension has to be the second one
ReDim myResults(0 To 5, 0 To 0)
' place make some headers in the array
myResults(0, 0) = "Filename"
myResults(1, 0) = "Size"
myResults(2, 0) = "Created"
myResults(3, 0) = "Modified"
myResults(4, 0) = "Accessed"
myResults(5, 0) = "Full path"
'Send the folder to the recursive function
FillFileList objFolder, myResults, lCount
' Dump these to a worksheet
fcnDumpToWorksheet myResults
CleanUpList
If Range("A2").Value = "" Then GoTo tidyup
AddFolders
Move_Folders
tidyup:
Cells.Delete
Range("A1").Select
'tidy up
Set objFSO = Nothing
End Sub
Private Sub FillFileList(objFolder As Object, ByRef myResults As Variant, ByRef lCount As Long, Optional strFilter As String)
Dim i As Integer
Dim objFile As Object
Dim fsoSubFolder As Object
Dim fsoSubFolders As Object
Dim lpath As String
Dim Fdtdiff As Integer
'load the array with all the files
For Each objFile In objFolder.Files
If InStr(objFile.Path, "~Archive") = 0 Then 'don't get files from the archive folder (assumes the archive folder is a subfolder of the folder from which you're moving the other subfolders
lCount = lCount + 1
ReDim Preserve myResults(0 To 5, 0 To lCount)
myResults(0, lCount) = objFile.Name
myResults(1, lCount) = objFile.Size
myResults(2, lCount) = objFile.DateCreated
myResults(3, lCount) = objFile.DateLastModified
myResults(4, lCount) = objFile.DateLastAccessed
myResults(5, lCount) = objFile.Path
'Fdtdiff = DateValue(Now) - DateValue(myResults(3, lCount))
'If Fdtdiff > 30 Then
'lpath = Replace(objFile.Path, "my_dir", "~Archive")
'objFile.Copy lpath
'End If
End If
Next objFile
'recursively call this function with any subfolders
Set fsoSubFolders = objFolder.SubFolders
For Each fsoSubFolder In fsoSubFolders
FillFileList fsoSubFolder, myResults, lCount
Next fsoSubFolder
End Sub
Private Sub fcnDumpToWorksheet(varData As Variant, Optional mySh As Worksheet)
'since we switched the array dimensions, have to transpose
With ThisWorkbook.Sheets(1) '<<change
Cells.ClearContents
Range(.Cells(1, 1), .Cells(UBound(varData, 2) + 1, UBound(varData, 1) + 1)) = _
Application.WorksheetFunction.Transpose(varData)
.UsedRange.Columns.AutoFit
End With
End Sub
Private Sub CleanUpList()
'sort most recent files to the top so when we remove dupes we'll be left with the most recent one
ThisWorkbook.Worksheets("Archive").Sort.SortFields.Clear '<<change sheet name
ThisWorkbook.Worksheets("Archive").Sort.SortFields.Add Key:=Range("D2:D65536") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ThisWorkbook.Worksheets("Archive").Sort
.SetRange Range("A1:F65536")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'remove parent folder from path we'll check later
Columns("F:F").Replace What:="D:\testing\", Replacement:="", LookAt:=xlPart, MatchCase:=False '<< Change
'remove file name, leaving just the folder we want to move
Columns("F:F").Replace What:="\*", Replacement:="", LookAt:=xlPart, MatchCase:=False
'we just need one!
ThisWorkbook.Sheets(1).Range("$A$1:$AZ$65536").RemoveDuplicates Columns:=6, Header:=xlYes '<< remove dupes of folders to move
Set Rng = Range("D1:D100") '<< change if you know it will be less or more than 100
For Each cell In Rng
If cell.Value <> "" Then
If cell.Value > Date - 30 Then '<<only keep it if more than 30 days (or whatever you want)
cell.Value = ""
End If
End If
Next
On Error Resume Next
Columns("D:D").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
End Sub
Private Sub AddFolders() 'we'll archive by year within the archive subfolder
Set Rng = Range("D2:D100") '<< change if you know it will be less or more than 100
For Each x In Rng
If x.Value <> "" Then
On Error Resume Next
MkDir "D:\testing\~Archive\" & Format(x.Value - 30, "yyyy") '<< Change
On Error GoTo 0
End If
Next x
End Sub
Private Sub Move_Folders()
'This example move the folder from FromPath to ToPath
Dim FSO As Object
Dim FromPath As String
Dim ToPath As String
Set Rng = Range("F2:F100") '<< change if you know it will be less or more than 100
For Each x In Rng
If x.Value <> "" Then
FromPath = "D:\testing\" & x.Value '<< Change
ToPath = "D:\testing\~Archive\" & Format(x.Offset(0, -2).Value - 30, "yyyy") & "\" & x.Value '<< Change
'Note: It is not possible to use a folder that exist in ToPath
'We created subfolders by year earlier so we can archive by year now
Set FSO = CreateObject("scripting.filesystemobject")
FSO.MoveFolder Source:=FromPath, Destination:=ToPath
End If
Next x
End Sub

Figured out a more direct way to get the subfolders needed to be archived:
Private Sub Archive_Hotel_Confs()
Sheets("Archiving").Select
Cells.ClearContents
Dim strStartPath As String
strStartPath = "W:testing\" 'ENTER YOUR START FOLDER HERE
ListHCFolder strStartPath
CleanUpList
If Range("A1").Value = "" Then GoTo tidyup
AddHCFolders
MoveHC_Folders
'tidy up
tidyup:
Cells.Delete
Range("A1").Select
Sheets("Last Run").Select
End Sub
Private Sub ListHCFolder(sFolderPath As String)
Dim FS As New FileSystemObject
Dim FSfolder As Folder
Dim subfolder As Folder
Dim i As Integer
Set FSfolder = FS.GetFolder(sFolderPath)
For Each subfolder In FSfolder.SubFolders
If InStr(subfolder.Name, "~Archive") = 0 Then
DoEvents
i = i + 1
'added this line
Cells(i, 1) = subfolder
Cells(i, 2) = subfolder.DateLastModified
'commented out this one
'Debug.Print subfolder
End If
Next subfolder
Set FSfolder = Nothing
End Sub
Private Sub CleanUpList()
Dim x As Variant
'remove parent folder from path we'll check later
Columns("A:A").Replace What:="W:testing\", Replacement:="", LookAt:=xlPart, MatchCase:=False '<< Change
Set Rng = Range(Range("B1"), Range("B" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
If x.Value > Date - 30 Then '<<only keep it if more than 30 days (or whatever you want)
x.Value = ""
End If
End If
Next x
On Error Resume Next
Columns("B:B").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
End Sub
Private Sub AddHCFolders() 'we'll archive by year within the archive subfolder
Dim x As Variant
Set Rng = Range(Range("B1"), Range("B" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
On Error Resume Next
MkDir "W:testing\~Archive\" & Format(x.Value - 30, "yyyy") '<< Change
On Error GoTo 0
End If
Next x
End Sub
Private Sub MoveHC_Folders()
'This example move the folder from FromPath to ToPath
Dim FSO As Object
Dim FromPath As String
Dim ToPath As String
Dim x As Variant
Set Rng = Range(Range("A1"), Range("A" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
FromPath = "W:testing\" & x.Value '<< Change
ToPath = "W:testing\~Archive\" & Format(x.Offset(0, 1).Value - 30, "yyyy") & "\" & x.Value '<< Change
'Note: It is not possible to use a folder that exist in ToPath
'We created subfolders by year earlier so we can archive by year now
Set FSO = CreateObject("scripting.filesystemobject")
FSO.MoveFolder Source:=FromPath, Destination:=ToPath
End If
Next x
End Sub

Related

VBA to List items (including folders) with specific word (excel)

I would like to ask if there's a way for VBA to list all files (including folders/subfolders) with word OLDIES-(whatever the text or number here)
Sub ListOLDIES()
Dim FSO As Object, FSOSubFolder As Object, FileName As String
Dim FSOFile As Object, objFolder As Object, RowNum As Integer
Dim ExtSplit As Variant, NameSplit As Variant
strDirectory = "C:\Desktop\"
RowNum = 1
Set FSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = FSO.GetFolder(strDirectory)
For Each FSOSubFolder In objFolder.subfolders
ListOLDIES
Next FSOSubFolder
For Each FSOFile In objFolder.Files
If InStr(FSOFile.path, "OLDIES") Then
ExtSplit = Split(FSOFile.path, ".")
NameSplit = Split(FSOFile.path, "\")
FileName = Left(NameSplit(UBound(NameSplit)), _
Len(NameSplit(UBound(NameSplit))) - Len(ExtSplit(UBound(ExtSplit))) - 1)
Flpath = Left(FSOFile.path, Len(FSOFile.path) - Len(NameSplit(UBound(NameSplit))))
ActiveSheet.Cells(RowNum, 1) = FileName & ", " & Flpath & ", ." & ExtSplit(UBound(ExtSplit))
RowNum = RowNum + 1
End If
Next FSOFile
Set objFolder = Nothing
Set FSO = Nothing
End Sub
Got an error "out of stack space" using that code.
Desired result;
Name
Location
Extension
OLDIES-12345
C:Desktop
Folder
OLDER-23456
C:Desktop
.zip
OLDER-23457
C:Desktop/OLDIES_12345
.xlsx
Thanks!
The issue is that your recursively run your procedure
For Each FSOSubFolder In objFolder.subfolders
ListOLDIES
Next FSOSubFolder
but because you set the start folder to strDirectory = "C:\Desktop\" with every run of the procedure it starts running endless for C:\Desktop\ and never goes into the subfolders.
If you put a Debug.Print into that loop
For Each FSOSubFolder In objFolder.subfolders
Debug.Print FSOSubFolder.Path
ListOLDIES
Next FSOSubFolder
You will see that it always prints the first subfolder and never goes into it. You can see that best when you run the code step by step using F8.
How to solve that issue?
So what you need to do is you need to set the start folder strDirectory to the subfolder when you recursively start your proceduer ListOLDIES again. Therefore we need to remove the strDirectory = "C:\Desktop\" add it as an argument.
Sub ListOLDIES(ByVal strDirectory As String)
And change the recourssive call to ListOLDIES FSOSubFolder.Path
If we now do a simple test using
Option Explicit
Public Sub Example()
ListOLDIES "C:\Desktop"
End Sub
Public Sub ListOLDIES(ByVal strDirectory As String)
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Dim objFolder As Object
Set objFolder = FSO.GetFolder(strDirectory)
Dim FSOSubFolder As Object
For Each FSOSubFolder In objFolder.subfolders
Debug.Print FSOSubFolder.Path
ListOLDIES FSOSubFolder.Path
Next FSOSubFolder
Dim FSOFile As Object
For Each FSOFile In objFolder.Files
Debug.Print FSOFile.Path
Next FSOFile
Set objFolder = Nothing
Set FSO = Nothing
End Sub
We get a list of all (sub)folders and files of "C:\Desktop".
I used a test setup as follows:
C:\Desktop\Sub Folder 1
C:\Desktop\Sub Folder 2
C:\Desktop\Sub Folder 2\OLDIES-12345
C:\Desktop\Sub Folder 2\OLDIES-23456
C:\Desktop\Sub Folder 2\OLDIES-23456\OLDIES-12345.zip
C:\Desktop\Sub Folder 2\OLDIES-23456\OLDIES-23456.xml
C:\Desktop\Sub Folder 3
C:\Desktop\Sub Folder 3\OLDIES-12345.txt
C:\Desktop\Sub Folder 3\OLDIES-23456.txt
To maintain the RowNum counting over the entire recursive calls, you need to make that variable Static. And if you want to be able to reset it, add a parameter:
Option Explicit
Public Sub Example()
ListOLDIES "C:\Desktop", True
End Sub
Public Sub ListOLDIES(ByVal strDirectory As String, Optional ByVal ResetRowNum As Boolean = False)
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Dim objFolder As Object
Set objFolder = FSO.GetFolder(strDirectory)
Static RowNum As Long
If ResetRowNum Then RowNum = 1
Dim ws As Worksheet ' output sheet
Set ws = ActiveSheet ' better use something like ThisWorkbook.Worksheets("Sheet1") to define a specific sheet name
Dim FSOSubFolder As Object
For Each FSOSubFolder In objFolder.subfolders
InStr(1, FSOSubFolder.Name, "OLDIES", vbTextCompare)
' output folders with OLDIES
ws.Cells(RowNum, 1).Value = FSOSubFolder.Name
ws.Cells(RowNum, 2).Value = FSOSubFolder.ParentFolder.Path & "\"
ws.Cells(RowNum, 3).Value = "Folder"
RowNum = RowNum + 1
End If
ListOLDIES FSOSubFolder.Path
Next FSOSubFolder
Dim FSOFile As Object
For Each FSOFile In objFolder.Files
If InStr(1, FSOFile.Name, "OLDIES", vbTextCompare) Then
' output files with OLDIES
ws.Cells(RowNum, 1).Value = FSO.getBaseName(FSOFile)
ws.Cells(RowNum, 2).Value = FSOFile.ParentFolder.Path & "\"
ws.Cells(RowNum, 3).Value = "." & FSO.getExtensionName(FSOFile)
RowNum = RowNum + 1
End If
Next FSOFile
Set objFolder = Nothing
Set FSO = Nothing
End Sub
So the output for my test setup would be:
this should work:
Sub list_oldies()
Dim FileSystem As Object
Dim HostFolder As String
Set FileSystem = CreateObject("Scripting.FileSystemObject")
HostFolder = "C:\Users\salzerm.kontura\Desktop\Test\"
DoFolder FileSystem.GetFolder(HostFolder), 1
End Sub
Sub DoFolder(folder, RowNum As Integer)
Dim SubFolder
Dim ExtSplit As Variant
Dim NameSplit As Variant
For Each SubFolder In folder.SubFolders
If InStr(SubFolder, "Oldies") Then
ExtSplit = "Folder"
NameSplit = Split(SubFolder, "\")
Filename = Left(NameSplit(UBound(NameSplit)), _
Len(NameSplit(UBound(NameSplit))) - 1)
Flpath = Left(SubFolder, Len(SubFolder) - Len(NameSplit(UBound(NameSplit))))
ActiveSheet.Cells(RowNum, 1) = Filename
ActiveSheet.Cells(RowNum, 2) = Flpath
ActiveSheet.Cells(RowNum, 3) = ExtSplit
RowNum = RowNum + 1
End If
DoFolder SubFolder, RowNum
Next
Dim file
For Each file In folder.Files
If file Like "*Oldies*.*" Then
ExtSplit = Split(file, ".")
NameSplit = Split(file, "\")
Filename = Left(NameSplit(UBound(NameSplit)), _
Len(NameSplit(UBound(NameSplit))) - Len(ExtSplit(UBound(ExtSplit))) - 1)
Flpath = Left(file, Len(file) - Len(NameSplit(UBound(NameSplit))))
ActiveSheet.Cells(RowNum, 1) = Filename
ActiveSheet.Cells(RowNum, 2) = Flpath
ActiveSheet.Cells(RowNum, 3) = ExtSplit(UBound(ExtSplit))
RowNum = RowNum + 1
End If
Next
End Sub
Please, try the next code. It is fast, more compact and returns all you required, plus the initial returned array (in column D:D):
Sub list_oldies()
Dim arrFoldFiles, strPath As String, strSearch As String
Dim strExt As String, arrFin, i As Long, arrName, arrExt
strSearch = "Oldies"
strExt = "*" & strSearch & "*.*"
strPath = "C:\Desktop\"
arrFoldFiles = filter(Split(CreateObject("wscript.shell").Exec("cmd /c dir """ & strPath & strExt & """ /b/s").StdOut.ReadAll, vbCrLf), "\")
ReDim arrFin(1 To UBound(arrFoldFiles) + 1, 1 To 3)
For i = 0 To UBound(arrFoldFiles)
arrName = Split(arrFoldFiles(i), "\")
arrExt = Split(arrName(UBound(arrName)), ".")
arrFin(i + 1, 1) = arrExt(0)
If UBound(arrExt) > 0 Then
arrFin(i + 1, 3) = arrExt(1)
Else
arrFin(i + 1, 3) = "Folder"
End If
arrFin(i + 1, 2) = left(arrFoldFiles(i), InStrRev(arrFoldFiles(i), "\"))
Next i
'drop the arrays content:
Range("A1:D1").value = Array("Name", "Location", "Extension", "All")
Range("A2").Resize(UBound(arrFin), UBound(arrFin, 2)).value = arrFin
Range("D2").Resize(UBound(arrFoldFiles) + 1, 1).value = Application.Transpose(arrFoldFiles)
Range("A1:D1").EntireColumn.AutoFit
End Sub

Insert Images into Excel from sub directories based on cell value

I am a VBA novice but have been able to modify the below code to insert images in my spreadsheet based on cell values as long as the images are in the specific folder. How would I go about changing the code so that it searches all the sub folders within the directory? Any help would be greatly appreciated.
Public Sub Add_Pics_Example()
Dim oCell As Range
Dim oRange As Range
Dim oActive As Worksheet
Dim sPath As String
Dim sFile As String
Dim oShape As Shape
Worksheets("Range").Activate
sPath = "Z:\Pictures\Product Images\"
ActiveSheet.DrawingObjects.Select
Selection.Delete
Set oActive = ActiveSheet
Set oRange = oActive.Range("B4:bz4")
On Error Resume Next
For Each oCell In oRange
sFile = oCell.Value & ".jpg"
Set oShape = oActive.Shapes.AddPicture(sPath & sFile, False, True, _
oCell.Offset(-3, 0).Left + 30, oCell.Offset(-3, 0).Top + 3, 60, 60)
Next oCell
On Error GoTo 0
Application.ScreenUpdating = True
End Sub
Untested but should be pretty close:
Public Sub Add_Pics_Example()
Dim oCell As Range
Dim oRange As Range
Dim wsActive As Worksheet
Dim sFile As String
Dim dictFiles As Object
Set wsActive = Worksheets("Range")
wsActive.DrawingObjects.Delete
'get all the image files first
Set dictFiles = AllFilesbyName("Z:\Pictures\Product Images\", "*.jpg")
For Each oCell In wsActive.Range("B4:BZ4")
sFile = oCell.Value & ".jpg"
'do we have this file ?
If dictFiles.exists(sFile) Then
wsActive.Shapes.AddPicture dictFiles(sFile), False, True, _
oCell.Offset(-3, 0).Left + 30, _
oCell.Offset(-3, 0).Top + 3, 60, 60
End If
Next oCell
End Sub
'starting at startFolder, return a dictionary mapping file names to
' full paths (note doesn't handle >1 file of the same name)
' from startfolder and all subfolders
Function AllFilesbyName(startFolder As String, filePattern As String, _
Optional subFolders As Boolean = True) As Object
Dim fso, fldr, f, subFldr
Dim dictFiles As Object, colSub As New Collection
Set fso = CreateObject("scripting.filesystemobject")
Set dictFiles = CreateObject("scripting.dictionary")
dictFiles.comparemode = 1 'TextCompare: case-insensitive
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
'EDIT: fixed the line below
dictFiles(f.Name) = fso.buildpath(fldr.Path, f.Name)
End If
Next f
If subFolders Then
For Each subFldr In fldr.subFolders
colSub.Add subFldr.Path
Next subFldr
End If
Loop
Set AllFilesbyName = dictFiles
End Function

How to iterate through all sub-folders and their sub-sub-folders and so on using vba to check a folder if it exist?

I have below code to check if a folder exist on the predefined directory.
Option Explicit
Public xStatus As String
Sub Status()
Application.ScreenUpdating = False
Dim fso As Object
Dim folder As Object
Dim subfolders As Object
Dim subfolder1 As Object
Dim Rg As Range
Dim xCell As Range
Dim xTxt As String
xTxt = ActiveWindow.RangeSelection.Address
Set Rg = Application.InputBox("Please select city/cities to check production status!!! ", "Lmtools", xTxt, , , , , 8)
If Rg Is Nothing Then
MsgBox ("No cities selected!!!")
Exit Sub
End If
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder("D:\")
Set subfolders = folder.subfolders
For Each xCell In Rg
If xCell.Value <> "" Then
For Each subfolder1 In subfolders
xStatus = subfolder1.path
If xStatus Like "*?\" & xCell.Value Then
Cells(xCell.Row, xCell.Column + 1).Value = "Completed"
Cells(xCell.Row, xCell.Column + 2).Value = xStatus
GoTo nextiteration
Else
Cells(xCell.Row, xCell.Column + 1).Value = "Ongoing"
End If
Next
End If
nextiteration:
Next
Application.ScreenUpdating = True
End Sub
It works fine but only checks the sub-folders of "D:\" and not beyond that.
My folder could be present anywhere (either inside the sub-folders or their sub-folders or alongside "D:\"'s sub-folders.
my concern is how to iterate through all the folders.
I creted this a while back. Basically i used this to rename file in folders and sub-folders,
Option Explicit
Sub VersionRename()
Dim SelectedFolder As FileDialog
Dim T_Str As String
Dim FSO As Object
Dim RenamingFolder As Object, SubFolder As Object
Dim T_Name As String
Set SelectedFolder = Application.FileDialog(msoFileDialogFolderPicker)
SelectedFolder.Title = "Select folder:"
SelectedFolder.ButtonName = "Select Folder"
If SelectedFolder.Show = -1 Then
T_Str = SelectedFolder.SelectedItems(1)
Else
'MsgBox "Cancelled by user.", vbInformation
Set SelectedFolder = Nothing
Exit Sub
End If
Set SelectedFolder = Nothing
Set FSO = CreateObject("Scripting.FileSystemObject")
Set RenamingFolder = FSO.GetFolder(T_Str)
File_Renamer RenamingFolder
For Each SubFolder In RenamingFolder.SubFolders
File_Renamer SubFolder
Next
Set SubFolder = Nothing
Set RenamingFolder = Nothing
Set FSO = Nothing
MsgBox "Process completed!", vbInformation, Title:="Renaming Files"
End Sub
Private Sub File_Renamer(Folder As Object)
Dim File As Object
Dim T_Str As String
Dim T_Name As String
Dim PreVersionID As Variant
Dim NextVersionID As Variant
Dim StringReplace As String
PreVersionID = Application.InputBox("Input 1 if no version number otherwise input existing version number:", Type:=1)
If PreVersionID = False Then Exit Sub
NextVersionID = Application.InputBox("Input your next version number:", Type:=1)
If NextVersionID = False Then Exit Sub
T_Str = Format("_V" & NextVersionID)
For Each File In Folder.Files
T_Name = File.Name
'Debug.Print T_Name
If NextVersionID > 1 Then
StringReplace = Replace(T_Name, "_V" & PreVersionID, "", 1, 3)
'Debug.Print StringReplace
File.Name = Left(StringReplace, InStrRev(StringReplace, ".") - 1) & T_Str & Right(StringReplace, Len(StringReplace) - (InStrRev(StringReplace, ".") - 1))
Else
File.Name = Left(T_Name, InStrRev(T_Name, ".") - 1) & T_Str & Right(T_Name, Len(T_Name) - (InStrRev(T_Name, ".") - 1))
End If
Next
End Sub

VBA Excel: Search in folders and subsolders specific extension, and write in excel the title

I need to create a VBA code to search in folders an subfolders file extension('.csv'), and write the file title in excel workbook.
I had a similar situation and I got this working:
Sub foo()
Dim iFilesNum As Integer
Dim iCount As Integer
Dim recMyFiles() As FoundFileInfo
Dim blFilesFound As Boolean
Dim LastRow As Long
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
For xy = 2 To LastRow
blFilesFound = FindFiles(Sheet1.Cells(xy, 1).Value, recMyFiles, iFilesNum, "*.csv", True) 'where column 1 on Sheet1 contains the Paths to be searched, include more rows with more paths to search through them too
If blFilesFound Then
For iCount = 1 To iFilesNum
With recMyFiles(iCount)
Sheet2.Cells(iCount, 1).Value = .sPath & .sName 'place the results in Sheet2
End With
Next
Else
MsgBox "No file(s) found matching the specified file spec.", vbInformation, "File(s) not Found"
End If
Next xy
MsgBox iFilesNum
End Sub
And then in a module add the following:
Type FoundFileInfo
sPath As String
sName As String
End Type
Function FindFiles(ByVal sPath As String, _
ByRef recFoundFiles() As FoundFileInfo, _
ByRef iFilesFound As Integer, _
Optional ByVal sFileSpec As String, _
Optional ByVal blIncludeSubFolders As Boolean = True) As Boolean
Dim iCount As Integer '* Multipurpose counter
Dim sFileName As String '* Found file name
'*
'* FileSystem objects
Dim oFileSystem As Object, _
oParentFolder As Object, _
oFolder As Object, _
oFile As Object
Set oFileSystem = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
Set oParentFolder = oFileSystem.GetFolder(sPath)
If oParentFolder Is Nothing Then
FindFiles = False
On Error GoTo 0
Set oParentFolder = Nothing
Set oFileSystem = Nothing
Exit Function
End If
sPath = IIf(Right(sPath, 1) = "\", sPath, sPath & "\")
'*
'* Find files
sFileName = Dir(sPath & sFileSpec, vbNormal)
If sFileName <> "" Then
For Each oFile In oParentFolder.Files
If LCase(oFile.Name) Like LCase(sFileSpec) Then
iCount = UBound(recFoundFiles)
iCount = iCount + 1
ReDim Preserve recFoundFiles(1 To iCount)
With recFoundFiles(iCount)
.sPath = sPath
.sName = oFile.Name
End With
End If
Next oFile
Set oFile = Nothing '* Although it is nothing
End If
If blIncludeSubFolders Then
'*
'* Select next sub-forbers
For Each oFolder In oParentFolder.SubFolders
FindFiles oFolder.Path, recFoundFiles, iFilesFound, sFileSpec, blIncludeSubFolders
Next
End If
FindFiles = UBound(recFoundFiles) > 0
iFilesFound = UBound(recFoundFiles)
On Error GoTo 0
'*
'* Clean-up
Set oFolder = Nothing '* Although it is nothing
Set oParentFolder = Nothing
Set oFileSystem = Nothing
End Function

Listing all folders in my directory visual basic

I am trying to list all my folders from a drive in a directory onto an excel spreadsheet with a touch of a button. I made the button and assigned this macro... why won't it compile? The *** **** shows what they debugged. Said object folder was not an object. Please help!
Sub ListAllFile()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim ws As Worksheet
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set ws = Worksheets.Add
'Get the folder object associated with the directory
***Set objFolder = fso.GetFolder("C:hello\EMILY")***
ws.Cells(1, 1).Value = objFolder.Name
'Loop through the Files collection
For Each objFile In objFolder.Files
ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objFile.Name
Next
End Sub
This will allow you to get the folder names, unless you actually want files. It was modified from your original code. I commented out the excel/worksheet logic.
Part of the problem was fso.GetFolder was not an object which was declared and set. If you want still want files, you can change objFolder.Subfolders to .Files
Sub ListAllFile()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim ws As Worksheet
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Set ws = Worksheets.Add
'Get the folder object associated with the directory
Set objFolder = objFSO.GetFolder("C:\users")
'ws.Cells(1, 1).Value = objFolder.Name
'Loop through the Files collection
For Each objFile In objFolder.subfolders
MsgBox objFile.Name ' to test output
'ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objFile.Name
Next
End Sub
There are many ways to do this. Here is one way.
Option Explicit
Sub FileListingAllFolder()
Dim pPath As String
Dim FlNm As Variant
Dim ListFNm As New Collection ' create a collection of filenames
Dim OWb As Workbook
Dim ShtCnt As Integer
Dim Sht As Integer
Dim MWb As Workbook
Dim MWs As Worksheet
Dim i As Integer
' Open folder selection
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select a Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
pPath = .SelectedItems(1)
End With
Application.WindowState = xlMinimized
Application.ScreenUpdating = False
' Create master workbook with single sheets
Set MWb = Workbooks.Add(1)
MWb.Sheets(1).Name = "Result"
Set MWs = MWb.Sheets("Result")
Cells(1, 1) = "No."
Cells(1, 2) = "Sheet Name"
Cells(1, 3) = "File Name"
Cells(1, 4) = "Link"
i = 2
' Filling a collection of filenames (search Excel files including subdirectories)
Call FlSrch(ListFNm, pPath, "*.xls", True)
' Print list to immediate debug window and as a message window
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
MWs.Cells(i, 1) = i - 1
MWs.Cells(i, 2) = Sheets(Sht).Name
MWs.Cells(i, 3) = OWb.Name
MWs.Cells(i, 4).Formula = "=HYPERLINK(""" & FlNm & """,""Click Here"")"
i = i + 1
Next Sht
'End file processing file
OWb.Close False
Next FlNm
' Print to immediate debug window and message if no file was found
If ListFNm.Count = 0 Then
Debug.Print "No file was found !"
MsgBox "No file was found !"
MWb.Close False
End
End If
MWb.Activate
MWs.Activate
Cells.Select
Selection.EntireColumn.AutoFit
Range("A1").Select
Application.ScreenUpdating = True
Application.WindowState = xlMaximized
End
NextCode:
MsgBox "You Click Cancel, and no folder selected!"
End Sub
Private Sub FlSrch(pFnd As Collection, pPath As String, pMask As String, pSbDir As Boolean)
Dim flDir As String
Dim CldItm As Variant
Dim sCldItm As New Collection
' Add backslash at the end of path if not present
pPath = Trim(pPath)
If Right(pPath, 1) <> "\" Then pPath = pPath & "\"
' Searching files accordant with mask
flDir = Dir(pPath & pMask)
Do While flDir <> ""
pFnd.Add pPath & flDir 'add file name to list(collection)
flDir = Dir ' next file
Loop
' Procedure exiting if searching in subdirectories isn't enabled
If Not pSbDir Then Exit Sub
' Searching for subdirectories in path
flDir = Dir(pPath & "*", vbDirectory)
Do While flDir <> ""
' Add subdirectory to local list(collection) of subdirectories in path
If flDir <> "." And flDir <> ".." Then If ((GetAttr(pPath & flDir) And _
vbDirectory) = 16) Then sCldItm.Add pPath & flDir
flDir = Dir 'next file
Loop
' Subdirectories list(collection) processing
For Each CldItm In sCldItm
Call FlSrch(pFnd, CStr(CldItm), pMask, pSbDir) ' Recursive procedure call
Next
End Sub
Also, check out the link below.
http://www.learnexcelmacro.com/wp/download/
Save the file from the link named 'File Manager (Excel Workbook)'. That is a very cool app!!

Resources