22

I'm trying to get a list of all shared folders available on a local intranet server.

The System.IO.Directory.GetDirectories() works fine for a path like \\myServer\myShare, however I'm getting an exception for a path like \\myServer:

Unhandled Exception: System.ArgumentException: The UNC path should be of the form \server\share.

Is there a way to get a list all shared folders for a server? Ultimately I'm looking for a method that can handle both scenarios based on a given path - returning a list of all shares for a given server and returning a list of all subdirectories for a given network shared folder.

Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
Misha Narinsky
  • 677
  • 1
  • 10
  • 24
  • 2
    possible duplicate of [Enumerating Network Shares with C#](http://stackoverflow.com/questions/2091126/enumerating-network-shares-with-c) – kbrimington Aug 25 '10 at 14:53
  • @kbrimington this Q asks for remote, that Q just asks for local. – Richard Aug 25 '10 at 15:16
  • 1
    @Richard: The accepted answer covers remote as well. – kbrimington Aug 25 '10 at 17:53
  • @kbrimington - for some reason I through `NetShareEnum` was local only... I like its remotability would need to be noted for it to be considered an answer to this (especially with the WMI answer here avoiding the need for P/Invoke. – Richard Aug 25 '10 at 19:12
  • 2
    @Richard: The CodeProject link in the accepted answer provides "Classes to enumerate network shares on local *and remote machines*, and convert local file paths to UNC paths." (emphasis added). The answer from @ajay_whiz references the same article. – kbrimington Aug 25 '10 at 21:15
  • Sorry, if this question might seem a duplicate for someone. I did search StackOverflow before posting and did not find the question @kbrimington is referring to. The solution from the CodeProject article actually worked for me, however I still think that my question is slightly different since I've been asking for a method that is able to enumerate both \\myServer and \\myServer\myShare paths (which can now be easily done by combining Directory.GetDirectories() and the CodeProject methods). – Misha Narinsky Aug 26 '10 at 13:27
  • @Michael: No need to apologize. Sometimes we don't find what we're looking for in a search. When a question gets posted, you immediately have dozens of people searching on your behalf. I learned a little something while finding the answer, so I'll not complain. Please don't take a lonely close vote as an accusation. Evidently, no one agreed with me. :) – kbrimington Aug 26 '10 at 13:45

3 Answers3

6

Here's a technique that uses System.Management (add a reference to this assembly):

using (ManagementClass shares = new ManagementClass(@"\\NameOfTheRemoteComputer\root\cimv2", "Win32_Share", new ObjectGetOptions())) {
    foreach (ManagementObject share in shares.GetInstances()) {
        Console.WriteLine(share["Name"]);
    }
}

Appropriate permissions are required.

Bradley Smith
  • 13,353
  • 4
  • 44
  • 57
  • 2
    Thanks, Bradley. Your technique worked fine for enumerating shares on my local machine, however it gave me `System.Management.ManagementException: Access denied` exception when I tried to access server on a local network. On the same time the other solution (uses P/Invoke) worked fine for the same server. – Misha Narinsky Aug 26 '10 at 13:43
  • Yeah, I checked it out and you're right. I think there is more to WMI than meets the eye - including the need to work with the ConnectionOptions and ManagementScope classes in a certain way in order to access remote computers. I'm sure it's possible, but at this stage I don't have the experience to describe how to do it. – Bradley Smith Aug 26 '10 at 13:55
  • Worked like a charm for me (hitting a remove machine). I was running as myself, however, and my user has admin rights on the target machine. – David Airapetyan Jun 01 '13 at 23:19
  • 1
    This would have been brilliant but I get the error `System.Runtime.InteropServices.COMException: 'The RPC server is unavailable.` Looks like it relates to a Windows Firewall setting which I have no control over. – MatthewD Jun 28 '19 at 15:45
5

I think this is what you are looking for http://www.codeproject.com/KB/IP/networkshares.aspx

ajay_whiz
  • 17,573
  • 4
  • 36
  • 44
  • 2
    Thanks, this worked for me. I ended up writing a method that extends System.IO.Directory.GetDirectories(). It uses regular expressions to figure out what kind of path is given (//server/share or just //server) and then calls either Directory.GetDirectories() or the CodeProject library respectively. – Misha Narinsky Aug 26 '10 at 13:34
3
    private DataTable GetSharedFolderAccessRule()
    {
        DataTable DT = new DataTable();

        try
        {
            DT.Columns.Add("ShareName");
            DT.Columns.Add("Caption");
            DT.Columns.Add("Path");
            DT.Columns.Add("Domain");
            DT.Columns.Add("User");
            DT.Columns.Add("AccessMask");
            DT.Columns.Add("AceType");

            ManagementScope Scope = new ManagementScope(@"\\.\root\cimv2");
            Scope.Connect();
            ObjectQuery Query = new ObjectQuery("SELECT * FROM Win32_LogicalShareSecuritySetting");
            ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
            ManagementObjectCollection QueryCollection = Searcher.Get();

            foreach (ManagementObject SharedFolder in QueryCollection)
            {
                {
                    String ShareName = (String) SharedFolder["Name"];
                    String Caption   = (String)SharedFolder["Caption"];
                    String LocalPath = String.Empty;
                    ManagementObjectSearcher Win32Share = new ManagementObjectSearcher("SELECT Path FROM Win32_share WHERE Name = '" + ShareName + "'");
                    foreach (ManagementObject ShareData in Win32Share.Get())
                    {
                        LocalPath = (String) ShareData["Path"];
                    }

                    ManagementBaseObject Method = SharedFolder.InvokeMethod("GetSecurityDescriptor", null, new InvokeMethodOptions());
                    ManagementBaseObject Descriptor = (ManagementBaseObject)Method["Descriptor"];
                    ManagementBaseObject[] DACL = (ManagementBaseObject[])Descriptor["DACL"];
                    foreach (ManagementBaseObject ACE in DACL)
                    {
                        ManagementBaseObject Trustee = (ManagementBaseObject)ACE["Trustee"];

                        // Full Access = 2032127, Modify = 1245631, Read Write = 118009, Read Only = 1179817
                        DataRow Row = DT.NewRow();
                        Row["ShareName"]  = ShareName;
                        Row["Caption"]    = Caption;
                        Row["Path"]       = LocalPath;
                        Row["Domain"]     = (String) Trustee["Domain"];
                        Row["User"]       = (String) Trustee["Name"];
                        Row["AccessMask"] = (UInt32) ACE["AccessMask"];
                        Row["AceType"]    = (UInt32) ACE["AceType"];
                        DT.Rows.Add(Row);
                        DT.AcceptChanges();
                    }
                }
            }
        }
        catch (Exception ex) 
        {
            MessageBox.Show(ex.StackTrace, ex.Message);
        }

        return DT;
    }