Excel VB - Shell object and Items extended properties - excel

First of all i'm not a VB geek, but I've found my way through googling around and I just can't figure out this one...
Put simply, I made a macro that allows me to select pdfs, zip them, and build a list of those zipped files on another sheet, then automatically prepares an email with that zip as an attachment. I want that list to contain the following entries:
The file name without the path, and without the extension (done and code works, though I've read that I may have issues if "hide extension of know file type" is activated, not tested);
Then each file name is hyperlinked to the actual file location before being zipped (done and code works);
The document title, which is an extended property (title metadata) of the pdf (WITHOUT having Acrobat installed, done and code works);
The document Tags (or Keywords?), again extended property of the pdf. It's this one that I need help with!. I browsed through office documentations and just can't find the info I need.
Like I said, I'm not a coder, I know my code is not optimal so please don't judge me. I just want it to work, then I'll optimize it ;)
To get the title property I use the following code :
Sheet1.Range("F54").Value = oShell.Namespace("FOLDERPATH").Items.Item("FILE IN FOLDERPATH).ExtendedProperty("DocTitle")
"DocTitle" is the property name for the title. I just can't find what it is to extract "Tags", I've tried "Tags", "DocTags" and "Keywords" and I got nothing. I've tried using GetDetailsOf("FILE", 18), but it returns the string "Tags", not the actual tags...like... the title of the tags...
Here is the full code :
Option Explicit
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
Sub ZipAndEmailFiles() 'By selecting individually
Dim CurDateTime As String
Dim DefaultFilePath As String
Dim FilesToZip As String
Dim oShell: Set oShell = CreateObject("Shell.Application")
Dim FileCount As Long
Dim FileNumb As Integer
Dim LastZipNumb As Integer
Dim FileNames As Variant
Dim VArr As Variant
Dim ZipFileName As Variant
Dim ProjectNumb As String
LastZipNumb = Main.Range("C13").Value 'Get last qty of file(s) zipped
CurDateTime = Format(Now, "yyyy-mmm-dd h-mm-ss") 'Get actual date and time
DefaultFilePath = Application.DefaultFilePath
If Right(DefaultFilePath, 1) <> "\" Then DefaultFilePath = DefaultFilePath & "\"
ProjectNumb = Main.Range("C4").Value 'Get project number (Entry by user)
ZipFileName = DefaultFilePath & ProjectNumb & "-" & CurDateTime & ".zip" 'Name of zip
'Browse For Files & Select Multiple files
FileNames = Application.GetOpenFilename("PDF Files (*.pdf),*.pdf", MultiSelect:=True, Title:="Select Files you want to Zip & Email")
If IsArray(FileNames) = False Then Exit Sub
'Create Empty Zipped File in DefaultFilePath
If Len(Dir(ZipFileName)) > 0 Then Kill ZipFileName
Open ZipFileName For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1
FileNumb = 0
'Clear cells from previous list
For FileCount = 1 To LastZipNumb
FileNumb = FileNumb + 1
ThisWorkbook.Worksheets("Transmittal").Range("B54:F54").Offset(2 * (FileNumb - 1), 0).Clear
Next
FileNumb = 0
'Build list & Fill zip
For FileCount = LBound(FileNames) To UBound(FileNames)
FileNumb = FileNumb + 1
'Insert name of each processed file, removing path, revision and extension
Transmittal.Range("B54").Offset(2 * (FileNumb - 1), 0).Value = Left(GetFilenameFromPath(FileNames(FileNumb)), 12)
'Create hyperlink to reference file being zipped
ActiveSheet.Hyperlinks.Add Transmittal.Range("B54").Offset(2 * (FileNumb - 1), 0), FileNames(FileNumb)
'Inscrire le titre dans la case indiquée
'Transmittal.Range("F54").Offset(2 * (FileNumb - 1), 0).Value = oShell.Namespace(FolderFromPath(FileNames(FileNumb))).GetDetailsOf(FileNameFromPath(FileNames(FileNumb)), FileNumb)
Transmittal.Range("D54").Offset(2 * (FileNumb - 1), 0).Value = oShell.Namespace(FolderFromPath(FileNames(FileNumb))).Items.Item(FileNameFromPath(FileNames(FileNumb))).ExtendedProperty("Keywords")
Transmittal.Range("F54").Offset(2 * (FileNumb - 1), 0).Value = oShell.Namespace(FolderFromPath(FileNames(FileNumb))).Items.Item(FileNameFromPath(FileNames(FileNumb))).ExtendedProperty("DocTitle")
'Copy said file in zip
oShell.Namespace(ZipFileName).CopyHere FileNames(FileCount)
'Keep Script waiting until compressing is done
On Error Resume Next
Do Until oShell.Namespace(ZipFileName).Items.Count = FileNumb
Sleep (100) 'Wait 100ms after each copied file
Loop
On Error GoTo 0
Next FileCount
Main.Range("C22").Value = ZipFileName 'Place zip location, to be attached to email
Main.Range("C13").Value = UBound(FileNames)
EmailZipFile
End Sub
Sub EmailZipFile()
Dim OutApp As Object
Dim OutEmail As Object
Set OutApp = CreateObject("Outlook.application")
Set OutEmail = OutApp.CreateItem(0)
With OutEmail
.To = Main.Range("C13").Value ' Email
If Main.Range("C16").Value <> "" Then .Attachments.Add Main.Range("C16").Value 'Zipped file
.Subject = Main.Range("C15").Value 'Email subject
.Body = Main.Range("C17").Value 'Email body
.Display 'Show Outlook windows
End With
End Sub
Function FileNameFromPath(ByVal strPath As String) As String
FileNameFromPath = Right(strPath, Len(strPath) - InStrRev(strPath, "\"))
End Function
Function FolderFromPath(ByVal strPath As String) As String
FolderFromPath = Left(strPath, InStrRev(strPath, "\"))
End Function
For the code to fully work, you have to have Outlook installed. But even without Outlook, the list generation works. Thanks for your help, and your time!

Related

Enhancing the macro

I want to improve my Excel VBA macro that creates the file list and the macro that renames the file name on the file list.
I made two Excel VBA macros. The macro named "Sub File_list" creates a file list in a folder where the xls file is stored and, The macro named "Sub Re_name" renames files using the file list. However, these macros cannot handle files in subfolders.These macros are show below, you can download the macro from this link.
【My Questions】
I want the "Sub File_list" to have the ability to list files in subfolders.
I want these "Sub Re_name" to have the ability to rename files in subfolders.(The renamed file shall stored in the same file as the original file.)
Assume that the files and folders shown in FIG. 1 are stored in the folders.
The "File_mng.xls" is the excel file that consists these macros.
Fig.1
At this time, when the "Sub File_list" is executed, all files stored in the same level (except "File_mng.xls" itself) are displayed on the spreadsheet (See Fig.2). However, sub folders and the files stored in that sub folders are not listed.
Fig.2
Note that, the backslash is garbled into the Yen sign because My Windows10 is Japanese version.
【The macros】
You can also download the macro from this link.
'Create a list of files in a specific folder
Sub File_list()
Dim myFileName As String
Dim FSO As Object
Dim cnt
myDir = ThisWorkbook.Path
myDir = myDir & "\"
Set FSO = CreateObject("Scripting.FileSystemObject")
cnt = FSO.GetFolder(myDir).Files.Count
Range("A1").Value = "File name (Number of files " & cnt & ")"
'Show hidden and system files
myFileName = Dir(myDir & "*", vbHidden + vbSystem)
While myFileName <> vbNullString
If myFileName <> ThisWorkbook.Name Then
Cells(Rows.Count, 1).End(xlUp).Offset(1).Value _
= myDir
Cells(Rows.Count, 2).End(xlUp).Offset(1).Value _
= myFileName
End If
myFileName = Dir()
Wend
Columns(1).AutoFit
Application.ScreenUpdating = True
End Sub
'Renames files using the file list
Sub Re_name()
myDir = ThisWorkbook.Path
Nmax = (ActiveSheet.Range("A1").End(xlDown).Row)
For n = 2 To Nmax
yenn = ""
If (Right(Cells(n, 1), 1) <> "\") Then
yenn = "\"
End If
N1 = Cells(n, 1) & yenn & Cells(n, 2)
N2 = Cells(n, 3) & Cells(n, 4) & Cells(n, 5) & Cells(n, 6)
If N2 = "" Then
N2 = N1
Else
N2 = myDir & "\" & N2
End If
Name N1 As N2
Next n
End Sub
P.S. I'm not very good at English, so I'm sorry if I have some impolite or unclear expressions. I welcome any corrections and English review. (You can edit my question and description to improve them)
You can download all related files from here.
Post hoc Note: (Added on 2019/12/15(JST))
【Comment on the trust settings for PASUMPON V N's macro 】
Thanks to the contributions of PASUMPON V N, I get a complete solution.
You can download a modified version so that it lists files based on the folder where the macro is.
(I modified HostFolder = "C:\User\" to HostFolder = ThisWorkbook.Path )
Running this macro, I came across one error, 'Error 1004: Programmatic access to Visual Basic Project is not trusted' at the line of ".VBProject.References". But It is solved by security settings of excel.
The setting method may depend on version and language
For the Japanese version, if you come across the following error, this site(but written in Japanese) might be helpful. What I actually tried was the procedure written in this site.
"プログラミングによる visual basic プロジェクトへのアクセスは信頼性に欠けます 1004"(that means "'Error 1004: Programmatic access to Visual Basic Project is not trusted")
For the English version,here or here might be helpful if you come across the Error 1004.
Hi I have modified the code for your requirement, could you please let me know if it is fine
i have used below code , for recursive type programming
Loop Through All Subfolders Using VBA
Sub sample()
Dim FileSystem As Object
Dim HostFolder As String
Dim Ref As Object, CheckRefEnabled%
CheckRefEnabled = 0
With ThisWorkbook
For Each Ref In .VBProject.References
If Ref.Name = "Scripting" Then
CheckRefEnabled = 1
Exit For
End If
Next Ref
If CheckRefEnabled = 0 Then
.VBProject.References.AddFromGUID "{420B2830-E718-11CF-893D-00A0C9054228}", 1, 0
End If
End With
HostFolder = "C:\User\"
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
End Sub
Sub DoFolder(Folder)
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Sheet1")
Dim LastRow As Long
Dim SubFolder
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
Dim File
For Each myFile In Folder.Files
Debug.Print myFile
Debug.Print Folder.Name
Debug.Print myFile.Name
With ws
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
i = LastRow + 1
ws.Cells(i, 1) = myFile.Path
ws.Cells(i, 2) = Folder.Name
ws.Cells(i, 3) = myFile.Name
Next
End Sub

Protecting Excel worksheets - Impossible?

I'm trying to share an Excel workbook, but with limited access to only a couple of visible sheets. This have proven to be much harder than first anticipated due to security loopholes with Excel and password protection of worksheets.
My problem arises due to some hidden sheets that needs to stay hidden and the contents inaccessible, but are required for calculations were the result is shown in the visible sheets.
So far I have tried to "super hide" the sheets in the VBA window and lock the VBA project. The idea is that the user then can't unhide the "super hidden" sheets without the VBA project password.
I have tried to add additional VBA code to counter certain "attacks", but I keep coming back to a known flaw that circumvents all my efforts:
Step 1:
Save or make sure that the Excel workbook is saved as .xlsx or .xlsm
Step 2:
Run the following code from a different workbook or your personal.xlsb that removes passwords from sheets and structure protection
(I would have linked to the post where I found the code, but I can't find it right now...).
Sub RemoveProtection()
Dim dialogBox As FileDialog
Dim sourceFullName As String
Dim sourceFilePath As String
Dim SourceFileName As String
Dim sourceFileType As String
Dim newFileName As Variant
Dim tempFileName As String
Dim zipFilePath As Variant
Dim oApp As Object
Dim FSO As Object
Dim xmlSheetFile As String
Dim xmlFile As Integer
Dim xmlFileContent As String
Dim xmlStartProtectionCode As Double
Dim xmlEndProtectionCode As Double
Dim xmlProtectionString As String
'Open dialog box to select a file
Set dialogBox = Application.FileDialog(msoFileDialogFilePicker)
dialogBox.AllowMultiSelect = False
dialogBox.Title = "Select file to remove protection from"
If dialogBox.show = -1 Then
sourceFullName = dialogBox.SelectedItems(1)
Else
Exit Sub
End If
'Get folder path, file type and file name from the sourceFullName
sourceFilePath = Left(sourceFullName, InStrRev(sourceFullName, "\"))
sourceFileType = Mid(sourceFullName, InStrRev(sourceFullName, ".") + 1)
SourceFileName = Mid(sourceFullName, Len(sourceFilePath) + 1)
SourceFileName = Left(SourceFileName, InStrRev(SourceFileName, ".") - 1)
'Use the date and time to create a unique file name
tempFileName = "Temp" & Format(Now, " dd-mmm-yy h-mm-ss")
'Copy and rename original file to a zip file with a unique name
newFileName = sourceFilePath & tempFileName & ".zip"
On Error Resume Next
FileCopy sourceFullName, newFileName
If Err.Number <> 0 Then
MsgBox "Unable to copy " & sourceFullName & vbNewLine _
& "Check the file is closed and try again"
Exit Sub
End If
On Error GoTo 0
'Create folder to unzip to
zipFilePath = sourceFilePath & tempFileName & "\"
MkDir zipFilePath
'Extract the files into the newly created folder
Set oApp = CreateObject("Shell.Application")
oApp.Namespace(zipFilePath).CopyHere oApp.Namespace(newFileName).Items
'loop through each file in the \xl\worksheets folder of the unzipped file
xmlSheetFile = Dir(zipFilePath & "\xl\worksheets\*.xml*")
Do While xmlSheetFile <> ""
'Read text of the file to a variable
xmlFile = FreeFile
Open zipFilePath & "xl\worksheets\" & xmlSheetFile For Input As xmlFile
xmlFileContent = Input(LOF(xmlFile), xmlFile)
Close xmlFile
'Manipulate the text in the file
xmlStartProtectionCode = 0
xmlStartProtectionCode = InStr(1, xmlFileContent, "<sheetProtection")
If xmlStartProtectionCode > 0 Then
xmlEndProtectionCode = InStr(xmlStartProtectionCode, _
xmlFileContent, "/>") + 2 '"/>" is 2 characters long
xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
xmlEndProtectionCode - xmlStartProtectionCode)
xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")
End If
'Output the text of the variable to the file
xmlFile = FreeFile
Open zipFilePath & "xl\worksheets\" & xmlSheetFile For Output As xmlFile
Print #xmlFile, xmlFileContent
Close xmlFile
'Loop to next xmlFile in directory
xmlSheetFile = Dir
Loop
'Read text of the xl\workbook.xml file to a variable
xmlFile = FreeFile
Open zipFilePath & "xl\workbook.xml" For Input As xmlFile
xmlFileContent = Input(LOF(xmlFile), xmlFile)
Close xmlFile
'Manipulate the text in the file to remove the workbook protection
xmlStartProtectionCode = 0
xmlStartProtectionCode = InStr(1, xmlFileContent, "<workbookProtection")
If xmlStartProtectionCode > 0 Then
xmlEndProtectionCode = InStr(xmlStartProtectionCode, _
xmlFileContent, "/>") + 2 ''"/>" is 2 characters long
xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
xmlEndProtectionCode - xmlStartProtectionCode)
xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")
End If
'Manipulate the text in the file to remove the modify password
xmlStartProtectionCode = 0
xmlStartProtectionCode = InStr(1, xmlFileContent, "<fileSharing")
If xmlStartProtectionCode > 0 Then
xmlEndProtectionCode = InStr(xmlStartProtectionCode, xmlFileContent, _
"/>") + 2 ''"/>" is 2 characters long
xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
xmlEndProtectionCode - xmlStartProtectionCode)
xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")
End If
'Output the text of the variable to the file
xmlFile = FreeFile
Open zipFilePath & "xl\workbook.xml" & xmlSheetFile For Output As xmlFile
Print #xmlFile, xmlFileContent
Close xmlFile
'Create empty Zip File
Open sourceFilePath & tempFileName & ".zip" For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1
'Move files into the zip file
oApp.Namespace(sourceFilePath & tempFileName & ".zip").CopyHere _
oApp.Namespace(zipFilePath).Items
'Keep script waiting until Compressing is done
On Error Resume Next
Do Until oApp.Namespace(sourceFilePath & tempFileName & ".zip").Items.count = _
oApp.Namespace(zipFilePath).Items.count
Application.Wait (Now + TimeValue("0:00:01"))
Loop
On Error GoTo 0
'Delete the files & folders created during the sub
Set FSO = CreateObject("scripting.filesystemobject")
FSO.deletefolder sourceFilePath & tempFileName
'Rename the final file back to an xlsx file
Name sourceFilePath & tempFileName & ".zip" As sourceFilePath & SourceFileName _
& "_" & Format(Now, "dd-mmm-yy h-mm-ss") & "." & sourceFileType
'Show message box
MsgBox "The workbook and worksheet protection passwords have been removed.", _
vbInformation + vbOKOnly, Title:="Password protection"
End Sub
Step 3:
Run the following code to unhide all sheets
Sub UnhideAllSheets()
For Each Worksheet In ActiveWorkbook.Sheets
Worksheet.Visible = -1
Next Worksheet
End Sub
The workbook is now clean of passwords on sheets and structure protection, and any "counter" VBA code is gone by saving the workbook as a .xlsx file.
I have thought about adding a user-defined function that checks if the extension of the workbook file is ".xlsb". The function would return "1" if the extension is ".xlsb" and then multiplying it on something important. This would cause the calculations to fail if the workbook is saved as something else, or if the VBA project is entirely removed to saving as .xlsx.
However, I do not like this approach as I don't think it is a long-term solution...
My question is therefore:
Is there a way to securely share an Excel workbook with only access to a couple of sheets without risking the user can access hidden sheets and/or unwanted contents?
In the VBE you can change the Visible property of a specific sheet to xlSheetVeryHidden.
This will remove it from the front end completely.
You can then add a password to protect the VBA project in the VBE to prevent a user from changing that property (if they even know about it).
Additionally, you will still be able to access these sheets with your VBA code.
EDIT:
What I also add to the above is a password to the specific sheet, as normal. But also a custom UserForm the UserForm gets triggered on the Worksheet_Activate event if they had to unhide it. If they enter the incorrect password or close the UserForm the sheet gets hidden away again. You can add all sorts to this event handler such as reprotect the worksheet, reprotect the project, protect the workbook with an encrypted password and close the workbook as a "breach" in security.
The possibilities are endless. Not an exact prevention, but hopefully this helps.

VBE macro that creates shortcuts which include the autor of the linked file as property

this is my first question so I would love to improve my style and such. Just tell me if I am doing something completely wrong.
My question:
I am searching files with a specific extensions. All results get printed to excel and then create shortcuts to each file which get then stored in a folder. This works perfectly fine for now, but I need the shortcut to include the author detail to filter all entries (hundreds to thousends) for it.
The result should be a shortcut with the same properties that you get when using the 'create shortcut' from context menu vie right click.
I hope you can help my since I am trying to get this to work for a while now.
If you know a solution, that does what I need but is maybe written in a different language that is fine for me as long as the user does not have to install runtimes/libraries (sory I am a complete beginner)
My code:
'This function searches for files with endings (ppt,pptx,pptm) and pastes the found entries into the excel sheet
Function Recurse(sPath As String) As String
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim mySubFolder As Folder
Dim myFile As File
Set myFolder = FSO.GetFolder(sPath)
Set Extensions = CreateObject("Scripting.Dictionary")
Extensions.CompareMode = 1 ' make lookups case-insensitive
'Extensions.Add Range("C5").Value, True
Extensions.Add "pptx", True
Extensions.Add "ppt", True
Extensions.Add "pptm", True
For Each mySubFolder In myFolder.SubFolders
For Each myFile In mySubFolder.Files
'
i = Range("D4").Value
If Extensions.Exists(FSO.GetExtensionName(myFile)) Then
Cells(8 + i, 3).Value = myFile.Name
Cells(8 + i, 4).Value = myFile.Path
i = i + 1
Range("D4").Value = i 'storing number of entrys found
'Exit For
End If
Next
Recurse = Recurse(mySubFolder.Path)
Next
End Function
'This Function creates a folder with the name "A1" if it does not exist already
Function PathExist(ByVal vPfadName As String) As Boolean
scutPath = Application.ActiveWorkbook.Path & "\" & Range("A1").Value
On Error GoTo ErrorPathExist
ChDir (vPfadName)
PathExist = True
Exit Function
ErrorPathExist:
MkDir scutPath
End Function
'Main Function that clears table and uses the found entries to get create shortcuts. Unfortunately the author is not integrated when doing it this way. The author is necessary to filter through hundreds of results.
Sub TestR()
Range("B8:C999999") = ""
Range("D4").Value = 0
Call Recurse(Application.ActiveWorkbook.Path)
i = 1
scutPath = Application.ActiveWorkbook.Path & "\" & Range("A1").Value
Call PathExist(scutPath)
For i = 1 To 200 '(last line)
Set oWSH = CreateObject("WScript.Shell")
Set oShortcut = oWSH.CreateShortCut(scutPath & "\" & Cells(7 + i, 3).Value & ".lnk")
With oShortcut
.TargetPath = Cells(7 + i, 4).Value
.Save
End With
Set oWSH = Nothing
Next i
MsgBox "Done"
End Sub

VBA to save attachments (based on defined criteria) from an email with multiple accounts

Situation: I have a code that, given an input of sender email, will download all attachments from outlook email (if the sender is the one specified, it saves the .xls attachments).
Problem 1: In my outlook, I have access to 2 accounts (lets say personal and public). I want to be able to select from which of those accounts the code should download the attachments.
Question 1: Is it possible to do this kind of selection? From previous research I was able to find criteria regarding the type of attachments, and more, but nothing regarding multiple inboxes.
Problem 2: Among the attachments in this second inbox (public) I want to select only the files which have a worksheet with a certain "NAME". I know how to do an if to account for that, but don't know if its possible to read the file (and check if it has the wanted sheet) and only then download it.
Question 2: Could I access a file like this? Would it be possible to do this kind of criteria check?
Code so far:
Sub email()
Application.ScreenUpdating = False
On Error Resume Next
Dim olApp As New Outlook.Application
Dim olNameSpace As Object
Dim olMailItem As Outlook.MailItem
Dim olFolder As Object
Dim olFolderName As String
Dim olAtt As Outlook.Attachments
Dim strName As String
Dim sPath As String
Dim i As Long
Dim j As Integer
Dim olSubject As String
Dim olSender As String
Dim sh As Worksheet
Dim LastRow As Integer
ThisWorkbook.Worksheets("FileNames").Rows(2 & ":" & ThisWorkbook.Worksheets("FileNames").Rows.count).Delete
olFolderName = ThisWorkbook.Worksheets("Control").Range("D10")
olSender = ThisWorkbook.Worksheets("Control").Range("D16")
sPath = Application.FileDialog(msoFileDialogFolderPicker).Show
sPathstr = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems(1)
Set olNameSpace = olApp.GetNamespace("MAPI")
'check if folder is subfolder or not and choose olFolder accordingly
Set olFolder = olNameSpace.GetDefaultFolder(olFolderInbox).Folders(olFolderName)
If (olFolder = "") Then
Set olFolder = olNameSpace.GetDefaultFolder(olFolderInbox).Parent.Folders(olFolderName)
End If
'loop through mails
h = 2
For i = 1 To olFolder.Items.count
Set olMailItem = olFolder.Items(i)
If (InStr(1, olMailItem.SenderEmailAddress, olSender, vbTextCompare) <> 0) Then
With olMailItem
'loop through attachments
For j = 1 To .Attachments.count
strName = .Attachments.Item(j).DisplayName
'check if file already exists
If Not Dir(sPathstr & "\" & strName) = "" Then
.Attachments(j).SaveAsFile sPathstr & "\" & "(1)" & strName
ThisWorkbook.Worksheets("FileNames").Range("A" & h) = "(1)" & strName
Else
.Attachments(j).SaveAsFile sPathstr & "\" & strName
ThisWorkbook.Worksheets("FileNames").Range("A" & h) = strName
End If
h = h + 1
Next
End With
End If
Next
Application.ScreenUpdating = True
MsgBox "Download complete!", vbInformation + vbOKOnly, "Done"
End Sub
Every folder in Outlook has a unique path. Even if they're both called Inbox, the path to them is different. Select the first Inbox in Outlook and go to the Immediate Window (Alt+F11 then Ctrl+G). Type this and press enter
?application.ActiveExplorer.CurrentFolder.FolderPath
You'll get something like
\\dkusleika#copmany.com\Inbox
Now go back to Outlook and select the other Inbox. Return to the Immediate Window and execute the same command. Now you'll have the path to each Inbox. Maybe the second one looks like
\\DKPersonal\Inbox
You use GetDefaultFolder, which is very handy. But you can get to any folder, even default folders, by following their path directly.
Set olFolder = Application.GetNamespace("MAPI").Folders("dkusleika#company.com").Folders("Inbox")
Just chain Folders properties together until you get to the one you want.
As for Question 2, you can't inspect an Excel file without opening it. You'll have to download it to a temporary location, open it to see if it contains the worksheet, and move it to the final location if it does. Or download it to the final location and delete it if it doesn't have the sheet.

importing from an external souce where source filename changes

Forgive me if this is an easy problem, Im still learning..
I have an excel file, that takes data and performs analytics to compose graphs. right now method to update is manual copying and pasting from 2 other data sources. I can easily create a macro to import the first source as the data location/file name is always the same. The second source is trickier, as the file has some standardized naming convention, but a date is added, as it is refreshed once a week, every Monday or tuesday. is there a way to automate pulling the data from the external source (sharepoint library) and telling it to find the most current version? either by understanding the date convention added in the file name, or by another means of modified date or other criteria? the file is kept with previous archived copies. I do not own the report, sharepoint site, or library it is kept in, so I cant influence those factors :(. any help appreciated, and I can provide better details and explanation.
There are two basic approaches that I know of, either allow the user to choose the file through a dialog box, or use the "Dir" function to find the file with the most recent date.
First approach (code I use frequently):
Public Function ChooseOpenFile() As String
Dim strSlash As String
If InStr(1, ActiveWorkbook.Path, "/") > 0 Then
strSlash = "/"
Else
strSlash = "\"
End If
With Application.FileDialog(msoFileDialogOpen)
.Title = "Select the first file to open in series:"
.InitialFileName = Replace(ActiveWorkbook.Path, "http:", "", 1) & strSlash
Call .Filters.Clear
Call .Filters.Add("Excel Files Only", "*.xls, *.xlsx, *.xlsb")
'only allow the user to select one file
.AllowMultiSelect = False
'make the file dialog visible to the user
intChoice = .Show
'determine what choice the user made
If intChoice <> 0 Then
'get the file path selected by the user
ChooseOpenFile = .SelectedItems(1)
End If
End With
End Function
As for the second approach, as long as you can already access the folder programmatically, you build a loop to cycle through the files, extract the date from each file, test for being more recent than previous versions and store the filename of the most recent version to pass out of the loop.
Function MostRecentFile() As String
Dim dateTest As Date
Dim dateRecent As Date
Dim strMyFile As String
Dim strMyFolder As String
Dim strCurrentFile As String
Dim strSlash As String
strMyFolder = ThisWorkbook.Path
If InStr(1, strMyFolder, "/") > 0 Then
strSlash = "/"
Else
strSlash = "\"
End If
strMyFile = Dir(Replace(strMyFolder, "http:", "") & strSlash & "*.xls*")
Do While strMyFile <> ""
'Modify this line (number of characters and extension to replace) as needed.
dateTest = CDate(Replace(Right(strMyFile, 15), ".xls*", ""))
If dateTest > dateRecent Then
dateRecent = dateTest
strCurrentFile = strMyFile
End If
Stop
Dir
Loop
MostRecentFile = strCurrentFile
End Function
You can browse to the file.
Sub GetOpenFile()
Dim fileStr As String
fileStr = Application.GetOpenFilename()
If fileStr = "False" Then Exit Sub
Workbooks.Open fileStr
End Sub
If you want some kind of automated solution, based on your system date, like the next Monday ot Tuesday, you can get the machine to figure it out, and pass the result to the appropriate string in the file path.
Sub NameAsNextMon()
Dim K As Integer
Dim dteMon As Date
Dim tempName As Variant
K = Weekday(Now)
dteMon = Now() + (9 - K)
tempName = Year(dteMon) & "-" & Month(dteMon) & "-" & Day(dteMon) & ".xls"
Do
fName = Application.GetSaveAsFilename(tempName)
Loop Until fName <> False
ActiveWorkbook.SaveAs Filename:=fName
End Sub

Resources