Hey, Scripting Guy! How Can I Tell to Which Folders a User Has Been Granted or Denied Access?

ScriptingGuy1

Share this post:

Hey, Scripting Guy! QuestionHey, Scripting Guy! I need to find out what folders a user has specifically been granted or denied access to. I do not need the specific rights that were granted. I only need to find out where the user was specifically granted or denied access. The reason for this is I am trying to clean up permissions on some of our shared directories, and I am having a hard time finding explicit permissions. As you know, when a user has been explicitly denied, it overrides other permissions. Also when a user has been granted specific permissions, they add to rights gained via groups. All of this is quite confusing. Needless to say, these permissions were granted by some clown who did not know what he was doing, and of course the clown has now been promoted to another department and is too good to answer questions from a storage administrator. Can you whip up a custom script for me?

— JS

Hey, Scripting Guy! AnswerHello JS,

Microsoft Scripting Guy Ed Wilson here. I recently had a scoping call with a large customer about providing some Windows PowerShell 2.0 training for them. During the phone call, I mentioned that reporting on certain configuration settings is best carried out by using tools such as System Center and that I did not think in the large enterprise writing scripts to detect the installation status of a particular hotfix was something that would be needed. They promptly informed me that, while it might be possible to obtain such a report, it might very well take more than a week to have it produced because the System Center team is responsible for managing System Center and not for producing ad hoc reports for the server administration team.  It is a shame, but it seems that most IT departments these days run extremely lean, and to accomplish their core mission, they must carefully guard against being randomized in too many different directions. Of course, this is not necessarily your problem; however, it might explain why your colleague seems to be a bit preoccupied with his new job. Another explanation might be that your co-worker does not remember what was done or why. If the documentation for such changes was not made, it might be that any forthcoming assistance would be useless drivel.

A good script is better than a clueless co-worker any day. The Get-SecurityOfFolders.ps1 script will search through an array of folders that you specify, and find which folders a specific user has been granted explicit security permissions to. The complete Get-SecurityOfFolders.ps1 script is seen here.

Get-SecurityOfFolders.ps1

$user = ‘nwtraders\bob’
$folders = "c:\fso","C:\fso1","c:\fso2"
$acls = Get-Acl -path $folders
$outputObject = @()

Foreach($acl in $acls)
{
 $folder = (convert-path $acl.pspath)
 Write-Progress -act "Getting Security" -status "checking $folder" -percent ($i/ $folders.count*100)
 $object = New-Object -TypeName PSObject
  Foreach($access in $acl.access)
  {
    Foreach($value in $access.identityReference.Value)
     {
       if ($value -eq $user)
          {
     $object | Add-Member -MemberType NoteProperty -Name Folder -Value $folder
     $object | Add-Member -MemberType NoteProperty -Name user -Value $user
     $object | Add-Member -MemberType NoteProperty -Name mode -Value $access.AccessControlType
     $outputObject += $object
          }
     } #end foreach value
  } # end foreach access
$i++
} #end Foreach acl
$outputObject | Format-Table -property * -autosize

The first thing that is done in the Get-SecurityOfFolders.ps1 script is to specify a user name. The user is the one whose security rights to folders will be determined. The folders are an array of folder paths. You could also use the Get-ChildItem cmdlet to obtain a collection of folders, but that would entail a bit more work. You might also wish to modify these two value assignments and turn them into command-line parameters. You will need to modify these two values before running the script, unless you actually have a user named nwtraders\bob and you have folders c:\fso – c:\fso2. The two lines are shown here:

$user = ‘nwtraders\bob’
$folders = "c:\fso","C:\fso1","c:\fso2"

Now we use a shortcut to grab the security objects from the folders. Because the Get-Acl cmdlet will accept an array of strings for the folder paths, the array of strings stored in the $folders variable is passed to the path argument of the Get-Acl cmdlet. The resulting collection of System.Security.AccessControl.DirectorySecurity .NET Framework classes are stored in the $acls variable. This is seen here:

$acls = Get-Acl -path $folders

After you have collected the access control lists and stored them in the variable $acls, it is time to create an empty array. The $outputObject variable will be used to store the custom access object that will be created later on in the script. It is created here:

$outputObject = @()

You can walk through the collection of access control lists by using the Foreach statement. This is seen here:

Foreach($acl in $acls)
{

The path to the folder the specific user has been granted rights to is obtained from the pspath property of the System.Security.AccessControl.DirectorySecurity .NET Framework class. The pspath property is added by Windows PowerShell. When you look at the pspath property value, it contains the path to the folder, but not in a very usable fashion. This is seen here:

PS C:\> (Get-Acl c:\fso).pspath
Microsoft.PowerShell.Core\FileSystem::C:\fso
PS C:\>

To translate the pspath property value into a path that is more useful for the script, you can use the Convert-Path cmdlet. The Convert-Path cmdlet will translate a Windows PowerShell path into a path that can be used by a Windows PowerShell provider. This is seen here:

PS C:\> Convert-Path -path (Get-Acl c:\fso).pspath
C:\fso
PS C:\>

In the Get-SecurityOfFolders.ps1 script, the converted path is stored in the $folder variable, which is seen here:

 $folder = (convert-path –path $acl.pspath)

The Write-Progress cmdlet is used to provide a visual indicator of the progress in obtaining the ACLs from each folder. The activity is the gathering of security information. The status is the current folder that is being scanned. The percent complete is calculated by using the number of folders in the $folders array. When the Get-SecurityOfFolders.ps1 script is run, this progress bar is displayed:

Image of progress bar displayed when script is run

The Write-Progress command is seen here:

 Write-Progress -activity "Getting Security" -status "checking $folder" -percent ($i/ $folders.count*100)

It is now time to create the custom Windows PowerShell object that will hold the security information for the specific user on each of the folders. To do this, use the New-Object cmdlet and specify the TypeName of PSObject. The resulting custom object is stored in the $object variable as seen here:

 $object = New-Object -TypeName PSObject

Because the user name that has been granted rights to a folder is stored in the value of the identityReference property of the System.Security.Principal.NTAccount .NET Framework class, it is necessary to somehow gain access to the NTAccount class.  To do this, each of the System.Security.AccessControl.FileSystemAccessRule .NET Framework classes that are returned by querying the access property of the DirectorySecurity object are queried. The Foreach statement is used to walk through the collection of FileSystemAccessRules, as seen here:

  Foreach($access in $acl.access)
  {

After a FileSystemAccessRule has been obtained and stored in the $access variable, the NTAccount class is obtained by referencing the identityReference property.  The value contained in the value property is stored in the $value variable as seen here:

    Foreach($value in $access.identityReference.Value)
     {

If the value stored in the $value variable is equal to the string that is stored in the $user variable, the Add-Member cmdlet is used to add three different note properties to the custom PSObject that is stored in the $object variable.

The use of the custom PSObject was a significant feature in the solutions submitted by our expert commentators during the 2009 Summer Scripting Games. Those guest commentaries, as well as my review of some of the solutions proposed by Games participants, can be seen in the Hey, Scripting Guy! archives.

The first NoteProperty is the folder name stored in the $folder variable; the second is the user name stored in the $user variable; and the last  NoteProperty is the access mode (either denied or granted). This last value is received from the AccessControlType property from the FileSystemAccessRule .NET Framework class stored in the $access variable. This is seen here:

       if ($value -eq $user)
          {
     $object | Add-Member -MemberType NoteProperty -Name Folder -Value $folder
     $object | Add-Member -MemberType NoteProperty -Name user -Value $user
     $object | Add-Member -MemberType NoteProperty -Name mode -Value $access.AccessControlType
     $outputObject += $object
          }
     } #end foreach value
  } # end foreach access

The value of the $i variable is incremented by one because it is used to track the progress through the folders for the Write-Progress command. This is done just before closing the curly brackets for the Foreach statement that is used to walk through the access control lists:

$i++
} #end Foreach acl

It is time to display the results that are stored in the $outputObject variable. Because the $outputObject contains an array of custom Windows PowerShell objects, the output can be manipulated by using standard Windows PowerShell cmdlets. To display a table, pipe the $outputObject variable to the Format-Table cmdlet, select the properties you are interested in seeing and then autosize it to maximize screen real estate. The command to produce the output is seen here:

$outputObject | Format-Table -property * -autosize

The output produced by the script is seen here:

Image of output produced when script is run

JS, this concludes our discussion of identifying folders to which a specific user has rights.

If you want to know exactly what we will be discussing tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon