Подтвердить что ты не робот

Как программно обнаруживать подключенные сетевые диски в системе и имена их серверов?

Я пытаюсь выяснить, как программно (я использую С#) определить имя (или i.p.) серверов, к которым у моей рабочей станции есть текущие карты. Другими словами, в какой-то момент в Windows Explorer я сопоставил сетевой диск с буквой диска (или использовал "net use w:" для его сопоставления). Я знаю, как получить сетевые диски в системе:

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

Но класс DriveInfo не имеет свойств, которые сообщают мне, какой сервер и общая папка связан с подключенным диском. Где-то еще я должен смотреть?

4b9b3361

Ответ 1

Вы пытались использовать WMI для этого?

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

чтобы облегчить загрузку WMI Code Creater

Ответ 2

Вы можете использовать WMI для перечисления и запроса подключенных дисков. Следующий код перечисляет подключенные диски, извлекает часть имени сервера и выводит его.

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

Здесь вы можете найти документ класса Win32_MappedLogicalDisk здесь. Вступление для доступа к WMI с С# здесь.

Ответ 3

Методы WMI не скажут вам, установлен ли диск для повторного подключения при входе в систему. Когда вы устанавливаете диск для повторного подключения при входе в систему, Windows создает ключ в HKCU\Network \. Метод, приведенный ниже, может быть использован для определения того, установлен ли диск при переадресации при регистрации.

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

    return key != null;
}

НТН!

EDIT: Чтобы адаптировать решения WMI для работы на любом произвольном компьютере, вам необходимо изменить параметр области, как приведенный ниже код. Вы, очевидно, должны иметь права администратора на удаленной машине.

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

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

Ответ 4

Вы, к сожалению, должны использовать WinAPI через P/Invoke. Для этого потребуется WNetGetUniversalName и структура GetFullPath не совпадает с тем, что универсальное имя для расширенного пути, то вы знаете, что оно отображается. Основной псевдокод выглядит следующим образом (0 проверка ошибок, минимум):

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

Вот объявления P/Invoke, которые помогут вам по пути:

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

Ответ 5

Я нашел еще один способ сделать это, который использует часть техники, размещенную на шестизначных языках. Мне хотелось бы получить отзывы о плюсах и минусах различных методов. Например, имеет ли мой недостаток, сценарий, где он не будет работать, например?

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

Это вызывается из этого кода:

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

Ответ 6

Мы также можем использовать net use, чтобы найти IP или имя компьютера подключенного сетевого диска.

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

Ответ 7

Вдохновленный сопоставьте путь сетевого диска в С# здесь еще один простой метод с использованием объектов Scripting:

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

Подробнее о IWshNetwork_Class см. https://msdn.microsoft.com/en-us/library/t9zt39at(v=vs.84).aspx.