Last active
January 13, 2017 18:06
-
-
Save danjpadgett/3a584969b067ff29080bf58a0d02827e to your computer and use it in GitHub Desktop.
Copies userdata between two file servers, resets ACL and Owner to user account.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.NOTES | |
=========================================================================== | |
Created on: 11/01/2017 11:59 | |
Created by: Dan Padgett (C) | |
Filename: UserMigration.ps1 | |
Version: 1.0 | |
Web: www.execmgr.net | |
=========================================================================== | |
.SYNOPSIS | |
Copies userdata between two file servers, resets ACL and Owner to user account. | |
.NOTES | |
This script was built for the purpose of copying data from previously redirected user profiles (that were used for folder redirection), | |
these directories has broken ACL's and admins could not read special folders. Users migrated would be using WorkFolders. | |
Previously edirected folders like Desktop, Documents and Favorites. This script was initially built using robocopy, however without even READ access to the directories | |
i had to switch to Dell Secure Copy (much faster than robocopy), which enables folder copies even without read access. Once the files are copied it will be repermissioned | |
to give the AD user specified Modify access, then that user will be set as the Owner for all files and folders. | |
Modify the following variables. | |
$workfolder = "\\serverdestination\users" | |
If you run this script on a server with Dell Secure Copy, you can utilise that instead of robocopy. | |
This setting is controlled by: | |
$useRobocopy = $false | |
If you plan on renaming files or folders after copy use this switch and add files/folders to the rename region. | |
$renamefolders = $true | |
REQUIREMENTS: | |
PSCX Module - http://pscx.codeplex.com/ | |
Dell Secure Copy (if used) - https://www.quest.com/products/secure-copy/ | |
.DISCLAIMER | |
All scripts are provided AS IS without warranty of any kind. The author further disclaims all implied warranties including, without limitation, | |
any implied warranties of merchantability or of fitness for a particular purpose. | |
The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. | |
In no event shall the author,or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever | |
including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss | |
arising out of the use of or inability to use the sample scripts or documentation, even if the author has been advised of the possibility of such damages. | |
#> | |
#region InstallModule | |
#// Begin script by importing PSCX Module, required for setting ownership | |
#// Script will exit if module is not found | |
if ((Get-Module).name -Match "PSCX") | |
{} #Null | |
else | |
{ | |
try { | |
Write-Host "Importing PSCX Module..please wait" -ForegroundColor Green | |
Import-Module "PSCX" | |
} | |
catch | |
{ | |
Write-Host "Module PSCX not found, Module is required from http://pscx.codeplex.com/ , script aborting" -ForegroundColor Red | |
} | |
} # Module is required from http://pscx.codeplex.com/ | |
#endregion | |
#SetScriptValues | |
$useRobocopy = $false | |
#//Set value to use robocopy | |
$renamefolders = $true | |
#//Set value to rename folders within #region FileNames | |
$rootpath = (Read-Host "Enter rootpath to source") | |
#//Prompts user to enter rootpath, script checks this path after appending SamAccountName | |
$username = (Read-Host "Enter Username") | |
#//Prompts user to username, checks against AD | |
try { | |
(Get-ADUser $username | select-object -expandproperty samAccountName) | |
} | |
catch | |
{ | |
throw "(The User has not been found in AD...exiting)" | |
} | |
$destination = "\\serverdestination\users" | |
#// Uncomment below block to prompt user for destination path | |
<#$destination = (Read-Host "Enter Destination root path") | |
if (!(test-path $destination)) | |
{ | |
Write-Host "Destination is not valid, you entered '$destination' - script will exit, try again" | |
pause | |
exit | |
} | |
else { | |
#continue | |
} | |
#> | |
$path = $rootpath+$username | |
#// Appends username to root path | |
$destination = "$destination\$username" | |
#// Appends username to destination path | |
$source = $path | |
#// Assigns $path to $source for readability later | |
if (!(test-path $source)) | |
#//checks if $source is valid, otherwise exits | |
{ | |
Write-Host "Source is not valid, you entered '$source' - script will exit, try again" | |
pause | |
exit | |
} | |
else { | |
#continue | |
} | |
$choice = "" | |
#resets choice | |
while ($choice -notmatch "[y|n]"){ | |
$choice = read-host "Do you want to continue migrating data from $source to $destination (Y/N)" | |
} | |
#// Sanity check to ensure $source and $destination are as intended | |
if ($choice -eq "y") | |
{ | |
#region SetACLVars | |
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 | |
$blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity | |
$blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators') | |
#//Created an ACL template of setting the built in admin account as owner. | |
#endregion | |
if ($useRobocopy -eq $true) | |
#//Will process if $robocopy was set to true at beginning. | |
{ | |
#region RoboCopy | |
Write-Host "Starting file copy from '$source' to Destination" -ForegroundColor Yellow | |
$date = Get-Date -UFormat %d-%m-%y | |
$logfile = "$destination\Log\$date-$username.txt" | |
if (!(test-path $logfile)) { New-Item $logfile -ItemType file } | |
$RobocopyParams = @("/IS", "/MIR", "/r:1", "/w:1", "/COPY:DAT", "/NJS", "/E") | |
$XD = @("WINDOWS", "APPDATA", "SendTo", "Temp", "Temporary Internet Files", "`$RECYCLE.BIN") | |
$XF = @("*.pif", "*.EXE", "*.ini", "*.bat", "*.tmp", "thumbs.db") | |
& C:\cmtrace.exe $logfile | |
robocopy.exe $source $destination $RobocopyParams /XD @XD /XF @XF /log+:$logfile | |
Write-Host "Copy Complete to Destination, adjusting permissions" -ForegroundColor Yellow | |
#endregion | |
} | |
else | |
{ | |
#region DellSecureCopy | |
#// Will process copy with Dell Secure Copy | |
if (Test-Path "C:\Program Files\Dell\Secure Copy 7") | |
{ | |
Set-Location "C:\Program Files\Dell\Secure Copy 7" | |
# Switches /DB = Job Database, /Name = Job Name | |
# see http://documents.software.dell.com/secure-copy/7.0/user-guide/using-the-command-line/using-securecopycmd-exe | |
$argsu = "/DB=SecureCopy.ssd /Name=JOBNAME /Source=$source /Target=$destination /CopySubFolders=True" | |
Start-Process SecureCopyCmd.exe $argsu | |
Write-Host "Running batch job externally with Dell Secure Copy! `nCopying Data from $source to $destination! " -ForegroundColor Yellow | |
Write-Host "When Secure Copy shows complete, close Secure Copy window to continue..(waiting for process to close)... " -ForegroundColor Green | |
wait-process -Name SecureCopyCmd | |
#//Waits for user to close Security Copy window, window can be supressed with /quiet switch in $argsu | |
Write-Host "Batch job completed..moving to permissions" -ForegroundColor Green | |
Set-Location "C:\" | |
} | |
else | |
{ | |
Write-Error "Dell Secure Copy Not found!" | |
} | |
#endregion | |
} | |
#region Set-Acl | |
$paths = (Get-Item -Path $destination ) | |
#//Gathers top level folders of $destination | |
##Blank Out ACL Info On path and reset | |
(Get-Item $paths.FullName).SetAccessControl($blankdirAcl) | |
#Lookup Current Path and Extract username ($samccountname) | |
try { | |
$sAMAccountName = (Get-ADUser $username | select-object -expandproperty samAccountName) | |
write-host $_.Directory | |
} catch { | |
Write-Warning "($_. - The User has not been found in AD)" | |
return | |
} | |
$FileSystemAccessRights = [System.Security.AccessControl.FileSystemRights]"Modify" | |
$InheritanceFlags = [System.Security.AccessControl.InheritanceFlags]::"ContainerInherit", "ObjectInherit" | |
$PropagationFlags = [System.Security.AccessControl.PropagationFlags]::None | |
$AccessControl =[System.Security.AccessControl.AccessControlType]::Allow | |
$NewAccessrule = New-Object System.Security.AccessControl.FileSystemAccessRule ` ($sAMAccountName, $FileSystemAccessRights, $InheritanceFlags, $PropagationFlags, $AccessControl) | |
$currentACL = Get-Acl -path $paths | |
$currentACL.SetAccessRule($NewAccessrule) | |
#// Builds new ACL based off domain user | |
Write-Host "Managing Permissions for $sAMAccountName - in folder path '$paths'.....please wait.." -ForegroundColor Yellow | |
Set-Acl -path $paths -AclObject $currentACL | |
#Set Owner back to SamAccountUser | |
$RepairedACL = New-Object System.Security.AccessControl.DirectorySecurity | |
#set owner for folder root | |
$RepairedACL.SetOwner([System.Security.Principal.NTAccount]$sAMAccountName) | |
(Get-Item $paths.FullName).SetAccessControl($RepairedACL) | |
#endregion | |
#region FileNames | |
if ($renamefolders -eq $true) | |
#//Will rename and folders or files specified, follow below example | |
{ | |
if (Test-Path $destination\Desktop) | |
{Rename-Item -path "$destination\Desktop" -newName ‘Archived Desktop’} | |
} | |
#endregion | |
#region Reset Owner | |
$SubDirectories = (Get-ChildItem $destination) | |
$ntAccount = New-Object System.Security.Principal.NTAccount("$sAMAccountName") | |
Foreach ($FolderName in $SubDirectories) { | |
#Set Parent Folder Ownership | |
Get-Item -LiteralPath "$destination\$FolderName" -ErrorAction SilentlyContinue | Get-Acl | | |
ForEach-Object { | |
$_.SetOwner($ntAccount) | |
Set-Acl -aclobject $_ -Path $_.PSPath | |
$Path = Split-Path $_.Path -NoQualifier | |
Write-Host $Path "Folder Owner Set -" $ntAccount | |
} | |
#Set Child Item Ownership | |
Get-ChildItem -LiteralPath "$destination\$FolderName" -Recurse –ErrorAction SilentlyContinue | Get-Acl | | |
ForEach-Object { | |
$_.SetOwner($ntAccount) | |
Set-Acl -aclobject $_ -Path $_.PSPath | |
$Path = Split-Path $_.Path -NoQualifier | |
Write-Host "File Owner Set to -" $ntAccount "in $Path" | |
} | |
} | |
#// Region above resets owner on all files to domain user specified at beginning of script | |
#endregion | |
Write-Host "Completed migration for '$sAMAccountName' - in folder path '$destination'" -ForegroundColor Yellow | |
} | |
else | |
{write-host "Script Exiting"} | |
#// Processed if user selects NO to proceeding with copy. | |
#End of script. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment