Link to home
Start Free TrialLog in
Avatar of Lobsterguy
Lobsterguy

asked on

Powershell Script to Retrieve Filtered Remote Share Information

History - I've been learning PowerShell for a few months now so I'm still a novice. Our environment is a Windows 2003 Mixed Mode. We can use PS 2.0 for our scripting. I use PowerGui and the "Quest.ActiveRoles.ADManagement" snapin.

Why ask my question - I'm tasked with identifying all shares where the "everyone" group has rights on the share. I need to identify those shares and perms and remove them.

Question - I want the remote share information from servers/workstations but I need to filter the results to only return the server name, share name, share path, and permissions for only the "Everyone" group. Additionally I only want results for the "Type" of "0" or which from my research is the "Disk Drive". Can my current script be modified to filter this information or will I need to take another approach?

I've seen various scripts on here that get some information but not all. I'm currently using "srvcheck.exe" from the "Windows Resource Kit" to obtain this information. I'm open to any PowerShell solution.

My Script Details:

I will attach the file I'm working with now so you can see the results I get. I changed the file extension to ".txt" from ".ps1" to be able to upload it. I'm using a list of servers that I read in.

Below is the output I'm currently getting. In this example the "Remit1", "Remit2", "Cannon2" etc. are all print queues and I don't want to see those shares and permissions.

.:| ServerName Share Permissions Review |:.
________________________________________________
 
 
***** Please remove all permissions for the EVERYONE group in each share as applicable. *****
 
Shares exempt to this include all PRINT shares and the IPC$ share.
 
\\ServerName\Documents
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
                Everyone              Read


\\ServerName\Images
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
                Everyone              Full Control

 \\ServerName\print$
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
            Everyone              Read


\\ServerName\Remit1
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
            Everyone              Full Control

\\ServerName\Remit2
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
            Everyone              Full Control

\\ServerName\Canon2
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
            Everyone              Full Control

\\ServerName\Cannon1
            BUILTIN\Power Users       Full Control
            BUILTIN\Administrators       Full Control
            Everyone              Full Control

Here's what I'd like to see:


.:| ServerName Share Permissions Review |:.
________________________________________________
 
 
***** Please remove all permissions for the EVERYONE group in each share as applicable. *****
 
Shares exempt to this include all PRINT shares and the IPC$ share.
 
 \\ServerName\Documents
            Everyone              Read


\\ServerName\Images
            Everyone              Full Control




Thanks for any input.
Get-Server-Share-Permissions.txt
Avatar of footech
footech
Flag of United States of America image

An easy way to see the shares of the type you want is
Get-WmiObject  Win32_Share -filter "type = 0"

I've mostly avoided setting any type of security through PS as I find it a pain.  I know this doesn't answer your question but I have to ask why would you want to remove those share permissions?  If you have any choice in the matter, I'd say it's much better to leave those and do your securing of the resources through NTFS permissions.
Avatar of Lobsterguy
Lobsterguy

ASKER

Our CIPP dictates we are not allowed to have any share or NTFS permission set to "Everyone". I don't see where having it on the share is a problem if it isn't granted on the NTFS permissions. But, I'm not to argue the point. I'm just to find a solution. I'll give your solution a try. Thanks.
I would probably just call net share commands to set the permissions.  Run net help share for the syntax.  Otherwise you may be able to set them through WMI calls, but would be much more painful to code, IMO.
I'm not trying to set the permissions, I'm just wanting to view them.
ASKER CERTIFIED SOLUTION
Avatar of footech
footech
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just to clarify...I do need to remove them when all is said and done. I first have to contact the server owners and inform them of the shares that don't meet compliance and give them time to research if it is going to break a process that may be using that access once removed. Once I have the okay from them I will be able to remove the permissions.

You stated, "if along the way you collect the information in a form that can later be used for other purposes". I'm in agreement with you. I'm just not proficient enough to know how to do that or that it is even an option. How would you have written this keeping it extensible for other uses?

Thank you for your feedback. I'll give the script a try.
Would you mind breaking down the script and explain what each line is doing?
1) It looks like you are using two hash tables to store the "Type" and "Permission" values.
2) Then you read in the list of servers.
3) For each server you set $shareInfo to gather the Name and Path of the drive type "0".
4) Then it looks like you are retrieving the permissons on line 19 but this is when it starts getting fuzzy for me and I can't seem to follow along with what you are doing.

Where would I put in a command to export the values into a CSV file or text file?  When I type the following it exports to a text file okay but I can't figure out how to export to a csv file.

|Out-File c:\results.txt

Thanks again for all your feedback.
I think I'm starting to understand what you mean by collecting the data and then being able to use it later for other purposes. After reviewing your script you're storing the data we are collecting in various hash tables and arrays which you then call to later to retrieve the data. Whereas I was not storing the data I was just outputting it to a text file as I retrieved the data initially. Your script makes more logical sense as you clearly stated.

The last part of the code where you display the results really has me baffled as to how the text is displaying on the screen. You create a new-object PSObject but I don't see how it is displaying on the console window. I'm used to seeing a simple variable like "$varName" or write-host "Text variable etc". Could you fill in the gap on this?
Responding to your first post...

What I posted is already written with that in mind.
All it does is gather information (with a little ordering thrown in).  If you were to remove the "ft -auto" at the end of the script and substitute
Export-CSV shareinfo.csv -notype
it would generate a .CSV file.  Then if you later ran the command
Import-CSV shareinfo.csv
you would have the exact same information available to you as if you had just run the script again.

Responding to your second post...

1)  Yes, I didn't have to use the hash tables of course, but it laid out the translations well.
2) and 3)  Correct.
4)  I'm just populating the $user, $type, and $perm variables, so that I can then create a new object with properties based on that info.  That's kind of the key here - I'm creating an object and sending it down the pipeline instead of just a bunch of strings.
When you use New-Object, it passes the object created to the pipeline.  You could leave out the Sort and Select statements at the end and still see the data.  PowerShell uses some default output rules - I don't know if I could explain it well.  If you read up on Out-Default, Format-List, and Format-Table I think you would get the picture.

Edit:  BTW it's probably worth mentioning that if I hadn't surrounded the foreach statements with array notation ("@()"), I wouldn't have been able to then pipe the output to the Sort-Object or Select-Object commands.  This is because the foreach statement doesn't send output to the pipeline.  This is different from the ForEach-Object cmdlet (which has an alias "foreach"), which does pass output to the pipeline.
Thank you for the explanations.
Not only did you help to solve my issue but you also helped to explain the pieces I didn't understand. I appreciate the thoroughness of your responses and willingness to help educate.
The last part I need to setup is to store all the share information for each server in its own file. Would it be better to import that information from one master .csv file containing all the servers and then filter out the individual servers from that? Or what method would you recommend?

Each server has an owner and I have to email them the shares with the everyone group that needs to be addressed. My thought was to list all the shares violating this permission setting  and just email the text document to them. I'm certainly open to other suggestions.
Two options:
1)  Pipe the results from line 47 to Export-CSV using a filename based on the server (I'm omitting any Sort or Select just to make the example simpler, you can add them as desired).
    }) | Export-CSV shareinfo-$server.csv -notype

Open in new window

Be aware that with the export here nothing is sent down the pipeline, so the pipe on line 48, and lines 49 and 50 could no longer be used.

2)  If you sent all the results to one master file, then you could use the following to then generate sub-files from it.
# with PS 3.0
# not efficient because of opening and closing files repeatedly, but simple code
Import-CSV shareinfo.csv | ForEach { $_ | Export-CSV "shareinfo-$($_.server).csv" -notype -append }

# or
# doesn't require PS 3.0
$servers = Get-Content serverlist.txt  #could generate the list of servers from shareinfo.csv, but if we already have the list this is simpler
$data = Import-CSV shareinfo.csv 
foreach ($server in $servers)
{ $data | Where {$_.server -eq $server } | Export-CSV "shareinfo-$server.csv" -notype }

Open in new window

Thank you. I'll have to with option #2 since we are using PS2.
I keep getting the following errors when I run the script. My code is at the bottom.

Currently processing shares for ALBADSDCP001P.
ForEach-Object : Cannot convert 'System.Management.ManagementBaseObject[]' to the type 'System.Management.Aut
omation.ScriptBlock' required by parameter 'Process'. Specified method is not supported.
At R:\SysAdmin\PowerShell\Scripts\AD\Share_Information\View_Perms_for_Everyone.ps1:23 char:69
+         $shareACL | Where {$_.Trustee.Name -eq "Everyone"} | ForEach <<<<  `
    + CategoryInfo          : InvalidArgument: (:) [ForEach-Object], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ForEachObjectCommand
 
ForEach-Object : Cannot convert 'System.Management.ManagementBaseObject[]' to the type 'System.Management.Aut
omation.ScriptBlock' required by parameter 'Process'. Specified method is not supported.
At R:\SysAdmin\PowerShell\Scripts\AD\Share_Information\View_Perms_for_Everyone.ps1:23 char:69
+         $shareACL | Where {$_.Trustee.Name -eq "Everyone"} | ForEach <<<<  `
    + CategoryInfo          : InvalidArgument: (:) [ForEach-Object], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ForEachObjectCommand


Code-->

cd "R:\SysAdmin\PowerShell\Scripts\AD\Share_Information"
cls
$typehash = @{
    0 = "Allow"
    1 = "Deny"
    }

$permhash = @{
    1179817 = "Read"
    1245631 = "Change"
    2032127 = "Full Control"
    }

$servers = Get-Content "Everyone_ServerList.txt"

@(foreach ($server in $servers)
{
	Write-Host "Currently processing shares for $server."
    $shareInfo = @(Get-WmiObject Win32_Share -ComputerName $server -filter "type = 0" | Select Name,Path)
    @(foreach ($share in $shareInfo)
    {
        $shareACL = (Get-WmiObject Win32_LogicalShareSecuritySetting -ComputerName $server -filter "name = '$($share.name)'").GetSecurityDescriptor().Descriptor.DACL
        $shareACL | Where {$_.Trustee.Name -eq "Everyone"} | ForEach `
        $shareACL | ForEach `
        {
            $user = If ($_.Trustee.Domain)
                    { $_.Trustee.Domain, $_.Trustee.Name -join "\" }
                    Else
                    { $_.Trustee.Name }
            $type = switch ($_.AceType)
                    {
                        0 { $typehash[0]; break }
                        1 { $typehash[1]; break}
                    }
            $perm = switch ($_.AccessMask)
                    {
                        1179817 { $permhash[1179817]; break }
                        1245631 { $permhash[1245631]; break }
                        2032127 { $permhash[2032127]; break }
                    }
            New-Object PsObject -Property @{
                    Server = $server
                    ShareName = $share.name
                    Path = $share.path
                    UserOrGroup = $user
                    Type = $type
                    Permission = $perm
                    }
        }
    }) | Sort Server,ShareName,UserOrGroup
}) |
 #Where {$_.UserOrGroup -eq "Everyone"} |
 Select Server,ShareName,Path,UserOrGroup,Type,Permission | ft -auto
 
 
 #Report
 # with PS 3.0
# not efficient because of opening and closing files repeatedly, but simple code
#Import-CSV shareinfo.csv | ForEach { $_ | Export-CSV "shareinfo-$($_.server).csv" -notype -append }

# or
# doesn't require PS 3.0
$servers = Get-Content serverlist.txt  #could generate the list of servers from shareinfo.csv, but if we already have the list this is simpler
$data = Import-CSV shareinfo.csv 
foreach ($server in $servers)
{ $data | Where {$_.server -eq $server } | Export-CSV "shareinfo-$server.csv" -notype }

Open in new window

The error came from uncommenting line 23 without then deleting the following line.
Also, you hadn't made a change to export the info to a master .CSV, so there would be an error when generating the per-server reports.  I made both changes below.
cd "R:\SysAdmin\PowerShell\Scripts\AD\Share_Information"
cls
$typehash = @{
    0 = "Allow"
    1 = "Deny"
    }

$permhash = @{
    1179817 = "Read"
    1245631 = "Change"
    2032127 = "Full Control"
    }

$servers = Get-Content "Everyone_ServerList.txt"

@(foreach ($server in $servers)
{
	Write-Host "Currently processing shares for $server."
    $shareInfo = @(Get-WmiObject Win32_Share -ComputerName $server -filter "type = 0" | Select Name,Path)
    @(foreach ($share in $shareInfo)
    {
        $shareACL = (Get-WmiObject Win32_LogicalShareSecuritySetting -ComputerName $server -filter "name = '$($share.name)'").GetSecurityDescriptor().Descriptor.DACL
        $shareACL | Where {$_.Trustee.Name -eq "Everyone"} | ForEach `
        {
            $user = If ($_.Trustee.Domain)
                    { $_.Trustee.Domain, $_.Trustee.Name -join "\" }
                    Else
                    { $_.Trustee.Name }
            $type = switch ($_.AceType)
                    {
                        0 { $typehash[0]; break }
                        1 { $typehash[1]; break}
                    }
            $perm = switch ($_.AccessMask)
                    {
                        1179817 { $permhash[1179817]; break }
                        1245631 { $permhash[1245631]; break }
                        2032127 { $permhash[2032127]; break }
                    }
            New-Object PsObject -Property @{
                    Server = $server
                    ShareName = $share.name
                    Path = $share.path
                    UserOrGroup = $user
                    Type = $type
                    Permission = $perm
                    }
        }
    }) | Sort Server,ShareName,UserOrGroup
}) |
 Select Server,ShareName,Path,UserOrGroup,Type,Permission |
 Export-CSV shareinfo.csv -notype
 
 
 #Report

$data = Import-CSV shareinfo.csv 
foreach ($server in $servers)
{ $data | Where {$_.server -eq $server } | Export-CSV "shareinfo-$server.csv" -notype }

Open in new window

Thank you. I will compare my code to yours to learn what I missed.