Solved

powershell code needs amending

Posted on 2016-07-26
9
87 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
NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.

 

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

Problems using Powershell and Active Directory?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

Question has a verified solution.

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

This article provides a convenient collection of links to Microsoft provided Security Patches for operating systems that have reached their End of Life support cycle. Included operating systems covered by this article are Windows XP,  Windows Server…
Let's recap what we learned from yesterday's Skyport Systems webinar.
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)
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…

630 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