Script to re setup user homefolders fully

Posted on 2013-02-02
Last Modified: 2013-02-12
Hi Guys,

We are about to move our user docs server, just a quick note on our setup. User home shares are \\docserver\username$ the server has file structure b:\users\yeargroup\username\ running windows server 2008 r2 ent.

I have a script which I have tried to compile from multiple posts from this site to do the following: Check and set recursive file permissions to the individual homefolders to the name of the folder, and grant domain admins full. Share the folder in format username$ to the same permissions and take ownership of the folder to the folder name.

I would like the script to say each subfolder of the subfolders so I can do it to the Users folder and then it goes into each year group folder and then works through the folders below it ie the usernames.

Also I would like it to if possible move any folders that it can't find a user for in AD to a folder called Deleted users with the date of "deletion" then the same folder structure so \deleted users\yeargroup\username(datedeleted)\.

It would be nice for the script to check a folder such as \users\new\username\ and if search AD for the user find the OU the user is under and put their folder in the relevant docs folder as the AD is layed out \students\year7\ and \students\year8\ and if it is not asking too much (I haven't really worked with any powershell scripts before) have it log any folder changes such as deletion?

Below is what I have compiled so far:

# Where is the root of the home drives?
# Report only? ($false = fix problems)
$reportMode = $true
# Print all valid directories?
$verbose = $false
# What domain are your users in?
$domainName = "domain.local"
# what is the name of the docs server?
$servername = "docserver"
# What is the user/group you would like full access to all folder?
$adminuser = $domainName + "\Domain Admins"
# 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)
$accessRule1 = New-Object System.Security.AccessControl.FileSystemAccessRule($adminuser,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)
# Attempt to apply the access rule to the ACL
#Set user permissions
Set-Acl $homeFolder $Acl
#Set admin permissions
Set-Acl $homeFolder $Acl1
#Set Up Share and Share Permissions
Invoke-Command -ComputerName $servername -ScriptBlock {
             param([string] $homeFolder.Name)
             $setupFolder = "$homeFolder.Name"
	     New-Item -Path $setupFolder -type directory -Force
	     "net share $homeFolder.Name$=$homeDirectory$homeFolder.Name /grant:$adminuser,full /grant:$homeFolder.Name,full" | cmd
         } -ArgumentList $homeFolder.Name
#Set ownership on all files and folders
     If (get-aduser "$homeFolder") {
          Get-Acl $homeFolder.FullName | Format-List
          #Addition here: Getting the entire list of files and folders under this root folder
          $folders = gci $homeFolder.FullName -recurse
          $acl = Get-Acl $homeFolder.FullName         
          $acct = New-Object System.Security.Principal.NTAccount($domainName,$
          Set-Acl $homeFolder.FullName $acl

          Foreach ($SubFolder in $Folders){
               Set-ACL -path $SubFolder.fullname -aclobject $ACL

          Get-Acl $homeFolder.FullName  | Format-List
# 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}
#go to start level finished script

Open in new window

Thank you to anyone who can give any advice :)
Question by:schooltechnician
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
LVL 40

Expert Comment

ID: 38850542
I hope the formatting on your script is better than what I see above - pretty difficult to read.  :)
Anyway, in a somewhat cursory look at what you have, here are some suggestions on corrections I believe should be made:
line 35 - need two spaces between "Allow" and "FullControl"
line 68 - pretty sure $Acl1.SetAccessRule($accessRule1) should just be $Acl.SetAccessRule($accessRule1) and therefore no need for line 72
line 82 and 86 - instead of issuing multiple Get-ACL, do it once and store it to a variable, if you need to display it, output the variable instead of making another call
line 74 - take out the computername parameter unless you're planning on working with a remote machine

Have you tested any of your script?  What parts are working and what parts aren't?

I have a bit that should help with deleted users.  I hate to post it untested, but I'll try to test it when I get a chance.  I would run this check before setting any permissions, since setting the perms is unnecessary if the folder is moved.
import-module activedirectory
$dateDeleted = Get-Date -format MMddyyyy
$userslist = Get-ADUser -filter * | select -expandProperty samAccountName
$userfolders = gci $homefolder | Where {($_.PsIsContainer)} | ForEach { gci $_.fullname | Where {($_.PsIsContainer)} }
foreach ($userfolder in $userfolders)
  If ( $userslist -notcontains $ )
    $targetfolder = ($userfolder.fullname -split "\\",3)[-1]
    $targetfolder = ((Join-Path b:\deleted-users $targetfolder) + "(" + $dateDeleted + ")")
    New-Item $targetfolder -type directory
    Move-item $userfolder $targetfolder -force
    #change permissions and set owner

Open in new window

Edit: tested the previously posted code and made some changes.  Should work as intended now.

Author Comment

ID: 38852660

Thanks, I have done what you said about corrections and the script now runs but the output log says it couldn't set ACL permissions but recognises that the permissions are wrong (i have turned reporting mode off).
I am thinking I might just separate the scripts so one does file perm, one does ownership and one does sharing just to get it sorted in the mean time.
I will test the script you provided about deleted users tomorrow on my test domain server I have running.
Thanks for the input will update tomorrow with more info as I am sure more people would find this type of script interesting to have.
LVL 40

Expert Comment

ID: 38857761
When I'm building scripts I will often comment out entire sections to focus on just one.  This can sometimes be made a little easier if the sections are functions.  I will also out the value of a variable right before it gets used in a command to make sure that it equals what I think it does.
So far I have avoided setting permissions with PS, but I've looked into it a couple times.  A couple changes I would try.
$Acl.SetAccessRule($accessRule)  --> $Acl.AddAccessRule($accessRule)
I believe it comes out the same with FullControl.
Set-Acl $homeFolder $Acl              --> Set-Acl $homefolder.fullname $Acl

You may want to give this a look for help in setting permissions:
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 38859961
Hi thanks for the input, I have had a rethink about the script and started from scratch after the one posted above didn't work at all.

Just testing it at the moment, have it doing deleted users, ntfs permissions. Just got to get it to do ownership and share + permissions and then will post an update.

Accepted Solution

schooltechnician earned 0 total points
ID: 38867260
Right, thanks for all the help :) I have spent a day looking at what the script was suppose to be doing and with some addon modules to powershell and the internet posts helping along the way.

Here is what I got below and what it does is: Creates a folder for deleted users with todays date, Checks if the name of the folder (also the username) is active in AD, if not then renames the folder to _DEL_username and moves to the deleted user folder with todays date. If the user does exist, gives ownership to admins, sets permissions on folder for the user to have full control and admins to have full control, sets the owner back to the user. Sets up a share with the username$ and grants the user full control and then sets the admins full control on the share. (Checks to see if share already exists first, will be adding a bit to stop existing share and set the new share up later)

That is everything that I needed for the moment, will be adding to it later. But for now anyone who wants this setup should find this script very helpful, I have fully tested it and everything that I have put above works.

#Share permissions:

#Configure your settings here
#Set Domain
$domain = "domain.local"
#Set admin group
$admin = "Domain Admins"
#Set the folder to work on here
$homesroot = "E:\Users\Homes"
#Set the deleted homes folder
$dhomesroot = "E:\Users\Deleted\"
#Where is subinacl
$subinacl = "C:\utils\subinacl.exe"
#Finished config

Write-Host "Cox Green School User Home Folder Check Script"
Write-Host "Written by Tom Smith"
Write-Host "With help from the interweb"
Write-Host "Version 1.0"
Write-Host "Date: 08/02/2013"
Write-Host "Editing Home Directories within $homesroot"
Write-Host "Deleted user homes will go to $dhomesroot"

#Load Quest even if installed
Add-PSSnapin Quest.ActiveRoles.ADManagement
#Load PSCX
Import-Module "PSCX"
Set-Privilege (New-Object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true)#Necessary to set Owner Permissions
Set-Privilege (New-Object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true)#Necessary to bypass Traverse Checking
Set-Privilege (New-Object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true)#Necessary to override FilePermissions & take Ownership
#Load ShareUtils
Import-Module ShareUtils
#Create folder in deleted users with todays date
$date = Get-Date -format "dd-MM-yyyy"
$dDay = Get-Date -format "dd"
$dMonth = Get-Date -format "MM"
$dYear = Get-Date -format "yyyy"
$dFolder = "$dhomesroot" + "$dYear" + "\" + "$dMonth" + "\" + "$dDay"
New-Item $dFolder -type directory -Force
Write-Host "Todays Date is $date"
$dirlist = gci $homesroot -Exclude *.* | ? { $_.PSIsContainer }

foreach ($userdir in $dirlist)
            $username = $
            Write-Host "Working on user folder $username"
            $adaccount = Get-QADUser $username
            #Verifies user is an active account, renamed folder to be deleted if not
            If (($adaccount.AccountIsDisabled -eq $TRUE) -or (!$adaccount))
                    write-host "$username is not a current user in active directory"
                    #takeownership to administrators
                    takeown /f $userdir /R /D Y /A
                    #rename folder to _DEL_originalname
                    $newname = "_DEL_$username"
                    rename-item -path $userdir -newname $newname
                    #Move deleted user folders to deleted user homes path
                    $oldpath = "$homesroot" + "\" + "$newname" + "\"
                    $newpath = "$dFolder" + "\" + "$newname"
                    move-item $oldpath $dFolder
                    Write-Host "User folder $username was moved to $dFolder "
                #get full path            
                Write-Host $
                Write-Host $username is valid in active directory
                $currentDir = $userdir.FullName
                #Take ownership for admins for setting permissions
                takeown /f $userdir /R /D Y /A

                #get ACL of folder
                $acl = Get-Acl $currentDir

                #variable to set new permissions for username of folder
                Write-Host "$domain\$username"
                $permission = "$domain\$username",”FullControl”,”ContainerInherit,ObjectInherit”,”None”,”Allow”
                $permission1 = "$domain\$admin",”FullControl”,”ContainerInherit,ObjectInherit”,”None”,”Allow”

                $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission
                $accessRule1 = new-object System.Security.AccessControl.FileSystemAccessRule $permission1

                #actually set the permissions
                Set-Acl $currentDir $acl

                $acl3 = Get-Acl $currentDir
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule ("Everyone","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($admin,"FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,"FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
				#Set Owner
                $domuser = "$domain\$username"
                $accnt = New-Object System.Security.Principal.NTAccount($domuser)
                Set-Acl $currentDir $acl
				dir -r $currentdir | Set-Acl -AclObject $acl
				#Set up share
				$shareperm = "/GRANT:" + $username + ",FULL"
				Write-Host "Start share script"
				function New-Share {
				param($Path, $Name)
				try {
				$ErrorActionPreference = 'Stop'
				if ( (Test-Path $Path) -eq $false) {
				$null = New-Item -Path $Path -ItemType Directory
				net share $Name=$Path $shareperm
				catch {
				Write-Warning "Create a new share: Failed, $_"
				New-Share $currentDir $username$
				#Set share permissions for admin keeping old permissions
				Get-Share -Name $username$ | Add-SharePermission $admin Allow FullControl | Set-Share
				Write-Host "Share script end"
                #Any further scripts here
Write-Host "Script complete todays date is $date "

Open in new window

Hope this helps people in my situation,

Author Closing Comment

ID: 38879551
What I was looking for in basic

Featured Post

Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Create and license users in Office 365 in bulk based on a CSV file. A step-by-step guide with PowerShell script examples.
Windows 10 came with  a lot of built in applications, Some organisations leave them there, some will control them using GPO's. This Article is useful for those who do not want to have any applications in their image (example:me).
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…

696 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question