none
Batch File to loop through folders and create shortcuts RRS feed

  • Question

  • I am not to keen on Batch files, and have talked to several people trying to get walked through this, but I think it is a little bit beyond my capabilities. I need a batch file that will be set in a top level directory. From here it will go through each subfolder, and open up each subfolder here then create a shortcut. The shortcut will be a preset path followed by the two subfolder names.

    Folder Structure:

    Projects (This is where the Batch file will reside)
    ->Job 1700 - 1799 (SubFolderLevel1)
     ->1701 - Project 1 (SubFolderLevel2)
     ->1702 - Project 2 (SubFolderLevel2)
    ->Job 1800 - 1899 (SubFolderLevel1)
     ->1801 - Project 3 (SubFolderLevel2)
     ->1802 - Project 4 (SubFolderLevel2)
    The link will be to the following \\SERVER\DavWWWRoot\RFI\SUBFOLDERLevel1\SUBFOLDERLevel2

    I also need a Batch File that will be placed in the first subfolder, and will copy a ProjectBlank Folder, rename it to whatever the user inputs, and create the same shortcut link as above.

    Can anyone point me in the right directions? I have been stuck trying to get something to work for the past week. Any help is appreciated!


    • Edited by Zach Little Wednesday, June 19, 2013 2:00 PM Folder Structure Clarification
    Wednesday, June 19, 2013 1:58 PM

Answers

  • This is a VBScript, which meets your requirement of being able to just put it in the root folder and double click it, and also gives access to Regular Expressions and the CreateShortcut method I mentioned earlier.  It needs to be saved in a text file with a .vbs extension. This part only covers the first part of your question; creating a shortcut for folders that already exist. I don't have time to work on the rest of it right now, but I might be able to get to it tonight or tomorrow.

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set WshShell = CreateObject("WScript.Shell")
    
    strScriptFolder = RegExGetBRef(WScript.ScriptFullName, "^(.+)\\[^\\]*$", 1, True)
    strShortcutRoot = "\\SERVER\DavWWWRoot\RFI"
    
    Set objRootFolder = objFSO.GetFolder(strScriptFolder)
    
    For Each objL1Folder In objRootFolder.SubFolders
      strMatch = RegExGetBRef(objL1Folder.Name, "^jobs\s*(\d+)\s*-\s*\d+\s*$", 1, True)
      
      If (strMatch <> "") Then
        For Each objL2Folder In objL1Folder.SubFolders
          strShortcutFile = objL2Folder.Path & "\" & objL2Folder.Name & ".lnk"
          strShortcutTarget = strShortcutRoot & "\" & objL1Folder.Name & "\" & objL2Folder.Name
          If ((objFSO.FileExists(strShortcutFile) = False) And (objFSO.FolderExists(strShortcutTarget) = True)) Then
            Set objShortcut = WshShell.CreateShortcut(strShortcutFile)
            objShortcut.TargetPath = strShortcutTarget
            objShortcut.Save
          End If
        Next
      End If
    Next
    
    Function RegExGetBRef(strString, strPattern, intBRef, blnIgnoreCase)
      RegExGetBRef = ""
      
      Dim objRegExp
      Dim colMatches, objMatch
      
      Set objRegExp = New RegExp
      
      objRegExp.Pattern = strPattern
      objRegExp.IgnoreCase = blnIgnoreCase
      objRegExp.Global = False
      objRegExp.MultiLine = True
      
      Set colMatches = objRegExp.Execute(strString)
      
      For Each objMatch In colMatches
        If ((intBRef > 0) And (intBRef <= objMatch.SubMatches.Count)) Then
          RegExGetBRef = objMatch.SubMatches(intBRef - 1)
        End If
      Next
    End Function
    

    • Marked as answer by Zach Little Thursday, June 20, 2013 12:55 PM
    Wednesday, June 19, 2013 7:47 PM
  • I think this will do the trick.  While I was working on this, though, I noticed that in my first script, I was looking for level 1 folders of "Jobs 1800 - 1899" instead of "Job 1800 - 1899" as you had typed.  You didn't mention this when you tested the first script, though, so I stuck with "Jobs" in this one as well.  If that's not correct, just update the line that starts with strL1Folder =

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set WshShell = CreateObject("WScript.Shell")
    
    strScriptFolder = RegExGetBRef(WScript.ScriptFullName, "^(.+)\\[^\\]*$", 1, True)
    strShortcutRoot = "\\SERVER\DavWWWRoot\RFI"
    
    ' Fetch and validate user input.
    
    strL2Folder = ""
    intProjectNumber = -1
    
    Do While (True)
      strL2Folder = InputBox("Please enter the name of the new project folder you want to create.  It must begin with a project number:")
      
      If (strL2Folder = "") Then
        MsgBox "Operation cancelled by user.", 0
        WScript.Quit 0
      End If
      
      strProjectNumber = RegExGetBRef(strL2Folder, "^(\d+)[^""<>\|\x00-\x1F:\*\?\\/]*$", 1, True)
      
      If (strProjectNumber <> "") Then
        On Error Resume Next
        intProjectNumber = CInt(strProjectNumber)
        
        If (Err.Number = 0) Then
          On Error Goto 0
          Exit Do
        End If
        
        On Error Goto 0    
      End If
      
      MsgBox "'" & strL2Folder & "' is not a valid project folder name.  Please try again.", 48
    Loop
    
    ' Calculate source / target paths
    
    intHundred = (intProjectNumber \ 100) * 100
    strL1Folder = "Jobs " & intHundred & " - " & (intHundred + 99)
    
    strTemplateFolder = strScriptFolder & "\" & strL1Folder & "\ZBlank"
    strTargetFolder = strScriptFolder & "\" & strL1Folder & "\" & strL2Folder
    strShortcutFile = strTargetFolder & "\" & strL2Folder & ".lnk"
    strShortcutTarget = strShortcutRoot & "\" & strL1Folder & "\" & strL2Folder
    
    ' Make sure the target doesn't already exist, and that the template folder does
    
    If (objFSO.FolderExists(strTargetFolder)) Then
      MsgBox "Project folder '" & strTargetFolder & "' already exists."
      WScript.Quit 0
    End If
    
    If (Not objFSO.FolderExists(strTemplateFolder)) Then
      MsgBox "Template folder '" & strTemplateFolder & "' does not exist.", 48
      WScript.Quit 1
    End If
    
    ' Attempt to copy over the template folder and create the shortcut.
    
    On Error Resume Next
    
    objFSO.CopyFolder strTemplateFolder, strTargetFolder, True
    
    If (Err.Number <> 0) Then
      MsgBox "Error 0x" & Hex(Err.Number) & " received when creating project folder '" & strTargetFolder & "'."
      WScript.Quit 1
    End If
    
    Set objShortcut = WshShell.CreateShortcut(strShortcutFile)
    objShortcut.TargetPath = strShortcutTarget
    objShortcut.IconLocation = "C:\Windows\System32\shell32.dll, 4"
    objShortcut.Save
    
    MsgBox "Project folder '" & strTargetFolder & "' created successfully."
    WScript.Quit 0
    
    Function RegExGetBRef(strString, strPattern, intBRef, blnIgnoreCase)
      RegExGetBRef = ""
      
      Dim objRegExp
      Dim colMatches, objMatch
      
      Set objRegExp = New RegExp
      
      objRegExp.Pattern = strPattern
      objRegExp.IgnoreCase = blnIgnoreCase
      objRegExp.Global = False
      objRegExp.MultiLine = True
      
      Set colMatches = objRegExp.Execute(strString)
      
      For Each objMatch In colMatches
        If ((intBRef > 0) And (intBRef <= objMatch.SubMatches.Count)) Then
          RegExGetBRef = objMatch.SubMatches(intBRef - 1)
        End If
      Next
    End Function
    

    • Marked as answer by Zach Little Thursday, June 20, 2013 8:44 PM
    Thursday, June 20, 2013 6:18 PM
  • Thank-you for your help! I had to make one minor change as the shortcuts were not generating. It is listed below:

     If ((objFSO.FileExists(strShortcutFile) = False) And (objFSO.FolderExists(strShortcutTarget) = True)) Then

    To

     If ((objFSO.FileExists(strShortcutFile) = False)) Then

    For whatever reason, after removing the Second condition it started generating the ShortCuts. I also added just so they look a little bit better the following before saving the Shorcut:

    		objShortcut.IconLocation = "C:\Windows\System32\shell32.dll, 4"

    Thank-You again for your assistance! If you do have time I would like to see what you could come up with for the second part!

    -Zach

    • Marked as answer by Zach Little Thursday, June 20, 2013 12:55 PM
    Thursday, June 20, 2013 12:55 PM
  • In both scripts, it makes the most sense to put that code right after objShortcut.Save.  That'll ensure you're still going through all of the script's existing logic / data validation before trying to create a folder.

    One thing to keep in mind, though, is that the FileSystemObject.CreateFolder method doesn't create an entire tree of folders.  If the parent (level 1) folder doesn't exist, you'll get a "Path not found" error when trying to create the L2 folder.  Here's a function I've used to address that problem in other scripts:

    Function CreateFolderTree(strFolderName)
      ' Recursive routine to create a folder (including nonexistent parent folders, if needed)
      ' Returns True if folder structure is successfully created.
      
      Dim strParent
      Dim objFSO
      
      Set objFSO = CreateObject("Scripting.FileSystemObject")
      
      strParent = RegExGetBRef(strFolderName, "^(.+)\\[^\\]+\\?$", 1, True)
      
      If (Not objFSO.FolderExists(strParent)) Then
        If (Not CreateFolderTree(strParent)) Then
          CreateFolderTree = False
          Exit Function
        End If
      End If
      
      On Error Resume Next
      objFSO.CreateFolder strFolderName
      On Error Goto 0
      
      If (objFSO.FolderExists(strFolderName)) Then
        CreateFolderTree = True
      Else
        CreateFolderTree = False
      End If
      
      Set objFSO = Nothing
    End Function
    

    • Marked as answer by Zach Little Friday, June 21, 2013 6:14 PM
    Friday, June 21, 2013 3:32 PM

All replies

  • Creating a shortcut with a batch file is annoying at best.  The only sample code I've found for it involves creating a temporary inf file and calling rundll32.  If you can use a VBScript or PowerShell, you'll get access to the WScript.Shell COM object, which provides an easy method for generating new shortcuts.  Does this absolutely have to be a batch file?  If so, I can run with that, but it may be difficult to understand or modify the script later.

    Also, your needs are a little bit unclear.  Is this script only creating the shortcuts, or does it also need to generate each level-2 subfolder based on the name of the level-1 subfolder?  In other words, will a folder named "1701 - Project 1" (for example) already exist before the script is run?

    Wednesday, June 19, 2013 2:39 PM
  • Currently we have this:

    Projects

    Job  1600 - 1699

    Jobs 1600 - 1699 All Exist

    Job  1700 - 1799

    Jobs 1700-1799 All Exist

    Job  1800 - 1899

    Jobs 1800-1894 Exist

    Job 1900 - 1999

    None of these exist yet

    So yes, currently most folders already exist. For Projects 1895 and on, I guess I will be needing a seperate script to run. This Script should Exist in the first subfolder level, and will copy and rename a Template Folder, then create the shortcut in the copy. That is something later down the road that is a whole nother issue in itself. This does not have to be a Batch file, but it does need to be simple in the fact that it can be double clicked and it runs through the subfolders doing its' task.

    If the second part is something you have insight on as well, that'd be helpful, but I understand that this is a time consuming and confusing task, which is why I'm asking for help. I guess the second script that will accomplish the task I need done will have to Copy a folder which will already exist, it's called "Z Blank", and it will rename the folder to whatever the user specifies, so say 1895 - Project X, then it will drop into that folder and create the shortcut.

    The ultimate goal here, is we are trying to quickly generate links in our FileServer to a SharePoint document library, which is where the link leads to. The document library is called RFI, and contains "Folders", which are the same as what are on our fileserver. Our staff needs to be able to interact with these files either through SharePoint or the Fileserver. To make this happen, we have the illusion of them doing so on the FileServer, but it actually resides in SharePoint. This scenario occurs because we require SharePoint generate specific documents, however management wants users to be able to use a familiar interface (Our FileServer) if they are unable to learn to navigate SharePoint.

    Wednesday, June 19, 2013 4:02 PM
  • This is a VBScript, which meets your requirement of being able to just put it in the root folder and double click it, and also gives access to Regular Expressions and the CreateShortcut method I mentioned earlier.  It needs to be saved in a text file with a .vbs extension. This part only covers the first part of your question; creating a shortcut for folders that already exist. I don't have time to work on the rest of it right now, but I might be able to get to it tonight or tomorrow.

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set WshShell = CreateObject("WScript.Shell")
    
    strScriptFolder = RegExGetBRef(WScript.ScriptFullName, "^(.+)\\[^\\]*$", 1, True)
    strShortcutRoot = "\\SERVER\DavWWWRoot\RFI"
    
    Set objRootFolder = objFSO.GetFolder(strScriptFolder)
    
    For Each objL1Folder In objRootFolder.SubFolders
      strMatch = RegExGetBRef(objL1Folder.Name, "^jobs\s*(\d+)\s*-\s*\d+\s*$", 1, True)
      
      If (strMatch <> "") Then
        For Each objL2Folder In objL1Folder.SubFolders
          strShortcutFile = objL2Folder.Path & "\" & objL2Folder.Name & ".lnk"
          strShortcutTarget = strShortcutRoot & "\" & objL1Folder.Name & "\" & objL2Folder.Name
          If ((objFSO.FileExists(strShortcutFile) = False) And (objFSO.FolderExists(strShortcutTarget) = True)) Then
            Set objShortcut = WshShell.CreateShortcut(strShortcutFile)
            objShortcut.TargetPath = strShortcutTarget
            objShortcut.Save
          End If
        Next
      End If
    Next
    
    Function RegExGetBRef(strString, strPattern, intBRef, blnIgnoreCase)
      RegExGetBRef = ""
      
      Dim objRegExp
      Dim colMatches, objMatch
      
      Set objRegExp = New RegExp
      
      objRegExp.Pattern = strPattern
      objRegExp.IgnoreCase = blnIgnoreCase
      objRegExp.Global = False
      objRegExp.MultiLine = True
      
      Set colMatches = objRegExp.Execute(strString)
      
      For Each objMatch In colMatches
        If ((intBRef > 0) And (intBRef <= objMatch.SubMatches.Count)) Then
          RegExGetBRef = objMatch.SubMatches(intBRef - 1)
        End If
      Next
    End Function
    

    • Marked as answer by Zach Little Thursday, June 20, 2013 12:55 PM
    Wednesday, June 19, 2013 7:47 PM
  • Thank-you for your help! I had to make one minor change as the shortcuts were not generating. It is listed below:

     If ((objFSO.FileExists(strShortcutFile) = False) And (objFSO.FolderExists(strShortcutTarget) = True)) Then

    To

     If ((objFSO.FileExists(strShortcutFile) = False)) Then

    For whatever reason, after removing the Second condition it started generating the ShortCuts. I also added just so they look a little bit better the following before saving the Shorcut:

    		objShortcut.IconLocation = "C:\Windows\System32\shell32.dll, 4"

    Thank-You again for your assistance! If you do have time I would like to see what you could come up with for the second part!

    -Zach

    • Marked as answer by Zach Little Thursday, June 20, 2013 12:55 PM
    Thursday, June 20, 2013 12:55 PM
  • You didn't technically ask for it, but I had that second condition in place to make sure it wasn't creating shortcuts to non-existent folders.

    For the second script, I need a little bit more specific detail:  What is the exact name of the "level 2" folder you want created?  In your original post, you listed this structure:

    ->Job 1700 - 1799 (SubFolderLevel1)
    ->1701 - Project 1 (SubFolderLevel2)
    ->1702 - Project 2 (SubFolderLevel2)
    ->Job 1800 - 1899 (SubFolderLevel1)
    ->1801 - Project 3 (SubFolderLevel2)
    ->1802 - Project 4 (SubFolderLevel2)

    Is that "Project ##" part of the folder name, or just something you added as a description?  Is the folder just named "1801", for instance?

    Thursday, June 20, 2013 12:59 PM
  • Here is how it breaks down. We have the Projects Folder, which is the root folder. In here we have the following folders:

    Job 1700 - 1799

    Job 1800 - 1899

    Job 1900 - 1999

    Under each of these folders will be a folder called "ZBlank" which will contain various subfolders and documents. The script would have to ask the user for the new folder name. Once it has the name, it will copy "ZBLANK" and paste it in the same directory, renaming it to whatever the user inputted. The user will be inputting something along the lines of "1901 - Project X" or "1902 - SomeRandomProject". I will not know the names of the projects which is why the user will have to specify. (The script will also be creating the shortcut as it did above, but I think with what you gave me I could figure that part out on my own). Thanks!

    Thursday, June 20, 2013 2:28 PM
  • OK, that's pretty straightforward.  I still think you would want to have some sort of check to determine whether the folder name the user specifies actually exists on your "\\SERVER\DavWWWRoot\RFI" share, but that's up to you (and you said that was breaking the first script I posted, for some reason)

    The only thing I'll enforce with the user input is that it must start with a project number (necessary so I can figure out which "level 1" folder to put it in), and obviously it can't contain any illegal characters for file / folder names in Windows.


    • Edited by David Wyatt Thursday, June 20, 2013 2:33 PM clarification
    Thursday, June 20, 2013 2:32 PM
  • Thanks David! And I see why it was breaking the script now. I am currently working remotely, so I do not have access to the \\SERVER\DavWWWRoot\RFI folder at the moment. Would explain a bit. These folders may not exist on the DavWWWRoot yet, as they are created from a workflow within SharePoint. If the Shortcut does not work, this is appropriate as our first document needs to be created within SharePoint so we can track all subsequent data through our SharePoint site. This is one of the last key pieces to a really long project =/ I appreciate all of your help!

    Thursday, June 20, 2013 5:15 PM
  • I think this will do the trick.  While I was working on this, though, I noticed that in my first script, I was looking for level 1 folders of "Jobs 1800 - 1899" instead of "Job 1800 - 1899" as you had typed.  You didn't mention this when you tested the first script, though, so I stuck with "Jobs" in this one as well.  If that's not correct, just update the line that starts with strL1Folder =

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set WshShell = CreateObject("WScript.Shell")
    
    strScriptFolder = RegExGetBRef(WScript.ScriptFullName, "^(.+)\\[^\\]*$", 1, True)
    strShortcutRoot = "\\SERVER\DavWWWRoot\RFI"
    
    ' Fetch and validate user input.
    
    strL2Folder = ""
    intProjectNumber = -1
    
    Do While (True)
      strL2Folder = InputBox("Please enter the name of the new project folder you want to create.  It must begin with a project number:")
      
      If (strL2Folder = "") Then
        MsgBox "Operation cancelled by user.", 0
        WScript.Quit 0
      End If
      
      strProjectNumber = RegExGetBRef(strL2Folder, "^(\d+)[^""<>\|\x00-\x1F:\*\?\\/]*$", 1, True)
      
      If (strProjectNumber <> "") Then
        On Error Resume Next
        intProjectNumber = CInt(strProjectNumber)
        
        If (Err.Number = 0) Then
          On Error Goto 0
          Exit Do
        End If
        
        On Error Goto 0    
      End If
      
      MsgBox "'" & strL2Folder & "' is not a valid project folder name.  Please try again.", 48
    Loop
    
    ' Calculate source / target paths
    
    intHundred = (intProjectNumber \ 100) * 100
    strL1Folder = "Jobs " & intHundred & " - " & (intHundred + 99)
    
    strTemplateFolder = strScriptFolder & "\" & strL1Folder & "\ZBlank"
    strTargetFolder = strScriptFolder & "\" & strL1Folder & "\" & strL2Folder
    strShortcutFile = strTargetFolder & "\" & strL2Folder & ".lnk"
    strShortcutTarget = strShortcutRoot & "\" & strL1Folder & "\" & strL2Folder
    
    ' Make sure the target doesn't already exist, and that the template folder does
    
    If (objFSO.FolderExists(strTargetFolder)) Then
      MsgBox "Project folder '" & strTargetFolder & "' already exists."
      WScript.Quit 0
    End If
    
    If (Not objFSO.FolderExists(strTemplateFolder)) Then
      MsgBox "Template folder '" & strTemplateFolder & "' does not exist.", 48
      WScript.Quit 1
    End If
    
    ' Attempt to copy over the template folder and create the shortcut.
    
    On Error Resume Next
    
    objFSO.CopyFolder strTemplateFolder, strTargetFolder, True
    
    If (Err.Number <> 0) Then
      MsgBox "Error 0x" & Hex(Err.Number) & " received when creating project folder '" & strTargetFolder & "'."
      WScript.Quit 1
    End If
    
    Set objShortcut = WshShell.CreateShortcut(strShortcutFile)
    objShortcut.TargetPath = strShortcutTarget
    objShortcut.IconLocation = "C:\Windows\System32\shell32.dll, 4"
    objShortcut.Save
    
    MsgBox "Project folder '" & strTargetFolder & "' created successfully."
    WScript.Quit 0
    
    Function RegExGetBRef(strString, strPattern, intBRef, blnIgnoreCase)
      RegExGetBRef = ""
      
      Dim objRegExp
      Dim colMatches, objMatch
      
      Set objRegExp = New RegExp
      
      objRegExp.Pattern = strPattern
      objRegExp.IgnoreCase = blnIgnoreCase
      objRegExp.Global = False
      objRegExp.MultiLine = True
      
      Set colMatches = objRegExp.Execute(strString)
      
      For Each objMatch In colMatches
        If ((intBRef > 0) And (intBRef <= objMatch.SubMatches.Count)) Then
          RegExGetBRef = objMatch.SubMatches(intBRef - 1)
        End If
      Next
    End Function
    

    • Marked as answer by Zach Little Thursday, June 20, 2013 8:44 PM
    Thursday, June 20, 2013 6:18 PM
  • Again, you are amazing! Thank-you for your assistance, this has all worked out perfectly in my test environment. I will be doing this in our live environment tomorrow, but I don't foresee any issues. Thanks David, you're a life saver!
    Thursday, June 20, 2013 8:45 PM
  • Last question in regards to this. First off, everything has worked perfectly. I am running into a small issue, and it is with SharePoint, so I need to see if I can get this script to do something else as well. I am trying to have it create the folders in the Webdav folder as well. I am able to manually do this, so I'm pretty sure it is possible to make the script do it. I have tried using the following code segment to do this:

    Set objFollder = objFSO.CreateFolder(strShortcutTarget)

    any ideas why this wouldn't work? I put this in the loop right before it throws Next

    Friday, June 21, 2013 2:28 PM
  • In both scripts, it makes the most sense to put that code right after objShortcut.Save.  That'll ensure you're still going through all of the script's existing logic / data validation before trying to create a folder.

    One thing to keep in mind, though, is that the FileSystemObject.CreateFolder method doesn't create an entire tree of folders.  If the parent (level 1) folder doesn't exist, you'll get a "Path not found" error when trying to create the L2 folder.  Here's a function I've used to address that problem in other scripts:

    Function CreateFolderTree(strFolderName)
      ' Recursive routine to create a folder (including nonexistent parent folders, if needed)
      ' Returns True if folder structure is successfully created.
      
      Dim strParent
      Dim objFSO
      
      Set objFSO = CreateObject("Scripting.FileSystemObject")
      
      strParent = RegExGetBRef(strFolderName, "^(.+)\\[^\\]+\\?$", 1, True)
      
      If (Not objFSO.FolderExists(strParent)) Then
        If (Not CreateFolderTree(strParent)) Then
          CreateFolderTree = False
          Exit Function
        End If
      End If
      
      On Error Resume Next
      objFSO.CreateFolder strFolderName
      On Error Goto 0
      
      If (objFSO.FolderExists(strFolderName)) Then
        CreateFolderTree = True
      Else
        CreateFolderTree = False
      End If
      
      Set objFSO = Nothing
    End Function
    

    • Marked as answer by Zach Little Friday, June 21, 2013 6:14 PM
    Friday, June 21, 2013 3:32 PM
  • Everything is running beautifully now! Thanks for everything!
    Friday, June 21, 2013 6:14 PM