Share via


List shared folders and subfolders using power shell

Question

Friday, November 14, 2014 2:19 PM

Hi all,
I would lke to use power shell to search recursvely all the shared Folders only in a particular directory and then output the acl result into a file.
I have put together the following:

Get-ChildItem -Recurse -Directory | get-acl | format-list > file.csv

I get all the folders and I can't find the right way to only get the shared folders.

Can someone help me please?
Thank you

All replies (20)

Friday, November 14, 2014 2:41 PM ✅Answered | 2 votes

This should work for you.  Get the shares first, compare them to the directory you want to search, then get the ACLs:

$RootDir = "C:\\Directory"
Get-WMIObject -query "select * from Win32_Share where Path like '$RootDir%'" | get-acl | format-list | Export-CSV .\file.csv -NoType

Make sure to  double the \ in the path or you'll get an error.

I hope this post has helped!


Wednesday, November 19, 2014 2:21 PM ✅Answered | 1 vote

Ah sorry, try it like this:

$RootDir = "C:\\Directory"
Get-WMIObject -query "select * from Win32_Share where Path like '$RootDir%'" | Get-ChildItem -recurse  | ?{$_.PSIsContainer} | get-acl 

I hope this post has helped!


Friday, November 14, 2014 4:00 PM

It works fine, thank you but I running it like so:

PS C:\> Get-WMIObject -query "select * from Win32_Share where Path like '$RootDir%'" | get-acl | format-list > e:\\permessi.csv

since the formatting and the data inside the csv file created by the Export-CSV was a mess of numbers (SIDs??)
Thank you again.


Friday, November 14, 2014 4:31 PM

You only need the double \ when assigning the $RootDir variable.

Yes, the output will include SIDs  and outputting it the way you are will include the converted accounts.  But why not just dump it into a text file?  Putting it into a CSV doesn't allow you to use the CSV the way it is intended, you'll end up with garbage entries that have no meaning in the context of a CSV file.  

I hope this post has helped!


Friday, November 14, 2014 4:53 PM | 1 vote

You can use this to populate a proper CSV with data that is then sortable, searchable, and better suited for reporting:

$FileSystemRights=[System.Security.AccessControl.FileSystemRights]

$GenericRights=@{
    GENERIC_READ = [int]0x80000000;
    GENERIC_WRITE = [int]0x40000000;
    GENERIC_EXECUTE = [int]0x20000000;
    GENERIC_ALL = [int]0x10000000;
    FILTER_GENERIC = [int]0x0FFFFFFF;
}

$MappedGenericRights=@{
    FILE_GENERIC_EXECUTE = $FileSystemRights::ExecuteFile -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::ReadAttributes -bor $FileSystemRights::Synchronize
    FILE_GENERIC_READ = $FileSystemRights::ReadAttributes -bor $FileSystemRights::ReadData -bor $FileSystemRights::ReadExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize
    FILE_GENERIC_WRITE = $FileSystemRights::AppendData -bor $FileSystemRights::WriteAttributes -bor $FileSystemRights::WriteData -bor $FileSystemRights::WriteExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize
    FILE_GENERIC_ALL = $FileSystemRights::FullControl
}

# Map generic file system rights
Function Map-GenericRightsToFileSystemRights {
    param( [System.Security.AccessControl.FileSystemRights]$OriginalRights )
    $MappedRights=New-Object -TypeName $FileSystemRights
    if ($OriginalRights -band $GenericRights.GENERIC_EXECUTE) {
        $MappedRights=$MappedRights -bor $MappedGenericRights.FILE_GENERIC_EXECUTE
    }
    if ($OriginalRights -band $GenericRights.GENERIC_READ) {
        $MappedRights=$MappedRights -bor $MappedGenericRights.FILE_GENERIC_READ
    }
    if ($OriginalRights -band $GenericRights.GENERIC_WRITE) {
        $MappedRights=$MappedRights -bor $MappedGenericRights.FILE_GENERIC_WRITE
    }
    if ($OriginalRights -band $GenericRights.GENERIC_ALL) {
        $MappedRights=$MappedRights -bor $MappedGenericRights.FILE_GENERIC_ALL
    }
    Return (($OriginalRights -bAND $GenericRights.FILTER_GENERIC) -bOR $MappedRights) -as $FileSystemRights
} # Convert generic rights to file system rights

$RootDir = "C:\\Directory"
Get-WMIObject -query "select * from Win32_Share where Path like '$RootDir%'" | get-acl | %{
  Foreach($access in $_.Access){
     New-Object PSObject -property @{
       Path = ($_.Path -split "::")[-1]
       Owner = $_.Owner
       FileSystemRights = $(If($access.FileSystemRights -match "[0-9]"){
          Map-GenericRightsToFileSystemRights $access.FileSystemRights
       } Else {$access.FileSystemRights})
       AccessControlType = $access.AccessControlType
       IdentityReference = $access.IdentityReference
       InheritanceFlags = $access.InheritanceFlags
       PropagationFlags = $access.PropagationFlags
     }
   }
} | Export-CSV .\file.csv -NoType
 

I hope this post has helped!


Friday, November 14, 2014 5:12 PM

All that extra code at the beginning is to convert the generic privileges into human readable privileges, otherwise you get a mysterious number for a file system right no matter which way you handle the output.

I hope this post has helped!


Wednesday, November 19, 2014 11:01 AM

Hi Rhys,
first of all thank you very much for your time and help.
Now I have been trying and test your PS script to get acl...I have tried on a shared folder with many shared sub folders and other shared sub folders inside them but the script only picks few of them not all.
I have also tried to run it recursive like this:

Get-WMIObject -recurse -query "select * from Win32_Share where Path like '$RootDir%'" | get-acl

but I get this error:

Get-WmiObject : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:14
+ Get-WMIObject <<<<  -recurse -query "select * from Win32_Share where Path like '$RootDir%'" | get-a
    + CategoryInfo          : InvalidArgument: (:) [Get-WmiObject], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Would you be so kind to put me on the right track?
Thanks


Wednesday, November 19, 2014 11:22 AM

Just a thought that occurred to me.
is it possible that the script does not pick the subfolders because they inherit the shared form the parent folder?
So maybe the shared folder is "marked" differently form an inherited shared folder?


Wednesday, November 19, 2014 12:25 PM

InheritanceFlags tells you if the permissions are inherited from a parent folder.

To what value are you settting $RootDir?

I hope this post has helped!


Wednesday, November 19, 2014 12:55 PM

well I have tried different paths lets say we have the following:

D:\DEPARTMENT
         \Sales (shared)
                     \June (shared)
                      \July (not shared)
         \Accounts (shared with 10 folders 2 shared 1 not shared)
         \Management (shared with 2 subfolders and inside one subfolders another 3 folders 2 shared)

Now I have tried $RootDir = "D:\DEPARTMENT" and $RootDir = "D:\DEPARTMENT\Sales"

Should the -Recurse switch work anyway no matter the structure of the Root variable?

Thanks


Wednesday, November 19, 2014 1:02 PM

Live scenario:

PS D:\> $RootDir = "D:\\DEPARTMENT\\ITALY_STATEMENT"
PS D:\> Get-WMIObject -query "select * from Win32_Share where Path like '$RootDir%'" | get-acl


    Directory: D:\DEPARTMENT


Path                                    Owner                                   Access
                                                                       
ITALY_STATEMENT                         BUILTIN\Administrators                  NT AUTHORITY\SYSTEM Allow  FullContr...


    Directory: D:\DEPARTMENT\ITALY_STATEMENT


Path                                    Owner                                   Access
                                                                       
Statements for Alberta                  BUILTIN\Administrators                  MYDOMAIN\legal Allow  FullControl...

I know for sure that inside the ITALY_STATEMENT folder there are 6 more shared folders that are not in the get-acl result.


Wednesday, November 19, 2014 3:55 PM

This is great thank you very much...sorry to bother you again but...the script is fine if run from top directory like

PS D:\> $RootDir = "D:\\DEPARTMENT"

but I get no result if I set as my root a sub folder inside the root directory like:

PS D:\> $RootDir = "D:\\DEPARTMENT\\ITALY_STATEMENT"

I woul dlike to do so because I can run different data sheets for different department to look at.

Thank you again for your time, much appreciated.


Wednesday, November 19, 2014 4:33 PM

The share has to have the $rootdir as part of the path.  So if none of your shares have d:\department\italy_statement in their path, it won't return any results.

I hope this post has helped!


Friday, November 21, 2014 6:07 AM


Friday, November 21, 2014 6:34 AM

Thanks I put the script together adding at the top:

$RootDir = Read-Host "Input a directory using this format c:\\dir\\subdir"

so other people can use it without being hard coded...I have appreciated your help on this :)


Friday, November 21, 2014 10:35 AM

If there are no folders in e:\powertest\chiavetta the result is expected.

I hope this post has helped!


Friday, November 21, 2014 12:59 PM

...as soon as I shared the folder powertest then it worked but....all the subfolders inside powertest have inherited the share property although when:

now it must be a difference between shared and inherit a share otherwise the net share would list all the folders that have inherited that property. Moreover now the script picks all of them up without distinction.
So that means that in order for me to run the script by one folder at a time I need to share it first but then I will have everything in it shared by inheritance which will defeaat the point.

I know....please tell me if you had enough with this, I am fine and understand. You have been helpfull enough.
Thanks


Friday, November 21, 2014 1:02 PM

there are more folders inside it:


Friday, November 21, 2014 4:55 PM

Sharing isn't an inheritable property, if you share a folder, everything under it is accessible based on the share permissions and the file/folder security.

I'm not sure what you're asking for, you wanted to get the acls recursively for any shared folders in a particular directory.  That's what the script does.  But now you're saying you don't want to share the folders, so I'm confused.

I hope this post has helped!


Monday, November 24, 2014 11:53 AM

I'm not sure what you're asking for, you wanted to get the acls recursively for any shared folders in a particular directory.

Hi Rhys, apologies for the confusion; I was testing in my test enviroment which was a mess.
I can confirm that everything is working as expected.
Thank you very much again for your time, patience and expertise.
Ciao