2009-07-06 7 views
19

J'essaie de savoir comment programmer (j'utilise C#) déterminer le nom (ou i.p.) des serveurs auxquels mon poste de travail a des cartes actuelles. En d'autres termes, à un certain moment dans l'explorateur Windows, j'ai mappé un lecteur réseau à une lettre de lecteur (ou utilisé "net use w:" pour le mapper). Je sais comment obtenir les lecteurs réseau sur le système:Comment faire pour découvrir par programmation les lecteurs réseau mappés sur le système et leurs noms de serveur?

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

Mais la classe DriveInfo n'a pas de propriétés qui me disent ce serveur et le dossier partagé le lecteur mappé est associé. Y a-t-il un autre endroit où je devrais regarder?

+1

Gosh, j'adore cet endroit! Posez une question et presque immédiatement quelqu'un s'enquiert d'une excellente réponse - dans ce cas, trois réponses exhaustives contenant du matériel incroyablement utile. J'aimerais pouvoir les marquer tous comme acceptés. Upvotes tout autour, tho! Merci! – Cyberherbalist

Répondre

25

Avez-vous essayé d'utiliser WMI pour le faire?

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

pour le rendre un peu plus facile pour commencer le téléchargement WMI Code Creater

+0

Savez-vous s'il existe un moyen de déterminer s'ils sont configurés pour se reconnecter à la connexion? –

+0

J'ai compris comment faire pour déterminer s'il sera reconnecté lors de la connexion (implique l'accès au registre, posté comme réponse ci-dessous) –

5

Vous devez malheureusement utiliser WinAPI via P/Invoke. Il faudra utiliser WNetGetUniversalName et la structure UNIVERSAL_NAME_INFO. Vous vérifiez que si l'expansion du chemin en utilisant GetFullPath ne correspond pas à ce que le nom universel est pour le chemin développé, alors vous savez qu'il est mappé. Le pseudo-code de base est la suivante (0 vérification d'erreur, minimum):

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

Voici les déclarations P/Invoke, qui devrait vous aider sur votre chemin:

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

Vous pouvez utiliser WMI pour énumérer et interroger les lecteurs mappés. Le code suivant énumère les lecteurs mappés, extrait la partie du nom du serveur et l'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]); 
       } 
      } 
     } 
    } 
} 

Vous pouvez trouver le documentaiton de la classe Win32_MappedLogicalDisk here. Une intro pour accéder à WMI à partir de C# est here.

+0

Savez-vous s'il existe un moyen de déterminer s'ils sont configurés pour se reconnecter à la connexion? –

+0

J'ai trouvé comment déterminer s'il sera reconnecté lors de la connexion (implique l'accès au registre, posté comme réponse ci-dessous) –

5

J'ai trouvé une autre façon de le faire, qui utilise une partie des sixlettervariables technique ci-dessous. J'aimerais avoir un retour sur les avantages et les inconvénients des différentes techniques. Par exemple, est-ce que le mien a un inconvénient, un scénario où cela ne fonctionnera pas, par exemple?

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

Ceci est appelé à partir de ce code:

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

Les méthodes WMI ne vous dira pas si le lecteur est réglé de se reconnecter à la connexion. Lorsque vous définissez un lecteur pour vous reconnecter à la connexion, Windows crée une clé sous HKCU \ Network \. La méthode ci-dessous peut être utilisée pour déterminer si le lecteur est configuré pour être remappé lors de la connexion.

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

    return key != null; 
} 

HTH! Pour adapter les solutions WMI à toute machine arbitraire, vous devez modifier le paramètre scope comme le code ci-dessous. Vous devez évidemment avoir des droits d'administrateur sur la machine distante.

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

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

C'est une addition cool aux réponses à cette question, @Tim, et tandis que la question originale se rapportait aux "cartes actuelles ", J'apprécie votre ajout de cette information supplémentaire. – Cyberherbalist

+0

Pas de problème. Peut-être que j'ai mal compris votre commentaire, mais cela s'applique certainement à vos cartes actuelles. C'est une information supplémentaire qui manquait dans les infos WMI. Cela vous indique si elles seront reconnectées lorsque l'utilisateur actuel se reconnecte. Le WMI signale toutes les cartes, qu'elles soient ou non remappées lors de la connexion. J'ai également adapté la solution WMI pour travailler sur le réseau sur tout PC arbitraire auquel vous avez des droits d'administrateur (principalement applicable aux environnements de domaine). Je vais ajouter l'information à la réponse. –

+0

J'ai posé la question originale parce que j'avais une application qui avait besoin de savoir à quelles cartes réseau elle avait déjà accès à ce moment; la réponse acceptée a répondu à cette question. Ce que je voulais dire par mon commentaire était que vos informations supplémentaires sur la propriété reconnecter rend cette question/réponse d'applicabilité plus générale, et augmente sa valeur à la fois pour moi et la communauté des développeurs. – Cyberherbalist

0

Nous pouvons également utiliser net use pour trouver IP ou Nom de l'ordinateur du lecteur réseau mappé

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

Inspiré par map network drive path in C# voici une autre méthode simple utilisant des objets de script:

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

Voir https://msdn.microsoft.com/en-us/library/t9zt39at(v=vs.84).aspx pour détails sur IWshNetwork_Class.

Questions connexes