2010-10-15 20 views
6

Dada una ruta DFS, ¿cómo sabría cuál es la ruta activa en la que se encuentra actualmente programaticamente?¿Cómo puedo obtener una ruta UNC activa en DFS programáticamente?

Para exmaple tengo 2 acciones Servidores como "\\Server1\Folder\" y "\\Server2\Folder\" y tiene DFS encendido por lo que se puede acceder en "\\DFS_Server\Folder\", ¿cómo iba a saber lo que es la ruta activa actualmente "\\DFS_Server\Folder\" está activada, si se trata de "\\Server1\Folder\" o "\\Server2\Folder\".

Respuesta

4

intente esto donde sDFSPath es la ruta que desea consultar y sHostServer es el servidor que desea consultar su WMI, este puede ser cualquiera de los dos servidores mencionados anteriormente. Usted puede incluso hacer un código más elegante cuando falla el primer servidor luego volver a consultar WMI en los próximos servidores

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

espero que tenga sentido

+0

¿Cómo sería el aspecto anterior en VBS mediante WMI? Cualquier orientación sería apreciada. – Lizz

5

Si entiendo su requerimiento correctamente, también hay una API que parece Haz lo que tengas:

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

utilizar de esta manera:

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

Para una referencia API, consulte msdn en NetDfsGetInfo, DFS_INFO_3, DFS_STORAGE_INFO y NetApiBufferFree.

+0

Gran solución, ¿podría agregar 'using System.Runtime.InteropServices;' a la parte superior? – MKesper

+0

@MKesper Siéntase libre de enviar una sugerencia de edición ... – takrl

4

Gracias, tus consejos fueron útiles. Sin embargo, tuve más éxito con NetDfsGetClientInfo. También se dio cuenta de que el proceso de resolución puede ser recursivo. Terminé con al menos 2 llamadas recursivas para obtener la parte física real de UNC y aquí está mi ejemplo.

No sé, cómo

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

Encontré poco modo. Entonces la resolución dfs es recursiva. Suponiendo que estés buscando unc a. Cada iteración necesita quitar EntryPath desde el principio de, y reconstruirlo (prefijo con ServerName y ShareName, que se obtiene de StorageInfo) recibiendo unc b. Si una == b resolución está completa. – user3042599

+0

NetDfsGetInfo estaba activando el error 1168 (no encontrado), que está cableado, así que usé NetDfsGetClientInfo. Esta devuelve datos solo para el almacenamiento activo. Para el almacenamiento no activo no devuelve nada. Workaround-hack es usar System.IO.Directory.Exists (...) en su camino unc antes de llamar a NetDfsGetClientInfo. – user3042599

+0

¿Se puede usar NetDfsGetClientInfo en VBS, quizás con WMI? – Lizz

Cuestiones relacionadas