25

I have a list of items in a sheet like so:

My code goes through each row and groups the supplier and copies some information into a work book for each supplier. In this scenario there are 2 unique suppliers, so 2 workbooks will be created. This works.

Next I want to save each workbook in a specific folder path. If the folder path does not exist then it should be created.

Here's the piece of code for this bit:

'Check directort and save
                Path = "G:\BUYING\Food Specials\4. Food Promotions\(1) PLANNING\(1) Projects\Promo Announcements\" & .Range("H" & i) & "\KW " & .Range("A" & i) & "\"
                
                If Dir(Path, vbDirectory) = "" Then
                Shell ("cmd /c mkdir """ & Path & """")
                End If
                
                wbTemplate.SaveCopyAs Filename:=Path & file & " - " & file3 & " (" & file2 & ").xlsx"

For some reason, both workbooks are saved if the directory exists, but only one workbook is saved if the directory doesn't exist and has to be created.

Full Code:

Sub Create()
'On Error GoTo Message
Application.DisplayAlerts = False
Application.ScreenUpdating = False
ActiveSheet.DisplayPageBreaks = False
    Dim WbMaster As Workbook
    Dim wbTemplate As Workbook
    Dim wStemplaTE As Worksheet
    Dim i As Long
    Dim Lastrow As Long
    Dim rngToChk As Range
    Dim rngToFill As Range
    Dim rngToFill2 As Range
    Dim rngToFill3 As Range
    Dim rngToFill4 As Range
    Dim rngToFill5 As Range
    Dim rngToFill6 As Range
    Dim rngToFill7 As Range
    Dim rngToFill8 As Range
    Dim rngToFill9 As Range
    Dim rngToFil20 As Range
    Dim CompName As String
    Dim WkNum As Integer
    Dim WkNum2 As Integer
    Dim WkNum3 As Integer
    Dim WkNum4 As Integer
    
    Dim FilePath1 As String
    Dim TreatedCompanies As String
    Dim FirstAddress As String
    '''Reference workbooks and worksheet
    Set WbMaster = ThisWorkbook
    
    WkNum = Left(ThisWorkbook.Worksheets(1).Range("C5").Value, (InStr(1, ThisWorkbook.Worksheets(1).Range("C5").Value, " - ")) - 1)
    WkNum2 = Trim(WkNum)
    WkNum3 = Right(ThisWorkbook.Worksheets(1).Range("C5").Value, (InStr(1, ThisWorkbook.Worksheets(1).Range("C5").Value, " - ")) - 1)
    WkNum4 = Trim(WkNum3)
    
    '''Loop through Master Sheet to get wk numbers and supplier names
    With WbMaster.Sheets(1)
    Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
    
    For i = 11 To Lastrow
    
    Set rngToChk = .Range("A" & i)
    MyWeek = rngToChk.Value
    CompName = rngToChk.Offset(0, 5).Value
    
    'Check Criteria Is Met
    If MyWeek >= WkNum2 And MyWeek <= WkNum4 And InStr(1, TreatedCompanies, CompName) Or CompName = vbNullString Then
    
    
    
    
    'Start Creation
        '''Company already treated, not doing it again
            Else
                '''Open a new template
                On Error Resume Next
                Set wbTemplate = Workbooks.Open("G:\BUYING\Food Specials\4. Food Promotions\(1) PLANNING\(1) Projects\Promo Announcements\Announcement Template.xlsx")
                Set wStemplaTE = wbTemplate.Sheets(1)

                '''Set Company Name to Template
                wStemplaTE.Range("C13").Value = CompName
                   
                
                '''Add it to to the list of treated companies
                TreatedCompanies = TreatedCompanies & "/" & CompName
                '''Define the 1st cell to fill on the template
                Set rngToFill = wStemplaTE.Range("A31")
                
                
                'Remove uneeded announcement rows
                'wStemplaTE.Range("A31:A40").SpecialCells(xlCellTypeBlanks).EntireRow.Hidden = True


                
                'On Error GoTo Message21
                'Create Folder Directory
                file = AlphaNumericOnly(.Range("G" & i))
                file2 = AlphaNumericOnly(.Range("C" & i))
                file3 = AlphaNumericOnly(.Range("B" & i))
                
                'Check directort and save
                Path = "G:\BUYING\Food Specials\4. Food Promotions\(1) PLANNING\(1) Projects\Promo Announcements\" & .Range("H" & i) & "\KW " & .Range("A" & i) & "\"
                
                If Dir(Path, vbDirectory) = "" Then
                Shell ("cmd /c mkdir """ & Path & """")
                End If
                
                wbTemplate.SaveCopyAs Filename:=Path & file & " - " & file3 & " (" & file2 & ").xlsx"
                
                wbTemplate.Close False
            
            
            End If
                 

    Next i
    
    End With

                            
End Sub



Function AlphaNumericOnly(strSource As String) As String
    Dim i As Integer
    Dim strResult As String

    For i = 1 To Len(strSource)
        Select Case Asc(Mid(strSource, i, 1))
            Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
                strResult = strResult & Mid(strSource, i, 1)
        End Select
    Next
    AlphaNumericOnly = strResult
End Function
2

8 Answers 8

42

You need to check if the folder exists. If not, then make it. This function does the job. Place it before saving your workbook.

'requires reference to Microsoft Scripting Runtime
Function Mk_Dir(strDir As String, strPath As String)

Dim fso As New FileSystemObject
Dim path As String

'examples of the input arguments
'strDir = "Folder"
'strPath = "C:\"

path = strPath & strDir

If Not fso.FolderExists(path) Then

' doesn't exist, so create the folder
          fso.CreateFolder path

End If

End Function

it's better to avoid using Shell command for this as it is likely to return errors for various reasons. Your code even ignores/bypasses errors which is not wise.

3
  • 1
    Needs reference 'Microsoft Scripting Runtime' activated in VBAProject (see: stackoverflow.com/questions/3233203)
    – Peter
    Commented Mar 24, 2021 at 16:09
  • 2
    @Peter read the first line of the code (I left a comment saying the exact same thing).
    – M--
    Commented Mar 24, 2021 at 16:10
  • 1
    MkDir is a Reserved name in vba, you should use some other name.
    – Noam Brand
    Commented Feb 22, 2023 at 9:00
41

No reference to Microsoft Scripting Runtime required.

Dim path_ As String
    path_ = "G:\BUYING\Food Specials\4. Food Promotions\(1) PLANNING\(1) Projects\Promo Announcements\" & .Range("H" & i) & "\KW " & .Range("A" & i)

Dim name_ As String
    name_ = file & " - " & file3 & " (" & file2 & ").xlsx"

With CreateObject("Scripting.FileSystemObject")
    If Not .FolderExists(path_) Then .CreateFolder path_
End With

wbTemplate.SaveCopyAs Filename:=path_ & "\" & name_

OR

Dim path_ As String
    path_ = "G:\BUYING\Food Specials\4. Food Promotions\(1) PLANNING\(1) Projects\Promo Announcements\" & .Range("H" & i) & "\KW " & .Range("A" & i)

Dim name_ As String
    name_ = file & " - " & file3 & " (" & file2 & ").xlsx"

If Len(Dir(path_, vbDirectory)) = 0 Then MkDir path_

wbTemplate.SaveCopyAs Filename:=path_ & "\" & name_
4
  • 3
    love this: If Len(Dir(path_)) = 0 Then MkDir path_ Commented Feb 10, 2021 at 21:44
  • 1
    If Len(Dir(path_)) = 0 Then MkDir path_ checks if a string exists, not a file object I think.
    – Timo
    Commented Jun 14, 2021 at 14:11
  • 1
    @Timo Indeed but not any string, the string returned from the Dir() function which is a directory.
    – Kostas K.
    Commented Jun 14, 2021 at 14:28
  • 6
    If the folder is empty, I think the vbDirectory argument needs to be added: If Len(Dir(path_, vbDirectory)) = 0 Then MkDir path_
    – olly
    Commented Jan 13, 2022 at 19:56
10

Run this Macro two times to confirm & test.

First run should create a direcotry "TEST" on desktop and MsgBox "Making Directory!".

Second run should just MsgBox "Dir Exists!"

Sub mkdirtest()
Dim strFolderPath As String

strFolderPath = Environ("USERPROFILE") & "\Desktop\TEST\"
CheckDir (strFolderPath)

End Sub

Function CheckDir(Path As String)

    If Dir(Path, vbDirectory) = "" Then
        MkDir (Path)
        MsgBox "Making Directory!"
    'End If
    Else
        MsgBox "Dir Exists!"
    End If

End Function
1
  • Short and Simple/Sweet, thanks! I hope you don't mind I added a test sub at the top :) Commented Nov 12, 2019 at 2:45
3

Why bother explicitly checking manually when one can use error handler:

On Error Resume Next
MkDir directoryname
On Error Goto 0
1
  • 2
    Explicitly checking for the folder makes it clear what the intent is. Using error handlers like this results not only in unclear code, but sometimes missing out on the actual cause of the error.
    – KalenGi
    Commented Apr 13, 2022 at 12:22
2

To ensure the whole path exists recursion may help:

    '.
    '.
    DIM FSO as new Scripting.FilesystemObject
    '.
    '.
    Public Sub MkDirIfNotExist(strPath As String)
        If strPath = "" Then Err.Raise 53 'File not found e.g. Drive does not exists
        If Not FSO.FolderExists(strPath) Then
            MkDirIfNotExist FSO.GetParentFolderName(strPath)
            FSO.CreateFolder strPath
        End If
    End Sub
1
sub dosomethingwithfileifitexists()
If IsFile("filepathhere") = True Then
end if
end sub

Function IsFile(ByVal fName As String) As Boolean
'Returns TRUE if the provided name points to an existing file.
'Returns FALSE if not existing, or if it's a folder
    On Error Resume Next
    IsFile = ((GetAttr(fName) And vbDirectory) <> vbDirectory)
End Function

This is a handy little function I found online, I cannot remember where it is from! Apologise to the autor of the code.

1
  • 2
    You're welcome ;-) --- but in this caseOP should rather using its sister IsFolder
    – iDevlop
    Commented Jan 22, 2019 at 16:08
0

after reading the accepted answer here, and trying it, it didn't work. So I wrote the following function, tested it and it does work.

It doesn't require to add any library refence at all as it uses late binding

Function FolderCreate(ByVal strPathToFolder As String, ByVal strFolder As String) As Variant

'The function FolderCreate attemps to create the folder strFolder on the path strPathToFolder _
' and returns an array where the first element is a boolean indicating if the folder was created/already exists
' True meaning that the folder already exists or was successfully created, and False meaning that the folder _
' wans't created and doesn't exists
'
'The second element of the returned array is the Full Folder Path , meaning ex: "C:\MyExamplePath\MyCreatedFolder"

Dim fso As Object
'Dim fso As New FileSystemObject
Dim FullDirPath As String
Dim Length As Long

'Check if the path to folder string finishes by the path separator (ex: \) ,and if not add it
If Right(strPathToFolder, 1) <> Application.PathSeparator Then
    strPathToFolder = strPathToFolder & Application.PathSeparator
End If

'Check if the folder string starts by the path separator (ex: \) , and if it does remove it
If Left(strFolder, 1) = Application.PathSeparator Then
    Length = Len(strFolder) - 1
    strFolder = Right(strFolder, Length)
End If

FullDirPath = strPathToFolder & strFolder

Set fso = CreateObject("Scripting.FileSystemObject")

If fso.FolderExists(FullDirPath) Then
    FolderCreate = Array(True, FullDirPath)
Else
    On Error GoTo ErrorHandler
    fso.CreateFolder path:=FullDirPath
    FolderCreate = Array(True, FullDirPath)
    On Error GoTo 0
End If

SafeExit:
    Exit Function

ErrorHandler:
    MsgBox prompt:="A folder could not be created for the following path: " & FullDirPath & vbCrLf & _
            "Check the path name and try again."
    FolderCreate = Array(False, FullDirPath)

End Function
-2

You can do that using the error handle function. Something like:

Sub subCreatesNewFolderIfThereIsNotExists(strFolderName As String)

On Error GoTo CaseFolderExists
    
    strFullPath = ThisWorkbook.path & "\" & strFolderName
    
    MkDir (strFullPath)

    Exit Sub


CaseFolderExists:
    ''' Do nothing
    
End Sub

Not the answer you're looking for? Browse other questions tagged or ask your own question.