Fix NTFS Permissions on Home Drives with PowerShell

Keeping permissions in check for your users’ home drives can be a pain at times. I’m a big fan of the \\server\share$\username model. This keeps it simple, and allows for easy migration of users between servers.

The problem with home drives is that NTFS permissions can often (accidently..or intentionally) be changed. In order to maintain appropriate security and accessibility, it’s often desirable to regularly keep these current. I have developed a small script to do this. It collects the name of the folder and attempts to grant permissions to a user in the domain by that same name.

I use this regularly to keep our three file servers of home drives current, and it works very effectively.

UPDATE: Thanks to reader ‘Noel’ for pointing out a fault with the  $inheritanceFlags and$propagationFlags variables. I’ve updated the script to suit

#############################################################################
# Script: Repair-HomeFolderPermissions.ps1
# Author: Chris Brown    http://www.flamingkeys.com
# Date: 20/10/2010
# Keywords:
# Comments:
# Pre-Requisites: Full Control over destination folder.
#
# +------------+-----+---------------------------------------------------------+
# |       Date | Usr | Description                                             |
# +------------+-----+---------------------------------------------------------+
# | 20/10/2010 | CJB | Initial Script                                          |
# | 28/09/2011 | CJB | Fixed flags issue                                       |
# +------------+-----+---------------------------------------------------------+
#
# DISCLAIMER
# ==========
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#############################################################################

# ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠
#            Variables
#
# Where is the root of the home drives?
$homeDrivesDir="\\msfs01\home$"
# Report only? ($false = fix problems)
$reportMode = $false
# Print all valid directories?
$verbose = $false
# What domain are your users in?
$domainName = "corp.msft"
#
# ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠

# Save the current working directory before we change it (purely for convenience)
pushd .
# Change to the location of the home drives
set-location $homeDrivesDir

# Warn the user if we will be fixing or just reporting on problems
write-host ""

if ($reportMode) {
 Write-Host "Report mode is on. Not fixing problems"
} else {
 Write-Host "Report mode is off. Will fix problems"
}

write-host ""

# Initialise a few counter variables. Only useful for multiple executions from the same session
$goodPermissions = $unfixablePermissions = $fixedPermissions = $badPermissions = 0
$failedFolders = @()

# For every folder in the $homeDrivesDir folder
foreach($homeFolder in (Get-ChildItem $homeDrivesDir | Where {$_.psIsContainer -eq $true})) {

 # dump the current ACL in a variable
 $Acl = Get-Acl $homeFolder

 # create a permission mask in the form of DOMAIN\Username where Username=foldername
 #    (adjust as necessary if your home folders are not exactly your usernames)
 $compareString = "*" + $domainName + "\" + $homeFolder.Name + " Allow  FullControl*"

 # if the permission mask is in the ACL
 if ($Acl.AccessToString -like $compareString) {

 # everything's good, increment the counter and move on.
 if ($verbose) {Write-Host "Permissions are valid for" $homeFolder.Name -backgroundcolor green -foregroundcolor white}
 $goodPermissions += 1

 } else {
 # Permissions are invalid, either fix or report
 # increment the number of permissions needing repair
 $badPermissions += 1
 # if we're in report mode
 if ($reportMode -eq $true) {
 # reportmode is on, don't do anything
 Write-Host "Permissions not valid for" $homeFolder.Name -backgroundcolor red -foregroundcolor white
 } else {
 # reportmode is off, fix the permissions
 Write-Host "Setting permissions for" $homeFolder.Name -foregroundcolor white -backgroundcolor red
 # Add the user in format DOMAIN\Username
 $username = $domainName + "\" + $homeFolder.Name
 # Grant the user full control
 $accessLevel = "FullControl"
 # Should permissions be inherited from above?
 $inheritanceFlags = "ContainerInherit, ObjectInherit"
 # Should permissions propagate to below?
 $propagationFlags = "None"
 # Is this an Allow/Deny entry?
 $accessControlType = "Allow"
 try {
 # Create the Access Rule
 $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)

 # Attempt to apply the access rule to the ACL
 $Acl.SetAccessRule($accessRule)
 Set-Acl $homeFolder $Acl
 # if it hasn't errored out by now, increment the counter
 $fixedPermissions += 1
 } catch {
 # It failed!
 # Increment the fail count
 $unfixablePermissions += 1
 # and add the folder to the list of failed folders
 $failedFolders += $homeFolder
 }
 } #/if
 } #/if
} #/foreach

# Print out a summary

Write-Host ""
Write-Host $goodPermissions "valid permissions"
Write-Host $badPermissions "permissions needing repair"
if ($reportMode -eq $false) {Write-Host $fixedPermissions "permissions fixed"}
if ($unfixablePermissions -gt 0) {
 Write-Host $unfixablePermissions "ACLs could not be repaired."
 foreach ($folder in $failedFolders) {Write-Host " -" $folder}
}

# Cleanup
popd
  • BR

    Absolutely perfect script mate.  I’ve been scratching my head on how to best fix some screwed up home profile permissions on a domain we inherited.

  • Noel

    Awesome, thank you.

    When I look at the user folder after running the script the permissions are applying to subfolders only, so the user has no access. How can I change this to ‘this folder, sunfolders and files’?

    Thanks!

    • Anonymous

      Hi Noel,

      Sorry to hear you’ve had this problem. May I suggest you spot-check the inheritance settings on these folders just to check that it’s set up correctly? I’ve used this script with great success and have not had the problem you’re mentioning. Does the script output any errors? Does $failedFolders return a set of folders that have had issues?

      • Noel

        Hi Chris, thanks for your fast reply!

        I still have this issue, but perhaps I should have explained what has been done to date.

        - Copied all user data via robocopy job to a new server. Robocopy has copied all the permissions and this has been verified.
        - A new top level share structure has been created- HOME – COUNTRIES – FRPA => User folders below based on username

        So we have a duplicate of the data. We have then reset the top level permissions to include a number of management groups and replaced the inheritance. Now we want to re-add the users to have full control of their own home drives. Your script does exactly what we want, but after testing we can only get it to set the permissions on the subfolders. All the files within the subfolders do not have permission set also which seems very odd!

        The resulting permission is set to SPECIAL – FULL CONTROL SUB FOLDERS ONLY

        We have tested this a fair bit by unchecking inheritance, sharing, unsharing, changing paths e.t.c but the result is the same.

        If you can offer any assistance it would be appreciated.

        Cheers
        Noel

        • Noel

          Hi Chris,

          I think I’ve found the issue. After reading this post I made some changes.

          http://blog.netnerds.net/2007/07/powershell-set-acl-does-not-appear-to-work/

          The changes I made for our environment to allow folder, subfolders and files:

           $inheritanceFlags = “ContainerInherit, ObjectInherit” $propagationFlags = “None”

          So it works the way I need it now.

          Thanks so much for this script, will save me a ton of time.

          All the best,

          Noel

  • Pingback: Folder Permissions

  • Craig Wallace

    Hello. Fantastic script and look forward to using it. To really make this work for me can you let me know how i could add in extra security groups to have change to full control to the users share?
    Many thanks

    • Anonymous

      Hi Craig,

      I’d suggest you manually apply permissions for the groups to the directory above. You don’t want to get your home folder permissions too messy.

  • SK

    Hello Chris,

    I am not able to get the script to work. The script seem to execute as no errors are reported but the permissions are not added. I tried running the script in report mode but nothing happens. All i am changing in the script is the path to shared user folder (the users shared folder is not a hidden folder – I dont think that should make a difference).

    I am copying and pasting the script in a notepad file and saving it as a  .ps1 file, then I am executing it from within windows powershell. I have tried using ./ and & but with same result.

    Is there anything I am overlooking?

    I need to run this script for messed up permissions after a server crash and files were restored from backup.

    Many Thanks
    SK

  • Mike Hanson

    How does it handle when one of the users either removes everyone elses access or if they are “smarter” actually Deny access to everyone else? We have some users that regularly remove or deny “Domain Admins” and “Backup-Restore Admins” access to their folders. Of course, then they in variable complain when we can’t restore something, but that is a different issue.

  • Karson K VanMeeteren

    Great script Chris – thanks for doing all the legwork on this.  One issue I can’t seem to figure out is why reporting doesn’t catch the previous permission changes as successful?  I’ve modified this to give users “Allow Modify*” - it runs and propagates down fine.  However, when I run the script in reporting mode only, it still says they’re not correct.

    See picture for details.  Again, thanks again!
    karson

  • Fivener

    Thank you! Thank You! Thank You!

  • Eric Gwillim

    Thanks for the script, but thought I would leave a note.

    I was getting the following error.

    set-acl : cannot set the acl because the method that it needs to invoke, setsecuritydescriptor, does not exist.

    What I ended up needing to do was change my Powershell version to v2.

    First type get-host to get what version of Powershell you are running. Mine (Win 7 x64 Ent) was running v3.

    Then to change the version type the following.

    powershell -version 2.0

    Then type get-host again to make sure the version has changed.

    Once I did that the script worked for me.

    Thanks again!

  • wagging_it

    This might be a uber-noob question, but how do you invoke/run in report mode?

    • chrisbrownie

      Not at all. Because I wrote this when I understood PowerShell less comprehensively, there’s a lot I’d do differently if I were to write it again.

      Anyway, to enable report mode you just need to change line 28 from:
      $reportMode = $false
      to
      $reportMode = $true

      This will make the script spit out which directories permissions need repairing on.

      To run it, just do the following at a PowerShell prompt:
      [PS] C:Scripts> .Repair-HomeFolderPermissions.ps1

      • wagging_it

        Thank you! Makes sense now.

  • eudonj

    Haven’t tried this yet but looks good, wondering if you or anyone has written something for a username that doesn’t match homefolder in powershell, I have a few usernames that get changed due to marriage, divorce etc but the homefolder doesnt get updated. I use dsquery and excel now :(

  • Hartmann

    Dear Chris,

    Thank you for you saving script.

    I’m just afraid that with it, you do not remove old permissions and just add domainuser with full control.

    We need to :

    1- add domain user that login id is the foldername within the home drive, with full control, recursively

    2- add NT AUTHORITYSystem with full control, recursively

    3- set domainuser (domainfoldername) as owner, recursively

    4- remove inheritance, to block inherit to folders within foldername from parentfolder

    and then also remove all old inherited permissions

    Here is how i edit your script, i beg your pardon to share it here for anyone needing it as i enumarte above : (I’m not a powershell crack so i’ve just add some command to perform actions needed)

    #############################################################################

    # Script: Repair-HomeFolderPermissions.ps1

    # Author: Chris Brown http://www.flamingkeys.com

    # Date: 20/10/2010 -_- EDIT: 28/10/2013

    # Keywords:

    # Comments:

    # Pre-Requisites: Full Control over destination folder.

    #

    # +————+—–+———————————————————+

    # | Date | Usr | Description |

    # +————+—–+———————————————————+

    # | 20/10/2010 | CJB | Initial Script |

    # | 28/09/2011 | CJB | Fixed flags issue |

    # +————+—–+———————————————————+

    #

    # DISCLAIMER

    # ==========

    # THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE

    # RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.

    #############################################################################

    # ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠

    # Variables

    #

    # Where is the root of the home drives?

    $homeDrivesDir=”\LPT-hmontaguereTest”

    # Report only? ($false = fix problems)

    $reportMode = $false

    # Print all valid directories?

    $verbose = $false

    # What domain are your users in?

    $domainName = “mtn.local”

    #

    # ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠ ♥ ♦ ♣ ♠

    takeown /F “$homeDrivesDir*.*” /R /A /D Y

    # Save the current working directory before we change it (purely for convenience)

    pushd .

    # Change to the location of the home drives

    set-location $homeDrivesDir

    # Warn the user if we will be fixing or just reporting on problems

    write-host “”

    if ($reportMode) {

    Write-Host “Report mode is on. Not fixing problems”

    } else {

    Write-Host “Report mode is off. Will fix problems”

    }

    write-host “”

    # Initialise a few counter variables. Only useful for multiple executions from the same session

    $goodPermissions = $unfixablePermissions = $fixedPermissions = $badPermissions = 0

    $failedFolders = @()

    # For every folder in the $homeDrivesDir folder

    foreach($homeFolder in (Get-ChildItem $homeDrivesDir | Where {$_.psIsContainer -eq $true})) {

    # dump the current ACL in a variable

    $Acl = Get-Acl $homeFolder

    # create a permission mask in the form of DOMAINUsername where Username=foldername

    # (adjust as necessary if your home folders are not exactly your usernames)

    $compareString = “*” + $domainName + “” + $homeFolder.Name + ” Allow FullControl*”

    # if the permission mask is in the ACL

    if ($Acl.AccessToString -like $compareString) {

    # everything’s good, increment the counter and move on.

    if ($verbose) {Write-Host “Permissions are valid for” $homeFolder.Name -backgroundcolor green -foregroundcolor white}

    $goodPermissions += 1

    } else {

    # Permissions are invalid, either fix or report

    # increment the number of permissions needing repair

    $badPermissions += 1

    # if we’re in report mode

    if ($reportMode -eq $true) {

    # reportmode is on, don’t do anything

    Write-Host “Permissions not valid for” $homeFolder.Name -backgroundcolor red -foregroundcolor white

    } else {

    # reportmode is off, fix the permissions

    Write-Host “Setting permissions for” $homeFolder.Name -foregroundcolor white -backgroundcolor red

    # Add the user in format DOMAINUsername

    $username = $domainName + “” + $homeFolder.Name

    # Grant the user full control

    $accessLevel = “FullControl”

    # Should permissions be inherited from above?

    $inheritanceFlags = “ContainerInherit, ObjectInherit”

    # Should permissions propagate to below?

    $propagationFlags = “None”

    # Is this an Allow/Deny entry?

    $accessControlType = “Allow”

    try {

    # Create the Access Rule

    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)

    $accessRuleb = New-Object System.Security.AccessControl.FileSystemAccessRule(“NT AUTHORITYSYSTEM”,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)

    $accessRuleO = New-Object System.Security.Principal.NTAccount($username)

    # Attempt to apply the access rule to the ACL

    $Acl.SetAccessRule($accessRule)

    $Acl.SetAccessRule($accessRuleb)

    $Acl.SetOwner($accessRuleO)

    Get-ChildItem -path “$homeFolder” -Recurse -Force | Set-Acl -AclObject $Acl

    icacls “$homeDrivesDir$homeFolder*” /inheritance:R

    # if it hasn’t errored out by now, increment the counter

    $fixedPermissions += 1

    } catch {

    # It failed!

    # Increment the fail count

    $unfixablePermissions += 1

    # and add the folder to the list of failed folders

    $failedFolders += $homeFolder

    }

    } #/if

    } #/if

    } #/foreach

    # Print out a summary

    Write-Host “”

    Write-Host $goodPermissions “valid permissions”

    Write-Host $badPermissions “permissions needing repair”

    if ($reportMode -eq $false) {Write-Host $fixedPermissions “permissions fixed”}

    if ($unfixablePermissions -gt 0) {

    Write-Host $unfixablePermissions “ACLs could not be repaired.”

    foreach ($folder in $failedFolders) {Write-Host ” -” $folder}

    }

    # Cleanup

    popd

  • Nick

    I am attempting to run this in on a Windows 2012 server and it does not seem to be working. The ownership applies, however the ACLs do not. I get the following output:

    0 valid permissions
    53 permissions needing repair
    0 permissions fixed
    53 ACLs could not be repaired.

    I attempted changing powershell to version 2.0 as noted below, but the command never completes. Any assistance is greatly welcomed! Thanks.

  • TimAdminS

    This is amazing, honestly, thankyou so so so much. It work for me first time using PSv2. I’ve spent the last 3 hours slaving over this issue that the last sys admin created and you’ve done an amazing job at saving me time.

    Mad props!

  • Steve Gold

    Hi Chris, great script… One thing I needed to do though was take ownership of the Folder so I added after:

    ……..
    # Is this an Allow/Deny entry?
    $accessControlType = “Allow”

    # take ownership of folder and set to BuiltInAdministrators
    takeown /f $homeFolder /a /d Y /r

    I am sure there are other ways, but it does seem to work, I do get an error when the set-acl runs, but then when I checked the Owner in the GUI it is been corrected and the permissions are right.

    If you have a better, cleaner way please let me know…

    Steve