Excel VBA Macro to match cell value from workbooks in a root folder then copy specific cell - vba

Picture above is the master workbook. Can anyone help me to write the vba so it will find workbooks throughout the root folder (e.g. C:\Work\2017) that match with the account number and copy the B9 and E9 cells to the master cell. The 2nd picture is a system generated workbook with random name (e.g. export!-097a0sdk.xls), that's why I need a shortcut to make this task easier.
This is the result I expected by using the code
This is the excel generated by system
Thank you

If I understood correctly then the following will loop through a given directory and it will open and check each file for the required information, if found, it will add the values to your Master workbook.
Note: This code will not open a file if it has "Master" in its filename.
Sub LoopThroughFolder()
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim wb As Workbook
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim myFile As File
Dim AccNumber As String
Dim LastRow As Long, i As Long
Dim sPath As String
sPath = "C:\Work\2017"
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
Application.DisplayAlerts = False
'do not display alerts
Set myFolder = FSO.GetFolder(sPath) 'set the root folder
For Each myFile In myFolder.Files 'for each file in the folder
If InStr(myFile.Name, "Master") = 0 Then
'if file to open does not have "Master" in it's name then
Set wb = Workbooks.Open(myFile.Path) 'open the file
AccNumber = wb.Sheets(1).Range("B2") 'check for account number on first Sheet
For i = 1 To LastRow 'loop through current Sheet to check if we have a match for the account number
If ws.Cells(i, 1) = AccNumber Then 'if match
ws.Cells(i, 2) = wb.Sheets(1).Range("B9") 'pass the values from the required range
ws.Cells(i, 3) = wb.Sheets(1).Range("E9")
End If
Next i
wb.Close False 'close and do not save changes
Set wb = Nothing
End If
Next
Application.DisplayAlerts = True
End Sub
Also you might have to set a reference to the relevant library to use FileSystemObject, to do that:
How do I use FileSystemObject in VBA?
Within Excel you need to set a reference to the VB script run-time library.
The relevant file is usually located at \Windows\System32\scrrun.dll
To reference this file, load the
Visual Basic Editor (ALT+F11)
Select Tools > References from the drop-down menu
A listbox of available references will be displayed
Tick the check-box next to 'Microsoft Scripting Runtime'
The full name and path of the scrrun.dll file will be displayed below the listbox
Click on the OK button.

Related

Excel VBA: pull specific worksheet from different files into existing workbook and change name

I am very new to VBA and am trying to do the following below
For example:
Worksheets' name is "Sheet1" I need to pull this specific sheet from many different files in different folders into an existing Workbook "Workbook A".
Paste the new sheets as values
Unprotect the sheet
Then rename these new sheets based on a cell value's "A2" first 4 values
Doing all this without altering the existing worksheets in Workbook A. Just applying this to the newly integrated sheets "Sheet1".
I have been using this code to pull in the worksheets, however the link to the folders do not alwys function especially if I change it. ChDir ("\C:Test") It also takes a long time opening and then closing files. And asking for updates to links everytime a workbook is opened.
Dim DataName As String
Dim DataWB As Workbook
Dim File As String
Dim MasterWB As Workbook
Dim MScnt As Integer
Dim Snr As Integer
'Find out number of sheets in Master
Set MasterWB = ActiveWorkbook
MScnt = MasterWB.Sheets.Count
'Switch to folder containing data workbooks
'Use path from master for now
ChDir ("\\C:Test")
'Find al xlsx workbooks in folder
File = Dir("*.xlsx")
While File <> ""
Debug.Print "Processing file " & File
'Do not process yourself
If InStr(File, MasterWB.Name) = 0 Then
'Open data workbook
Set DataWB = Workbooks.Open(File, xlUpdateLinksNever, True)
DataWB.Activate
'Catch missing input sheet
On Error Resume Next
Snr = 0
Snr = Sheets("2. Hours Reconciliation").Index
On Error GoTo 0
If Snr > 0 Then
Sheets(Snr).Copy After:=MasterWB.Sheets(1)
MasterWB.Activate
'Rename added sheet; use data wb name for now
End If
MasterWB.Activate
DataWB.Close False
End If
'Next file
File = Dir()
Wend
End Sub

Save outlook excel attachments and concatenate the data

I have a requirement that I am doing everyday and spending around 3 hours to do that. I would like it to be automated so that I can save time.
Every day I will get an email which contains around 100 attachments in *.msg format (Attachments are actually mails from different vendors).
In the *.msg files there will be one Excel file and this Excel file contains one line of data.
What I would like to do is Extract the first email attachments (which is in .Msg format) and extract the Excel file in each .Msg attachment and then copy the data from the XLS files into a new Excel file (Consolidating the data from each Excel attachment for calculations)!!
Can some one please provide a way to automate this process in vba macro and I would require detailed step as I am a newbie into the coding area.
This is as close as I can get to automating this using VBA. It's a semi-automatic solution that will require you to save the .msg attachments in a folder first and then open them all manually (i.e. select all, right-click one and chose Open). I tested this on 98 emails being opened at once, my Outlook slowed down a bit towards the end but it did not crash. The code itself takes under 3 minutes to complete the task.
But first, some assumptions were made based on the info provided:
All the .msg attachments are in one email message - if they are not, you may need to repeat step 1 as many times as necessary.
The Excel files inside the .msg files are in ".xls" format. If they are in ".xlsx" or other Excel format simply modify the relevant lines of code under Step 3.
You stated that the Excel files contain just 1 row of data - the below assumes it's row 1 in sheet 1. If not, the code will need to be adjusted slightly before it works.
Also, the solution ignores cell formatting in the Excel files - only the values from cells will be copied - this can be modified if needed.
You have some understanding of VBA, know how to insert module, compile, run and edit code in VB Editor - if not, just post your questions in a comment below, I'll be happy to help further.
The solution:
Step 1 - Save all the ".msg" attachments to a folder.
Step 2 - Select all emails in the folder and open them - this should open multiple Outlook inspector windows.
Step 3 - In Excel, activate VB Editor and paste the below code in a module:
Sub GetAttachments()
'loops through Outlook inspector windows extracting .xls attachments into a folder
Dim oShell As Object
Dim olApp As Object
Dim Insp As Object
Dim Att As Object
Dim FldPth As String
Dim myFname As String
Dim i As Long
Set olApp = CreateObject("Outlook.Application")
Set oShell = CreateObject("Shell.Application").BrowseForFolder(0, "Select Folder with attachments", 0)
If oShell Is Nothing Then MsgBox "Folder was not selected", vbCritical: Exit Sub
FldPth = oShell.self.Path
'loop through open outlook windows (inspectors)
'use reversed loop, otherwise every second iteration will be skipped
For i = olApp.Inspectors.Count To 1 Step -1
Set Insp = olApp.Inspectors.Item(i)
'loop through attachments in the email message
For Each Att In Insp.CurrentItem.Attachments
myFname = Att.Filename
'if the attached file is an xls type, save it in a folder
If LCase(Right(myFname, 4)) = ".xls" Then
Att.SaveAsFile FldPth & "\" & myFname
End If
Next Att
'close the inspector window
Insp.Close olDiscard
Next i
Set oShell = Nothing
Set olApp = Nothing
MsgBox "Done!"
End Sub
Sub GetDataFromWbks()
'loops through Excel files in selected folder extracting data from first row in sheet 1 into active worksheet
Dim oShell As Object
Dim FSO As Object
Dim f As Object
Dim srcWbk As Workbook
Dim dstWs As Worksheet
Dim srcRng As Range
Dim dstRng As Range
Dim FldPth As String
Dim i As Long
Set oShell = CreateObject("Shell.Application").BrowseForFolder(0, "Select Folder with attachments", 0)
If oShell Is Nothing Then MsgBox "Folder was not selected", vbCritical: Exit Sub
FldPth = oShell.self.Path
Set dstWs = ActiveSheet
Set dstRng = dstWs.Rows(1)
Set FSO = CreateObject("Scripting.FileSystemObject")
Application.ScreenUpdating = False
'loop through all files in folder
For Each f In FSO.GetFolder(FldPth).Files
If LCase(Right(f.Name, 4)) = ".xls" Then
'show progress in Excel's status bar
Application.StatusBar = i
'open xls file
Set srcWbk = Workbooks.Open(f.Path)
'set source range
Set srcRng = srcWbk.Sheets(1).UsedRange.Rows(1)
'copy source range to destination range
dstWs.Range(srcRng.Address).Offset(i).Value = srcRng.Value
i = i + 1
'close workbook
srcWbk.Close
End If
Next f
Application.ScreenUpdating = True
Application.StatusBar = False
Set FSO = Nothing
Set oShell = Nothing
MsgBox "Done!"
End Sub
Step 4 - Run the "GetAttachments" procedure. When prompted, select the folder you saved your attachments in. The procedure should extract all the Excel attachments from .msg files into the same folder.
Step 5 - Once done (PopUp box showed up), activate the Excel worksheet you want your data to be copied into (I suggest you use a new empty worksheet here) and run the "GetDataFromWbks" procedure - again, select your folder when prompted. You can watch the progress in Excel's status bar.
Step 6 - That's it, enjoy the saved time!

Get data from another excel file with not fixed worksheet name

I have a excel file that contain daily order id and I need to get some data from other excel use the order id as index. The source file contain many worksheet that means a listbox with sheet name for selection is required.
The workbook & worksheet used for data source is not fixed and will determine by user, so a listbox for user to select relevant worksheet is required
The workflow is when i call the vba at the daily excel file, a listbox with all sheet name of the source excel file will pop up for select worksheet, then the daily excel file will get data from the source excel base on the order id as index.
Now I have a vba using activeworkbook and activeworksheet to set the lookup range, but I don't think this is a good coding method. Could someone can give me some suggestion?
For the userform code if the strfile is set to an exact file the code is fine, but the source file may be change.
All source files are save in same location, the required source file name is in Range("Z1") of the daily excel file, is it possible the strfile can change base on Range("Z1")?
Please let me know if I can clarify anything for you.
Sub example()
Dim dest_wbk As Workbook
Dim dest_ws As Worksheet
Dim source_wbk As Workbook
Dim source_ws As Worksheet
Set dest_wbk = ThisWorkbook
Set dest_ws = dest_wbk.ActiveSheet
sourcefilename = Range("Z1")
UserForm1.Show
Set source_wbk = ActiveWorkbook
Set source_ws = source_wbk.ActiveSheet
sourcelastrow = source_ws.Cells(Rows.Count, 2).End(xlUp).Row
Set lookuprange = source_ws.Range("A2:E" & sourcelastrow)
dest_lastrow = dest_ws.Cells(Rows.Count, 4).End(xlUp).Row
For i = 2 To des_lastrow
ID = dest_ws.Range("D" & i)
dest_ws.Range("K" & i) = Application.VLookup(ID, lookuprange, 3, False)
dest_ws.Range("L" & i) = Application.VLookup(ID, lookuprange, 4, False)
Next i
source_wbk.Close
End Sub
'Below in the code in the userform
Private Sub ListBox1_Click()
Sheets(ListBox1.Value).Activate
Unload Me
End Sub
Private Sub UserForm_Initialize()
Dim sh As Worksheet
strfile = ("C:\Documents\" & sourcefilename)
Set wbk = Workbooks.Open(strfile, ReadOnly:=True)
For Each sh In wbk.Sheets
ListBox1.AddItem sh.Name
Next sh
End Sub
You need to change your two variables dest_wbk and dest_ws to something like
In case your destination Workbook is already open
'Change Workbook2.xls to whatever the file is (assuming it is open already)
Set dest_wbk = Workbooks("Workbook2.xls")
'Change SheetName to whatever the sheet name is inside dest_wbk
Set dest_ws = dest_wbk.Sheets("SheetName")
Otherwise, you need to open the workbook
'Change Workbook2.xls to whatever the file is
Set dest_wbk = Workbooks.Open("Workbook2.xls")
'Change SheetName to whatever the sheet name is inside dest_wbk
Set dest_ws = dest_wbk.Sheets("SheetName")
It is up to you, to get those values (Workbook name and Sheet name) from the UserForm, which I believe it shouldn't be a problem for you.

Excel VBA writes data to second workbook, but starts opening read-only versions because " _ is already open

I have some VBA script in one Excel Workbook that has three subs that each either read from a second Workbook. Each of the subs uses the following algorithm (simplified to distill the interaction with the second book):
Public Sub EditRemote()
Dim remoteDataSheet As Worksheet
Dim source As String 'Source worksheet name
Dim target As String 'Target worksheet name
Dim path As String
Dim wkbName As String
source = "CountData"
path = ThisWorkbook.Worksheets("Parameters").Range("B2").Value
wkbName = ThisWorkbook.Worksheets("Parameters").Range("A2").Value
target = "CountData"
Application.EnableCancelKey = xlDisabled
Set localDataSheet = ThisWorkbook.Sheets(source)
If Not WorkbookIsOpen(wkbName) Then
Workbooks.Open (path)
End If
Set remoteDataSheet = Workbooks(wkbName).Sheets(source)
remoteDataSheet.Cells(1,1) = localDataSheet.Cells(1,1)
remoteDataSheet.Cells(1,2) = localDataSheet.Cells(1,2)
Workbooks(wkbName).Close SaveChanges:=True
End Sub
Function WorkbookIsOpen(targetWorkbook As String) As Boolean
Dim testBook As Workbook
On Error Resume Next
Set testBook = Workbooks(targetWorkbook)
If Err.Number = 0 Then
WorkbookIsOpen = True
Else:
WorkbookIsOpen = False
End If
End Function
There is also a pivot table in this Workbook that draws its data from the second file though an external data connection as well. The issue that is plaguing me is that it seems that not initially but after a few operations, these subs stop making the edits properly and instead it opens a read only copy of the second Workbook. When I try to open the second workbook manually I get a message saying that the file is already open and is locked for editing. Right now both files are local to my computer and couldn't be opened by anyone else. What am I missing to be sure that I can make the code work as intended?
I made some modification to your code, ran it a few times, and didn't get your "Read-only" message.
In your code the line of declaring localDataSheet is missing, added Dim localDataSheet As Worksheet , also added Dim remoteWb As Workbook for the remote workbook.
(didn't modify your Funtion WorkbookIsOpen code).
Sub EditRemote Code
Option Explicit
Public Sub EditRemote()
Dim remoteDataSheet As Worksheet
Dim localDataSheet As Worksheet
Dim source As String 'Source worksheet name
Dim target As String 'Target worksheet name
Dim path As String
Dim wkbName As String
Dim remoteWb As Workbook
source = "CountData"
path = ThisWorkbook.Worksheets("Parameters").Range("B2").Value
wkbName = ThisWorkbook.Worksheets("Parameters").Range("A2").Value
target = "CountData"
Application.EnableCancelKey = xlDisabled
Set localDataSheet = ThisWorkbook.Sheets(source)
' check if workbbok already open
If Not WorkbookIsOpen(wkbName) Then
Set remoteWb = Workbooks.Open(path)
Else
Set remoteWb = Workbooks(wkbName) ' workbook is open >> set remoteWb accordingly
End If
Set remoteDataSheet = remoteWb.Sheets(source)
remoteDataSheet.Cells(1, 1) = localDataSheet.Cells(1, 1)
remoteDataSheet.Cells(1, 2) = localDataSheet.Cells(1, 2)
Workbooks(wkbName).Close SaveChanges:=True
End Sub
Just to verify the data in your Excel "Parameters" sheet, the screen-shot below shows the data I used for my testing.
Cell A2 contains the "Clean" workbook name.
Cell B2 contains workbbok "full" name - path + "clean" workbook name.
After some further testing to diagnose the issue, I found that there was nothing wrong with the VBA code, but rather the external data connection to the remote Workbook was locking that Workbook every time I refreshed the data in the pivot table that used the external data connection as its source. It isn't unlocking the file when it is done refreshing, and that leaves the file locked until I close the Workbook with the pivot table. Now I just need to solve that problem.

Run the same VBA macro on different excel files with a button on my custom Ribbon

I've created a VBA macro and need to perform the same tasks on multiple different files. Ideally i'd like to create a button on my Ribbon and execute the tasks with the click of a button. How do I make the macro available to multiple files and execute the tasks using the data from a newly opened worksheet? I've added the macro to a PERSONALS.xlsb file and can see the macro available every time I open Excel, but the macro only executes the tasks on the PERSONALS.xlsb file, not the newly opened file.
Sub Export_Files()
Dim sExportFolder, sFN
Dim rDiscription As Range
Dim rHTMLcode As Range
Dim oSh As Worksheet
Dim oFS As Object
Dim oTxt As Object
'sExportFolder = path to the folder you want to export to
'oSh = The sheet where your data is stored
sExportFolder = "C:\Users\bhinton\Desktop\ActionTags"
Set oSh = Sheet1
Set oFS = CreateObject("Scripting.Filesystemobject")
For Each rDiscription In oSh.UsedRange.Columns("C").Cells
Set rHTMLcode = rDiscription.Offset(, 6)
'Add .txt to the article name as a file name
sFN = rDiscription.Value & ".html"
Set oTxt = oFS.OpenTextFile(sExportFolder & "\" & sFN, 2, True)
oTxt.Write rHTMLcode.Value
oTxt.Close
Next
End Sub
Instead of
Set oSh = Sheet1
You need to use
Set oSh = ActiveSheet
Using ActiveSheet means that the code will use the newly opened workbook and the active sheet which I think is what you want.
Or if you always want Sheet1 of the currently active workbook, you can do this:
Set oSh = ActiveWorkbook.Worksheets("Sheet1")
Here's one way to prompt the user to select files then iterate through them:
Option Explicit
Sub OpenFilesAndIterate()
Dim DataDialog As FileDialog
Dim NumFiles As Long, Counter As Long
Dim MyWorkbook As Workbook
Dim MySheet As Worksheet
'prompt the user to select data files
Set DataDialog = Application.FileDialog(msoFileDialogOpen)
With DataDialog
.AllowMultiSelect = True
.Title = "Please pick the files you'd like to operate on:"
.ButtonName = ""
.Filters.Clear
.Filters.Add ".xlsx files", "*.xlsx"
.Show
End With
'assign the number of files selected for an easy loop boundary
NumFiles = DataDialog.SelectedItems.Count
'check to see if the user clicked cancel
If NumFiles = 0 Then Exit Sub
'Start looping through and do work
For Counter = 1 To NumFiles
Set MyWorkbook = Workbooks.Open(DataDialog.SelectedItems(Counter))
Set MySheet = MyWorkbook.Worksheets("Sheet1")
'
'insert your code to operate on worksheet here
'
MyWorkbook.Save
MyWorkbook.Close SaveChanges:=False
Next Counter
End Sub
In the options for Excel, click on Customize Ribbon. Above the list of things you can add there should be a dropdown box where you can select Macros. The list should then be populated with macros to add to your ribbon!