2010-10-15 29 views
6

Cho một đường dẫn DFS làm cách nào để tôi biết đường dẫn hiện hoạt của nó là gì trên chương trình.Làm thế nào tôi có thể có được một đường dẫn UNC hoạt động trong DFS theo chương trình

Đối exmaple Tôi có 2 máy chủ chia sẻ như "\\Server1\Folder\""\\Server2\Folder\" và nó có DFS bật để nó có thể được truy cập trên "\\DFS_Server\Folder\", làm thế nào tôi sẽ biết con đường hoạt động là những gì hiện "\\DFS_Server\Folder\" được bật, cho dù đó là "\\Server1\Folder\" hoặc "\\Server2\Folder\".

Trả lời

4

thử điều này trong đó sDFSPath là đường dẫn bạn muốn truy vấn và sHostServer là Máy chủ bạn muốn truy vấn WMI, đây có thể là bất kỳ máy chủ nào mà bạn đã đề cập ở trên. Bạn thậm chí có thể làm cho một mã thanh lịch hơn khi nó không thành công trên máy chủ đầu tiên sau đó truy vấn WMI trên các máy chủ tiếp theo

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

Hy vọng nó sẽ làm cho tinh thần

+0

Làm thế nào sẽ giao diện trên trong VBS bằng WMI? Mọi hướng dẫn sẽ được đánh giá cao. – Lizz

5

Nếu tôi hiểu yêu cầu của bạn một cách chính xác, cũng có một API mà dường như làm những gì bạn cần:

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

Sử dụng nó như thế này:

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

Đối tham chiếu API, hãy kiểm tra msdn trên NetDfsGetInfo, DFS_INFO_3, DFS_STORAGE_INFONetApiBufferFree.

+0

Giải pháp tuyệt vời, bạn có thể vui lòng thêm 'using System.Runtime.InteropServices;' vào đầu trang không? – MKesper

+0

@MKesper Vui lòng gửi đề xuất chỉnh sửa ... – takrl

4

Cảm ơn bạn, các gợi ý của bạn hữu ích. Tuy nhiên tôi đã thành công hơn với NetDfsGetClientInfo. Cũng nhận ra rằng quá trình giải quyết có thể đệ quy. Tôi đã kết thúc với ít nhất 2 cuộc gọi đệ quy để có được chia sẻ UNC thực tế thực tế và đây là ví dụ của tôi.

Tôi không biết, làm thế nào

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

Tôi đã phát hiện ra một chế độ nhỏ. Vì vậy, độ phân giải dfs là reciveive. Giả sử bạn đang tìm kiếm một. Mỗi lần lặp lại bạn cần phải loại bỏ EntryPath từ đầu của một, và xây dựng lại nó (tiền tố với ServerName và ShareName, mà bạn nhận được từ StorageInfo) nhận được unc b. Nếu độ phân giải == b hoàn tất. – user3042599

+0

NetDfsGetInfo đã kích hoạt lỗi 1168 (không tìm thấy), có dây, vì vậy tôi đã sử dụng NetDfsGetClientInfo. Điều này chỉ trả về dữ liệu cho lưu trữ đang hoạt động. Đối với lưu trữ không hoạt động, nó sẽ không trả về gì cả. Workaround-hack là sử dụng System.IO.Directory.Exists (...) trên đường dẫn unc của bạn trước khi gọi NetDfsGetClientInfo. – user3042599

+0

NetDfsGetClientInfo có thể được sử dụng trong VBS, có lẽ với WMI không? – Lizz

Các vấn đề liên quan