File info pull from sub folders only 2-3 levels deep - vba

I currently have a code that will allow the user to pick a folder and then the code will pull the file information for the files in that folder but not for any files in sub folders. I have 7 levels of subfolders containing about 140,000 files. I was wondering if there is a way for me to pull only pull the info of files in subfolder level 2-3 not solely 1 and not from all 7 levels. Thank you for your help.
I don't think the "pasting formula in column 3" section will be relevant for this problem.
The sections that probably matter are "Picking a folder" and "Running through each file in the selected folder"
Sub Compile3()
Dim oShell As Object
Dim oFile As Object
Dim oFldr As Object
Dim lRow As Long
Dim iCol As Integer
Dim vArray As Variant
vArray = Array(10, 0, 1, 156, 2, 4, 144, 146, 183, 185)
Set oShell = CreateObject("Shell.Application")
Dim iRow As Long
iRow = Cells.find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row
lRow = iRow
'----------------------Picking a folder-------------------------------------
With Application.FileDialog(msoFileDialogFolderPicker)
.title = "Select the Folder..."
If .Show Then
Set oFldr = oShell.Namespace(.SelectedItems(1))
With oFldr
'Don't show update on the screen until the macro is finished
Application.EnableEvents = False
'---------------Column header information-----------------------------------
For iCol = LBound(vArray) To UBound(vArray)
If lRow = 2 Then
Cells(lRow, iCol + 4) = .getdetailsof(.items, vArray(iCol))
Else
Cells(lRow, iCol + 4) = "..."
End If
Next iCol
'---------------Running through each file in the selected folder------------
For Each oFile In .items
lRow = lRow + 1
For iCol = LBound(vArray) To UBound(vArray)
Cells(lRow, iCol + 4) = .getdetailsof(oFile, vArray(iCol))
Next iCol
' ---------------Pasting formula in column 3 -----------------------------
If lRow < 4 Then
Cells(lRow, 3).Formula = "=IFERROR(VLOOKUP(D3,$A$3:$B$10,2,FALSE),""User Not Found"")"
Else
Cells((lRow - 1), 3).Copy
Cells(lRow, 3).PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Cells(lRow, 3).PasteSpecial Paste:=xlPasteFormulas, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
End If
'------------------------------------------------------------------------------
Next oFile
End With
End If
Application.EnableEvents = True
End With
End Sub

I modified your code to work with arrays and use a recursive function to return the folder file information.
Sub ProcessFolder()
Dim FolderPath As String
Dim results As Variant
Dim Target As Range
FolderPath = getFileDialogFolder
If Len(FolderPath) = 0 Then Exit Sub
getFolderItems FolderPath, results
CompactResults results
With Worksheets("Sheet1")
.Range("C3", .Range("I" & Rows.Count).End(xlUp)).ClearContents
Set Target = .Range("C3")
Set Target = Target.EntireRow.Cells(1, 4)
Target.Resize(UBound(results), UBound(results, 2)).Value = results
Target.Offset(1, -1).Resize(UBound(results) - 1).Formula = "=IFERROR(VLOOKUP(D3,$A$3:$B$10,2,FALSE),""User Not Found"")"
End With
End Sub
Sub CompactResults(ByRef results As Variant)
Dim data As Variant
Dim x As Long, x1 As Long, y As Long, y1 As Long
ReDim data(1 To UBound(results) + 1, 1 To UBound(results(0)) + 1)
For x = LBound(results) To UBound(results)
x1 = x1 + 1
y1 = 0
For y = LBound(results(x)) To UBound(results(x))
y1 = y1 + 1
data(x1, y1) = results(x)(y)
Next
Next
results = data
End Sub
Function getFileDialogFolder() As String
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select the Folder..."
.AllowMultiSelect = False
If .Show Then
getFileDialogFolder = .SelectedItems(1)
End If
End With
End Function
Sub getFolderItems(FolderPath As String, ByRef results As Variant, Optional MaxLevels As Long = 1, Optional oShell As Object, Optional Level As Long)
Dim oFile As Object, oFldr As Object
If oShell Is Nothing Then
ReDim results(0)
Set oShell = CreateObject("Shell.Application")
End If
If Not IsEmpty(results(UBound(results))) Then ReDim Preserve results(UBound(results) + 1)
Set oFldr = oShell.Namespace(CStr(FolderPath))
results(UBound(results)) = getFolderFileDetailArray(oFldr.Self, oFldr)
results(UBound(results))(1) = oFldr.Self.Path
For Each oFile In oFldr.Items
ReDim Preserve results(UBound(results) + 1)
If oFldr.getDetailsOf(oFile, 2) = "File folder" Then
If Level < MaxLevels Then
getFolderItems oFile.Path, results, MaxLevels, oShell, Level + 1
End If
End If
results(UBound(results)) = getFolderFileDetailArray(oFile, oFldr)
Next oFile
End Sub
Function getFolderFileDetailArray(obj As Object, oFldr As Object) As Variant
Dim iCol As Integer
Dim vDetailSettings As Variant
vDetailSettings = Array(10, 0, 1, 156, 2, 4, 144, 146, 183, 185)
For iCol = LBound(vDetailSettings) To UBound(vDetailSettings)
vDetailSettings(iCol) = oFldr.getDetailsOf(obj, vDetailSettings(iCol))
Next iCol
getFolderFileDetailArray = vDetailSettings
End Function

The file system object can do this for you.
In this example, the code returns every subfolder on your C:\ drive.
' Returns every folder under the C:\.
Sub CrawlFolder()
Dim fso As FileSystemObject ' Access the Windows file system.
Dim folder As folder ' Used to loop over folders.
Set fso = New FileSystemObject
For Each folder In fso.GetFolder("C:\").SubFolders
Debug.Print folder.Name
Next
End Sub
To view the results make sure you've turned the Immediate window on (View >> Immediate Window).
To use the file system object you'll need to add a reference (Tools >> References >> Windows Script Host Object Model).
You can add a second For Each Loop to view the files:
' Returns every folder under the C:\.
Sub CrawlFolder()
Dim fso As FileSystemObject ' Access the Windows file system.
Dim folder As folder ' Used to loop over folders.
Dim file As file ' Used to loop over files.
Set fso = New FileSystemObject
For Each folder In fso.GetFolder("C:\").SubFolders
For Each file In folder.Files
Debug.Print file.Name
Next
Next
End Sub

Related

Copy range in Word avoiding clipboard

I have the code below to copy an array of tables in Word to Excel. The volume of data being copied gives memory problems, so I would like to avoid the clipboard - i.e. avoid using Range.Copy
Word does not support Range.Value and I have not been able to get Range(x) = Range(y) to work.
Any suggestions for a way to avoid the clipboard? Word formatting can be junked.
Sub ImportWordTableArray()
Dim WordApp As Object
Dim WordDoc As Object
Dim arrFileList As Variant, FileName As Variant
Dim tableNo As Integer 'table number in Word
Dim tableStart As Integer
Dim tableTot As Integer
Dim Target As Range
On Error Resume Next
arrFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
If Not IsArray(arrFileList) Then Exit Sub
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Worksheets("Test").Range("A:AZ").ClearContents
Set Target = Worksheets("Test").Range("A1")
For Each FileName In arrFileList
Set WordDoc = WordApp.Documents.Open(FileName, ReadOnly:=True)
With WordDoc
'For array
Dim tables() As Variant
Dim tableCounter As Long
tableNo = WordDoc.tables.Count
tableTot = WordDoc.tables.Count
If tableNo = 0 Then
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
End If
tables = Array(1, 3, 5) '<- define array manually here if not using InputBox
For tableCounter = LBound(tables) To UBound(tables)
With .tables(tables(tableCounter))
.Range.Copy
Target.Activate
'Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False '<- memory problems!
'Or
ActiveSheet.Paste '<- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Next tableCounter
.Close False
End With
Next FileName
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub
You may need to tweak the code below to get it to do exactly what you want (Excel is not something I use often) as the calculation of ranges is a bit wonky, but it will transfer text from word to excel without cutting and pasting
Option Explicit
' This code is based on it being in an Excel VBA Module with the reference
' to the Microsoft Word Object XX.X Object Library (Tools.References)
' enabled so that we get intellisense for Word objects
Public Enum ImportError
NoTablesInDocument
End Enum
Sub ImportWordTableArray()
Dim myFileList As Variant
If Not TryGetFileList(myFileList) Then Exit Sub
Dim myWdApp As Word.Application
Set myWdApp = New Word.Application
myWdApp.Visible = True
If Application.ReferenceStyle = xlA1 Then Application.ReferenceStyle = xlR1C1
ThisWorkbook.Worksheets("Test").Range("A:AZ").ClearContents
Dim myFileName As Variant
For Each myFileName In myFileList
Dim myDoc As Word.Document
If TryGetWordDoc(myFileName, myWdApp, myDoc) Then
CopyDocTablesToExcel myDoc, ThisWorkbook.Worksheets("Test")
End If
Next
If Application.ReferenceStyle = xlR1C1 Then Application.ReferenceStyle = xlA1
End Sub
Public Sub CopyDocTablesToExcel(ByVal ipDoc As Word.Document, ByVal ipWs As Excel.Worksheet)
If ipDoc.Tables.Count = 0 Then
Report ipDoc.Name, ImportError.NoTablesInDocument
Exit Sub
End If
Dim myTable As Variant
Dim Target As Excel.Range
For Each myTable In ipDoc.Tables
' This code assumes that the Word table is 'uniform'
Dim myCols As Long
myCols = myTable.Range.Tables.Item(1).Range.Columns.Count
Dim myRows As Long
myRows = myTable.Range.Tables.Item(1).Range.Rows.Count
Dim myTLCell As Excel.Range
Dim myBRCell As Excel.Range
If Target Is Nothing Then
Set myTLCell = ipWs.Cells(1, 1)
Set myBRCell = ipWs.Cells(myCols, myRows)
Else
Set myTLCell = ipWs.Cells(1, Target.Cells.SpecialCells(xlCellTypeLastCell).Row + 2)
Set myBRCell = ipWs.Cells(myCols, Target.Cells.SpecialCells(xlCellTypeLastCell).Row + 2 + myRows)
End If
Set Target = ipWs.Range(myTLCell, myBRCell)
Target = GetTableArray(myTable)
Next
End Sub
Public Function GetTableArray(ByVal ipTable As Word.Table) As Variant
Dim myArray As Variant
Dim myRow As Long
Dim myCol As Long
ReDim myArray(1 To ipTable.Range.Tables.Item(1).Range.Rows.Count, 1 To ipTable.Range.Tables.Item(1).Range.Columns.Count)
For myRow = 1 To UBound(myArray, 1) - 1
For myCol = 1 To UBound(myArray, 2) - 1
Dim myText As String
myText = ipTable.Cell(myRow, myCol).Range.Text
myArray(myRow, myCol) = VBA.Left$(myText, Len(myText) - 2)
Next
Next
GetTableArray = myArray
End Function
Public Function TryGetFileList(ByRef opFileList As Variant) As Boolean
On Error Resume Next
opFileList = _
Application.GetOpenFilename _
( _
"Word files (*.doc; *.docx),*.doc;*.docx", _
2, _
"Browse for file containing table to be imported", _
, _
True _
)
TryGetFileList = (Err.Number = 0) And IsArray(opFileList)
On Error GoTo 0
End Function
Public Function TryGetWordDoc _
( _
ByVal ipName As String, _
ByRef ipWdApp As Word.Application, _
ByRef opDoc As Word.Document _
) As Boolean
On Error Resume Next
Set opDoc = ipWdApp.Documents.Open(ipName, ReadOnly:=True)
TryGetWordDoc = (Err.Number = 0) And (Not opDoc Is Nothing)
On Error GoTo 0
End Function
Public Function Report(ByVal ipString As String, ByVal ipError As ImportError)
Select Case ipError
Case NoTablesInDocument
MsgBox ipString & " Contains no tables", vbExclamation, "Import Word Table"
Case Else
End Select
End Function
For tableCounter ... Next code modified below to extract data directly rather than using copy and paste.
Sub ImportWordTablesArray()
Dim WordApp As Object
Dim WordDoc As Object
Dim arrFileList As Variant, Filename As Variant
Dim tableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
Dim resultRow As Long
Dim tables() As Variant
Dim tableCounter As Long
On Error Resume Next
arrFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
If Not IsArray(arrFileList) Then Exit Sub '<-user cancelled import file browser
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Worksheets("Test").Range("A:E").Clear '<-ClearContents to clear only text
For Each Filename In arrFileList
Set WordDoc = WordApp.Documents.Open(Filename, ReadOnly:=True)
With WordDoc
If WordDoc.ProtectionType <> wdNoProtection Then
WordDoc.Unprotect Password:=SREPedit
End If
tableNo = WordDoc.tables.Count
If tableNo = 0 Then
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
End If
tables = Array(1, 2, 8) '<- Select tables for data extraction
For tableCounter = LBound(tables) To UBound(tables)
With .tables(tables(tableCounter))
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean(.Cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableCounter
.Close False
End With
Next Filename
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub

VBA- Import Multiple CSV to a Sheet, Remove Certain Rows/Columns

I am completely new to VBA, but I have CSV files(same format for all of them), and I want to import them to a single sheet on Excel. I was able to read the CSV file according to this code:
Sub R_AnalysisMerger()
Dim WSA As Worksheet
Dim bookList As Workbook
Dim SelectedFiles() As Variant
Dim NFile As Long
Dim FileName As String
Dim ws As Worksheet, vDB As Variant, rngT As Range
Application.ScreenUpdating = False
'Selects the CSV files as SELECTED FILES
Set ws = ThisWorkbook.Sheets(1)
ws.UsedRange.Clear 'Clears current worksheet
SelectedFiles = Application.GetOpenFilename(filefilter:="Excel Files (*.csv*), *.csv*", MultiSelect:=True) 'Selects csv files
For NFile = LBound(SelectedFiles) To UBound(SelectedFiles)
FileName = SelectedFiles(NFile)
Set bookList = Workbooks.Open(FileName, Format:=2)
Set WSA = bookList.Sheets(1)
With WSA
vDB = .UsedRange
Set rngT = ws.Range("a" & Rows.count).End(xlUp)(2)
If rngT.Row = 2 Then Set rngT = ws.Range("A1")
rngT.Resize(UBound(vDB, 1), UBound(vDB, 2)) = vDB
bookList.Close (0)
End With
Next
Application.ScreenUpdating = True
ws.Range("A1").Select
But I have additional requirements:
Skip the first column.
Skip the first four rows.
Remove a certain String from each word in the fifth row.
Im used to java, and usually I would read each line with a "for" loop and set "if" statements to skip the first row and four columns and remove the string from each string if it was present.
I don't know how to do this with this code. From what I understand it just copies the whole CSV file into the sheet?
This solution is based on reading CSV as textstream. I have tried to include feature that makes possible most all things like selecting columns, Rows and so on.
Sub ImportCSV()
Dim fso As New IWshRuntimeLibrary.FileSystemObject
Dim txtStream As IWshRuntimeLibrary.TextStream
Dim files As IWshRuntimeLibrary.files
Dim file As IWshRuntimeLibrary.file
Dim txtLine As String
Dim lineCount As Integer
Dim lastRow As Integer
Dim lineCol As Variant
Dim rng As Range
Application.ScreenUpdating = False
ThisWorkbook.Sheets(1).usedRange.Delete
Set rng = ThisWorkbook.Sheets(1).usedRange
lastRow = 1
Set files = fso.GetFolder("path\folder").files
For Each file In files
If file.Name Like "*.csv" Then
Set txtStream = file.OpenAsTextStream(ForReading, TristateUseDefault)
txtStream.SkipLine ' skip first line, since it containes headers
lineCount = 1
Do
txtLine = txtStream.ReadLine
If lineCount = 5 Then
txtLine = Replace(txtLine, "stringToReplace", "StringToReplcaeWith") ' replace certain string from words in 5'th row
End If
lineCount = lineCount + 1
lineCol = sliceStr(Split(txtLine, ";"), startIdx:=4) ' slice the array so to skip four first columns
For iCol = 0 To UBound(lineCol) ' write columns to last row
rng(lastRow, iCol + 1).Value = lineCol(iCol)
Next iCol
lastRow = lastRow + 1
'Debug.Print Join(lineCol, ";") ' debug
Loop Until txtStream.AtEndOfStream
End If
Next file
Application.ScreenUpdating = True
End Sub
This is the slicer function
Function sliceStr(arr As Variant, startIdx As Integer, Optional stopIdx As Integer = 0) As String()
If stopIdx = 0 Then
stopIdx = UBound(arr)
End If
Dim tempArrStr() As String
ReDim tempArrStr(stopIdx - startIdx)
Dim counter As Integer
counter = 0
For i = startIdx To stopIdx
tempArrStr(counter) = arr(i)
counter = counter + 1
Next
sliceStr = tempArrStr
End Function
I just did a simple test and the code below seems to work. Give it a go, and feedback.
Sub Demo()
Dim fso As Object 'FileSystemObject
Dim fldStart As Object 'Folder
Dim fld As Object 'Folder
Dim fl As Object 'File
Dim Mask As String
Application.ScreenUpdating = False
Dim newWS As Worksheet
Set newWS = Sheets.Add(before:=Sheets(1))
Set fso = CreateObject("scripting.FileSystemObject") ' late binding
'Set fso = New FileSystemObject 'or use early binding (also replace Object types)
Set fldStart = fso.GetFolder("C:\Users\ryans\OneDrive\Desktop\output\") ' <-- use your FileDialog code here
Mask = "*.csv"
'Debug.Print fldStart.Path & ""
ListFiles fldStart, Mask
For Each fld In fldStart.SubFolders
ListFiles fld, Mask
ListFolders fld, Mask
Next
Dim myWB As Workbook, WB As Workbook
Set myWB = ThisWorkbook
Dim L As Long, t As Long, i As Long
L = myWB.Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row
t = 1
For i = 1 To L
Workbooks.OpenText Filename:=myWB.Sheets(1).Cells(i, 1).Value, DataType:=xlDelimited, Tab:=True
Set WB = ActiveWorkbook
lrow = WB.Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row
WB.Sheets(1).Range("B4:E" & lrow).Copy newWS.Cells(t, 2)
t = myWB.Sheets(1).Cells(Rows.Count, "B").End(xlUp).Row + 1
WB.Close False
Next
myWB.Sheets(1).Columns(1).Delete
Application.ScreenUpdating = True
End Sub
Sub ListFolders(fldStart As Object, Mask As String)
Dim fld As Object 'Folder
For Each fld In fldStart.SubFolders
'Debug.Print fld.Path & ""
ListFiles fld, Mask
ListFolders fld, Mask
Next
End Sub
Sub ListFiles(fld As Object, Mask As String)
Dim t As Long
Dim fl As Object 'File
For Each fl In fld.Files
If fl.Name Like Mask Then
t = Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row + 1
'Debug.Print fld.Path & "" & fl.Name
If Sheets(1).Cells(1, 1) = "" Then
Sheets(1).Cells(1, 1) = fld.Path & "\" & fl.Name
Else
Sheets(1).Cells(t, 1) = fld.Path & "\" & fl.Name
End If
End If
Next
End Sub

Excel VBA List Files in Folder with Owner/Author Properties

This works, but is painfully slow:
Option Explicit
Sub GetDetails()
Dim oShell As Object
Dim oFile As Object
Dim oFldr As Object
Dim lRow As Long
Dim iCol As Integer
Dim vArray As Variant
vArray = Array(0, 3, 10, 20)
Set oShell = CreateObject("Shell.Application")
lRow = 1
Set oFldr = oShell.Namespace("\\mysite\www\docs\f150\group\IDL\collection\")
With oFldr
For iCol = LBound(vArray) To UBound(vArray)
Cells(lRow, iCol + 1) = .getdetailsof(.items, vArray(iCol))
Next iCol
For Each oFile In .items
lRow = lRow + 1
For iCol = LBound(vArray) To UBound(vArray)
On Error Resume Next
Cells(lRow, iCol + 1) = .getdetailsof(oFile, vArray(iCol))
Next iCol
Next oFile
End With
End Sub
I have the code below working, but I still cant get the Owner/Author or the specific file types.
Sub getFiles()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the folder object
Set objFolder = objFSO.GetFolder("\\mysite\www\docs\f150\group\IDL\collection")
i = 1
'loops through each file in the directory and prints their names and path
For Each objFile In objFolder.Files
'print file name
Cells(i + 1, 1) = objFile.Name
With Cells(i + 1, 1)
Cells(i + 1, 1).Select
Selection.Hyperlinks.Add Anchor:=Selection, Address:=objFile.Path
End With
'print file path
Cells(i + 1, 2) = objFile.DateLastModified
i = i + 1
Next objFile
Columns.AutoFit
End Sub
I am trying to get a list of certain files and attributes into an Excel document, but the code keeps causing Excel to crash.
The code below may have some redundancy because I've been fiddling with it all day. Ultimately I would like to get the .pptx and .pdf file names, DateLastModified, and the owner or author
Sub ListAllFile()
Application.ScreenUpdating = False
Dim objFSO As Object
Dim objFolder As Object
Dim objFolderItem As Object
Dim objFile As Object
Dim ws As Worksheet
Dim myExt1 As String
Dim myExt2 As String
myExt1 = "*.pptx"
myExt2 = "*.pdf"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set ws = Worksheets.Add
'Get the folder object associated with the directory
Set objFolder = objFSO.GetFolder("\\mysite\www\docs\f150\group\IDL\collection")
ws.Cells(1, 1).Value = "The current files found in " & objFolder.Name & "are:"
Set objFile = objFile
'Loop through the Files collection
For Each objFile In objFolder.Files
If StrComp(objFile.Name, myExt1) = 1 Or StrComp(objFile.Name, myExt2) = 1 Then
Dim strFilePath As Object
Dim arrHeaders(35)
Dim i As Integer
Dim objShell As Object
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace("\\mysite\www\docs\f150\group\IDL\collection")
Set objFileName = objFolder.ParseName(objFile.Name)
For Each objFile In objFolder.Items
ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objFile.Name
ws.Cells(ws.UsedRange.Rows.Count + 0, 2).Value = objFile.DateLastModified
'This returns the "Owner" as the value for every file (not what I want)
ws.Cells(ws.UsedRange.Rows.Count + 0, 3).Value = objFolder.GetDetailsOf(objFile, 10)
'This returns the "Author" as the value for every file (not what I want)
ws.Cells(ws.UsedRange.Rows.Count + 0, 4).Value = objFolder.GetDetailsOf(objFile, 20)
'This returns the actual owner
ws.Cells(ws.UsedRange.Rows.Count + 0, 5).Value = objFolder.GetDetailsOf(strFileName, 10)
'This returns the actual author
ws.Cells(ws.UsedRange.Rows.Count + 0, 6).Value = objFolder.GetDetailsOf(strFileName, 20)
Next
End If
Next
Columns.AutoFit
'Clean up
Set objFolder = Nothing
Set objFile = Nothing
Set objFSO = Nothing
Set objShell = Nothing
Set objFileName = Nothing
Set ws = Nothing
Application.ScreenUpdating = True
End Sub
I changed the second for each loop variable name to objfile1 and made appropriate modifications below it:
For Each objfile1 In objFolder.Items
ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objfile1.Name
ws.Cells(ws.UsedRange.Rows.Count + 0, 2).Value = objFile.DateLastModified
Note that DateLastModified is a property of objFile while Name belongs to objfile1.
Hope this helps.
You could try and use the CMD.exe DIR command to optimize it a bit, as well as a couple of other tweaks:
Sub Foo()
Dim myExt1 As String
Dim myExt2 As String
Dim searchFolder As Variant
Dim finalArray As Object
Dim shellObj As Object
searchFolder = "\\mysite\www\docs\f150\group\IDL\collection"
myExt1 = "*.pptx"
myExt2 = "*.pdf"
Set finalArray = CreateObject("System.Collections.ArrayList")
Set shellObj = CreateObject("Shell.Application").Namespace(searchFolder)
For Each file In Filter(Split(CreateObject("WScript.Shell").Exec("CMD /C DIR " & searchFolder & "\" & myExt1 & " /B /A:-D").StdOut.ReadAll, vbCrLf), ".")
finalArray.Add CStr(file)
Next
For Each file In Filter(Split(CreateObject("WScript.Shell").Exec("CMD /C DIR " & searchFolder & "\" & myExt2 & " /B /A:-D").StdOut.ReadAll, vbCrLf), ".")
finalArray.Add CStr(file)
Next
For Each file In finalArray.ToArray()
With Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
.Value = CStr(file)
.Offset(0, 1).Value = shellObj.GetDetailsOf(CStr(file), 10)
.Offset(0, 2).Value = shellObj.GetDetailsOf(CStr(file), 20)
End With
Next
End Sub

Excel VBA: Create list of subfolders and files within source folder

I am using the following code to list all files in a host folder and it's sub folders. The code works great but, do you know how I can update the code to also list some the file attributes.
Sub file_list()
Call ListFilesInFolder("W:\ISO 9001\INTEGRATED_PLANNING\", True)
End Sub
Sub ListFilesInFolder(ByVal SourceFolderName As String, ByVal IncludeSubfolders As Boolean)
Dim FSO As Object
Dim SourceFolder As Object
Dim SubFolder As Object
Dim FileItem As Object
Dim r As Long
Set FSO = CreateObject("Scripting.FileSystemObject")
Set SourceFolder = FSO.getFolder(SourceFolderName)
r = Range("A65536").End(xlUp).Row + 1
For Each FileItem In SourceFolder.Files
Cells(r, 1).Formula = FileItem.Name
r = r + 1
X = SourceFolder.Path
Next FileItem
If IncludeSubfolders Then
For Each SubFolder In SourceFolder.Subfolders
ListFilesInFolder SubFolder.Path, True
Next SubFolder
End If
Set FileItem = Nothing
Set SourceFolder = Nothing
Set FSO = Nothing
End Sub
Function GetFileOwner(ByVal FilePath As String, ByVal FileName As String)
Dim objFolder As Object
Dim objFolderItem As Object
Dim objShell As Object
FileName = StrConv(FileName, vbUnicode)
FilePath = StrConv(FilePath, vbUnicode)
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(StrConv(FilePath, vbFromUnicode))
If Not objFolder Is Nothing Then
Set objFolderItem = objFolder.ParseName(StrConv(FileName, vbFromUnicode))
End If
If Not objFolderItem Is Nothing Then
GetFileOwner = objFolder.GetDetailsOf(objFolderItem, 8)
Else
GetFileOwner = ""
End If
Set objShell = Nothing
Set objFolder = Nothing
Set objFolderItem = Nothing
End Function
What I would really like to see is;
Column A = Host folder/subfolder
Column B = File name
Column C = hyperlink to file
Is this possible?
I do have a code that created hyperlinks but, I do not know how to add to the existing code.
Sub startIt()
Dim FileSystem As Object
Dim HostFolder As String
HostFolder = "W:\ISO 9001\INTEGRATED_PLANNING\"
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
End Sub
Sub DoFolder(Folder)
Dim SubFolder
For Each SubFolder In Folder.Subfolders
DoFolder SubFolder
Next
i = Cells(Rows.Count, 1).End(xlUp).Row + 1
Dim File
For Each File In Folder.Files
ActiveSheet.Hyperlinks.Add Anchor:=Cells(i, 1), Address:= _
File.Path, TextToDisplay:=File.Name
i = i + 1
Next
End Sub
You can see the list of properties that the File Object supports here: https://msdn.microsoft.com/en-us/library/1ft05taf(v=vs.84).aspx
So you can enhance your code, where it is taking the .Name property and putting that in a cell formula, to do something similar with other properties, such as the .Type of the file.
For Each FileItem In SourceFolder.Files
Cells(r, 1).Formula = FileItem.Name
Cells(r, 2).Value = FileItem.Type
ActiveSheet.Hyperlinks.Add Anchor:=Cells(r, 3), Address:= _
FileItem.Path, TextToDisplay:=FileItem.Name
r = r + 1
X = SourceFolder.Path
Next FileItem
n.b. I've used Value instead of Formula, but in this case the result will be the same.
In a similar manner, you can add another Cells(r, 3).Value = line to set the value of cell in the current row r and column 3 to whatever your hyperlink is.
I wrote a little script for this purpose to my colleague for a time ago...
See my code below:
Sub FolderNames()
'Written by Daniel Elmnas Last update 2016-02-17
Application.ScreenUpdating = False
Dim xPath As String
Dim xWs As Worksheet
Dim fso As Object, j As Long, folder1 As Object
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Choose the folder"
.Show
End With
On Error Resume Next
xPath = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems(1) & "\"
Application.Workbooks.Add
Set xWs = Application.ActiveSheet
xWs.Cells(1, 1).Value = xPath
xWs.Cells(2, 1).Resize(1, 5).Value = Array("Subfolder", "Hostfolder", "Filename", "Date Created", "Date Last Modified")
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder1 = fso.getFolder(xPath)
getSubFolder folder1
xWs.Cells(2, 1).Resize(1, 5).Interior.Color = 65535
xWs.Cells(2, 1).Resize(1, 5).EntireColumn.AutoFit
Application.ScreenUpdating = True
End Sub
Sub getSubFolder(ByRef prntfld As Object)
Dim SubFolder As Object
Dim subfld As Object
Dim xRow As Long
For Each SubFolder In prntfld.SubFolders
xRow = Range("A1").End(xlDown).Row + 1
Cells(xRow, 1).Resize(1, 5).Value = Array(SubFolder.Path, Left(SubFolder.Path, InStrRev(SubFolder.Path, "\")), SubFolder.Name, SubFolder.DateCreated, SubFolder.DateLastModified)
Next SubFolder
For Each subfld In prntfld.SubFolders
getSubFolder subfld
Next subfld
End Sub
Here is the result:
You can modify it a bit though.
If you example dont want to use a window-dialog and instead use
"W:\ISO 9001\INTEGRATED_PLANNING\"
Cheers!

Double loop (loop inside a loop) vba excel

I am relatively new to VBA, and am in need of some help to fully understand some issues.
I have a file with many sheets, and am in need to make a copy of the file for every team. Each file must not have the information of other teams.
I have managed to assemble this code that seems to work for one sheet, but not for every sheet that I need.
The first four sheets are supposed to remain unchanged (no filtering in these ones) and the sheet in yellow is a different arrangement from the others (I need to look at this later) but the remaining sheets have exactly the same construction, so the column to do "the math" is the same. (file in attachment with example)
Sub DeleteRowBasedOnCriteria()
'lobs names
Dim lob(14) As String
lob(0) = "AV"
lob(1) = "CA"
lob(2) = "G_13"
lob(3) = "HSTP"
lob(4) = "JLS"
lob(5) = "JR"
lob(6) = "LPV"
lob(7) = "MAO"
lob(8) = "NML"
lob(9) = "PRJ"
lob(10) = "RB"
lob(11) = "RG"
lob(12) = "SPN"
lob(13) = "VE"
'counter
Dim i As Integer
'numbers of rows
Dim rowtotest As Long
' to create a copy of the template to be filled'
Dim sFile As String 'Source file - Template'
Dim sDFile As String 'Destination file - Template'
Dim sSFolder As String 'Source folder - Template'
Dim sDFolder As String 'Destination Folder'
sSFolder = "C:\Users\Pacosta\Desktop\ParaIndividuals\team.xlsx"
MsgBox (sSFolder)
'Destination Path Window selector
Dim destinationWindow As FileDialog
Set destinationWindow = Application.FileDialog(msoFileDialogFolderPicker)
destinationWindow.Title = "Select Destination Folder"
'only select one folder
destinationWindow.AllowMultiSelect = False
If destinationWindow.Show Then
sDFolder = destinationWindow.SelectedItems(1) + "\"
End If
'copy cell content to excel file based on template with bookmarks'
Dim objExcel As Object
Dim ws As Worksheet
For i = 0 To 14
'create a file with same name as lob
sDFile = lob(i) + ".xlsx"
'Create object excel document'
Set FSO = CreateObject("Scripting.FileSystemObject")
'Copy the template do destination'
FSO.CopyFile (sSFolder + sFile), sDFolder + sDFile, True
Next i
Dim file As String
For i = 0 To 11
file = sDFolder + lob(i) + ".xlsx"
Call GetIndices(lob(i), file)
Next i
End Sub
'delete rows diferents from lobs namefile
Sub DeleteRows(lob As String, file As String)
'disable automatic calculation
Application.Calculation = xlCalculationManual
'count number of rows
Dim rowtotest As Long
'variable to work with all files
Dim ficheiro As Workbook
Set ficheiro = Workbooks.Open(file)
With ficheiro.Sheets(1)
'delete rows of the other lob's
For rowtotest = .Cells(Rows.Count, 7).End(xlUp).Row + 1 To 5 Step -1
If StrComp(.Cells(rowtotest, 7).Value, lob) <> 0 Then
.Rows(rowtotest).Delete
End If
Next rowtotest
End With
' Force a calculation
Application.Calculate
' Then remember to run automatic calculations back on
Application.Calculation = xlCalculationAutomatic
'save file
ficheiro.Save
'close file
ficheiro.Close
End Sub
Sub GetIndices(lob As String, file As String)
'count number of rows
Dim rowtotest As Long
'primeiro indice
Dim indice1 As Integer
'segundo indice
Dim indice2 As Integer
'variable to work with all files
Dim ficheiro As Workbook
Set ficheiro = Workbooks.Open(file)
With ficheiro.Sheets(1)
'delete rows of the other lob's
For rowtotest = .Cells(Rows.Count, 8).End(xlUp).Row + 1 To 5 Step -1
If StrComp(.Cells(rowtotest, 8).Value, lob) = 0 Then
indice2 = rowtotest
rowtotest = 0
End If
Next rowtotest
'delete rows of the other lob's
For rowtotest = 4 To .Cells(Rows.Count, 8).End(xlUp).Row + 1 Step 1
If StrComp(.Cells(rowtotest, 8).Value, lob) = 0 Then
indice1 = rowtotest
rowtotest = 1000
End If
Next rowtotest
Dim texto As String
texto = indice2 & ":" & .Cells(Rows.Count, 8).End(xlUp).Row + 1
.Rows(texto).Delete
texto = 5 & ":" & indice1
.Rows(texto).Delete
ficheiro.Save
ficheiro.Close
End With
End Sub
Can someone help me with this problem?
Thanks in advance.