2009-07-06 10 views
19

Próbuję dowiedzieć się, jak programowo (używam C#) określić nazwę (lub i.p.) serwerów, na których moja stacja robocza ma bieżące mapy. Innymi słowy, w pewnym momencie Eksploratora Windows zamapowałem dysk sieciowy na literę dysku (lub użyłem "net use w:", aby go zmapować). Wiem jak zdobyć dysków sieciowych w systemie:Jak programowo wykryć zmapowane dyski sieciowe w systemie i nazwy ich serwerów?

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

Ale klasa DriveInfo nie posiada właściwości, które mówią mi, co serwer i wspólny folder zmapowany dysk jest skojarzony. Czy jest jeszcze gdzieś powinienem szukać?

+1

Gosh, uwielbiam to miejsce! Zadaj pytanie i prawie natychmiast ktoś sprawdza się z doskonałą odpowiedzią - w tym przypadku trzy wyczerpujące odpowiedzi zawierające niezwykle użyteczny materiał. Chciałabym móc je wszystkie nazwać Akceptowanymi. Rozgrywki dookoła, tho! Dzięki! – Cyberherbalist

Odpowiedz

25

Czy próbowałeś użyć WMI, aby to zrobić?

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

zrobić to trochę łatwiej zacząć Pobierz WMI Code Creater

+0

Czy wiesz, czy istnieje sposób, aby ustalić, czy są one ustawione na ponowne połączenie przy logowaniu? –

+0

Wymyśliłem, jak ustalić, czy zostanie on ponownie połączony podczas logowania (dotyczy dostępu do rejestru, zamieszczonego jako odpowiedź poniżej). –

5

Niestety, musisz użyć WinAPI poprzez P/Invoke. Będzie to wymagało użycia struktury WNetGetUniversalName i UNIVERSAL_NAME_INFO. Sprawdzenie, czy rozszerzenie ścieżki przy użyciu GetFullPath nie jest równe rozszerzonej ścieżce dla nazwy uniwersalnej, oznacza to, że jest ona mapowana. Podstawowym pseudo-kod jest następujący (sprawdzanie 0 błędów, absolutne 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)); 
    } 
} 

Oto P/Invoke deklaracji, które powinny pomóc Ci w drodze:

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

można użyć WMI do wyliczenia i zapytania zmapowanych dysków. Poniższy kod wylicza zmapowane dyski, wyodrębnia część nazwy serwera i drukuje ją.

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

można znaleźć documentaiton klasy Win32_MappedLogicalDisk here. Wstęp do dostępu do WMI z C# to here.

+0

Czy wiesz, czy istnieje sposób, aby ustalić, czy są one ustawione na ponowne połączenie przy logowaniu? –

+0

Dowiedziałem się, jak ustalić, czy zostanie on ponownie połączony podczas logowania (dotyczy dostępu do rejestru, opublikowanego jako odpowiedź poniżej). –

5

Znalazłem kolejny sposób robienia tego, który wykorzystuje część sixlettervariables techniki wysłana. Chciałbym poznać opinie na temat zalet i wad różnych technik. Na przykład, czy moje ma wadę, scenariusz, na którym nie zadziała, na przykład?

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

Nazywa się to z tym kodem:

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

Metody WMI nie powie, czy dysk jest ustawiony ponownie przy logowaniu. Po ustawieniu dysku, aby ponownie się połączyć przy logowaniu, system Windows tworzy klucz w gałęzi HKCU \ Network \. Poniższa metoda może być użyta do określenia, czy napęd jest ustawiony na remapowanie przy logowaniu.

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

    return key != null; 
} 

HTH!

EDYTOWANIE: Aby dostosować rozwiązania WMI do pracy na dowolnej maszynie, należy zmienić parametr zasięgu, tak jak poniższy kod. Oczywiście musisz mieć uprawnienia administratora na zdalnym komputerze.

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

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

To fajny dodatek do odpowiedzi na to pytanie @Tim i podczas gdy pierwotne pytanie odnosiło się do "aktualnych map" ", Doceniam twoje dodanie tej dodatkowej informacji. – Cyberherbalist

+0

Nie ma problemu. Może źle zrozumiałem twój komentarz, ale to zdecydowanie dotyczy twoich obecnych map. Jest to dodatkowa informacja, której brakowało w informacji WMI. Informuje o tym, czy zostaną one ponownie połączone, gdy bieżący użytkownik się zaloguje. WMI zgłasza wszystkie mapy, niezależnie od tego, czy zostaną one zmienione podczas logowania. Ponadto zaadaptowałem rozwiązanie WMI do pracy w sieci na dowolnym komputerze PC, na którym masz prawa administratora (głównie w środowiskach domen). Dodam informację do odpowiedzi. –

+0

Zadałem oryginalne pytanie, ponieważ miałem aplikację, która potrzebowała dowiedzieć się, jakie mapy sieciowe już miała w tym momencie; Przyjęta odpowiedź spełniła to pytanie. Co rozumiem przez mój komentarz, to że twoje dodatkowe informacje na temat właściwości reconnect sprawiają, że to pytanie/odpowiedź jest bardziej ogólną stosowalnością i zwiększa jego wartość zarówno dla mnie, jak i społeczności programistów. – Cyberherbalist

0

Możemy również użyć net use znaleźć IP lub nazwa komputera z odwzorowanym dysku sieciowym

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

Zainspirowany map network drive path in C# oto kolejny prosty sposób za pomocą obiektów skryptów:

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

Zobacz https://msdn.microsoft.com/en-us/library/t9zt39at(v=vs.84).aspx dla szczegóły dotyczące klasy IWshNetwork_Class.

Powiązane problemy