Solved

powershell code needs amending

Posted on 2016-07-26
9
84 Views
Last Modified: 2016-07-27
Dear Experts,

I have this excellent code written by one you experts and did the job for me. However, I need to change it get inputs from .csv file for user names ( firstname.surname) and move their home drives from old server (server1) to new server ( server2, retaining the permissions on the home folders and finally change their home drive path in AD ( from server1 to server2.

Could you help me on this please? thanks
$oldRootServerPath = "\\localhost\share\"
$newRootServerPath = "\\localhost\share2\"
$errorLog = "C:\Users\Administrator\Desktop\error.txt"
$copyLog = "C:\Users\Administrator\Desktop\copy.txt"
$sourceOU = "OU=TestCompany,OU=Clients,OU=zUsers,DC=myDC,DC=local"

function WriteError($message)
{
    $stamp = Get-Date
    $error = $stamp.ToString() + " -- " + $message
    Add-Content -Path $errorLog -Value $error
}

function WriteCopy($message)
{
    $stamp = Get-Date
    $msg = $stamp.ToString() + " -- " + $message
    Add-Content -Path $copyLog -Value $msg
}


function CopyHomeDirectory($source)
{
    $newRoot = $source -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    if (!(Test-Path $newRoot)) 
    {
        New-Item -ItemType Directory $newRoot
        $acl = Get-Acl $source
        Set-Acl -Path $newRoot -AclObject $acl
    }
    $folders = Get-ChildItem $source -Recurse | ?{$_.PSIsContainer}
    foreach ($folder in $folders)
    {
        try {
        $oldFolder = $folder.FullName
        $acl = Get-Acl $oldFolder
        $newFolder = $oldFolder -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
        if (!(Test-Path $newFolder)) {
            New-Item -ItemType Directory $newFolder
            Set-Acl -Path $newFolder -AclObject $acl
            }
        }
        catch {
        $eMessage = "Could not copy folder " + $oldFolder
        WriteError($eMessage)
        $errors++
        }
    }

        $files = Get-ChildItem $source -Recurse | ?{!$_.PsIsContainer}
        foreach ($file in $files)
        {
            try {
            $oldFile = $file.FullName
            $acl = Get-Acl $oldFile
            $newFile = $oldFile -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
            Copy-Item $oldFile -Destination $newFile
            Set-Acl -Path $newFile -AclObject $acl
            }
            catch {
            $eMessage = "Could not copy file " + $oldFile
            WriteError($eMessage)
            $errors++
            }
        }


}

$users = Get-ADUser -Filter * -SearchBase $sourceOU -Properties homeDirectory | ?{$_.homeDirectory} | select  sAMAccountName,homeDirectory

foreach ($user in $users)
{
    $errors = 0
    $path = $user.homeDirectory.ToString()
    CopyHomeDirectory($path)
    $copyMsg = "Copy completed for " + $path + " -- " + $errors + " errors occurred."
    WriteCopy($copyMsg)
    $newPath = $path -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    Set-AdUser -Identity $user.sAMAccountName -HomeDrive "H:" -HomeDirectory $newPath
}

Open in new window

0
Comment
Question by:kuzum
[X]
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
  • 2
9 Comments
 
LVL 70

Expert Comment

by:Qlemo
ID: 41729301
What's the exact structure of the CSV file? Can you show a short mock-up example?
Am I correct that you want to change the script from searching in a specific OU to using specific names coming from the CSV?
0
 
LVL 70

Expert Comment

by:Qlemo
ID: 41729317
Assuming you have a CSV file like
FirstName,SurName
Charles,Bronson
River,Phoenix

Open in new window

replace line 5 with the complete path to it:
$userfile = 'C:\Users\Administrator\Desktop\Users.CSV'

Open in new window

and line 70 with
$users = Import-CSV $userfile | % { Get-ADUser -Filter {GivenName -eq $_.FirstName -and SurName -eq $_.SurName} -Properties homeDirectory | ?{$_.homeDirectory} | select  sAMAccountName,homeDirectory

Open in new window

0
 

Author Comment

by:kuzum
ID: 41729373
Qlemo,

thanks for your response.  Yes, you are right. instead of searching for a OU, it should read through the csv file and copy the home folders to new server, Of course with permissions and change the home folder path in AD for those users. ,  ( I do not want home folders to be deleted in old location)

csv file sample is attached.
Doc3.docx
0
The Orion Papers

Are you interested in becoming an AWS Certified Solutions Architect?

Discover a new interactive way of training for the exam.

 

Author Comment

by:kuzum
ID: 41729374
basically, csv file will be Firstname.surname
0
 
LVL 13

Accepted Solution

by:
Dustin Saunders earned 500 total points
ID: 41729465
These changes will perform the search:

@line5
$userfile = 'C:\Users\Administrator\Desktop\name.CSV'

Open in new window


@line70
$users = Import-CSV $userfile | % {Get-ADUser -Filter "sAMAccountName -eq '$($_.SamAccountName)'" -Properties homeDirectory | ?{$_.homeDirectory} | select  sAMAccountName,homeDirectory }

Open in new window


The whole thing:
$oldRootServerPath = "\\localhost\share\"
$newRootServerPath = "\\localhost\share2\"
$errorLog = "C:\Users\Administrator\Desktop\error.txt"
$copyLog = "C:\Users\Administrator\Desktop\copy.txt"
$userfile = 'C:\Users\Administrator\Desktop\name.CSV'

function WriteError($message)
{
    $stamp = Get-Date
    $error = $stamp.ToString() + " -- " + $message
    Add-Content -Path $errorLog -Value $error
}

function WriteCopy($message)
{
    $stamp = Get-Date
    $msg = $stamp.ToString() + " -- " + $message
    Add-Content -Path $copyLog -Value $msg
}


function CopyHomeDirectory($source)
{
    $newRoot = $source -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    if (!(Test-Path $newRoot)) 
    {
        New-Item -ItemType Directory $newRoot
        $acl = Get-Acl $source
        Set-Acl -Path $newRoot -AclObject $acl
    }
    $folders = Get-ChildItem $source -Recurse | ?{$_.PSIsContainer}
    foreach ($folder in $folders)
    {
        try {
        $oldFolder = $folder.FullName
        $acl = Get-Acl $oldFolder
        $newFolder = $oldFolder -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
        if (!(Test-Path $newFolder)) {
            New-Item -ItemType Directory $newFolder
            Set-Acl -Path $newFolder -AclObject $acl
            }
        }
        catch {
        $eMessage = "Could not copy folder " + $oldFolder
        WriteError($eMessage)
        $errors++
        }
    }

        $files = Get-ChildItem $source -Recurse | ?{!$_.PsIsContainer}
        foreach ($file in $files)
        {
            try {
            $oldFile = $file.FullName
            $acl = Get-Acl $oldFile
            $newFile = $oldFile -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
            Copy-Item $oldFile -Destination $newFile
            Set-Acl -Path $newFile -AclObject $acl
            }
            catch {
            $eMessage = "Could not copy file " + $oldFile
            WriteError($eMessage)
            $errors++
            }
        }


}

$users = Import-CSV $userfile | % {Get-ADUser -Filter "sAMAccountName -eq '$($_.SamAccountName)'" -Properties homeDirectory | ?{$_.homeDirectory} | select  sAMAccountName,homeDirectory }

foreach ($user in $users)
{
    $errors = 0
    $path = $user.homeDirectory.ToString()
    CopyHomeDirectory($path)
    $copyMsg = "Copy completed for " + $path + " -- " + $errors + " errors occurred."
    WriteCopy($copyMsg)
    $newPath = $path -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    Set-AdUser -Identity $user.sAMAccountName -HomeDrive "H:" -HomeDirectory $newPath
}

Open in new window


Be sure to take that top line out of your CSV (#TYPE Selected.Microsoft.ActiveDirectory.Management.ADUsers)
0
 

Author Comment

by:kuzum
ID: 41729525
Hi Dustin,

is it also possible to add what-if in the end and run it first please?
0
 
LVL 13

Expert Comment

by:Dustin Saunders
ID: 41729536
This should be in 'test mode'.  There are 3 whatif(s)
$oldRootServerPath = "\\localhost\share\"
$newRootServerPath = "\\localhost\share2\"
$errorLog = "C:\Users\Administrator\Desktop\error.txt"
$copyLog = "C:\Users\Administrator\Desktop\copy.txt"
$userfile = 'C:\Users\Administrator\Desktop\name.CSV'

function WriteError($message)
{
    $stamp = Get-Date
    $error = $stamp.ToString() + " -- " + $message
    Add-Content -Path $errorLog -Value $error
}

function WriteCopy($message)
{
    $stamp = Get-Date
    $msg = $stamp.ToString() + " -- " + $message
    Add-Content -Path $copyLog -Value $msg
}


function CopyHomeDirectory($source)
{
    $newRoot = $source -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    if (!(Test-Path $newRoot)) 
    {
        New-Item -ItemType Directory $newRoot
        $acl = Get-Acl $source
        Set-Acl -Path $newRoot -AclObject $acl
    }
    $folders = Get-ChildItem $source -Recurse | ?{$_.PSIsContainer}
    foreach ($folder in $folders)
    {
        try {
        $oldFolder = $folder.FullName
        $acl = Get-Acl $oldFolder
        $newFolder = $oldFolder -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
        if (!(Test-Path $newFolder)) {
            New-Item -ItemType Directory $newFolder 
            Set-Acl -Path $newFolder -AclObject $acl
            }
        }
        catch {
        $eMessage = "Could not copy folder " + $oldFolder
        WriteError($eMessage)
        $errors++
        }
    }

        $files = Get-ChildItem $source -Recurse | ?{!$_.PsIsContainer}
        foreach ($file in $files)
        {
            try {
            $oldFile = $file.FullName
            $acl = Get-Acl $oldFile
            $newFile = $oldFile -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
            Copy-Item $oldFile -Destination $newFile -whatif
            Set-Acl -Path $newFile -AclObject $acl -whatif
            }
            catch {
            $eMessage = "Could not copy file " + $oldFile
            WriteError($eMessage)
            $errors++
            }
        }


}

$users = Import-CSV $userfile | % {Get-ADUser -Filter "sAMAccountName -eq '$($_.SamAccountName)'" -Properties homeDirectory | ?{$_.homeDirectory} | select  sAMAccountName,homeDirectory }

foreach ($user in $users)
{
    $errors = 0
    $path = $user.homeDirectory.ToString()
    CopyHomeDirectory($path)
    $copyMsg = "Copy completed for " + $path + " -- " + $errors + " errors occurred."
    WriteCopy($copyMsg)
    $newPath = $path -replace [regex]::Escape($oldRootServerPath),$newRootServerPath
    Set-AdUser -Identity $user.sAMAccountName -HomeDrive "H:" -HomeDirectory $newPath -whatif
}

Open in new window


@line80
Set-AdUser -Identity $user.sAMAccountName -HomeDrive "H:" -HomeDirectory $newPath -whatif

Open in new window


@line57-58
Copy-Item $oldFile -Destination $newFile -whatif
            Set-Acl -Path $newFile -AclObject $acl -whatif

Open in new window


Test mode will create directories but simulate the file copy (@line-57-58 restricts this) so you don't have to wait for the copy to finish to confirm results.  Remove these 3 or run the previous code when ready to migrate.
0
 

Author Closing Comment

by:kuzum
ID: 41731166
excellent work
0

Featured Post

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

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

A company’s centralized system that manages user data, security, and distributed resources is often a focus of criminal attention. Active Directory (AD) is no exception. In truth, it’s even more likely to be targeted due to the number of companies …
I was prompted to write this article after the recent World-Wide Ransomware outbreak. For years now, System Administrators around the world have used the excuse of "Waiting a Bit" before applying Security Patch Updates. This type of reasoning to me …
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

729 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