FileCopy in Access with wildcards - vba

I am having a heck of a time with something that I think should be so very simple. I think age is getting to me.
All I want to do is in access, run a command that would mimic the following DOS command:
copy c:\1\ABC123-*.txt c:\1\ABC456-*.txt
It seems that filecopy does not support wildcards and for the life of me fso.copyfile just wont work (probably because I am dense). I have also tried to use the copy command using shell and cant get that to work.
To be a little clearer:
The database keeps track of parcels of land. These are "owned" by a land company. On occasion, these parcels are sold from one land company to another. When that happens we have to keep the old records and the new, so the parcel is "copied" to the new land company complete with all its payment history, etc. There are physical documents attached to that record too, and these must appear in BOTH places. I need to copy those PDF files from one parcel number to another (I already have code that duplicates the document entries in the database, I just need to fix the physical files).
So, as an example, parcel 1234 may have a deed, a latenotice, and a survey. Those files would exist as something like 1234-deed.pdf, 1234-latenotice.pdf, and 1234-survey.pdf. I need those files copied to 5678-deed.pdf, 5678-latenotice.pdf, and 5678-survey.pdf after the rest of the database copy code runs.
I need something simple, it only needs to run in that one part of the database so I do not need it to be extensible, or to create a new function, or whatever.
Thanks!

Add reference to "Microsoft Scripting Runtime".
Give this a try:
Dim F As File
Dim FSO As New FileSystemObject
Dim FromPath As String
Dim ToPath As String
FromPath = "C:\1"
ToPath = "C:\1"
Debug.Print FSO.GetFolder(FromPath).Files.Count
For Each F In FSO.GetFolder(FromPath).Files
If Instr(F.Name,"ABC123-") Then
FileCopy FromPath & "\" & F.Name, ToPath & "\" & Replace(F.Name, "123", "456")
End If
Next

Related

How to use the relative path in SQL - ODBC?

I have a problem with Excel (ODBC / Access). I would like to refresh data from any folder in my computer. I have file which I use from Desktop, but I would like to refresh data from the same file when it will be move to documents, etc. Please could you provide what I should do?
I have a file connection as below:
DSN=Excel Files;DBQ=C:\Users\User\Desktop\Task1\SalesBudget2018.xlsx;DefaultDir=C:\Users\User\Desktop\Task1;DriverId=1046;MaxBufferSize=2048;PageTimeout=5;
Thank you.
EDIT1: Thank you. I tried use your solution and I received error: "run time error 2147467259 Database or object is read-only", my code below. The bug is related to ".Open" line:
Sub RefreshData()
Dim CreateNew As Object
Dim RunSELECT As Object
Dim Data As String
Dim SQL As String
FolderPath = ActiveWorkbook.path
Path = Left(FolderPath, InStrRev(FolderPath, "\") - 1)
Set CreateNew = CreateObject("ADODB.Connection")
With CreateNew
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & Path & "\SalesBudget2018.xlsx" & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES;"";"
.Open
End With
'Run SQL
SQL = "SELECT * FROM [twRynki$]"
Set RunSELECT = cn.Execute(SQL)
Do
output = output & RunSELECT(0) & ";" & RunSELECT(1) & ";" & RunSELECT(2) & vbNewLine
Debug.Print RunSELECT(0); ";" & RunSELECT(1) & ";" & RunSELECT(2)
rs.Movenext
Loop Until rs.EOF
End Sub
Your path actually is not relative at all. But ACE/JET data engine does not support relative paths anyway.
A relative path would be
\Data\mydb.mdb
So, above would be one folder up called data from current location. And one folder down using relative would be:
..\Data\mydb.mdb
However, with ACE/Access relative paths are not supported. However, what we do when we want software to work say from the current folder? We simple get and use the full path name ON APPLICATION start up. So, you can get/grab the current folder. In Excel VBA you can use this:
ActiveWorkbook.Path
So above will give you the current path. And thus you use that in code to set the connection string. So, even in access, if we want the software to work in any folder? We simply get/grab the full path name on startup. As a result, the software works in any folder and you effective get relative address in that you "don't care" where the software is placed, since you always get/grab the full path name anyway. So, with above, you could append a folder name called data
ActiveWorkbook.Path & "\Data\Mydb.accdb"
So, from the current workbook location, you could always have a folder called data, and inside that folder you can have your database. So, in effect you do get relative addressing, but you always pulling the full path name of the current workbook as per above.
The end result is you don't miss not having some form of relative addressing since you don't need to with this approach.
The above is for Excel VBA. To get current path from Access VBA? You can use this:
currentproject.Path
So, your connection string to Excel could be this:
dim strExcelPath as string
strExcelPath = CurrentProject.Path & "\Task1\SalesBudget2018.xlsx"
It not clear if the access application is in the SAME folder as task1?
Assuming yes, then this would work:
strExcelPath = CurrentProject.Path & "\SalesBudget2018.xlsx"
So, now the folder can be on the desktop, my documents - it will not matter. You can thus use above as part of your connection string. It not clear if you linking to Excel (linked table), or you using VBA and say ADO code. However, it really don't matter. On application startup, you get the above connection string, check it against the linked table -- if same then do nothing. If different, then you re-link that one table. Thus you ONLY re-link one time if the folder been moved. And no matter where you move the folder? As long as you assume the Excel sheet is in the same folder as the access app, then you good to go. And as noted, you could add a sub folder say ExcelSheets to above. And once again, no matter where you move this folder with the Access part, as long as the sub folder is in the same dir/folder, then this will work - despite you not having relative addressing.

Bulk rename Outlook Folders using replace strings

I'm now tasked with a massive project to import and reorganize about 50 outlook pst archives (probably around 100-200GB) into a single library account for my freight forwarding company.
I'm using a Windows 10 Pro computer with Office 365 Business Premium installed on the local machine and Outlook is using a current "Exchange Online" version 15.20.xxxx.xx so everything is available in the cloud.
The importing of archives isn't a problem.
My problem is having to rename several thousand outlook folders so they are organized!
End Goal is to have all email folders renamed starting with the full file number our company software set for this shipment:
CHI-AE0xxxxx (air export)
CHI-AI0xxxxx (air import)
CHI-OE0xxxxx (ocean export)
CHI-OI0xxxxx (ocean import)
CHI-DO0xxxxx (domestic)
where the x's are numeric and must now be 6 numbers
Until now, there was no naming structure, so everyone uses whatever made sense in their personal brain. Here's some examples:
CHOIxxxxx
CHOI0xxxxx
CHIOIxxxxx
CHIOI0xxxxx
or just xxxxx (I'll know what prefix needs to get attached to this person's folders)
So basically what I'm wanting to do is replace "CHOI" or "CHIOI" with "CHI-OI" and then if there's 5 digits, turn it into 6 digits with a leading 0.
I'm very experienced with Excel VBA and Macros.
I'm pretty good at using Powershell with Excel and SQL Server Databases.
I have no experience with Outlook and/or attempts to manipulate it with external tools like VBA or Powershell, but I'm willing to learn!
Turns out Outlook VBA was the way to go for this task.
I finally found a great answer yesterday:
https://www.datanumen.com/blogs/batch-find-replace-specific-words-outlook-folder-names/
I had to modify the code a little by replacing:
Set objFolders = Outlook.Application.Session.Folders("Personal").Folders
With this so it searches / modifies only the subfolders within the folder I currently have selected:
Set objFolders = Outlook.Application.ActiveExplorer.CurrentFolder.Folders
Here's the (almost) finished code:
Public strFind, strReplace As String
Sub FindReplaceWordsinFolderNames()
Dim objFolders As Outlook.Folders
Dim objFolder As Outlook.Folder
Set objFolders = Application.ActiveExplorer.CurrentFolder.Folders
'You need to input the specific words for find and replace
strFind = InputBox("Enter the specific words you want to change.")
strReplace = InputBox("Enter the specific words you want to change to. (Case Sensitive)")
For Each objFolder In objFolders
Call ProcessFolders(objFolder)
Next
MsgBox "Complete!", vbExclamation, "Rename Folders"
End Sub
Private Sub ProcessFolders(ByVal objCurrentFolder As Outlook.Folder)
Dim objSubfolder As Outlook.Folder
On Error Resume Next
If InStr(LCase(objCurrentFolder.Name), LCase(strFind)) > 0 Then
'Find and replace the specific words
objCurrentFolder.Name = Replace(LCase(objCurrentFolder.Name), LCase(strFind), strReplace)
End If
'Process all folders recursively
If objCurrentFolder.Folders.Count > 0 Then
For Each objSubfolder In objCurrentFolder.Folders
Call ProcessFolders(objSubfolder)
Next
End If
End Sub
It doesn't have any error checking, so if I click cancel in inputbox or leave it blank and click ok, the macro will act like "" is the strFind, so it then turns all folder names into all lower case, lol.
I think adding this just after the 2 inputboxes will solve it, but I'll test that tomorrow:
If strFind = "" Or strReplace = "" Then
Exit Sub
End If
This solution seems really good for me, as there are so many varieties of search strings I need to address, that hard coding each one would have been a nightmare. Instead, this will allow me to adjust on the fly to how each user's brain was working when they developed their personal naming structures over the years.
After seeing and using this, I then developed another macro to batch move everything from the selected directory to whatever folder I wish to merge them into ... to create my true library of files, but that's a different topic so I suppose you don't want that posted in here.

Change the path of an Excel file linked to Access 2011 with VBA

I was trying something more fancy and did post on accessforums, where I got got no responses and on programmers access, where I got links to more reading material, but which did not help me - probably due to my lack of VBA expertise.
I have done lots of other programming like PHP and Arduino, but VBA is new for me, although I been watching hours of videos, they don't quite cover what I want to do.
After 4 days of researching an failed attempts, I have simplified my approach and I would appreciate some "real" help with actual code.
Scenario:
I have multiple Excel source file with 9 tabs each.
All the source files are in the same directory, (not in the same directory as the database)
Only one source is ever linked.
Each tab of the source file is a linked table within Access.
Objective:
I wish regularly switch source files.
Method:
I want to replace only the connect file property (i.e. the full file path) for each of the 9 sheets/tabs that use the particular file.
The full path must be "picked up" from my form and applied on an event e.g. on closing of form.
Progress:
I have built a form in which I can enter the file name to use and which calculates the full path to the file in question.
I have a button on the form, which is used to close the form.
Code:
Private Sub Form_Close()
Dim dbs As Database
Dim tdf As TableDef
Dim sfl As String
Dim basePath As String
Dim sName As String
Set dbs = CurrentDb
Set sfl = "SourceData_"
Set sName = "JoeSmith"
Set basePath = "D:\Databases\BOM Consolidator\data_source"
' Loop through all tables in the database.
For Each tdf In dbs.TableDefs
If InStr(10, tdf.Connect, sfl, 1) > 10 Then
tdf.Connect = ";DATABASE=" & basePath & sfl & sName & "\" & dbs
Err = 0
On Error Resume Next
tdf.RefreshLink ' Relink the table.
If Err <> 0 Then
End If
End If
Next tdf End Sub
In the above I am entering the path etc directly just to get it working first.
Access froze :(
Help would be appreciated.
Posting this before I try a restart.
After a restart it is not freezing.
It is saying I have a missing object.
The first line is highlighted in yellow, so I assume something must go in the parenthesis, but no idea what.
If it was a function, I would normally put a variable that is not declared inside the function. This being a subroutine, I was not expecting it to ask for something...
Ultimately I will turn it into a function, sothat I can provide the file name.
A clue to what is needed on the first line please...?
Oh also I am using "Code Builder" - is that the correct option to use with closing a form?

DateCreated glitch? How to identify if overwriting

As part of an auto-update macro, I have a copy of an Access FrontEnd on the local drive which when opened, checks to see if the file on the server has a newer CreatedDate. If it is newer, my code currently uses fileSystemObject to CopyFile and overwrites the local drive version (filename remains the same).
The problem I am having however is that when this is done, the 'date created' does not change to that of the newer file and so continually loops as the old file is closed and the new one opened - which checks for updates based on date created... I even tried using kill on the local file and waiting 10 seconds before doing the Copyfile command but even then it appears with the deleted file's creation date.
When I get back to the office I'm going to try copying the file from the server to the local drive without renaming it, deleting the original local drive file, then copying the newly created file so I can rename it back to the original name (the name should not be changed so that any shortcuts will still work).
Has anyone come across this before and found a solution? Am I missing something obvious that would 'refresh' the created date of the file?
EDIT
I think this is pretty close to what I had.
Dim strSource As String, strDest As String, strOrigDB As String, strSvrDB As String
Dim varOldDB As Variant, varNewDB As Variant, fso As Object
Set fso = CreateObject("scripting.filesystemobject")
strSource = "\\192.168.1.2\Data\svrDatabase"
strSvrDB = "AnyOldName.mde"
strDest = "C:\myFolder\myDatabase"
strOrigDB = "KeepMyName.mde"
varOldDB = (strDest & "\" & strOrigDB)
varNewDB = (strSource & "\" & strSvrDB)
If fso.getfile(varOldDB).DateCreated < fso.getfile(varNewDB).DateCreated Then
Kill strDest & "\" & strOrigDB
Excel.Application.Wait Now() + TimeValue("00:00:05")
fso.copyfile (strSource & "\" & strSvrDB), (strDest & "\" & strOrigDB), True
'open new database version
ShellExecute 0, "Open", (strDest & "\" & strOrigDB), "", "", 1
DoCmd.Quit
End If
I was originally using date modified, but noticed that as soon as the Front end opened, this would get renewed and would therefore always be a newer date value than the server file.
EDIT
After thinking about this, and hoping my logic hasn't completely broken down, it would be best if I had a shortcut for the user to click on, but instead of opening the Frontend, it opens a script file that checks for an update. If there is an update, then it deletes the local Frontend and copies the server one (which should be named differently to the original) to the local folder - then opens the new frontend.
This would mean that the datecreated being checked is always going to be updated on copy to the local folder and the kill will work because the file has not been opened. I am still a little wary of using lastdatemodified incase a user has the database open when an update is created - the Frontend contains tables used in searches which I believe will alter the modified date of the Frontend. In this scenario the local date modified would still be greater than a new frontend on the server.
You should be using Date Modified. That's when the file was last changed.
This is what helps says about times.
Timestamps are updated at various times and for various reasons. The only guarantee about a file timestamp is that the file time is correctly reflected when the handle that makes the change is closed.
So try closing all files before comparing times.
Also From https://support.microsoft.com/en-us/kb/172190
When a name is removed from a directory (rename or delete), its short/long name pair and creation time are saved in a cache, keyed by the name that was removed. When a name is added to a directory (rename or create), the cache is searched to see if there is information to restore. The cache is effective per instance of a directory. If a directory is deleted, the cache for it is removed.
Also coping from an untrusted source will change last modified for sure.
Also there are rules for copy versus move.
Also files need to be wholey within Windows eco system for windows rules to apply for sure.

Kill Command Deleting Wrong File(s)i

In Access VBA, I have a procedure I've put together to do this:
Allow the user to select zip file(s)
Extract any files from the zip files to the same directory (In this
specific use-case instance, it is ALWAYS extracting Excel files from
Zip files, never any change, and always using the same password)
Then I want the code to Delete the Zip file after extracting the
.xls file.
Everything works beautifully except the delete file portion. The issue is that when I tell it to delete "FileName.Zip", it is deleting "FileName.Zip" AND "FileName.xls"
Is there any way to make sure that he kill command ONLY deletes what I want it to delete? I've used it before on various occasions, and never had this happen before.
Here is the code I am using:
Dim fd As FileDialog
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim i As Variant
Set db = CurrentDb
Set rs = db.OpenRecordset("tblProjectPath")
Set fd = FileDialog(msoFileDialogFilePicker)
fd.AllowMultiSelect = True
fd.Title = "Select TOC Return File(s) to process"
fd.InitialFileName = rs.Fields("ProjectPath") & "\FilingReports\*.zip"
fd.Show
For Each i In fd.SelectedItems
'Debug.Print i
Debug.Print '------------------------'
Debug.Print i
Unzip (i) 'The bit calling the command line unzip utility to unzip the file - just telling it to extract all files to the current folder.
Debug.Print i
'Kill i
'had to take out the kill bit, b/c it was deleting both the .zip and .xls files which is not desired nor expected
If InStr(i, ".zip") Then
Kill i 'Tried to specify only .zip files even though think I shouldn't need to, but it's still deleting .xls files
End If
Next i
Edit: Add Unzip code to post:
Unzip code:
Sub Unzip(Path As String)
Dim strUnzip As String
Dim QU As String 'quotation mark
QU = Chr(34)
strUnzip = QU & "c:\program files (x86)\winzip\wzunzip" & QU & " -s" & _
"ZipPassword " & _
Path & " " '& _
Call Shell(strUnzip)
End Sub
At this point, I don't really think a "real" answer will come about. However, I'll post what I've decided to do with the particular process I'm writing this code for anyway.
I'm going to use a folder structure to divide up the files:
1. Place zip file(s)
2. Unzip files to a 2nd folder
3. After processing Excel files in 2nd folder, move to a 3rd "complete" folder.
This will get around the deleting wrong files bit.
Also, it appears that the cause for the issue is related to something to do with the call to the WinZip Command Line Unzip utility (wzunzip) in the Unzip code above, or else something with the tool itself. I thought that maybe it was b/c the tool was asking me if I wanted to overwrite existing files, but that wasn't the case, b/c I had the same issue when there were no files to overwrite.
Anyway, I'm attempting to close this one up at this point. Thanks to Wayne G. Dunn for his assistance on this.