2009-07-06 19 views
19

Estoy tratando de averiguar cómo programáticamente (estoy usando C#) determinar el nombre (o i.p.) de los servidores a los que mi estación de trabajo tiene mapas actuales. En otras palabras, en algún momento en Windows Explorer mapeé una unidad de red en una letra de unidad (o usé "net use w:" para mapearla). Yo sé cómo conseguir las unidades de red en el sistema:¿Cómo descubrir mediante programación unidades de red mapeadas en el sistema y sus nombres de servidor?

DriveInfo[] allDrives = DriveInfo.GetDrives(); 
foreach (DriveInfo d in allDrives) 
{ 
    if (d.IsReady && d.DriveType == DriveType.Network) 
    { 
    } 
} 

Pero la clase DriveInfo no tiene propiedades que me dicen qué servidor y la carpeta compartida en la unidad asignada está asociado. ¿Hay algún otro lugar donde debería estar mirando?

+1

Gosh, me encanta este lugar! Haga una pregunta y casi inmediatamente alguien ingresa con una respuesta excelente, en este caso, tres respuestas exhaustivas que contienen material increíblemente útil. Ojalá pudiera marcarlos como Aceptados. ¡Voto total por todos lados, aunque! ¡Gracias! – Cyberherbalist

Respuesta

25

¿Has intentado utilizar WMI para hacerlo?

using System; 
using System.Management; 
using System.Windows.Forms; 

public static void Main() 
{ 
    try 
    { 
     var searcher = new ManagementObjectSearcher(
      "root\\CIMV2", 
      "SELECT * FROM Win32_MappedLogicalDisk"); 

     foreach (ManagementObject queryObj in searcher.Get()) 
     { 
      Console.WriteLine("-----------------------------------"); 
      Console.WriteLine("Win32_MappedLogicalDisk instance"); 
      Console.WriteLine("-----------------------------------"); 
      Console.WriteLine("Access: {0}", queryObj["Access"]); 
      Console.WriteLine("Availability: {0}", queryObj["Availability"]); 
      Console.WriteLine("BlockSize: {0}", queryObj["BlockSize"]); 
      Console.WriteLine("Caption: {0}", queryObj["Caption"]); 
      Console.WriteLine("Compressed: {0}", queryObj["Compressed"]); 
      Console.WriteLine("ConfigManagerErrorCode: {0}", queryObj["ConfigManagerErrorCode"]); 
      Console.WriteLine("ConfigManagerUserConfig: {0}", queryObj["ConfigManagerUserConfig"]); 
      Console.WriteLine("CreationClassName: {0}", queryObj["CreationClassName"]); 
      Console.WriteLine("Description: {0}", queryObj["Description"]); 
      Console.WriteLine("DeviceID: {0}", queryObj["DeviceID"]); 
      Console.WriteLine("ErrorCleared: {0}", queryObj["ErrorCleared"]); 
      Console.WriteLine("ErrorDescription: {0}", queryObj["ErrorDescription"]); 
      Console.WriteLine("ErrorMethodology: {0}", queryObj["ErrorMethodology"]); 
      Console.WriteLine("FileSystem: {0}", queryObj["FileSystem"]); 
      Console.WriteLine("FreeSpace: {0}", queryObj["FreeSpace"]); 
      Console.WriteLine("InstallDate: {0}", queryObj["InstallDate"]); 
      Console.WriteLine("LastErrorCode: {0}", queryObj["LastErrorCode"]); 
      Console.WriteLine("MaximumComponentLength: {0}", queryObj["MaximumComponentLength"]); 
      Console.WriteLine("Name: {0}", queryObj["Name"]); 
      Console.WriteLine("NumberOfBlocks: {0}", queryObj["NumberOfBlocks"]); 
      Console.WriteLine("PNPDeviceID: {0}", queryObj["PNPDeviceID"]); 

      if(queryObj["PowerManagementCapabilities"] == null) 
       Console.WriteLine("PowerManagementCapabilities: {0}", queryObj["PowerManagementCapabilities"]); 
      else 
      { 
       UInt16[] arrPowerManagementCapabilities = (UInt16[])(queryObj["PowerManagementCapabilities"]); 
       foreach (UInt16 arrValue in arrPowerManagementCapabilities) 
       { 
        Console.WriteLine("PowerManagementCapabilities: {0}", arrValue); 
       } 
      } 
      Console.WriteLine("PowerManagementSupported: {0}", queryObj["PowerManagementSupported"]); 
      Console.WriteLine("ProviderName: {0}", queryObj["ProviderName"]); 
      Console.WriteLine("Purpose: {0}", queryObj["Purpose"]); 
      Console.WriteLine("QuotasDisabled: {0}", queryObj["QuotasDisabled"]); 
      Console.WriteLine("QuotasIncomplete: {0}", queryObj["QuotasIncomplete"]); 
      Console.WriteLine("QuotasRebuilding: {0}", queryObj["QuotasRebuilding"]); 
      Console.WriteLine("SessionID: {0}", queryObj["SessionID"]); 
      Console.WriteLine("Size: {0}", queryObj["Size"]); 
      Console.WriteLine("Status: {0}", queryObj["Status"]); 
      Console.WriteLine("StatusInfo: {0}", queryObj["StatusInfo"]); 
      Console.WriteLine("SupportsDiskQuotas: {0}", queryObj["SupportsDiskQuotas"]); 
      Console.WriteLine("SupportsFileBasedCompression: {0}", queryObj["SupportsFileBasedCompression"]); 
      Console.WriteLine("SystemCreationClassName: {0}", queryObj["SystemCreationClassName"]); 
      Console.WriteLine("SystemName: {0}", queryObj["SystemName"]); 
      Console.WriteLine("VolumeName: {0}", queryObj["VolumeName"]); 
      Console.WriteLine("VolumeSerialNumber: {0}", queryObj["VolumeSerialNumber"]); 
     } 
    } 
    catch (ManagementException ex) 
    { 
     MessageBox.Show("An error occurred while querying for WMI data: " + ex.Message); 
    } 
} 

para que sea un poco más fácil para descargar WMI Code Creater

+0

¿Sabes si hay una forma de determinar si están configurados para volver a conectarse al iniciar sesión? –

+0

Descubrí cómo determinar si se volverá a conectar al iniciar sesión (implica el acceso de registro, publicado como respuesta a continuación) –

5

Desgraciadamente tiene que usar WinAPI a través de P/Invoke. Se requerirá el uso de WNetGetUniversalName y la estructura UNIVERSAL_NAME_INFO. Comprueba que si expandir la ruta usando GetFullPath no es igual a lo que es el nombre universal para la ruta expandida, entonces sabe que está mapeado. El pseudo-código básico es el siguiente (comprobación de error 0, mínimo):

var nfo = new UNIVERSAL_NAME_INFO(); 
var size = Marshal.SizeOf(nfo); 

if (ERROR_MORE_DATA == WNetGetUniversalName(path, InfoLevel.UniversalName, 
    ref nfo, ref size) 
{ 
    var buffer = Marshal.AllocHGlobal(size); 
    if (NO_ERROR == WNetGetUniversalName(path, InfoLevel.UniversalName, 
             buffer, ref size)) 
    { 
     nfo = (UNIVERSAL_NAME_INFO)Marshal.PtrToStructure(buffer, 
            typeof(UNIVERSAL_NAME_INFO)); 
    } 
} 

Aquí están los P/Invoke declaraciones, que debe ayudar a lo largo de su camino:

internal class NativeMethods 
{ 
    /// <summary> 
    /// The type of structure that the function stores in the buffer. 
    /// </summary> 
    public enum InfoLevel 
    { 
     /// <summary> 
     /// The function stores a <see cref="UNIVERSAL_NAME_INFO"/> structure in the 
     /// buffer. 
     /// </summary> 
     UniversalName = 1, 

     /// <summary> 
     /// The function stores a <c>REMOTE_NAME_INFO</c> structure in the buffer. 
     /// </summary> 
     /// <remarks> 
     /// Using this level will throw an <see cref="NotSupportedException"/>. 
     /// </remarks> 
     RemoteName = 2 
    } 

    /// <summary> 
    /// The <see cref="WNetGetUniversalName(string,int,UNIVERSAL_NAME_INFO,int)"/> function 
    /// takes a drive-based path for a network resource and returns an information 
    /// structure that contains a more universal form of the name. 
    /// </summary> 
    /// <param name="lpLocalPath">A pointer to a constant null-terminated string that 
    /// is a drive-based path for a network resource.</param> 
    /// <param name="dwInfoLevel">The type of structure that the function stores in 
    /// the buffer pointed to by the <paramref name="lpBuffer"/> parameter.</param> 
    /// <param name="lpBuffer">A pointer to a buffer that receives the structure 
    /// specified by the <paramref name="dwInfoLevel"/> parameter.</param> 
    /// <param name="lpBufferSize">A pointer to a variable that specifies the size, 
    /// in bytes, of the buffer pointed to by the <paramref name="lpBuffer"/> parameter.</param> 
    /// <returns>If the function succeeds, the return value is <see cref="NO_ERROR"/>.</returns> 
    [DllImport("mpr.dll", CharSet = CharSet.Auto)] 
    public static extern int WNetGetUniversalName(
     string lpLocalPath, 
     InfoLevel dwInfoLevel, 
     ref UNIVERSAL_NAME_INFO lpBuffer, 
     ref int lpBufferSize); 

    /// <summary> 
    /// The <see cref="WNetGetUniversalName(string,int,IntPtr,int)"/> function 
    /// takes a drive-based path for a network resource and returns an information 
    /// structure that contains a more universal form of the name. 
    /// </summary> 
    /// <param name="lpLocalPath">A pointer to a constant null-terminated string that 
    /// is a drive-based path for a network resource.</param> 
    /// <param name="dwInfoLevel">The type of structure that the function stores in 
    /// the buffer pointed to by the <paramref name="lpBuffer"/> parameter.</param> 
    /// <param name="lpBuffer">A pointer to a buffer that receives the structure 
    /// specified by the <paramref name="dwInfoLevel"/> parameter.</param> 
    /// <param name="lpBufferSize">A pointer to a variable that specifies the size, 
    /// in bytes, of the buffer pointed to by the <paramref name="lpBuffer"/> parameter.</param> 
    /// <returns>If the function succeeds, the return value is <see cref="NO_ERROR"/>.</returns> 
    [DllImport("mpr.dll", CharSet = CharSet.Auto)] 
    public static extern int WNetGetUniversalName(
     string lpLocalPath, 
     InfoLevel dwInfoLevel, 
     IntPtr lpBuffer, 
     ref int lpBufferSize); 

    /// <summary> 
    /// The <see cref="UNIVERSAL_NAME_INFO"/> structure contains a pointer to a 
    /// Universal Naming Convention (UNC) name string for a network resource. 
    /// </summary> 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public struct UNIVERSAL_NAME_INFO 
    { 
     /// <summary> 
     /// Pointer to the null-terminated UNC name string that identifies a 
     /// network resource. 
     /// </summary> 
     [MarshalAs(UnmanagedType.LPTStr)] 
     public string lpUniversalName; 
    } 
} 
13

Usted podría utilizar WMI para enumerar y consultar unidades mapeadas. El siguiente código enumera las unidades mapeadas, extrae la parte del nombre del servidor y las imprime.

using System; 
using System.Text.RegularExpressions; 
using System.Management; 

namespace ConsoleApplication1 { 
    class Program { 
     static void Main(string[] args) { 
      ManagementObjectSearcher searcher = new ManagementObjectSearcher(
       "select * from Win32_MappedLogicalDisk"); 
      foreach (ManagementObject drive in searcher.Get()) { 
       Console.WriteLine(Regex.Match(
        drive["ProviderName"].ToString(), 
        @"\\\\([^\\]+)").Groups[1]); 
       } 
      } 
     } 
    } 
} 

Puede encontrar el documentaiton de la clase Win32_MappedLogicalDisk here. Una introducción para acceder a WMI desde C# es here.

+0

¿Sabes si hay una manera de determinar si están configurados para volver a conectarse al iniciar sesión? –

+0

Descubrí cómo determinar si se volverá a conectar al iniciar sesión (implica el acceso al registro, publicado como respuesta a continuación) –

5

he encontrado otra manera de hacer esto, que utiliza parte de los sixlettervariables técnica publicados comenzado. Me gustaría recibir algunos comentarios sobre los pros y los contras de las diversas técnicas. Por ejemplo, ¿el mío tiene una desventaja, un escenario donde no funcionará, por ejemplo?

[DllImport("mpr.dll")] 
static extern uint WNetGetConnection(string lpLocalName, StringBuilder lpRemoteName, ref int lpnLength); 

internal static bool IsLocalDrive(String driveName) 
{ 
    bool isLocal = true; // assume local until disproved 

    // strip trailing backslashes from driveName 
    driveName = driveName.Substring(0, 2); 

    int length = 256; // to be on safe side 
    StringBuilder networkShare = new StringBuilder(length); 
    uint status = WNetGetConnection(driveName, networkShare, ref length); 

    // does a network share exist for this drive? 
    if (networkShare.Length != 0) 
    { 
     // now networkShare contains a UNC path in format \\MachineName\ShareName 
     // retrieve the MachineName portion 
     String shareName = networkShare.ToString(); 
     string[] splitShares = shareName.Split('\\'); 
     // the 3rd array element now contains the machine name 
     if (Environment.MachineName == splitShares[2]) 
      isLocal = true; 
     else 
      isLocal = false; 
    } 

    return isLocal; 
} 

Esto se llama desde este código:

DriveInfo[] drives = DriveInfo.GetDrives(); 
foreach (DriveInfo drive in drives) 
{ 
    bool isLocal = IsLocalDrive(drive.Name); 
    if (isLocal) 
    { 
     // do whatever 
    } 
} 
8

Los métodos de WMI no le dirá si la unidad se fija para volver a conectar al iniciar la sesión. Cuando configura una unidad para volver a conectarse al iniciar sesión, Windows crea una clave en HKCU \ Network \. El siguiente método se puede usar para determinar si la unidad está configurada para ser reasignada al iniciar sesión.

private static bool DriveSetForReconnect(string ComputerName, string DriveLetter) 
{ 
    RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.CurrentUser, ComputerName); 
    key = key.OpenSubKey("Network\\" + DriveLetter); 

    return key != null; 
} 

HTH!

EDITAR: Para adaptar las soluciones WMI para trabajar en cualquier máquina arbitraria, debe cambiar el parámetro de ámbito como el siguiente código. Obviamente tiene que tener derechos de administrador en la máquina remota.

string scope = string.Format(@"\\{0}\root\CIMV2", ComputerName); 

ManagementObjectSearcher searcher = 
    new ManagementObjectSearcher(scope, 
    "SELECT * FROM Win32_MappedLogicalDisk"); 
+0

Es una buena adición a las respuestas a esta pregunta, @Tim, y aunque la pregunta original se refería a "mapas actuales" ", Le agradezco que agregue esta información adicional. – Cyberherbalist

+0

No hay problema. Tal vez malinterpreté tu comentario, pero esto definitivamente se aplica a tus mapas actuales. Es una información extra que faltaba en la información de WMI. Esto le indica si se volverán a conectar cuando el usuario actual vuelva a iniciar sesión. El WMI informa todos los mapas, independientemente de si se volverán a asignar al iniciar sesión. También he adaptado la solución WMI para que funcione en la red en cualquier PC arbitraria a la que tenga derechos de administrador (principalmente aplicable a entornos de dominio). Agregaré la información a la respuesta. –

+0

Hice la pregunta original porque tenía una aplicación que necesitaba saber a qué mapas de red ya tenía acceso en ese momento; la respuesta aceptada cumplió esa pregunta. Lo que quise decir con mi comentario fue que su información adicional sobre la propiedad de reconexión hace que esta pregunta/respuesta tenga una aplicación más general, y aumenta su valor tanto para mí como para la comunidad de desarrolladores. – Cyberherbalist

0

Podemos también utilizar net use encontrar IP o nombre de equipo de la unidad de red asignada

Process process = new Process(); 
process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.StartInfo.FileName = "cmd.exe"; 
process.StartInfo.Arguments = "/c net use"; 
process.Start(); 
string output = process.StandardOutput.ReadToEnd(); 
process.WaitForExit(); 

string driveName = "Y:"; 
var line = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) 
        .Where(x => x.Contains(driveName)).FirstOrDefault(); 
if (!string.IsNullOrEmpty(line)) 
{ 
    var host = line.Substring(line.IndexOf("\\"), line.Substring(line.IndexOf("\\")).IndexOf(" ")).Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); 
} 
0

Inspirado por map network drive path in C# aquí hay otro método sencillo el uso de objetos de secuencias de comandos:

  private static IDictionary<DriveInfo, string> GetMappedNetworkDrives() 
     { 
      var rawDrives = new IWshRuntimeLibrary.IWshNetwork_Class() 
       .EnumNetworkDrives(); 
      var result = new Dictionary<DriveInfo, string>(
       rawDrives.length/2); 
      for (int i = 0; i < rawDrives.length; i += 2) 
      { 
       result.Add(
        new DriveInfo(rawDrives.Item(i)), 
        rawDrives.Item(i + 1)); 
      } 
      return result; 
     } 

Ver https://msdn.microsoft.com/en-us/library/t9zt39at(v=vs.84).aspx de detalles sobre IWshNetwork_Class.

Cuestiones relacionadas