0

I have created and am using the following function to map and shorten the path-length of a network drive using SUBST command to work with my tool that implements ADO.

Function MapBasePathToDrive(FullDirectory As String, strDrive As String, blnReadAttr As Boolean) As String

    Dim objShell As Object
    Dim sCmd$
    Dim WaitOnReturn As Boolean: WaitOnReturn = True
    Dim WindowStyle As Integer: WindowStyle = 0
    Dim i&, lngErr&

    ' remove backslash for `SUBST` dos command to work
    If Right(FullDirectory, 1) = "\" Then FullDirectory = Left(FullDirectory, Len(FullDirectory) - 1)

    ' prefix & suffix directory with double-quotes
    FullDirectory = Chr(34) & FullDirectory & Chr(34)

    Set objShell = CreateObject("WScript.Shell")
    For i = 1 To 2
        If i = 1 Then
            'remove drive
            sCmd = "SUBST" & " " & strDrive & " " & "/D"
            lngErr = objShell.Run(sCmd, WindowStyle, WaitOnReturn)
        Else
            'add drive
            sCmd = "SUBST" & " " & strDrive
            lngErr = objShell.Run(sCmd & " " & FullDirectory, WindowStyle, WaitOnReturn)
        End If
    Next i

    ' remove read-only attribute from Destination folder if you plan to copy files
    If blnReadAttr Then
        sCmd = "ATTRIB " & "-R" & " " & strDrive & "\*.*" & " " & "/S /D"
        lngErr = objShell.Run(sCmd, WindowStyle, WaitOnReturn)
    End If

    ' to refresh explorer to show newly created drive
    sCmd = "%windir%\explorer.exe /n,"
    lngErr = objShell.Run(sCmd & strDrive, WindowStyle, WaitOnReturn)

    ' add backslash to drive if absent
    MapBasePathToDrive = PathWithBackSlashes(strDrive)

End Function

The above function works well most of the time to shorten the long network path and then passing it to Application.FileDialog.InitialFilename. However, if a drive (say Y:) is already mapped, then the problem ensues as Application.FileDialog.InitialFilename goes for a toss and end user is not able to select the required files, but sees files of Y:\!

What i want to do :

  • See if the concerned Drive e.g. Y: is available or not.
  • If in use, assign Y:'s network path to the next freely available drive.
  • Disconnect (delete) Y:
  • Assign Y: to concerned Directory.

I have the below batch file that does exactly that, but i don't know how to convert this batch code into a VBA function i.e. similar to above shown function. Any help would be most appreciated.

@echo off 
if exist y:\ (
    for /F "tokens=1,2,3" %%G in ('net use^|Find /I "Y:"^|Find "\\"')  do ( net use * %%H >nul 2>&1)
    net use y: /delete >nul 2>&1
)
net use y: \\xx.xx.xx.xx\SomeFolder >nul 2>&1

EDIT:

I modified the above Function to add this code. The problem lies only with the sCMD string that is not getting executed by WScript.Shell because of incorrect double-quotes.

  • Can someone help me with the proper syntax?
  • If it is a local folder i need to map, how would the syntax change?

...

Sub TestDriveMapping()
    MapBasePathToDrive "\\xx.xx.xx.xx\SomeFolder", "Y:", True
End Sub

Function MapBasePathToDrive(FullDirectory As String, strDrive As String, blnReadAttr As Boolean) As String

    Dim objShell As Object
    Dim sCmd$
    Dim WaitOnReturn As Boolean: WaitOnReturn = True
    Dim WindowStyle As Integer: WindowStyle = 0
    Dim i&, lngErr&

    ' remove backslash for `NET USE` dos command to work
    If Right(FullDirectory, 1) = "\" Then FullDirectory = Left(FullDirectory, Len(FullDirectory) - 1)

    ' prefix & suffix directory with double-quotes
    FullDirectory = Chr(34) & FullDirectory & Chr(34)

    Set objShell = CreateObject("WScript.Shell")
    sCmd = ""
    sCmd = "@Echo Off " & vbCrLf
    sCmd = sCmd & " IF EXIST " & strDrive & " (" & vbCrLf
    sCmd = sCmd & "  FOR /F " & Chr(34) & "TOKENS=1,2,3" & Chr(34) & " %G IN (" & Chr(39) & "NET USE ^|Find /I " & Chr(34) & strDrive & Chr(34) & "^|Find ""\\""" & Chr(39) & ")  DO ( NET USE * %H >NUL 2>&1)" & vbCrLf
    sCmd = sCmd & "  NET USE " & strDrive & " /DELETE >NUL 2>&1" & vbCrLf
    sCmd = sCmd & " )" & vbCrLf
    sCmd = sCmd & " NET USE " & strDrive & " " & FullDirectory & " >NUL 2>&1"

    lngErr = objShell.Run(sCmd, WindowStyle, WaitOnReturn)

    ' remove read-only attribute from Destination folder if you plan to copy files
    If blnReadAttr Then
        sCmd = "ATTRIB " & "-R" & " " & strDrive & "\*.*" & " " & "/S /D"
        lngErr = objShell.Run(sCmd, WindowStyle, WaitOnReturn)
    End If

    ' to refresh explorer to show newly created drive
    sCmd = "%windir%\explorer.exe /n,"
    lngErr = objShell.Run(sCmd & strDrive, WindowStyle, WaitOnReturn)

    ' add backslash to drive if absent
    MapBasePathToDrive = PathWithBackSlashes(strDrive)

End Function
sifar
  • 1,086
  • 1
  • 17
  • 43
  • Maybe I'm over simplifying this but if you just want to check if the drive is in use before you do anything with the drive letter, you could use `FileSystemObject` to do that. [This might help](https://stackoverflow.com/questions/24562491/check-if-mapped-network-available) – Zac Mar 02 '20 at 13:25

1 Answers1

1

Try the next code, please. It uses VBScript objects for checking and doing the mapping...

Sub ReMapDrive()
  Dim objNet As Object, strLocal As String, strPath As String, fso As Object
  Set fso = CreateObject("Scripting.FileSystemObject")
  Set objNet = CreateObject("WScript.Network")
  'Name the drive and its path:
  strLocal = "Y:"
  strPath = "\\xx.xx.xx.xx\SomeFolder"

    'Check if it is mapped and map it if it is not:
    If fso.FolderExists(strLocal) = True Then
        MsgBox (strLocal & " Mapped")
    Else
        objNet.MapNetworkDrive strLocal, , False
        MsgBox (strLocal & " Re-mapped")
    End If
   Set fso = Nothing: Set objNet = Nothing
End Sub

I am not the father of the code. I have it from the internet (not knowing its provenience) and I use it for years... I just adapted it in a way to work (I hope) in your case.

The next function will return (in an array) your mapped drives and their path. I also included a sub to see how it can be tested/used...

Sub testEnumMPapp()
 Dim arrMap As Variant, i As Long
  arrMap = enumMappedDrives
  For i = 0 To UBound(arrMap, 2)
    Debug.Print arrMap(0, i), arrMap(1, i)
  Next i
End Sub

    Private Function enumMappedDrives() As Variant
      Dim objNet As Object, fso As Object, oDrives As Object
      Dim mapRep As Variant, i As Long, k As Long
      ReDim mapRep(1, 100)
      Set fso = CreateObject("Scripting.FileSystemObject")
      Set objNet = CreateObject("WScript.Network")
      Set oDrives = objNet.EnumNetworkDrives
        If oDrives.Count > 0 Then
            For i = 0 To oDrives.Count - 1 Step 2
                mapRep(0, k) = oDrives.Item(i)
                mapRep(1, k) = oDrives.Item(i + 1)
                k = k + 1
            Next
        End If
        ReDim Preserve mapRep(1, k - 1)
        enumMappedDrives = mapRep
    End Function
FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • Thanks @FaneDuru. The only problem that i am facing is how to save a Remotepath of an existing `Y: drive` to the next free available drive, before removing/setting the Y: drive to a new remotepath address i.e. i want to retain the existing remotepath of the Y:\ drive to another freely available drive, before disconnecting/setting Y:\ again. Hope you are getting my point. – sifar Mar 02 '20 at 13:09
  • @sifar: There is a `EnumNetworkDrives` property of `objNet`, which will retrieve all the mapped drives. But, we must find a way to report them/it to something. Let us say an array of letters... For such a way I have an idea regarding how to proceed. Let me check to see if it is really possible to find the last empty letter. I am not so sure it is. Or if this is something easy to be achieved. Now, I have something urgent to do, but I promise to dig deeper. In the meantime I will also post the code able to retrieve the mapped drives list. – FaneDuru Mar 02 '20 at 13:24
  • My only concern is, when i remove any existing remote shares on `Y:\`, i want to `retain` them by assigning them to any freely available drive letter before reassigning a new share to `Y:\`. – sifar Mar 02 '20 at 13:30
  • Unfortunately the above code doesn't list out disconnected drives. I had googled and tried a similar code earlier. – sifar Mar 02 '20 at 13:35
  • If they are disconnected, why would you like to take them in consideration? Besides that, if your above code uses "Y:" mapped drive, why not rebuilding the (necessary) path for this connection? Why would you like to keep it, even being not correct one? If you will always run the code (I can make it a function to return `True`) to check and remake the mapping, why do you bother about one connection having a wrong path? I am asking that trying to put myself instead of you and together find a solution... – FaneDuru Mar 02 '20 at 13:38
  • because if a drive is already assigned i.e. existing even though in a disconnected state, it will not map again unless i remove it first. Also, since the remote shares are client folders, i cannot lose them when reassigning Y:. How do i get the next available free drive to save an existing remoteshare folder that is currently attached to Y:? I cannot delete the disconnected drives as they are already attached to some other important remote shares. – sifar Mar 02 '20 at 13:41
  • I checked now my code which enumerates all the mapped drives and it RETURNS ALL MAPPED DRIVES, connected or not... – FaneDuru Mar 02 '20 at 13:55
  • unfortunately for me, the above code only lists network drives that are live (GREEN) and not the ones that are disconnected (RED with a CROSS). – sifar Mar 02 '20 at 14:04
  • 1
    @sifar: I would propose the next approach: I will transform the sub enumerating the mapping drives in a function, returning an array. Its first parameter will be the mapping letter and the second will be the mapping path. The second one will be checked against your wished path and used if it matches. If not, a new mapping will be done on another Letter, but not the one in the array. Not necessarily to be the following letter. Would that be convenient for you? – FaneDuru Mar 02 '20 at 14:10
  • @sifar: Strange... I disconnected my laptop from the network and that enumerating sub returned all my mappings, even not connected... Can you check that again, please? I consider that problem a challenge... :) Is your computer connected to a domain? – FaneDuru Mar 02 '20 at 14:12
  • i am on VPN not on office network. Does that help?....disconnected from vpn, same limited list of network drives showing and not all... – sifar Mar 02 '20 at 14:12
  • @sifar: I am afraid that does things worst... Unfortunately, I cannot check on such an environment... And I missed some of your comments when I was disconnected. That's why I answered like I did not see them... I really did not see them. For now, I will post the function and maybe you will test it and find an appropriate way on your working environment. – FaneDuru Mar 02 '20 at 14:16