Solved

Script to re setup user homefolders fully

Posted on 2013-02-02
6
628 Views
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?
$homeDrivesDir="B:\Users\Student\Year7\"
# 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
$Acl.SetAccessRule($accessRule)
$Acl1.SetAccessRule($accessRule1)
#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,$homeFolder.name)
          $acl.SetOwner($acct)
          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
popd

Open in new window


Thank you to anyone who can give any advice :)
Thanks,
Tom
0
Comment
Question by:schooltechnician
  • 4
  • 2
6 Comments
 
LVL 39

Expert Comment

by:footech
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 $userfolder.name )
  {
    $targetfolder = ($userfolder.fullname -split "\\",3)[-1]
    $targetfolder = ((Join-Path b:\deleted-users $targetfolder) + "(" + $dateDeleted + ")")
    New-Item $targetfolder -type directory
    Move-item $userfolder $targetfolder -force
  }
  Else
  {
    #change permissions and set owner
  }
}

Open in new window

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

Author Comment

by:schooltechnician
ID: 38852660
Hi,

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.
Thanks,
Tom
0
 
LVL 39

Expert Comment

by:footech
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:
http://gallery.technet.microsoft.com/scriptcenter/1abd77a5-9c0b-4a2b-acef-90dbb2b84e85
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:schooltechnician
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.
0
 

Accepted Solution

by:
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.

#Prerequisites
#Share permissions: http://en-us.sysadmins.lv/Lists/Posts/Post.aspx?List=332991f0-bfed-4143-9eea-f521167d287c&ID=28
#Subinacl: http://www.microsoft.com/en-gb/download/details.aspx?id=23510
#Quest: http://www.quest.com/powershell/activeroles-server.aspx

#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 = $userdir.name
            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 "
                }
            Else
                {
                #get full path            
                Write-Host $userdir.name
                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
                $acl.SetAccessRule($accessRule)
                $acl.SetAccessRule($accessRule1)
                Set-Acl $currentDir $acl

                $acl3 = Get-Acl $currentDir
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule ("Everyone","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
                $acl3.RemoveAccessRuleAll($rule)
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($admin,"FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
                $acl3.AddAccessRule($rule)
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,"FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
                $acl3.AddAccessRule($rule)
				
				#Set Owner
                $domuser = "$domain\$username"
                $accnt = New-Object System.Security.Principal.NTAccount($domuser)
				$acl.SetOwner($accnt)
                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,
Thanks,
Tom
0
 

Author Closing Comment

by:schooltechnician
ID: 38879551
What I was looking for in basic
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

This article shows how a content item can be identified directly or through translation of a navigation type. It then shows how this information can be used to create a menu for further navigation.
Synchronize a new Active Directory domain with an existing Office 365 tenant
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

759 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

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now