How to create your Active Directory Lab with Powershell. We are working with the latest Windows Server 2019 version aka 1809, We use Standard version with GUI, but you can run all this step in a Windows Server Core this is more secure to my mind, but you need have a remote Windows 10 with RSAT.

In my Lab I use free API https://randomuser.me/ for create random user in my Active Directory.

1. Configure Windows Server 2019

1.1 Networking

How to configure networking with powershell.

#Find the Interface Index for your NIC with the name Ethernet
$InterfaceIndex = $(Get-NetIPAddress | Where-Object {$_.InterfaceAlias -like "Ethernet*"}).InterfaceIndex

#Assign Address IPv4
New-NetIPAddress -InterfaceIndex $InterfaceIndex -AddressFamily IPv4 -IPAddress “172.17.0.1” –PrefixLength 16 -DefaultGateway 172.17.255.254

#Assign Server DNS
Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex  -ServerAddresses 172.17.0.1

1.2 ComputerName

Rename-Computer -NewName DC -Restart 

1.3 Install WindowsFeature

  • The first step is to install Ad-Domain-Services.
Get-WindowsFeature -Name *AD-Domain*
  • Install the Feature with all subfeatures
Install-WindowsFeature -Name AD-Domain-services -IncludeAllSubFeature -IncludeManagementTools
  • Verify all the Feature installed
Get-WindowsFeature | Where-Object {$_. installstate -eq "installed"} | Format-List Name,Installstate | more

The Output :

Name         : AD-Domain-Services
InstallState : Installed

Name         : FileAndStorage-Services
InstallState : Installed

Name         : File-Services
InstallState : Installed

Name         : FS-FileServer
InstallState : Installed

Name         : Storage-Services
InstallState : Installed

Name         : NET-Framework-45-Features
InstallState : Installed

Name         : NET-Framework-45-Core
InstallState : Installed

Name         : NET-WCF-Services45
InstallState : Installed

Name         : NET-WCF-TCP-PortSharing45
InstallState : Installed

Name         : GPMC
InstallState : Installed

Name         : RSAT
InstallState : Installed

Name         : RSAT-Role-Tools
InstallState : Installed

Name         : RSAT-AD-Tools
InstallState : Installed

Name         : RSAT-AD-PowerShell
InstallState : Installed

Name         : RSAT-ADDS
InstallState : Installed

Name         : RSAT-AD-AdminCenter
InstallState : Installed

Name         : RSAT-ADDS-Tools
InstallState : Installed

Name         : WoW64-Support
InstallState : Installed

Name         : Windows-Defender
InstallState : Installed

Name         : PowerShellRoot
InstallState : Installed

Name         : PowerShell
InstallState : Installed

Name         : PowerShell-ISE
InstallState : Installed

Name         : XPS-Viewer
InstallState : Installed

2. Create Active Directory Forest

For Create Forest you have one powershell cmdlet `Install-ADDSforest’. the full documentation is available here. The function accept many parameters in my Lab, I use the minimal parameter to quickly promote my domain controller.

#Secure my password
$Password ="123+aze"
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force

# Promote the domain controller
Install-ADDSForest -DomainName JM2K69.pwsh -SafeModeAdministratorPassword $SecurePassword -Force

The Output in French sorry ;-)! :

AVERTISSEMENT : Les contrôleurs de domaine Windows Server 2019 offrent un paramètre de sécurité par défaut nommé « Autoriser les algorithmes de chiffrement compatibles avec Windows NT 4.0 ». Ce paramètre empêche l’utilisation d’algorithmes de chiffrement faibles lors de l’établissement de sessions sur canal sécurisé.

Pour plus d’informations sur ce paramètre, voir l’article 942564 de la Base de connaissances (http://go.microsoft.com/fwlink/?LinkId=1
04751).

AVERTISSEMENT : Il est impossible de créer une délégation pour ce serveur DNS car la zone parente faisant autorité est introuvable ou elle n’exécute pas le serveur DNS Windows. Si vous procédez à l’intégration avec une infrastructure DNS existante, vous devez manuellement créer une délégation avec ce serveur DNS dans la zone parente pour activer une résolution de noms fiable en dehors du domaine « JM2K69.pwsh ». Sinon, aucune action n’est requise.

AVERTISSEMENT : Les contrôleurs de domaine Windows Server 2019 offrent un paramètre de sécurité par défaut nommé « Autoriser les algorithmes de chiffrement compatibles avec Windows NT 4.0 ». Ce paramètre empêche l’utilisation d’algorithmes de chiffrement faibles lors de l’établissement de sessions sur canal sécurisé.

Pour plus d’informations sur ce paramètre, voir l’article 942564 de la Base de connaissances (http://go.microsoft.com/fwlink/?LinkId=1
04751).

Then you computer restart.

3. Create your Organizational Unit (OU)

Now that the domain controller is up and running, you can start creating OUs. they allow to organize the objects of your company (Users, Computers, Printers …). On these organizational units will be positioned the GPOs.

ComputerSection

3.1 PowerShell Time

At first, the script must be able to work on any ADDS. This code below allows us to retrieve all the information needed to create objects in active directory.

$fqdn = Get-ADDomain
$fulldomain = $fqdn.DNSRoot
$domain = $fulldomain.split(".")
$Dom = $domain[0]
$Ext = $domain[1]

3.2 Create one OU

Th powershell Cmdlet for create OU is very simple :

New-ADOrganizationalUnit -Name Test -Description Test

In your Lab Only and not in Production you can add the -parameter -ProtectedFromAccidentalDeletion $false you can easily remove the OU.

3.3 My Script

# Informations
$Sites = ("Lyon","New-York","London")
$Services = ("Production","Marketing","IT","Direction","Helpdesk")
$Materiel = ("Computer","Server","Printers")
$FirstOU ="Sites"

New-ADOrganizationalUnit -Name $FirstOU -Description $FirstOU  -Path "DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false


foreach  ($S in $Sites)
{
        New-ADOrganizationalUnit -Name $S -Description "$S"  -Path "OU=$FirstOU,DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false

     foreach ($Serv in $Services)
     {
        New-ADOrganizationalUnit -Name $Serv -Description "$S $Serv"  -Path "OU=$S,OU=$FirstOU,DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false
     }

 }

4. Create User

I Create a function to use a free API.

function New-RandomUser {
    <#
        .SYNOPSIS
            Generate random user data from Https://randomuser.me/.
        .DESCRIPTION
            This function uses the free API for generating random user data from https://randomuser.me/
        .EXAMPLE
            Get-RandomUser 10
        .EXAMPLE
            Get-RandomUser -Amount 25 -Nationality us,gb 
        .LINK
            https://randomuser.me/
    #>
    [CmdletBinding()]
    param (
        [Parameter(Position = 0)]
        [ValidateRange(1,500)]
        [int] $Amount,

        [Parameter()]
        [ValidateSet('Male','Female')]
        [string] $Gender,

        # Supported nationalities: AU, BR, CA, CH, DE, DK, ES, FI, FR, GB, IE, IR, NL, NZ, TR, US
        [Parameter()]
        [string[]] $Nationality,

        [Parameter()]
        [ValidateSet('json','csv','xml')]
        [string] $Format = 'json',

        # Fields to include in the results.
        # Supported values: gender, name, location, email, login, registered, dob, phone, cell, id, picture, nat
        [Parameter()]
        [string[]] $IncludeFields,

        # Fields to exclude from the the results.
        # Supported values: gender, name, location, email, login, registered, dob, phone, cell, id, picture, nat
        [Parameter()]
        [string[]] $ExcludeFields
    )

    $rootUrl = "http://api.randomuser.me/?format=$($Format)"

    if ($Amount) {
        $rootUrl += "&results=$($Amount)"
    }

    if ($Gender) {
        $rootUrl += "&gender=$($Gender)"
    }

    if ($Nationality) {
        $rootUrl += "&nat=$($Nationality -join ',')"
    }

    if ($IncludeFields) {
        $rootUrl += "&inc=$($IncludeFields -join ',')"
    }

    if ($ExcludeFields) {
        $rootUrl += "&exc=$($ExcludeFields -join ',')"
    }
    Invoke-RestMethod -Uri $rootUrl
}

4.1 How to use the function

How to :

$users = New-RandomUser -Amount 30 -Nationality us -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results

foreach ($user in $users) {
    $newUserProperties = @{
        Name = "$($user.name.first) $($user.name.last)"
        City = "City"
        GivenName = $user.name.first
        Surname = $user.name.last
        Path = $adPath
        title = "Director"
        department="IT"
        OfficePhone = $user.phone
        MobilePhone = $user.cell
        Company="JM2K69"
        EmailAddress="$($user.name.first).$($user.name.last)@$($adDomain)"
        AccountPassword = (ConvertTo-SecureString $userPassword -AsPlainText -Force)
        SamAccountName = $($user.name.first).Substring(0,1)+$($user.name.last)
        UserPrincipalName = "$(($user.name.first).Substring(0,1)+$($user.name.last))@$($adDomain)"
        Enabled = $true
    }

    try {New-ADUser @newUserProperties}
    catch {}
}

5. The final Script

All the part combined in one. For The different site I change the -parameter Nationality. In this example I create 20 Employees and 5 Directors / Sites / Services.

$fqdn = Get-ADDomain
$fulldomain = $fqdn.DNSRoot
$domain = $fulldomain.split(".")
$Dom = $domain[0]
$Ext = $domain[1]
$userPassword = '123+aze'
$Sites = ("Lyon","New-York","London")
$Services = ("Production","Marketing","IT","Direction","Helpdesk")
$Materiel = ("Computer","Server","Printers")
$FirstOU ="Sites"

New-ADOrganizationalUnit -Name $FirstOU -Description $FirstOU  -Path "DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false


foreach  ($S in $Sites)
{
        New-ADOrganizationalUnit -Name $S -Description "$S"  -Path "OU=$FirstOU,DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false
 
     foreach ($Serv in $Services)
     {
        New-ADOrganizationalUnit -Name $Serv -Description "$S $Serv"  -Path "OU=$S,OU=$FirstOU,DC=$Dom,DC=$EXT" -ProtectedFromAccidentalDeletion $false
      
      switch ($S)
      {
          'Lyon' {
                        $Employees = New-RandomUser -Amount 20 -Nationality fr -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results
                        $Directors = New-RandomUser -Amount 5 -Nationality fr -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results
                 }
          'New-York' {
                        $Employees = New-RandomUser -Amount 20 -Nationality us -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results
                        $Directors = New-RandomUser -Amount 5 -Nationality us -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results
                     }
          'London' {
                        $Employees = New-RandomUser -Amount 20 -Nationality gb -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results
                        $Directors = New-RandomUser -Amount 5 -Nationality gb -IncludeFields name,dob,phone,cell -ExcludeFields picture | Select-Object -ExpandProperty results

          }
          Default {}
      }

        foreach ($user in $Employees)
        {
          $newUserProperties = @{
        Name = "$($user.name.first) $($user.name.last)"
        City = "$S"
        GivenName = $user.name.first
        Surname = $user.name.last
        Path = "OU=$Serv,OU=$S,OU=$FirstOU,dc=$Dom,dc=$EXT"
        title = "Employees"
        department="$Serv"
        OfficePhone = $user.phone
        MobilePhone = $user.cell
        Company="$Dom"
        EmailAddress="$($user.name.first).$($user.name.last)@$($fulldomain)"
        AccountPassword = (ConvertTo-SecureString $userPassword -AsPlainText -Force)
        SamAccountName = $($user.name.first).Substring(0,1)+$($user.name.last)
        UserPrincipalName = "$(($user.name.first).Substring(0,1)+$($user.name.last))@$($fulldomain)"
        Enabled = $true
    }

           Try{ New-ADUser @newUserProperties}
           catch{}

        }
        foreach ($user in $Directors)
        {
          $newUserProperties = @{
        Name = "$($user.name.first) $($user.name.last)"
        City = "$S"
        GivenName = $user.name.first
        Surname = $user.name.last
        Path = "OU=$Serv,OU=$S,OU=$FirstOU,dc=$Dom,dc=$EXT"
        title = "Directors"
        department="$Serv"
        OfficePhone = $user.phone
        MobilePhone = $user.cell
        Company="$Dom"
        EmailAddress="$($user.name.first).$($user.name.last)@$($fulldomain)"
        AccountPassword = (ConvertTo-SecureString $userPassword -AsPlainText -Force)
        SamAccountName = $($user.name.first).Substring(0,1)+$($user.name.last)
        UserPrincipalName = "$(($user.name.first).Substring(0,1)+$($user.name.last))@$($fulldomain)"
        Enabled = $true
    }

           Try{ New-ADUser @newUserProperties}
           catch{}

        }
     }
 }

Written by Jérôme Bezet-Torres @JM2K69.