如何以编程方式在DFS中获取活动的UNC路径

时间:2010-10-15 00:44:19

标签: c# wmi dfs

给定DFS路径,我如何知道它当前以编程方式存在的活动路径。

例如,我有2个服务器共享为"\\Server1\Folder\""\\Server2\Folder\"并且它已打开DFS,因此可以在"\\DFS_Server\Folder\"上访问它,我怎么知道当前的活动路径是什么"\\DFS_Server\Folder\"已启用,无论是"\\Server1\Folder\"还是"\\Server2\Folder\"

3 个答案:

答案 0 :(得分:6)

如果我正确理解您的要求,那么还有一个似乎可以满足您需求的API:

// mscorlib (no additional assemblies needed)
using System.Runtime.InteropServices;

public static class Dfs
{
    private enum NetDfsInfoLevel
    {
        DfsInfo1 = 1,
        DfsInfo2 = 2,
        DfsInfo3 = 3,
        DfsInfo4 = 4,
        DfsInfo5 = 5,
        DfsInfo6 = 6,
        DfsInfo7 = 7,
        DfsInfo8 = 8,
        DfsInfo9 = 9,
        DfsInfo50 = 50,
        DfsInfo100 = 100,
        DfsInfo150 = 150,
    }

    [DllImport("netapi32.dll", SetLastError = true)]
    private static extern int NetApiBufferFree(IntPtr buffer);

    [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int NetDfsGetInfo(
        [MarshalAs(UnmanagedType.LPWStr)] string DfsEntryPath, // DFS entry path for the volume
        [MarshalAs(UnmanagedType.LPWStr)] string ServerName,   // This parameter is currently ignored and should be NULL
        [MarshalAs(UnmanagedType.LPWStr)] string ShareName,    // This parameter is currently ignored and should be NULL.
        NetDfsInfoLevel Level,                                 // Level of information requested
        out IntPtr Buffer                                      // API allocates and returns buffer with requested info
        );

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct DFS_INFO_3
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string EntryPath;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string Comment;
        public int State;
        public int NumberOfStorages;
        public IntPtr Storage;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct DFS_STORAGE_INFO
    {
        public int State;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string ServerName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string ShareName;
    }

    private static T GetStruct<T>(IntPtr buffer, int offset=0)where T:struct
    {
        T r = new T();
        r = (T) Marshal.PtrToStructure(buffer + offset * Marshal.SizeOf(r), typeof(T));
        return r;
    }

    public static string GetDfsInfo(string server)
    {
        string rval = null;
        IntPtr b;
        int r = NetDfsGetInfo(server, null, null, NetDfsInfoLevel.DfsInfo3, out b);
        if(r != 0)
        {
            NetApiBufferFree(b);

            // return passed string if not DFS
            return rval;
        }

        DFS_INFO_3 sRes = GetStruct<DFS_INFO_3>(b);
        if(sRes.NumberOfStorages > 0)
        {
            DFS_STORAGE_INFO sResInfo = GetStruct<DFS_STORAGE_INFO>(sRes.Storage);
            rval = string.Concat(@"\\", sResInfo.ServerName, @"\", sResInfo.ShareName, @"\");
        }

        NetApiBufferFree(b);

        return rval;
    }
}

像这样使用:

string dfsPath = @"\\DFS_Server\Folder\";
string share = Dfs.GetDfsInfo(dfsPath)

有关API参考,请检查NetDfsGetInfoDFS_INFO_3DFS_STORAGE_INFONetApiBufferFree上的msdn。

答案 1 :(得分:4)

尝试这样的情况,其中sDFSPath是您要查询的路径,sHostServer是您要查询WMI的服务器,这可以是您上面提到的两台服务器中的任何一台。您甚至可以在第一台服务器上发生故障时生成更优雅的代码,然后在下一台服务器上查询WMI

public static ArrayList GetActiveServers(string sDFSPath, string sHostServer)
{
    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 LinkName LIKE '%" + sDFSPath.Replace("\\", "\\\\") + "%' and State = 1";

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

    if (oObjectCollection.Count != 0)
    {
        foreach (ManagementObject oItem in oObjectCollection)
        {
            sHostNames.Add(oItem.Properties["ServerName"].Value.ToString());
        }
    }

    return sHostNames;
}

希望它有意义

答案 2 :(得分:4)

谢谢你,你的提示很有用。但是我使用NetDfsGetClientInfo更成功。还意识到解析过程可能是递归的。我最终得到了至少2次递归调用以获得实际的物理UNC共享,这是我的榜样。

我不知道,怎么样

public static class DFS
{
    #region Import

    [DllImport("Netapi32.dll", EntryPoint = "NetApiBufferFree")]
    public static extern uint NetApiBufferFree(IntPtr Buffer);

    [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,
        out IntPtr Buffer);

    [DllImport("Netapi32.dll")]
    public static extern int NetDfsGetClientInfo(
        [MarshalAs(UnmanagedType.LPWStr)] string EntryPath,
        [MarshalAs(UnmanagedType.LPWStr)] string ServerName,
        [MarshalAs(UnmanagedType.LPWStr)] string ShareName,
        int Level,
        out IntPtr Buffer);

    #endregion

    #region Structures

    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;
    }

    #endregion

    const int DFS_VOLUME_STATE_OK = 0x00000001;
    const int DFS_VOLUME_STATE_ONLINE = 0x00000004;
    const int DFS_STORAGE_STATE_ONLINE = 0x00000002;
    const int DFS_STORAGE_STATE_ACTIVE = 0x00000004;

    public static String GetSharePath(String DFSPath)
    {
        if (!String.IsNullOrEmpty(DFSPath))
        {
            IntPtr Buffer = IntPtr.Zero;
            try
            {
                int Error = NetDfsGetClientInfo(DFSPath, null, null, 3, out Buffer);
                if (Error == 0)
                {
                    DFS_INFO_3 DFSInfo = (DFS_INFO_3)Marshal.PtrToStructure(Buffer, typeof(DFS_INFO_3));
                    if ((DFSInfo.State & DFS_VOLUME_STATE_OK) > 0)
                    {
                        String SubPath = DFSPath.Remove(0, 1 + DFSInfo.EntryPath.Length).TrimStart(new Char[] { '\\' });
                        for (int i = 0; i < DFSInfo.NumberOfStorages; i++)
                        {
                            IntPtr Storage = new IntPtr(DFSInfo.Storages.ToInt64() + i * Marshal.SizeOf(typeof(DFS_STORAGE_INFO)));
                            DFS_STORAGE_INFO StorageInfo = (DFS_STORAGE_INFO)Marshal.PtrToStructure(Storage, typeof(DFS_STORAGE_INFO));
                            if ((StorageInfo.State & DFS_STORAGE_STATE_ACTIVE) > 0)
                            {
                                if (String.IsNullOrEmpty(SubPath))
                                {
                                    return String.Format(@"\\{0}\{1}", StorageInfo.ServerName, StorageInfo.ShareName);
                                }
                                else
                                {
                                    return GetSharePath(String.Format(@"\\{0}\{1}\{2}", StorageInfo.ServerName, StorageInfo.ShareName, SubPath));
                                }
                            }
                        }
                    }
                }
                else if (Error == 2662)
                    return DFSPath;
            }
            finally
            {
                NetApiBufferFree(Buffer);
            }
        }
        return null;
    }

    public static String GetShareName(String SharePath)
    {
        if (!String.IsNullOrEmpty(SharePath))
        {
            String[] Tokens = SharePath.Trim(new Char[] { '\\' }).Split(new Char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            if (2 <= Tokens.Length)
                return Tokens[1];
        }
        return null;
    }
}