Alexander McFarlane
Alexander McFarlane

Reputation: 11293

Obtain the DFS path of a network location in Python

I want to obtain a ping-like response from a Windows network location that has a Distributed File System architecture e.g.

path = r'\\path\to\some\shared\folder_x'
delay = ping_func(path)
print delay # return response in milliseconds ?
234

Once I have host computer I can easily ping the location.

I can determine the host name for folder_x by looking at the DFS tab in the windows explorer which will look like e.g.

\\hostcomputer.server.uk\shared$\folder_x

How can I do this programmatically in Python?

Upvotes: 4

Views: 2014

Answers (2)

Wardy
Wardy

Reputation: 73

I've been able to directly call the NetDfsGetInfo function using Python's "ctypes" module.

Some stumbling points I had was understanding the C++/Python interface and variable marshalling - that's what the dfs.argtypes helps with.

The C++ calls return their structures by placing pointers into a buffer you supply to the call. Using byref you are matching the function prototype LPBYTE *Buffer

Processing the output requires defining a "Structure" that matches the function return, in this case DFS_INFO_3. The python "buffer" variable is cast as a pointer to DFS_INFO_3 and ctypes.Structure defines the field names and the types the struct is build from. Then you can access them via attribute name, eg, dfs_info.EntryPath

There was a pointer to a variable-length array (DFS_STORAGE_INFO) returned too, which is able to be accessed via normal Python storage[i] syntax.

import ctypes as ct
from ctypes import wintypes as win

dfs = ct.windll.netapi32.NetDfsGetInfo
dfs.argtypes = [
    win.LPWSTR,
    win.LPWSTR,
    win.LPWSTR,
    win.DWORD,
    ct.POINTER(win.LPBYTE),
]

class DFS_STORAGE_INFO(ct.Structure):
    """Contains information about a DFS root or link target in a DFS namespace."""

    _fields_ = [  # noqa: WPS120
        ("State", win.ULONG),
        ("ServerName", win.LPWSTR),
        ("ShareName", win.LPWSTR),
    ]

class DFS_INFO_3(ct.Structure):  # noqa: WPS114
    """Contains information about a Distributed File System (DFS) root or link."""

    _fields_ = [  # noqa: WPS120
        ("EntryPath", win.LPWSTR),
        ("Comment", win.LPWSTR),
        ("State", win.DWORD),
        ("NumberOfStorages", win.DWORD),
        ("Storage", ct.POINTER(DFS_STORAGE_INFO)),
    ]

# ----- Function call -----

buffer = win.LPBYTE()  # allocate a LPBYTE type buffer to be used for return pointer
dret = dfs(r"\\something.else\here", None, None, 3, ct.byref(buffer))
# specify that buffer now points to a DFS_INFO_3 struct
dfs_info = ct.cast(buffer, ct.POINTER(DFS_INFO_3)).contents

print(dfs_info.EntryPath)

for i in range(dfs_info.NumberOfStorages):
    storage = dfs_info.Storage[i]
    print(
        f"{storage.ServerName=}",
        f"{storage.ShareName=}",
    )

Upvotes: 1

Tarun Lalwani
Tarun Lalwani

Reputation: 146520

Since you are using Windows, your always install pywin32 and WMI to get the WMI functions. And below should help you connect to remote DFS. Can't test it as I don't have Windows or DFS

import wmi

c = wmi.WMI (ip, user="user", password="pwd")

for share in c.Win32_Share (Type=0):
  print share.Caption, share.Path
  for session in share.associators (
    wmi_result_class="Win32_ServerConnection"
  ):
    print "  ", session.UserName, session.ActiveTime

Upvotes: 1

Related Questions