Overblog
Editer l'article Suivre ce blog Administration + Créer mon blog

Migration multiples AD

Publié le par damcuvelier

How to migrate multiple AD when you can not upgrade? That is when there is a mounted of several versions (for example: 2008 to 2016).
Here is my approach to the subject:

1. Create new ADs (in mixed mode (**)) in the same subnet as the old ADs
2. Create a trust relationship between each pair [old AD - new AD]
3. Capture old AD users + old AD objects (script Powershell ADCapture.ps1)
4. Create old AD users + objects on new AD (script Powershell ADCreate.ps1)
5. Link new AD users on old AD DFS (script Powershell oldDSFjonction.ps1)
5bis. The new desktops will automatically be attached to the new AD and the non-migrated desktops will remain on old AD (*)
6. Copy full of old DFS on new DFS (script Powershell copyDFS.ps1)
7. Once all the desktops have been migrated:
7.1. A Saturday: DFS Migration Operation: Copy of the Old DFS Delta on New DFS (*) (script Powershell DeltaDFS.ps1)
7.2. Link new AD users on new DFS (script Powershell LinkNewDFS.ps1)
8. Bind desktops + new AD users with new AD objects (script Powershell LinkNewObjects.ps1)
9. Close the relationship of approval of the pair [old AD - new AD]
10. MCO: Keep old AD time to be sure everything is running on new AD and save it then delete it after 3 months.

(*): Provides continuity of service for old and new positions during the transitional period
(**): Allows you to install servers in a lower version (lower license cost)

So 10 scripts:
ADCapture.ps1 (from a Windows 10 Station)
ADCreate.ps1
oldDSFjonction.ps1
CreateAndCopyDFS.ps1
DeltaDFS.ps1
LinkNewDFS.ps1
LinkNewObjects.ps1
Install-AD.ps1
BackUp_GPOs.ps1 (https://gallery.technet.microsoft.com/scriptcenter/Comprehensive-Group-Policy-5f9d3ea6/file/100083/10/BackUp_GPOs.ps1)
Import_GPOs.ps1 https://gallery.technet.microsoft.com/scriptcenter/Comprehensive-Group-Policy-212562cb/file/100084/7/Import_GPOs.ps1

 

Install-AD.ps1:

# Install Group Policy Module
Function Install-ADModule {
    [CmdletBinding()]
    Param(
        [switch]$Test = $false
    )

    If ((Get-CimInstance Win32_OperatingSystem).Caption -like "*Windows 10*") {
        Write-Verbose '---This system is running Windows 10'
    } Else {
        Write-Warning '---This system is not running Windows 10'
        break
    }

    If (Get-HotFix -Id KB2693643 -ErrorAction SilentlyContinue) {

        Write-Verbose '---RSAT for Windows 10 is already installed'

    } Else {

        Write-Verbose '---Downloading RSAT for Windows 10'

        If ((Get-CimInstance Win32_ComputerSystem).SystemType -like "x64*") {
            $dl = 'WindowsTH-KB2693643-x64.msu'
        } Else {
            $dl = 'WindowsTH-KB2693643-x86.msu'
        }
        Write-Verbose "---Hotfix file is $dl"

        Write-Verbose "---$(Get-Date)"
        #Download file sample
        #https://gallery.technet.microsoft.com/scriptcenter/files-from-websites-4a181ff3
        $BaseURL = 'https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/'
        $URL = $BaseURL + $dl
        $Destination = Join-Path -Path $HOME -ChildPath "Downloads\$dl"
        $WebClient = New-Object System.Net.WebClient
        $WebClient.DownloadFile($URL,$Destination)
        $WebClient.Dispose()

        Write-Verbose '---Installing RSAT for Windows 10'
        Write-Verbose "---$(Get-Date)"
        # http://stackoverflow.com/questions/21112244/apply-service-packs-msu-file-update-using-powershell-scripts-on-local-server
        wusa.exe $Destination /quiet /norestart /log:$home\Documents\RSAT.log

        # wusa.exe returns immediately. Loop until install complete.
        do {
            Write-Host "." -NoNewline
            Start-Sleep -Seconds 3
        } until (Get-HotFix -Id KB2693643 -ErrorAction SilentlyContinue)
        Write-Host "."
        Write-Verbose "---$(Get-Date)"
    }

    # The latest versions of the RSAT automatically enable all RSAT features
    If ((Get-WindowsOptionalFeature -Online -FeatureName `
        RSATClient-Roles-AD-Powershell -ErrorAction SilentlyContinue).State `
        -eq 'Enabled') {

        Write-Verbose '---RSAT AD PowerShell already enabled'

    } Else {

        Write-Verbose '---Enabling RSAT AD PowerShell'
        Enable-WindowsOptionalFeature -Online -FeatureName RSATClient-Roles-AD-Powershell

    }

    Write-Verbose '---Downloading help for AD PowerShell'
    Update-Help -Module ActiveDirectory -Verbose -Force

    Write-Verbose '---ActiveDirectory PowerShell module install complete.'

    # Verify
    If ($Test) {
        Write-Verbose '---Validating AD PowerShell install'
        dir (Join-Path -Path $HOME -ChildPath Downloads\*msu)
        Get-HotFix -Id KB2693643
        Get-Help Get-ADDomain
        Get-ADDomain
    }
}

Install-ADModule -Verbose

ADCapture.ps1:

param {Dom}
# Prerequire: have installed Powershell Group Policy Module (Install-AD.ps1)

# Get GPOs Extract
.\BackUp_GPOs.ps1 -Domain $Dom -BackupFolder "c:\GPObackups" -MigTable


# Get Users list
$OUList = @(Get-ADOrganizationalUnit -Filter *)
$Users = Foreach($OU in $OUList){Get-ADUser -Filter * -SearchBase $OU | Select-Object SamAccountName}
$Users | Export-CSV -Path "C:\Users.csv" -NoTypeInformation

#Get the permission level for Users on the GPOs
$CustomGpoXML = Import-Clixml -Path "c:\GPObackups\GpoDetails.xml"
    foreach ($CustomGPO in $CustomGpoXML) {
        ForEach($User in $Users){
        $UsrPermission += Get-GPPermission -Name $CustomGPO.Name -TargetName $User -TargetType User
        }
    $UsrPermission | Export-CSV –append -Path "C:\UsersGPOAcl.csv"
}

# Get Groups List
$GRPList = @(get-adgroup -filter *)
$NewCSVObject = @()
$GRPs = Foreach($GRP in $GRPList)
{
    $AdGrpMbr = @(Get-AdGroupMember -identity $GRP | Select-Object SamAccountName)
    if($Users -contains $AdGrpMbr){$NewCSVObject += $GRP | Select-Object SamAccountName}
    $NewCSVObject | Export-CSV -Path "C:\GRPs.csv" -NoTypeInformation
    
    #Get Group ACLs
    Get-Acl -Path "AD:\CN=$GRP\#U,$GRP.cn" | Select-Object -ExpandProperty access | Export-CSV -Path "C:\GRPAcl.csv"
    
    #Get the permission level for Groups on the GPOs
    $CustomGpoXML = Import-Clixml -Path "c:\GPObackups\GpoDetails.xml"
    foreach ($CustomGPO in $CustomGpoXML) {$GPPermission += Get-GPPermission -Name $CustomGPO.Name -TargetName $GRP -TargetType Group}
    $GPPermission | Export-CSV –append -Path "C:\GRPGPOAcl.csv"
}

# Get OU List
Foreach($OU in $OUList){
$UsersOU = Get-ADUser -Filter * -SearchBase $OU | Select-Object SamAccountName
ForEach($UserOU in $UsersOU){
$UserOUList = @()
$UserOUList += $UserOU
}
"$UserOUList ::: $OU" | Export-CSV -Path "c:\OUs.csv" -NoTypeInformation

    #Get OU ACLs
    Get-Acl -Path "AD:\$OU" | Export-CSV -Path "c:\OUAcl.csv"
}


# Get Group Members List
$GRPList = @(get-adgroup -filter *)
$GRPs = Foreach($GRP in $GRPList){
    $AdGrpMbr = @(Get-AdGroupMember -identity $GRP | Select-Object SamAccountName)
    "$GRP ::: $AdGrpMbr"  | Export-CSV -Path "c:\GrpMbrs.csv" -NoTypeInformation
}

To Capture AD settings and users and groups

 --> Run Install-AD.ps1 and then run ADCapture.ps1 <--

# Example Command run script: .\ADCreate.ps1 -Domain <Your new AD domain Netbios Name> -CSVUsers "C:\Users.csv" -CSVGRPs "C:\GRPs.csv" -CSVGrpMbrs "C:\GrpMbrs.csv" -CSVOUs "C:\OUs.csv" -CSVGRPGPOAcl "C:\GRPGPOAcl.csv" -CSVGRPAcl "C:\GRPAcl.csv" -CSVOUAcl "C:\OUAcl.csv" -CSVUsersGPOAcl "C:\UsersGPOAcl.csv"


#Get New AD informations
param {$Domain,$CSVUsers,$CSVGRPs,$CSVGrpMbrs,$CSVOUs,$CSVGRPGPOAcl,$CSVGRPAcl,$CSVOUAcl,$CSVUsersGPOAcl}

# Import active directory module for running AD cmdlets
Import-Module activedirectory

##########################
# Import Users to new AD #
##########################

#Store the data from ADUsers.csv in the $ADUsers variable
$ADUsers = Import-csv $CSVUsers

#Loop through each row containing user details in the CSV file
foreach ($User in $ADUsers)
{
    #Read user data from each field in each row and assign the data to a variable as below
        
    $Username     = $User.username
    $Password     = $User.password
    $Firstname     = $User.firstname
    $Lastname     = $User.lastname
    $OU         = $User.ou #This field refers to the OU the user account is to be created in
    $email      = $User.email
    $streetaddress = $User.streetaddress
    $city       = $User.city
    $zipcode    = $User.zipcode
    $state      = $User.state
    $country    = $User.country
    $telephone  = $User.telephone
    $jobtitle   = $User.jobtitle
    $company    = $User.company
    $department = $User.department
    $Password = $User.Password


    #Check to see if the user already exists in AD
    if (Get-ADUser -F {SamAccountName -eq $Username})
    {
         #If user does exist, give a warning
         Write-Warning "A user account with username $Username already exist in Active Directory."
    }
    else
    {
        #User does not exist then proceed to create the new user account
        
        #Account will be created in the OU provided by the $OU variable read from the CSV file
        New-ADUser `
            -SamAccountName $Username `
            -UserPrincipalName "$Username@$Domain" `
            -Name "$Firstname $Lastname" `
            -GivenName $Firstname `
            -Surname $Lastname `
            -Enabled $True `
            -DisplayName "$Lastname, $Firstname" `
            -Path $OU `
            -City $city `
            -Company $company `
            -State $state `
            -StreetAddress $streetaddress `
            -OfficePhone $telephone `
            -EmailAddress $email `
            -Title $jobtitle `
            -Department $department `
            -AccountPassword (convertto-securestring $Password -AsPlainText -Force) -ChangePasswordAtLogon $True
            
    }
}


###########################
# Import Groups to new AD #
###########################

#Import CSV
$GRPs = Import-Csv -Path $CSVGRPs
 
#Get Domain Base
$searchbase = Get-ADDomain | ForEach {  $_.DistinguishedName }
 
#Loop through all items in the CSV
ForEach ($item In $GRPs)
{
  #Check if the OU exists
  $check = [ADSI]::Exists("LDAP://$($item.GroupLocation),$($searchbase)")
   
  If ($check -eq $True)
  {
    Try
    {
      #Check if the Group already exists
      $exists = Get-ADGroup $item.GroupName
      Write-Host "Group $($item.GroupName) alread exists! Group creation skipped!"
    }
    Catch
    {
      #Create the group if it doesn't exist
      $create = New-ADGroup -Name $item.GroupName -GroupScope $item.GroupType -Path ($($item.GroupLocation)+","+$($searchbase))
      Write-Host "Group $($item.GroupName) created!"
    }
  }
  Else
  {
    Write-Host "Target OU can't be found! Group creation skipped!"
  }
}


####################################
# Import Users to Groups in new AD #
####################################

$GrpMbrscsv = Import-Csv -Path C:\GrpMbrs.csv
foreach($line in $GrpMbrscsv)
{

$AdGrpMbr = split(line," ::: ")[1]
$GRP =  split(line," ::: ")[0]

$User = Get-ADUser -Identity $AdGrpMbr
$Group = Get-ADGroup -Identity $GRP
Add-ADGroupMember -Identity $Group -Members $User
}


################################
# Import Users to OU in new AD #
################################

$OUscsv = Import-Csv -Path C:\OUs.csv
foreach($line in $OUscsv)
{
$OUGet = split(line," ::: ")[1]
$UserOUList =  split(line," ::: ")[0]
    ForEach($UserOU in $UserOUList)
    {
    $User = Get-ADUser -Identity $UserOU
    $OU = Get-ADGroup -Identity $OUGet
    Add-ADGroupMember -Identity $OU -Members $User
    }
}

###############################
# Import GPOs in new AD #
###############################
.\Import_GPOs.ps1 -Domain $Dom -BackupFOlder "c:\GPObackups" -MigTable -SomInfo


###############################
# Import Group ACLs in new AD #
###############################

$GRPAcl = Import-Csv -Path $CSVGRPAcl
ForEach($line in $GRPAcl)
{
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($line.AccessToString.split(" Allow  ")[0],$line.AccessToString.split(" Allow  ")[1],"Allow")
$acl.SetAccessRule($AccessRule)
$acl | Set-Acl $line.path
}


############################
# Import OU ACLs in new AD #
############################

$OUAcl = Import-Csv -Path $CSVOUAcl
ForEach($line in $OUAcl)
{
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($line.AccessToString.split(" Allow  ")[0],$line.AccessToString.split(" Allow  ")[1],"Allow")
$acl.SetAccessRule($AccessRule)
$acl | Set-Acl $line.path
}


##############################################
# Import Groups Permissions to GPO in new AD #
##############################################
$UsersGPOAcl = Import-Csv -path $CSVUsersGPOAcl
$CustomGpoXML = Import-Clixml -Path "c:\GPObackups\GpoDetails.xml"
Foreach ($CustomGPO in $CustomGpoXML) {ForEach($User in $GRPs){ForEach($UserGPOAcl in $UsersGPOAcl){Set-GPPermission -Name $CustomGPO.Name -TargetName $User -TargetType User -PermissionLevel $UserGPOAcl}}}


#############################################
# Import Users Permissions to GPO in new AD #
#############################################

$GRPsGPOAcl = Import-Csv -path $CSVGRPGPOAcl
$CustomGpoXML = Import-Clixml -Path "c:\GPObackups\GpoDetails.xml"
Foreach ($CustomGPO in $CustomGpoXML) {ForEach($GRP in $GRPs){ForEach($GRPGPOAcl in $GRPsGPOAcl){Set-GPPermission -Name $CustomGPO.Name -TargetName $GRP -TargetType User -PermissionLevel $GRPGPOAcl}}}

 

CreateAndCopyDFS.ps1:

# Command: .\CreateAndCopyDFS.ps1 -Dom <your old Domain name> -NewDom <your new Domain name>

param ($Dom,$NewDom)
$DfsNamespaces = (Get-DfsnRoot -Domain $Dom).Where( {$_.State -eq 'Online'} ) | Select-Object -ExpandProperty Path

Foreach ($DfsNamespace in $DfsNamespaces)
{
$DfsPath = DfsNamespace.path
$NewDfsPath = $NewDom+$DfsPath.split ($Domain)[1]
#Create $NewDfsPath

$NewDFSFolder = @{
    Path = "$NewDfsPath"
    State = 'Online'
    TargetPath = $NewDfsPath
    TargetState = 'Online'
    ReferralPriorityClass = 'globalhigh'
}

New-DfsnFolder @NewDFSFolder

#Copy old Dfs to new Dfs
Robocopy /MIR $DfsPath $NewDfsPath
}

 

 

Enjoy

Commenter cet article