Saveas xlsm in xlsx without opening files - excel

Sorry to bother you, but I'm at an impasse :(
To summarize my situation, I need to recover an entire sheet of all files in a folder. My macro goes through them one by one and picks it up.
The problem is that I can have "xlsm" files that show me a warning pop up because there are macros and "trust" etc... Pop up that I can't remove because it doesn't cannot be disabled.
(I also can't change my excel options for X reasons because I'm not the only one using the macro).
I would therefore like to convert my "xlsm" to "xlsx" without having to open it to avoid the pop up. A simple change of extension damages the file (obvious)
Do you have a solution for saveas without opening the file or opening it without having the pop-up?
Thanks in advance !

Make the macro to open the files as read-only, so the pop up doesn't apear regarding trust.
Set my_wb = Workbooks.Open(Filename:=file_path, ReadOnly:=True)
And make the make macro to save the files as xlsx
Application.DisplayAlerts = False
my_wb.SaveAs fileName:="myFileName.xlsx"

As I said in my above comment, adding the folder where the workbooks in discussion exist in Excel Trusted Locations can be a solution, to avoid warnings related to trustful workbooks. Adding the folder path, in code, can be done in the next way:
Private Function CreatePathInTrLoc(ByVal sPath As String, ByVal sDescription As String, Optional boolReplace As Boolean) As Boolean
Const HKEY_CURRENT_USER = &H80000001, sAppExe As String = "excel.exe", sApp As String = "Excel"
Dim oRegistry As Object, sAppVer As String, sParentKey As String, bAlreadyExists As Boolean
Dim arrChildKeys As Variant, sChildKey As Variant, sValue As String, sNewKey As String
Dim iLocCounter As Long, strReplace As String, sExtPath As String
Set oRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
sAppVer = GetAppVersion(sAppExe)
sAppVer = left(sAppVer, InStr(sAppVer, ".") - 1) & "." & Mid(sAppVer, InStr(sAppVer, ".") + 1, 1)
sParentKey = "Software\Microsoft\Office\" & sAppVer & "\" & sApp & "\Security\Trusted Locations"
iLocCounter = 0
oRegistry.EnumKey HKEY_CURRENT_USER, sParentKey, arrChildKeys
For Each sChildKey In arrChildKeys
oRegistry.GetStringValue HKEY_CURRENT_USER, sParentKey & "\" & sChildKey, "Description", sValue
If sValue = sDescription Then
If boolReplace Then
oRegistry.GetStringValue HKEY_CURRENT_USER, sParentKey & "\" & sChildKey, "Path", sExtPath
If sExtPath <> sPath Then
oRegistry.DeleteKey HKEY_CURRENT_USER, sParentKey & "\" & sChildKey
strReplace = sChildKey
GoTo OverDeleteKey
Else
bAlreadyExists = True
CreatePathInTrLoc = True
End If
Else
bAlreadyExists = True
CreatePathInTrLoc = True
End If
End If
If CInt(Mid(sChildKey, 9)) > iLocCounter Then
iLocCounter = CInt(Mid(sChildKey, 9))
End If
Next
OverDeleteKey:
If Not bAlreadyExists Then
sNewKey = sParentKey & IIf(strReplace <> "", "\" & strReplace, "\Location" & CStr(iLocCounter + 1))
oRegistry.CreateKey HKEY_CURRENT_USER, sNewKey
oRegistry.SetStringValue HKEY_CURRENT_USER, sNewKey, "Path", sPath
oRegistry.SetStringValue HKEY_CURRENT_USER, sNewKey, "Description", sDescription
oRegistry.SetDWORDValue HKEY_CURRENT_USER, sNewKey, "AllowSubFolders", 1
CreatePathInTrLoc = True
Debug.Print "Path """ & sPath & """ added in Trusted Locations."
Else
Debug.Print "Path """ & sPath & """ already exists..."
End If
End Function
Private Function GetAppVersion(sAppExe As String) As String 'extract application version
Const HKEY_LOCAL_MACHINE = &H80000002
Dim oRegistry As Object, oFSO As Object, sKey As String, sValue As String
Set oRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}//./root/default:StdRegProv")
Set oFSO = CreateObject("Scripting.FileSystemObject")
sKey = "Software\Microsoft\Windows\CurrentVersion\App Paths"
oRegistry.GetStringValue HKEY_LOCAL_MACHINE, sKey & "\" & sAppExe, "", sValue
GetAppVersion = oFSO.GetFileVersion(sValue)
Set oFSO = Nothing: Set oRegistry = Nothing
End Function
The above solution can be tested as:
Sub testCreatePathInTrLoc()
Debug.Print CreatePathInTrLoc("C:\temp", "TestLocation")
End Sub
The called Sub needs as parameters: folder path to be added, Trusted location name/description and a Boolean Optional parameter if you want replacing an existing trusted location.

Related

SaveAs a file and move it’s icon on Desktop to the same old position of the original file

I have used the below code to a workbook (SaveAs) and then delete the original file.
The Windows OS put the new created file on the first left vacant space on My Desktop.
What I need after using SaveAs , is to move it’s icon to the same old position of the original file on my Desktop.
Meaning, If my file is initially placed on the upper right of my desktop , I want to keep it in that location after using SaveAs.
In advance, appreciate for your time to help.
Sub Rename_Me_Automatic()
Application.DisplayAlerts = False
Dim FilePath As String, wb As Workbook, FolderPath As String
Dim oldName As String, newName As String
Set wb = ThisWorkbook
FilePath = wb.FullName
FolderPath = wb.Path & Application.PathSeparator
oldName = wb.Name
newName = Left(oldName, Len(oldName) - 5) & WorksheetFunction.RandBetween(1, 20)
wb.SaveAs FolderPath & newName
Kill FilePath 'delete orginal file
Application.DisplayAlerts = True
End Sub
Please, also try this code. It uses classical Windows behavior. VBA writes a VBScript, creates the file and runs it. The script finds the open Excel session, the workbook in discussion, save, close it, quits Excel application in certaing circumstances and changes the workbook name only after that (keeping the same file icon position). Finally, the script kills itself:
Sub SaveAndChangeActiveWorkbookName_VBScript()
Dim vbsStr As String, fso As Object, vbsObj As Object, strVBSPath As String
Dim newName As String, wb As Workbook, ext As String, searchName As String
Set wb = ThisWorkbook
With wb
ext = Split(.Name, ".")(UBound(Split(.Name, ".")))
searchName = Left(.Name, Len(.Name) - (Len(ext) + 1))
End With
newName = searchName & WorksheetFunction.RandBetween(5, 20) & "." & ext
strVBSPath = ThisWorkbook.Path & "\Rename.vbs" 'the fullname of the VBScript to be created and run
vbsStr = "Dim objExcel, wb, objFile, FSO, fullName" & vbCrLf & _
"Set objExcel = GetObject(, ""Excel.Application"")" & vbCrLf & _
"Set FSO = CreateObject(""Scripting.FileSystemObject"")" & vbCrLf & _
" Set wb = objExcel.Workbooks(""" & ThisWorkbook.Name & """)" & vbCrLf & _
"fullName = wb.FullName" & vbCrLf & _
"wb.Close True" & vbCrLf & _
"If objExcel.Workbooks.Count = 0 Then" & vbCrLf & _
" objExcel.Quit" & vbCrLf & _
"ElseIf objExcel.Workbooks.Count = 1 Then" & vbCrLf & _
" If not UCase(Workbooks(1).Name) = ""PERSONAL.XLSB"" Then" & vbCrLf & _
" objExcel.Quit" & vbCrLf & _
" End If" & vbCrLf & _
"End If" & vbCrLf & _
"Set objFile = FSO.GetFile(fullName)" & vbCrLf & _
"objFile.Name = """ & newName & """" & vbCrLf & _
"FSO.DeleteFile Wscript.ScriptFullName, True" 'kill itself...
Set fso = CreateObject("Scripting.FileSystemObject")
Set vbsObj = fso.OpenTextFile(strVBSPath, 2, True)
vbsObj.Write vbsStr 'write the above string in the VBScript file
vbsObj.Close
Shell "cmd.exe /c """ & strVBSPath & """", 0 'execute/run the VBScript
End Sub
The next version tries simplifying your code, not needing any API:
Sub SaveAndChangeActiveWorkbookName_ShellAppl()
Dim sh32 As Object, oFolder As Object, oFolderItem As Object, wb As Workbook
Dim newName As String, ext As String, searchName As String
Set sh32 = CreateObject("Shell.Application")
Set wb = ThisWorkbook
With wb
ext = Split(.Name, ".")(UBound(Split(.Name, "."))) 'extract extension
searchName = Left(.Name, Len(.Name) - (Len(ext) + 1)) 'extract the rest of its name
newName = searchName & WorksheetFunction.RandBetween(5, 20) & _
IIf(showExtension, "." & ext, "") 'it sets correct new name...
.Save
.ChangeFileAccess xlReadOnly '!
Set oFolder = sh32.Namespace(.Path & "\")
Set oFolderItem = oFolder.ParseName(.Name)
oFolderItem.Name = newName
If (UCase(Workbooks(1).Name) = "PERSONAL.XLSB" _
And Workbooks.Count = 2) Or Workbooks.Count = 1 Then
Application.Quit
Else
.Close False 'no need to save it again and it closes faster in this way...
End If
End With
End Sub
'Function to check how 'Hide extension for known file type' is set:
Function showExtension() As Boolean
Dim fileExt As String, Shl As Object, hideExt As Long
fileExt = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\HideFileExt"
Set Shl = CreateObject("WScript.Shell")
hideExt = Shl.RegRead(fileExt)
If hideExt = 0 Then showExtension = True
End Function
I've been educated that Windows does not allow changing name of an open workbook. Which is true, you cannot do it manually. Windows does not let you do it, this is its philosophy to avoid data loss.
But setting ReadOnly file attribute looks to temporarily remove the file full name from the Windows File Allocation Table. If you try Debug.Print wb.FullFileName before and after changing its attribute, it will show the same (old) one. But it looks that there are ways to do it and letting the open workbook outside the Allocation Table, you can change its name. I did not even imagine this is possible and I consider that this is the most important issue I learned today.
Intro: Windows OS saves the positions of desktop icons somewhere in registry or another location.
When I post my question, I thought the answer will depend on extracting coordinates of (SavedAs workbook icon) on my desktop,
And then using an API method to place it on the old location of the original file.
But , It looks hard for VBA programmers.
So, I tried the idea of #Daniel Dušek :
(The idea was to SaveAs with the original file name which will just overwrite the old file and then rename it instead of deleting).
The idea itself is excellent, But using native VBA methods (Name and FileSystemObject. MoveFile) ,
have a possible behavior to move the file beside renaming and I need to imitate how Windows OS works when it rename a file (like when you use right-click and choose Rename),
and also, I cannot rename the open workbook by using (Name and FSO. MoveFile) even after set ChangeFileAccess to xlReadOnly.
But, with using native OS API , you can do much more than you can imagine.
I have got a sophisticated API to Rename Link by the professional #Siddharth Rout
The advantage of this API is you can rename a workbook while it is still open (sure after Change File Access to xlReadOnly) 😊.
Now, All works correctly as expected, and I can SaveAs a file keep it’s icon on desktop at the same old position of the original file.
Sub SaveAs_and_Rename_Me_Automatically()
Dim wb As Workbook, filePath As String, folderPath As String
Dim oldName As String, newName As String, ext As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set wb = ThisWorkbook
filePath = wb.FullName
folderPath = wb.Path & "\"
oldName = fso.GetBaseName(filePath)
ext = fso.GetExtensionName(filePath)
newName = oldName & WorksheetFunction.RandBetween(5, 20) & "." & ext
Application.DisplayAlerts = False
wb.SaveAs folderPath & oldName 'SaveAs with orginal name (just overwrite)
wb.ChangeFileAccess xlReadOnly 'change file access to Read_Only:
SHRenameFile filePath, folderPath & newName 'to rename the Workbook while it is still open!
Application.DisplayAlerts = True
If Workbooks.Count = 1 Then
Application.Quit
Else
ThisWorkbook.Close SaveChanges:=True
End If
End Sub
And this the great API to rename:
Private Declare PtrSafe Function SHFileOperation Lib "shell32.dll" _
Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As LongPtr
Private Const FOF_SIMPLEPROGRESS = &H100
Private Const FO_RENAME = &H4
Private Type SHFILEOPSTRUCT
hWnd As LongPtr
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Boolean
hNameMaps As LongPtr
sProgress As String
End Type
Public Sub SHRenameFile(ByVal strSource As String, ByVal strTarget As String)
Dim op As SHFILEOPSTRUCT
With op
.wFunc = FO_RENAME
.pTo = strTarget
.pFrom = strSource
.fFlags = FOF_SIMPLEPROGRESS
End With
SHFileOperation op '~~> Perform operation
End Sub
a bit hacky setup but works, the idea is following:
save workbook with the suffix "to_del"
from that temp file we rename the original file
save the workbook as the renamed file
delete "to_del" file from the original file
the code:
Sub Rename_Me_Automatic()
Application.DisplayAlerts = False
Dim filePath As String
Dim folderPath As String
Dim oldName As String
Dim newName As String
Dim wb As Workbook
Set wb = ThisWorkbook
filePath = wb.FullName
folderPath = wb.path & Application.PathSeparator
oldName = wb.Name
newName = Left(oldName, Len(oldName) - 5) & WorksheetFunction.RandBetween(1, 20)
wb.SaveAs Filename:=folderPath & newName & "_to_del.xlsm", _
FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
Name folderPath & oldName As folderPath & newName & ".xlsm"
wb.SaveAs Filename:=folderPath & newName & ".xlsm", _
FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
Kill folderPath & newName & "_to_del.xlsm"
Application.DisplayAlerts = True
End Sub
You do not say anything...
I have something to do in the next time interval, so I prepared a workaround, but working code based on my comment to your answer assumption, respectively:
A workbook named as the one keeping the code, only having a different numeric suffix before its extension, must exist on Desktop, like reference for the place where the other workbook to be placed;
Your code creates a new workbook, with a random (new) suffix.
ThisWorkbook is saved overwriting the existing workbook on Desktop, but using SaveCopyAs, to let the original workbook open and the overwitted workbook to be renamed (not being open):
Private Sub testSaveCopyAsOverwrite()
'References:
'Microsoft Shell Controls And Automation '(C:\Windows\System32\Shell32.dll)
Dim oShell As Shell32.Shell, oFolder As Shell32.Folder, oFolderItem As Shell32.FolderItem
Dim filePath As String, initFileName As String, newFileName As String, wb As Workbook
Dim thisName As String, newName As String, ext As String, searchName As String
filePath = "C:\Users\Fane Branesti\OneDrive\Desktop\"
Set wb = ThisWorkbook
thisName = wb.name
ext = Split(thisName, ".")(UBound(Split(thisName, ".")))
searchName = left(thisName, Len(thisName) - (Len(ext) + 1))
RecreateName: 'for the case when RandBetween returns the same name suffix...
newName = searchName & WorksheetFunction.RandBetween(5, 20) & "." & ext
Set oShell = New Shell32.Shell
initFileName = Dir(filePath & searchName & "*." & ext) 'find the file to be overwriten
If initFileName <> "" Then
If newName = initFileName Then GoTo RecreateName 'if RandBetween returned the same suffix...
ThisWorkbook.SaveCopyAs fileName:=filePath & initFileName 'overwrite the existing workbook, but keeping the original wb open
Set oFolder = oShell.NameSpace(filePath)
Set oFolderItem = oFolder.ParseName(initFileName)
oFolderItem.name = newName 'change the initial file name with the necessary one, without moving it!
Else
MsgBox "No any workbook having the name pattern as: """ & filePath & searchName & """*." & ext & """"
End If
End Sub
Please, take care to add the required reference (from C:\Windows\System32\Shell32.dll) before running it...
In fact, you can run the next code to add it:
Sub addShellControlsAndAutomation()
'Add a reference to 'Microsoft Shell Controls And Automation':
'In case of error ('Programmatic access to Visual Basic Project not trusted'):
'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
' check "Trust access to the VBA project object model"
On Error Resume Next
Application.vbE.ActiveVBProject.References.AddFromFile "C:\Windows\System32\Shell32.dll"
If err.number = 32813 Then
err.Clear: On Error GoTo 0
MsgBox "'Microsoft Shell Controls And Automation' reference already added...", vbInformation, _
"Reference already existing"
End If
On Error GoTo 0
End Sub

Create new Folder in OneDrive

Been using code below for years. It creates new folder, and names it to next work-day's date + adds another folder within this, named "VO".
Code got two "fPath"-lines. The one at pause is the original one. With this one I can move my files around, and code will still create new folder, based on location of ThisWorkbook.
However, with OneDrive, original "fPath"-line ends in "Run-time error 52: Bad file name or number", marking line .CreateFolder (EndDir1).
Why doesn't this code work in OneDrive? When I change "fPath"-line into complete address, it works just fine.
Sub NewFolderNextWorkDay()
Dim FSO As Object
Dim fsoObj As Object
Dim NeArbDg As Double
NeArbDg = Application.WorkDay(Date, 1)
Dim Dato As String
Dim fPath As String
Dim EndDir1, EndDir2 As String
Dato = Format(NeArbDg, "yyyy-mm-dd")
'fPath = ThisWorkbook.Path & "\..\" '(old code, worked fine until OneDrive came along)
fPath = "C:\Users\MyId\OneDrive - MyJob\Mine dokumenter\PROD\TEST\2022\" '(new code, works ok with OneDrive)
EndDir1 = (fPath & Dato & "\")
EndDir2 = (fPath & Dato & "\VO")
Set fsoObj = CreateObject("Scripting.FileSystemObject")
With fsoObj
If Not .FolderExists(EndDir1) Then
.CreateFolder (EndDir1)
End If
If Not .FolderExists(EndDir2) Then
.CreateFolder (EndDir2)
End If
End With
End Sub
This function from the linked post (https://stackoverflow.com/a/67582367/478884) seems to work for me. I did need to make a change to fix an issue when strCID has no content. See lines marked ####
Function GetLocalFile(wb As Workbook) As String
' Set default return
GetLocalFile = wb.FullName
Const HKEY_CURRENT_USER = &H80000001
Dim strValue As String
Dim objReg As Object: Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
Dim strRegPath As String: strRegPath = "Software\SyncEngines\Providers\OneDrive\"
Dim arrSubKeys() As Variant
objReg.EnumKey HKEY_CURRENT_USER, strRegPath, arrSubKeys
Dim varKey As Variant
For Each varKey In arrSubKeys
' check if this key has a value named "UrlNamespace", and save the value to strValue
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "UrlNamespace", strValue
' If the namespace is in FullName, then we know we have a URL and need to get the path on disk
If InStr(wb.FullName, strValue) > 0 Then
Dim strTemp As String
Dim strCID As String
Dim strMountpoint As String
' Get the mount point for OneDrive
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "MountPoint", strMountpoint
' Get the CID
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "CID", strCID
' strip off the namespace and CID
If Len(strCID) > 0 Then strValue = strValue & "/" & strCID '#####
strTemp = Right(wb.FullName, Len(wb.FullName) - Len(strValue)) '#####
' replace all forward slashes with backslashes
GetLocalFile = strMountpoint & "\" & Replace(strTemp, "/", "\")
Exit Function
End If
Next
End Function
Change https://my.... to C:\users\...:
Sub Sample()
GetLocalFile = Split(ThisWorkbook.Path, "/Documents")(2)
GetLocalFile = Replace(GetLocalFile, "/", "\")
MyPath = Environ("onedrive") & "\documents" & GetLocalFile
MkDir (MyPath & "\New")
End Sub

Excel VBA macro dir() function incorrect return value when folder is empty

Trying to use the DIR function in a Macro to determine whether a folder exists. Have found the following code
Function FileOrFolderExistsOnMac(FileOrFolderstr As String) As Boolean
Ron de Bruin : 1-Feb-2019
Function to test whether a file or folder exist on a Mac in office 2011 and up
'Uses AppleScript to avoid the problem with long names in Office 2011,
'limit is max 32 characters including the extension in 2011.
Dim ScriptToCheckFileFolder As String
Dim TestStr As String
If Val(Application.Version) < 15 Then
ScriptToCheckFileFolder = "tell application " & Chr(34) & "System Events" & Chr(34) & _
"to return exists disk item (" & Chr(34) & FileOrFolderstr & Chr(34) & " as string)"
FileOrFolderExistsOnMac = MacScript(ScriptToCheckFileFolder)
Else
On Error Resume Next
TestStr = Dir(FileOrFolderstr & "*", vbDirectory)
On Error GoTo 0
If Not TestStr = vbNullString Then FileOrFolderExistsOnMac = True
End If
End Function
from
https://www.rondebruin.nl/win/s9/win003.htm
However, when the folder in the path location is empty, the function determines that the path directory does not exist.
Thank you for the post, it helped me identify the source of my problem.
I modified my often-used function to account for this quirk.
Here's a modified function that should work for empty folders (works on Windows, not tested on Macs).
Function directoryExists(ByVal dirPath As String) As Boolean
'amy#logicallytech.com
'7/15/2022
directoryExists = (Dir(dirPath) <> "")
If directoryExists Then Exit Function
'If folder is empty, above will show it does not exist, so just to confirm...
Dim strParentFolder As String
Dim strSubFolder As String
Dim myfso As Object
Dim parentFolder As Object
Dim subFolder As Object
If InStr(dirPath, "\") > 0 Then
If Right(dirPath, 1) = "\" Then dirPath = Left(dirPath, Len(dirPath) - 1)
strParentFolder = Left(dirPath, InStrRev(dirPath, "\", , vbTextCompare))
strSubFolder = Right(dirPath, Len(dirPath) - InStrRev(dirPath, "\", , vbTextCompare))
ElseIf InStr(dirPath, "/") > 0 Then
If Right(dirPath, 1) = "/" Then dirPath = Left(dirPath, Len(dirPath) - 1)
strParentFolder = Left(dirPath, InStrRev(dirPath, "/", , vbTextCompare))
strSubFolder = Right(dirPath, Len(dirPath) - InStrRev(dirPath, "/", , vbTextCompare))
End If
Set myfso = CreateObject("Scripting.FileSystemObject")
Set parentFolder = myfso.GetFolder(strParentFolder)
For Each subFolder In parentFolder.SubFolders
If LCase(Trim(subFolder.Name)) = LCase(Trim(strSubFolder)) Then
directoryExists = True
GoTo CleanUp
End If
Next subFolder
CleanUp:
Set subFolder = Nothing
Set parentFolder = Nothing
Set myfso = Nothing
End Function

If folder already exists add next number to folder name

I have code for creating new folder on users desktop. I would like to add more functionality to it. Before creating new folder it should check if folder already exists (it is doing it right now). Then if there is folder with the same name, code should create new folder with next available number 1,2,3...
So if there is already folder with name "T34-23, Quotation", code should create folder named "T34-23, Quotation 1". If there is "T34-23, Quotation 1" then create "T34-23, Quotation 2" etc.
Sub MakeMyFolder()
Dim fdObj As Object
Application.ScreenUpdating = False
Set fdObj = CreateObject("Scripting.FileSystemObject")
If fdObj.FolderExists(Environ$("USERPROFILE") & "\Desktop\" & ThisWorkbook.Sheets("Other Data").Range("AK2").Value & ", " & _
ThisWorkbook.Sheets("Other Data").Range("AK7").Value) Then
'MsgBox "Found it.", vbInformation, "Excel"
Else
fdObj.CreateFolder (Environ$("USERPROFILE") & "\Desktop\" & ThisWorkbook.Sheets("Other Data").Range("AK2").Value & ", " & _
ThisWorkbook.Sheets("Other Data").Range("AK7").Value)
'MsgBox "It has been created.", vbInformation, "Excel"
End If
Set fdObj = Nothing
Application.ScreenUpdating = True
End Sub
As #urderboy suggests, you should use some variables in this.
Function CheckAndSuffixFolder(strPathToCheck As String, _
Optional blnCreateFolder As Boolean = False) As String
Dim f As New Scripting.FileSystemObject
Dim l As Long
Dim s As String
s = strPathToCheck
l = 1
Do While f.FolderExists(s)
l = l + 1
s = strPathToCheck & l
Loop
If blnCreateFolder Then f.CreateFolder s
CheckAndSuffixFolder = s
End Function
Calling like so, I have Folder, FOlder1 and FOlder2.
CheckAndSuffixFolder("C:\Workspace\Training\Folder") Gives me Folder3
Can't test it out now, but I'm thinking the solution will require you to loop through numbers until there is one that value that returns False. If the file check returns True then the file exists increment up until you get to the number needed. untested code:
Dim createFile Boolean: createFile = False
Dim i as Integer: i = 1
Do while createFile = False
Dim strDir As String
strDir = folderDir & "T34-23, Quotation" & i & "\"
If Dir(strDir, vbDirectory) = "" Then
MkDir strDir
createFile = True
Else
i = i+1
End If
wend

Create folder and subfolder

I have an Excel file with hundreds of Customer names and several article numbers.
I want to check if a folder with selected customer name exists and create a folder if it is missing.
Once the customer folder is found or created, check if there is a folder for each article number and if it is missing, create one.
I found code that seems to do all that and more posted by Scott Holtzman.
I have referenced Microsoft Scripting Runtime as the code requests.
Both of the "If not" statements are marked red and the pop-up window only says "Compile error".
I checked the syntax of "If not" statements and it seems to be correct.
'requires reference to Microsoft Scripting Runtime
Sub MakeFolder()
Dim strComp As String, strPart As String, strPath As String
strComp = Range("A1") ' assumes company name in A1
strPart = CleanName(Range("C1")) ' assumes part in C1
strPath = "C:\Images\"
If Not FolderExists(strPath & strComp) Then
'company doesn't exist, so create full path
FolderCreate strPath & strComp & "\" & strPart
Else
'company does exist, but does part folder
If Not FolderExists(strPath & strComp & "\" & strPart) Then
FolderCreate strPath & strComp & "\" & strPart
End If
End If
End Sub
Function FolderCreate(ByVal path As String) As Boolean
FolderCreate = True
Dim fso As New FileSystemObject
If Functions.FolderExists(path) Then
Exit Function
Else
On Error GoTo DeadInTheWater
fso.CreateFolder path ' could there be any error with this, like if the path is really screwed up?
Exit Function
End If
DeadInTheWater:
MsgBox "A folder could not be created for the following path: " & path & ". Check the path name and try again."
FolderCreate = False
Exit Function
End Function
Function FolderExists(ByVal path As String) As Boolean
FolderExists = False
Dim fso As New FileSystemObject
If fso.FolderExists(path) Then FolderExists = True
End Function
Function CleanName(strName as String) as String
'will clean part # name so it can be made into valid folder name
'may need to add more lines to get rid of other characters
CleanName = Replace(strName, "/","")
CleanName = Replace(CleanName, "*","")
' etc...
End Function
Take a look at the below example, it shows one of the possible approaches using recursive sub call:
Option Explicit
Sub TestArrays()
Dim aCustomers
Dim aArticles
Dim sCustomer
Dim sArticle
Dim sPath
sPath = "C:\Test"
aCustomers = Array("Customer01", "Customer02", "Customer03", "Customer04", "Customer05")
aArticles = Array("Article01", "Article02", "Article03", "Article04", "Article05")
For Each sCustomer In aCustomers
For Each sArticle In aArticles
SmartCreateFolder sPath & "\" & sCustomer & "\" & sArticle
Next
Next
End Sub
Sub TestFromSheet()
Dim aCustomers
Dim aArticles
Dim i
Dim j
Dim sPath
sPath = "C:\Test"
With ThisWorkbook.Sheets(1)
aCustomers = .Range(.Range("A1"), .Range("A1").End(xlDown)).Value
aArticles = .Range("B1:B10").Value
End With
For i = LBound(aCustomers, 1) To UBound(aCustomers, 1)
For j = LBound(aArticles, 1) To UBound(aArticles, 1)
SmartCreateFolder sPath & "\" & aCustomers(i, 1) & "\" & aArticles(j, 1)
Next
Next
End Sub
Sub SmartCreateFolder(sFolder)
Static oFSO As Object
If oFSO Is Nothing Then Set oFSO = CreateObject("Scripting.FileSystemObject")
With oFSO
If Not .FolderExists(sFolder) Then
SmartCreateFolder .GetParentFolderName(sFolder)
.CreateFolder sFolder
End If
End With
End Sub
Sub TestArrays() checks and creates folders for customers and articles from the hardcoded arrays, and Sub TestFromSheet() gets customers and articles from the first worksheet, as an example customers range from A1 up to the last element, so it should be more than one element there, and articles set to fixed range B1:B10, like shown below:
The StrComp Issue
You cannot use StrComp, its a reserved word, actually a string function. I lost about 15 minutes the other day on this issue.
VBA says: Returns a Variant (Integer) indicating the result of a string comparison.
If you want to shorthand a bunch of that code, use MKDIR to create each level of folder\subfolder with error pass-over.
Option Explicit
Sub main()
Dim pth As String
pth = "c:\test\abc\123\test_again\XYZ\01-20-2019"
'folder may or may not exist
makeFolder pth
'folder definitely exists
End Sub
Sub makeFolder(fldr As String)
Dim i As Long, arr As Variant
'folder may or may not exist
arr = Split(fldr, Chr(92))
fldr = arr(LBound(arr))
On Error Resume Next
For i = LBound(arr) + 1 To UBound(arr)
fldr = Join(Array(fldr, arr(i)), Chr(92))
MkDir fldr
Next i
On Error GoTo 0
'folder definitely exists
End Sub
To rename an existing file to a new location WITH creation of all subdirectories, you can use:
File_Name_OLD = File_Pad_OLD & "Test.txt"
File_Pad_NEW = "e:\temp\test1\test2\test3\"
File_Name_NEW = File_Pad_NEW & "Test.txt"
X = File_Pad_NEW
A = 1
Do Until A = 0
A = InStr(X, "\")
Y = Y & Left(X, A)
X = Mid(X, A + 1)
If Dir(Y, 16) = "" Then MkDir Y
Loop
Name File_Name_OLD As File_Name_NEW
This is creating the new path with subdirectories and renames the old file to the new one.

Resources