PowerShell script to add permission to directory and child items

Hello,

I could really use some help with my script. The purpose of my script is to add Modify rights to a folder and it's child folders for a domain user.

The script works to accomplish this, however, as you will see in my script I retrieve the access list for each folder at the End{}. What I am finding is that the domain user account that is added, is in there twice for all the child folders. The parent folder does not have this occurrence.

In other words, after I run the script, I go into Properties > Security > Advanced for any of the child folders and what I will see is that my domain\User is not only being Inheritedfrom "ParentFolder" but also is added a second time to permissions under Inheritedfrom "None" as seen in below screenshot.

Seen here is the same domain\User account added twice by the script for child folders only
This is a step up from what it used to do though, it was previously adding the System, NTAccount, and another default system permission a second time also. All under the Inheritedfrom "None". I was able to adjust script enough so that at least it is now only doubling up on the domain\User.

Am I even doing this the best way? I am adding the $acl to the parent folder and then adding the $acl to the child items. If I only save the child items to a variable and add the $acl by way of piping to the variable objects, it doesn't include the parent. There must be a better way? Feel free to offer feedback. Ultimately, I just want it to stop adding the domain\User twice.

function Set-Permission {
<#
.Synopsis
   Short description
.DESCRIPTION
   Long description
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.INPUTS
   Inputs to this cmdlet (if any)
.OUTPUTS
   Output from this cmdlet (if any)
.NOTES
   General notes
.COMPONENT
   The component this cmdlet belongs to
.ROLE
   The role this cmdlet belongs to
.FUNCTIONALITY
   The functionality that best describes this cmdlet
#>

    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # Param1 help description
        [Parameter(Mandatory=$true,Position=0)]
        [Alias("Path")]
        [string]
        $dirPath,

        # Param2 help description
        [Parameter(Mandatory=$true,Position=1)]
        [string]
        $samAccountName,

        # Param3 help description
        [Parameter(Mandatory=$true, Position=2)]
        [ValidateSet("Modify")]
        [string]
        $accessLevel,
        
        # Param4 help description
        [Parameter(Mandatory=$false)]
        [string]
        $domain = 'domainName'
    )
    Begin {
        $domainAccount = $domain + "\" + $samAccountName
        $inheritanceFlags = "ContainerInherit, ObjectInherit"                     
        $propagationFlags = "None"                    
        $accessControlType = "Allow"

        $AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
                        $domainAccount,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)
        Write-Verbose 'Print New Access Rule object'
        $AccessRule

        Write-Verbose 'Access Control List of parent folder before applying new rules'
        $Parent = gi $dirPath | where {$_.psIsContainer -eq $true}
        $pFN = $Parent.FullName
        $pFN

        $ParentRecurse = gci $dirPath -Recurse | where {$_.psIsContainer -eq $true}

        $acl = ($Parent).GetAccessControl("Access")
        $acl.SetAccessRule($AccessRule)
    }
    Process {
        Write-Verbose "Applying $samAccountName $accessLevel permissions to parent $pFN"
        ($Parent).GetAccessControl("Access") |select accesstostring |fl
        $acl |Set-Acl -Path $Parent.FullName

        $ParentRecurse |
        ForEach-Object {
            $fnDir = $_.FullName
            Write-Verbose "Applying $samAccountName $accessLevel permissions to child $fnDir"
            ($_).GetAccessControl('Access') |select accesstostring |fl
            $acl |Set-Acl -Path $_.FullName
        }# \ForEach
    } # \Process
    End {
        Write-Verbose 'New permissions have been set'
        $Parent.FullName
        ($Parent).GetAccessControl("Access") |select accesstostring |fl
        ForEach ($dir in $ParentRecurse) {
            $dir.FullName
            ($dir).GetAccessControl("Access") |select accesstostring |fl
        }
    }# \End
}

Open in new window


What you will find in my script is that during the Process{}, I am calling the Access Control List for each folder Before the permissions are added and then at the end I call the ACL again After the permissions are added to compare.

It does that thing where it has doubled all the system account permissions, but looks like it cleans it up for the most part after the $acl is set, but again it still leaves a domain\User account double with Inheritedfrom "None" for some reason unknown to me.

Hope this makes sense, thanks for your time!
ryanmavesAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

David Johnson, CD, MVPOwnerCommented:
use the get-acl and set-acl cmdlets and ?et-ntfsaccessinheritance
function Set-Permission {
<#
.Synopsis
   Short description
.DESCRIPTION
   Long description
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.INPUTS
   Inputs to this cmdlet (if any)
.OUTPUTS
   Output from this cmdlet (if any)
.NOTES
   General notes
.COMPONENT
   The component this cmdlet belongs to
.ROLE
   The role this cmdlet belongs to
.FUNCTIONALITY
   The functionality that best describes this cmdlet
#>

    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # Param1 help description
        [Parameter(Mandatory=$true,Position=0)]
        [Alias("Path")]
        [string]
        $dirPath,
        # Param2 help description
        [Parameter(Mandatory=$true,Position=1)]
        [string]
        $samAccountName,

        # Param3 help description
        [Parameter(Mandatory=$true, Position=2)]
        [ValidateSet("Modify")]
        [string]
        $accessLevel,
        
        # Param4 help description
        [Parameter(Mandatory=$false)]
        [string]
        $domain = 'domainName'
    )
Begin {
    $domainAccount = $domain + "\" + $samAccountName
    Write-Verbose 'Print New Access Rule object'
    $AccessRule
    Write-Verbose 'Access Control List of parent folder before applying new rules'
    $oldacl = get-acl $path 
    write-verbose $oldacl
}
Process {
    Write-Verbose "Applying $samAccountName $accessLevel permissions to parent $pFN"
    Add-NTFSAccess -Path $path -Account $domainaccount -AccessRights $accesslevel
    Write-Verbose "Applying $samAccountName $accessLevel permissions to child $fnDir"
    Get-ChildItem -path $path -Recurse | Get-NTFSAccessInheritance | 
    Where-Object { -not $_.InheritanceEnabled } |                     Enable-NTFSAccessInheritance -PassThru
    } 

End {
    Write-Verbose 'New permissions have been set'
    get-childitem -Path $path -Recurse | get-acl | out-gridview
    }
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ryanmavesAuthor Commented:
Thanks for the suggestion. Slight problem, I don't have those cmdlets. I looked into it and it appears to be a Module that you have to install first to get those commands.

I have also tried to do that, but it appears this is a learning opportunity for me. So at this point, either I need a solution that involves innate commands of PowerShell or I need help getting this module to test your solution.

Thanks very much for your time (this is a notoriously known problem that everyone wants a solution to online and I have yet to find one that works -- or that I could get to work)

Also, the bit in the End{} block to export to out-gridview is very nice. However, it doesn't include the actual parent folder itself; any trick to get the parent folder in there with the report?
0
ryanmavesAuthor Commented:
Apparently I filed this under Shell Scripting (as a third choice in my defense) but never the less, it was a quick pick and now I realize that shell scripting is more Unix. Even though we are talking about Windows shell, it is not the same. My apologies for any confusion.

However, do I need to rewrite this request or simplify the question?

I'll admit, I know I am asking for a challenge for a change, usually I have easy questions. This one just so happens to be one that is not easily solved apparently because lots and lots of research has not revealed yet to me, how to manage permissions using innate PowerShell commands.

Frankly, I don't know how to use the cacls, or I'd probably just use that at this point it has become such a challenge. Not even Don Jones takes it on from what I research.

Thanks for your time.
0
Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

ryanmavesAuthor Commented:
I stumbled over a link here regarding managing permissions with PS. I'm going to dig into it and see if this helps. I may have answered my own question, I'll update when I know for sure because this could really help someone else.

http://blogs.technet.com/b/josebda/archive/2010/11/12/how-to-handle-ntfs-folder-permissions-security-descriptors-and-acls-in-powershell.aspx
0
David Johnson, CD, MVPOwnerCommented:
That module is located @ https://gallery.technet.microsoft.com/scriptcenter/1abd77a5-9c0b-4a2b-acef-90dbb2b84e85  I didn't go back far enough in the Hey! Scripting Guy Blog  in your WindowsPowershell folder/modules create a folder NTFSSecurity and unpack the files there
0
ryanmavesAuthor Commented:
@David

Thanks! Turns out I had to learn how to properly add a Module. Once I got the module loaded properly and the commands working, your script was flawless. Really appreciate you assisting and recommending this module with the example script.

For those finding this page and in need of a script that adds Modify rights to a directory and it's child items, here is the updated BEGIN, PROCESS, END blocks below, you just have to fit this into the function with the params mentioned above in the first code I posted.

Also, here is the link on how to properly add a module obtained from the internet for those learning like myself:

http://www.powertheshell.com/installpsmodule/

    Begin {
        $domainAccount = $domain + "\" + $samAccountName
        $inheritanceFlags = "ContainerInherit, ObjectInherit"                     
        $propagationFlags = "None"                    
        $accessControlType = "Allow"

        $AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
                        $domainAccount,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)
        
        Write-Verbose 'Print New Access Rule object'
        $AccessRule

        # Saving parent folder directory into variable
        $Parent = gi $dirPath | where {$_.psIsContainer -eq $true}
        $pFN = $Parent.FullName

        Write-Verbose 'Access Control List of parent folder before applying new rules'
        $pFN
        $oldacl = Get-Acl $Parent
        $oldacl |select accesstostring |fl
    } # \Begin
    Process {
        Write-Verbose "Applying $samAccountName $accessLevel permissions to parent $pFN"
        Add-Access -Path $Parent -Account $domainaccount -AccessRights $accesslevel 

        Get-ChildItem -path $dirPath -Recurse | 
            ForEach-Object { 
                $fnDir = $_.FullName
                Write-Verbose "Applying $samAccountName $accessLevel permissions to child $fnDir"
            }# \ForEach
        Get-ChildItem -path $dirPath -Recurse | Get-NTFSAccessInheritance | 
        Where-Object { -not $_.InheritanceEnabled } | Enable-NTFSAccessInheritance -PassThru
    } # \Process
    End {
        Write-Verbose 'New permissions have been set'
        get-childitem -Path $dirPath -Recurse | get-acl | out-gridview
    }# \End

Open in new window


Thank you again!!
0
ryanmavesAuthor Commented:
Worked great. I had to put some pieces together, but in the end this is definitely a solution to my problem. Thank you kindly.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.