Click here to Skip to main content
15,885,985 members
Articles / Programming Languages / C#

How to Determine Active UNC Path in DFS Programatically

Rate me:
Please Sign up or sign in to vote.
4.67/5 (2 votes)
26 Oct 2010CPOL3 min read 38.1K   5   6
How to determine active UNC path in DFS programmatically

WMI is really helpful specially when you don't have a DLL or Assembly that you can reference to or even if it's hard to understand how a DLL works and how you define those structures that the assembly is outputting, one of this is finding out what are the active UNCs given a DFS Link. To use WMI on .NET is as easy as referencing to:

C#
using System.Management;

then query the WMI objects you need. Now to get which are the active UNC paths given a link or folder location, you usually right click properties of the folder to find out which is active:

But programmatically, you need to query Win32_DfsTarget in the root\cimv2 namespace, by filtering the results to State = 1 will show all current active connections. Now below are the codes to achieve that on .NET.

Determine Active UNC Path in DFC using WMI

C#
public static ArrayList GetActiveServers(string sPath)
{
    ArrayList aHostNames = new ArrayList();
    ArrayList aDFSServers = new ArrayList();
    aDFSServers.Add("Server1");
    aDFSServers.Add("Server2");

    foreach (string sHostServer in aDFSServers)
    {
        ManagementObjectCollection oObjectCollection = null;
        if (IsHostOnline(sHostServer, "LinkName", sPath, ref oObjectCollection))
        {
            if (oObjectCollection.Count != 0)
            {
                foreach (ManagementObject oItem in oObjectCollection)
                {
                    aHostNames.Add(oItem.Properties["ServerName"].Value.ToString());
                }
            }
            break;
        }
    }
    return aHostNames;
}

public static bool IsHostOnline(string sHostServer, string sSearchField,
    string sSearchString, ref ManagementObjectCollection oManagementObjectCollection)
{
    try
    {
        ArrayList sHostNames = new ArrayList();

        ManagementPath oManagementPath = new ManagementPath();
        oManagementPath.Server = sHostServer;
        oManagementPath.NamespacePath = @"root\cimv2";

        oManagementScope = new ManagementScope(oManagementPath);
        oManagementScope.Connect();

        SelectQuery oSelectQuery = new SelectQuery();
        oSelectQuery.QueryString = 
        @"SELECT * FROM Win32_DfsTarget WHERE " + sSearchField + 
            " LIKE '%" + sSearchString.Replace
            ("\\", "\\\\") + "%' and State = 1";

        ManagementObjectSearcher oObjectSearcher = new ManagementObjectSearcher(
            oManagementScope, oSelectQuery);
        ManagementObjectCollection oObjectCollection = oObjectSearcher.Get();

        if (oObjectCollection.Count != 0)
        {
            oManagementObjectCollection = oObjectCollection;
            return true;
        }
        return false;
    }
    catch
    {
        return false;
    }
}

To explain a bit on what happens on the code, I had separated them on two Functions, one is to check whether the Host is online and another is to place those query results in a more useable type to be consumed by your application which is an ArrayList Type. Now the Function which checks for the Availability of the host you are querying is also outputting the result set you need so it executes one action for the whole process saving time and resources rather than pinging the server first using WMI then do your stuff, they both go to WMI anyways.

Now if you notice, we are checking this for all servers, that's why you have that ArrayList aDFSServers on GetActiveServers which enumerates all your DFS Host, were doing that so in an event that one is down, you can still check the other servers on roster that's the reason why you also have DFS anyways, for redundancy. All servers on your DFS Environment will have the same contents on the Win32_DfsTarget anyways.

Now you notice WMI is a bit slow as you are querying a big set of extension data of the Windows Driver Model, if you opt to choose another option, then using Netapi32.dll will be the better option as it is faster but requires more understanding on how it works and the data model that it outputs. Netapi32.dll is a process belonging to the Microsoft Network Program that contains the Windows NET API used so that applications gain access to Microsoft network like DFS. Now to achieve the same results as above, you need the following codes.

Determine Active UNC Path in DFC using Netapi32.dll

C#
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetDfsGetInfo
    (
    [MarshalAs(UnmanagedType.LPWStr)] string EntryPath,
    [MarshalAs(UnmanagedType.LPWStr)] string ServerName,
    [MarshalAs(UnmanagedType.LPWStr)] string ShareName,
    int Level,
    ref IntPtr Buffer
    );

public struct DFS_INFO_3
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string EntryPath;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string Comment;
    public UInt32 State;
    public UInt32 NumberOfStorages;
    public IntPtr Storages;
}

public struct DFS_STORAGE_INFO
{
    public Int32 State;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ServerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ShareName;
}

public static ArrayList GetActiveServersPKI(string sDFSPath)
{
    ArrayList sServers = new ArrayList();
    IntPtr pBuffer = new IntPtr();
    int iResult = NetDfsGetInfo(sDFSPath, null, null, 3, ref pBuffer);
    if (iResult == 0)
    {

        DFS_INFO_3 oDFSInfo = 
        (DFS_INFO_3)Marshal.PtrToStructure(pBuffer, typeof(DFS_INFO_3));
        for (int i = 0; i < oDFSInfo.NumberOfStorages; i++)
        {
            IntPtr pStorage = new IntPtr(oDFSInfo.Storages.ToInt64() + i * Marshal.SizeOf(
                typeof(DFS_STORAGE_INFO)));
            DFS_STORAGE_INFO oStorageInfo = (DFS_STORAGE_INFO)Marshal.PtrToStructure(pStorage,
                typeof(DFS_STORAGE_INFO));

            //Get Only Active Hosts
            if (oStorageInfo.State == 2)
            {
                sServers.Add(oStorageInfo.ServerName);
            }
        }
    }
    return sServers;
}

If you noticed, we don't have to enumerate the servers to query if we are directly communicating with the DLL, delivering the result will be fast as well. Now for a bit of an explanation on what the piece of code does.

On the method NetDfsGetInfo, you are just importing the DLL called “Netapi32.dll” and exposing that to your application, now since the DLL methods output a buffer, you need to understand how that buffer is structured which is defined here. That is why if you notice, we defined structures DFS_INFO_3 and DFS_STORAGE_INFO to handle that output into a more usable type.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
New Zealand New Zealand
http://nz.linkedin.com/in/macaalay
http://macaalay.com/

Comments and Discussions

 
QuestionHow to call Pin
Rocker_Amit5-Feb-15 21:04
Rocker_Amit5-Feb-15 21:04 
Questioncan not determine which storage server is active Pin
steven725-Apr-13 11:16
steven725-Apr-13 11:16 
QuestionObtaining DFS Link Target Free Space Pin
Member 829578718-Jan-12 13:02
Member 829578718-Jan-12 13:02 
AnswerRe: Obtaining DFS Link Target Free Space Pin
Raymund Macaalay18-Jan-12 13:56
Raymund Macaalay18-Jan-12 13:56 
GeneralRe: Obtaining DFS Link Target Free Space Pin
Member 829578719-Jan-12 5:01
Member 829578719-Jan-12 5:01 
GeneralNative American Jewelry | Turquoise Jewelry | SilverTribe Pin
silvertribe.links19-Oct-10 5:07
silvertribe.links19-Oct-10 5:07 
Turquoise Jewelry

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.