Active Directory Domain with Group Policy
Build a Windows Server 2022 AD domain with OUs, GPOs, and PowerShell automation.
Introduction
30 Second Summary
Every time a company hires new employees, someone has to create their accounts, set the right permissions, and enforce security rules across the board. In the Windows world, that entire job belongs to Active Directory.
In this project, you will build a fully functional Active Directory domain on Windows Server 2022. You'll go from a blank server all the way to automated bulk user provisioning with a PowerShell script.
What You'll Build
Picture running a single script that reads a list of new hires from a spreadsheet and provisions every account into the right department with the correct security group membership in seconds.
By the end of this project, you'll have:
- A populated employee directory organized by department, where a single PowerShell query shows every user across IT, HR, and Sales Organizational Units.
- A custom Group Policy Object enforcing password complexity and account lockout rules across the entire domain, visible in the Group Policy Management Console.
- A PowerShell script that reads a CSV file and bulk-provisions new user accounts into the correct departments with proper security group memberships in seconds.
- Secret Mission: Install and configure a DHCP server with a scope and IP reservations.
Are there any prerequisites?
This project uses a Hyper-V sandbox running Windows Server 2022. Make sure you have access to your sandbox before getting started.
Before We Start
Before diving into any commands, let's lock in what you're about to build and why it matters. This step is your chance to commit to the goal before the hands-on work begins.
Install AD DS and Promote to Domain Controller
Your Windows Server 2022 sandbox is a standalone server with no identity services. Without Active Directory, there is no central way to manage users, groups, or policies.
In this step, you will rename the server, assign it a static IP address, install the AD DS role, and promote it to a Domain Controller for a brand-new forest called corp.lab. This gives you the foundation for everything else in the project.
In this step, get ready to:
- Rename the server to DC01 and configure a static IP address.
- Install the AD DS role with management tools.
- Create a new Active Directory forest and promote the server to a Domain Controller.
Rename the server and configure a static IP
Before promoting a server to a Domain Controller, it needs a meaningful hostname and a static IP address. A domain controller that changes its IP address would break every client trying to find it.
- Open PowerShell as Administrator by pressing the Windows key, typing PowerShell, right-clicking Windows PowerShell, and selecting Run as administrator.
- Rename the server to DC01 by running this command:
Rename-Computer -NewName "DC01" -Force -Restart
What does this command do?
`Rename-Computer` changes the server's hostname from the random default to DC01. The -Force flag skips the confirmation prompt. The -Restart flag reboots the server immediately so the new name takes effect.
Your server will restart automatically. Wait for it to come back up and sign in again.
- Open PowerShell as Administrator again.
- Confirm the hostname changed by running this command:
hostname
You should see DC01 printed in the output.
Still seeing the old hostname?
The rename only takes effect after a full restart. If the server did not restart, run Restart-Computer -Force manually and wait for it to come back up.
help me troubleshoot why my server hostname didn't change after running Rename-Computer
- Before setting the static IP, find your network adapter's interface index by running:
Get-NetIPInterface -AddressFamily IPv4
- Look at the output and note the ifIndex number for the Ethernet adapter (not the Loopback). Record it here:
Your adapter's interface index: your Ethernet interface index number
- Set the static IP address to 10.0.0.1 with a /24 subnet by running this command (replace the interface index with yours):
New-NetIPAddress -InterfaceIndex [[IFINDEX="your Ethernet interface index number"]] -IPAddress 10.0.0.1 -PrefixLength 24
- Point the DNS server to the loopback address 127.0.0.1 by running:
Set-DnsClientServerAddress -InterfaceIndex [[IFINDEX="your Ethernet interface index number"]] -ServerAddresses 127.0.0.1
Why point DNS to itself?
A Domain Controller runs its own DNS service. By pointing DNS to 127.0.0.1 (the loopback address), the server will use itself for name resolution once DNS is installed with the forest.
- Verify the IP configuration by running:
ipconfig /all
You should see 10.0.0.1 as your IPv4 Address and 127.0.0.1 as your DNS Server.
Seeing an error about an existing IP?
If the adapter already has a DHCP address, you may need to remove it first. Run Remove-NetIPAddress -InterfaceIndex with your interface index, confirm the removal, and then re-run the New-NetIPAddress command.
help me fix an IP address conflict when setting a static IP on Windows Server 2022
Install the AD DS role
With the server renamed and its network configured, you can install the Active Directory Domain Services role. This adds the software needed to turn the server into a Domain Controller.
- Install AD DS and its management tools by running this command:
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
What does this command do?
`Install-WindowsFeature` adds a Windows Server role or feature. The -Name AD-Domain-Services parameter specifies the AD DS role.
The -IncludeManagementTools flag also installs the Active Directory Users and Computers console and other GUI tools you will use later.
The installation takes a minute or two. You should see a result table with Success as the exit code and True in the Success column.
Seeing a failure or restart required?
Make sure you are running PowerShell as Administrator. If the output says a restart is needed, run Restart-Computer -Force and try the install command again after the reboot.
help me troubleshoot the Install-WindowsFeature command failing for AD-Domain-Services
Create the AD forest and promote to Domain Controller
The AD DS role is installed, but the server is not a Domain Controller yet. You need to create a new forest and promote this server to be its first (and only) Domain Controller.
- Create the corp.lab forest and promote the server to a Domain Controller by running:
Install-ADDSForest -DomainName "corp.lab" -DomainNetbiosName "CORP" -InstallDns:$true -Force:$true
What does this command do?
`Install-ADDSForest` creates a brand-new Active Directory forest. The -DomainName "corp.lab" sets the domain's fully qualified name. The -DomainNetbiosName "CORP" sets the short (NetBIOS) name used for older protocols.
The -InstallDns:$true flag installs the DNS Server role alongside AD. Active Directory depends on DNS to locate domain controllers and services. The -Force:$true flag suppresses confirmation prompts.
You will be prompted for a password
The command prompts you for a SafeModeAdministratorPassword (also called the DSRM password). This is a recovery password used if Active Directory ever needs to be repaired offline. Type a strong password, confirm it, and press Enter. Remember this password.
The promotion process runs for a few minutes. You will see several warnings about DNS delegation and cryptography. These are normal in a lab environment. The server reboots automatically when the promotion completes.
- Wait for the server to restart and sign back in.
- Notice that the sign-in screen now shows CORP\Administrator instead of a local account. This confirms you are now logging into the domain.
Before you run the verification command, what do you think Get-ADDomainController will show? Will it list DC01 as the domain controller for corp.lab?
- Verify the promotion succeeded by running this command in PowerShell:
Get-ADDomainController
You should see your server listed as DC01 with the domain corp.lab, the forest corp.lab, and an IPv4Address of 10.0.0.1.
Get-ADDomainController not recognized?
If PowerShell says the command is not recognized, the Active Directory module may not be loaded yet. Run Import-Module ActiveDirectory first, then try Get-ADDomainController again. If the module is not found, the server may not have finished promoting. Wait a minute and try again.
help me troubleshoot why Get-ADDomainController is not recognized on my Windows Server 2022 after promoting to a Domain Controller
Your server is now the Domain Controller for corp.lab with integrated DNS running. Next up, you will build the organizational structure that mirrors a real company and create your first user accounts.
Build Your OU Structure and Create First Users
Your domain controller is live, but every object in Active Directory sits in the default containers. That is a flat structure with no way to target policies or permissions at specific teams.
A real company organizes users by department so administrators can apply different rules to different groups of people. In this step, you will create that departmental structure with Organizational Units, populate them with user accounts, and assign users to security groups.
In this step, get ready to:
- Create three department OUs (IT, HR, Sales) under the domain root.
- Create two user accounts in each department OU.
- Create security groups and assign users to their department group.
Create three department Organizational Units
Organizational Units are containers within Active Directory that let you group objects like users, groups, and computers by department or location. They are also the targets you attach Group Policy Objects to later.
- Create the IT, HR, and Sales OUs under the domain root by running these commands in PowerShell:
# Create department OUs under the corp.lab domain root
New-ADOrganizationalUnit -Name "IT" -Path "DC=corp,DC=lab"
New-ADOrganizationalUnit -Name "HR" -Path "DC=corp,DC=lab"
New-ADOrganizationalUnit -Name "Sales" -Path "DC=corp,DC=lab"
What do these commands do?
Each New-ADOrganizationalUnit call creates a new container in your directory. The -Name parameter sets the OU's display name, and -Path "DC=corp,DC=lab" places it directly under the domain root.
- Confirm the OUs exist by running:
Get-ADOrganizationalUnit -Filter * | Select-Object Name, DistinguishedName
You should see three rows listing IT, HR, and Sales with their distinguished names (e.g. OU=IT,DC=corp,DC=lab).
Not seeing all three OUs?
- Check for typos in the -Path value. It must be exactly "DC=corp,DC=lab" with no spaces around the comma.
- Make sure you are running PowerShell as an administrator on DC01.
- If you get a "directory object not found" error, confirm your domain is corp.lab by running Get-ADDomain.
Help me troubleshoot why my New-ADOrganizationalUnit command failed on Windows Server 2022.
Create user accounts in each department
Each user account needs basic identity attributes: a display name, a login name, a department, and the OU where it lives. You will create two users per department using New-ADUser.
- Create two IT department users by running:
# Create two IT department users
New-ADUser `
-Name "Alex Turner" `
-SamAccountName "aturner" `
-GivenName "Alex" `
-Surname "Turner" `
-Department "IT" `
-Title "IT Manager" `
-Path "OU=IT,DC=corp,DC=lab"
New-ADUser `
-Name "Priya Patel" `
-SamAccountName "ppatel" `
-GivenName "Priya" `
-Surname "Patel" `
-Department "IT" `
-Title "Network Engineer" `
-Path "OU=IT,DC=corp,DC=lab"
What does this code do?
- -Name sets the user's display name in the directory.
- -SamAccountName is the login name the user types to sign in. This parameter is required for every new user.
- -GivenName and -Surname store the user's first and last name.
- -Department and -Title tag the user with organizational metadata for filtering and reporting.
- -Path places the user object inside the correct department OU instead of the default Users container.
- Confirm the IT users were created by running:
Get-ADUser -Filter * -SearchBase "OU=IT,DC=corp,DC=lab" | Select-Object Name, SamAccountName
You should see Alex Turner and Priya Patel listed.
Users not showing up?
- Double-check that -SamAccountName is unique for each user. Duplicate login names cause the command to fail.
- Verify the -Path matches the OU you created. Run Get-ADOrganizationalUnit -Filter * to confirm the OU's distinguished name.
Help me troubleshoot why my New-ADUser command failed on Windows Server 2022.
- Create two HR department users by running:
# Create two HR department users
New-ADUser `
-Name "James Reed" `
-SamAccountName "jreed" `
-GivenName "James" `
-Surname "Reed" `
-Department "HR" `
-Title "HR Coordinator" `
-Path "OU=HR,DC=corp,DC=lab"
New-ADUser `
-Name "Nina Ortega" `
-SamAccountName "nortega" `
-GivenName "Nina" `
-Surname "Ortega" `
-Department "HR" `
-Title "Benefits Specialist" `
-Path "OU=HR,DC=corp,DC=lab"
- Create two Sales department users by running:
# Create two Sales department users
New-ADUser `
-Name "Kevin Brooks" `
-SamAccountName "kbrooks" `
-GivenName "Kevin" `
-Surname "Brooks" `
-Department "Sales" `
-Title "Account Manager" `
-Path "OU=Sales,DC=corp,DC=lab"
New-ADUser `
-Name "Megan Foster" `
-SamAccountName "mfoster" `
-GivenName "Megan" `
-Surname "Foster" `
-Department "Sales" `
-Title "Sales Analyst" `
-Path "OU=Sales,DC=corp,DC=lab"
- Verify all six users across every department by running:
Get-ADUser -Filter * -SearchBase "DC=corp,DC=lab" | Select-Object Name, SamAccountName, DistinguishedName | Format-Table
You should see six user accounts spread across the IT, HR, and Sales OUs. You will also see the built-in Administrator and Guest accounts in the default Users container.
Create security groups and assign members
Security groups let you grant permissions to a set of users at once instead of managing access user by user. Each department gets its own group.
- Create the three department security groups and add users to them by running:
# Create department security groups in their matching OUs
New-ADGroup -Name "IT Staff" `
-SamAccountName "ITStaff" `
-GroupScope Global `
-GroupCategory Security `
-Path "OU=IT,DC=corp,DC=lab"
New-ADGroup -Name "HR Staff" `
-SamAccountName "HRStaff" `
-GroupScope Global `
-GroupCategory Security `
-Path "OU=HR,DC=corp,DC=lab"
New-ADGroup -Name "Sales Staff" `
-SamAccountName "SalesStaff" `
-GroupScope Global `
-GroupCategory Security `
-Path "OU=Sales,DC=corp,DC=lab"
# Add each department's users to their group
Add-ADGroupMember -Identity "IT Staff" -Members "aturner","ppatel"
Add-ADGroupMember -Identity "HR Staff" -Members "jreed","nortega"
Add-ADGroupMember -Identity "Sales Staff" -Members "kbrooks","mfoster"
What does this code do?
Each New-ADGroup creates a security group with Global scope, meaning the group can contain members from the same domain and be used for permissions across trusted domains.
Each Add-ADGroupMember call adds the two department users to their matching group. Later, you can grant access to a resource by assigning a single group instead of individual users.
- Verify the group memberships by running:
Get-ADGroupMember -Identity "IT Staff" | Select-Object Name
Get-ADGroupMember -Identity "HR Staff" | Select-Object Name
Get-ADGroupMember -Identity "Sales Staff" | Select-Object Name
Each command should return two names. IT Staff should show Alex Turner and Priya Patel. HR Staff should show James Reed and Nina Ortega. Sales Staff should show Kevin Brooks and Megan Foster.
Seeing an empty result?
- Make sure the -Identity value in Add-ADGroupMember matches the group name exactly, including the space ("IT Staff" not "ITStaff").
- Confirm the -Members values match the SamAccountName you set when creating each user.
Help me troubleshoot why Add-ADGroupMember is not adding users to my security group.
Verify your directory in Active Directory Users and Computers
You have built the full structure in PowerShell. Before you move on, take a look at the result in the graphical management console.
Before you open the console, predict what you expect to see. How many OUs should appear under corp.lab? How many user objects should be inside each one?
- Open **Server Manager** if it is not already open.
- Click **Tools** in the top-right menu bar.
- Select **Active Directory Users and Computers**.
- In the left pane, expand corp.lab.
- Click on each OU (IT, HR, Sales) and confirm you see two user accounts and one security group inside each one.
You should see three department OUs directly under corp.lab. Each OU contains two user objects and one group object.
Why use ADUC when PowerShell already works?
PowerShell is faster for bulk operations, but Active Directory Users and Computers gives you a visual overview of your entire directory tree. In practice, sysadmins switch between both tools constantly.
Your directory has structure. In the next step, you will get these accounts ready for their first day at work.
Fix Disabled Accounts and Master Password Management
In the last step, you built a proper organizational structure for your domain. Three department OUs hold six user accounts and three security groups. The directory is starting to look like a real company.
Before any of those users can log in, though, their accounts need to be managed. In this step, you'll discover a critical gotcha that catches every new admin, fix it, and then practice the day-to-day account management tasks that sysadmins handle: password resets, account unlocks, and disabling terminated employees.
In this step, get ready to:
- Discover why your user accounts are disabled and fix them by setting passwords and enabling each account.
- Practice the three most common helpdesk tasks: password resets, account unlocks, and account disables.
- Verify that all your security group memberships are correct.
Discover and fix your disabled user accounts
You created six user accounts across three OUs in the last step. Before doing anything else, check whether those accounts are actually ready to use.
What status do you expect to see for the accounts you just created? Run this command to find out:
- Check the status of your IT department users by running this command:
Get-ADUser -Filter * -SearchBase "OU=IT,DC=corp,DC=lab" | Select-Object Name, Enabled
Every single account shows Enabled: False. This is not a bug. This is exactly what Active Directory is designed to do.
Why are all the accounts disabled?
Active Directory refuses to enable any account that does not have a password meeting the domain's password policy. In Step 2, you created users with New-ADUser without setting the -AccountPassword parameter.
AD created the accounts but left them disabled as a security measure. This is the number one gotcha new admins hit, and now you know exactly how to spot it.
The fix has three parts for each user: set a compliant password, enable the account, and force a password change at next logon. Start by fixing one user so you can see each command in action.
- Look at the Name column in your output above and pick one of your IT users.
- Find that user's SamAccountName by running this command:
Get-ADUser -Filter * -SearchBase "OU=IT,DC=corp,DC=lab" | Select-Object Name, SamAccountName
- Note one of the SamAccountName values: a SamAccountName from your output
- Set a password, enable the account, and force a password change at next logon by running these three commands:
# Set a compliant password on the account
Set-ADAccountPassword -Identity [[FIRST_USER="a SamAccountName from your output"]] -NewPassword (ConvertTo-SecureString "P@ssw0rd2024!" -AsPlainText -Force) -Reset
# Enable the account
Enable-ADAccount -Identity [[FIRST_USER="a SamAccountName from your output"]]
# Force the user to set a new password at first logon
Set-ADUser -Identity [[FIRST_USER="a SamAccountName from your output"]] -ChangePasswordAtLogon $true
What do these commands do?
- Set-ADAccountPassword with -Reset sets a new password without needing the old one. The password is converted to a SecureString, which is how PowerShell handles sensitive values in memory.
- Enable-ADAccount flips the account from disabled to enabled. This only works now because the account has a compliant password.
- Set-ADUser -ChangePasswordAtLogon $true forces the user to choose their own password the first time they log in. In production, you never want users keeping a password that an admin knows.
- Verify that your user is now enabled by running:
Get-ADUser -Identity [[FIRST_USER="a SamAccountName from your output"]] -Properties Enabled | Select-Object Name, Enabled
You should see Enabled: True for that user. One down, five to go.
Still seeing Enabled: False?
- Make sure you ran the Set-ADAccountPassword command before Enable-ADAccount. AD will not enable an account without a compliant password set first.
- Double-check that the SamAccountName you entered matches the exact value from your Get-ADUser output. It is case-insensitive but must be spelled correctly.
- Why can't I enable my AD account after setting the password?
Running three commands per user for five more users would be tedious. A loop handles all six users across all three OUs in one go.
- Fix all remaining users across every department by running this loop:
# Set passwords, enable accounts, and force password change for all department users
$password = ConvertTo-SecureString "P@ssw0rd2024!" -AsPlainText -Force
foreach ($ou in @("OU=IT,DC=corp,DC=lab", "OU=HR,DC=corp,DC=lab", "OU=Sales,DC=corp,DC=lab")) {
Get-ADUser -Filter * -SearchBase $ou | ForEach-Object {
Set-ADAccountPassword -Identity $_.SamAccountName -NewPassword $password -Reset
Enable-ADAccount -Identity $_.SamAccountName
Set-ADUser -Identity $_.SamAccountName -ChangePasswordAtLogon $true
Write-Host "Enabled: $($_.Name) in $ou" -ForegroundColor Green
}
}
What does this loop do?
The loop iterates through all three OU paths. For each OU, Get-ADUser -Filter * retrieves every user account and pipes them into ForEach-Object. Each user gets the same three-step fix you ran manually: password, enable, force change.
The user you already fixed individually will have the commands re-applied. That is fine because these commands are idempotent. Setting the same password again and enabling an already-enabled account produces no errors.
You should see a green Enabled: message printed for each of your six users.
- Confirm every account across the entire domain is now enabled by running:
Get-ADUser -Filter * -SearchBase "DC=corp,DC=lab" -Properties Enabled |
Where-Object { $_.Enabled -eq $true } |
Select-Object Name, Enabled
All six of your user accounts should appear with Enabled: True. The disabled-account gotcha is fully resolved.
Practice the most common helpdesk tasks
Setting passwords and enabling accounts is just the first part of account management. Every sysadmin handles password resets, account unlocks, and account disables on a daily basis. These are the exact tasks the hiring manager described.
You will practice all three tasks using the same user account you worked with earlier.
- Reset a user's password by running this command:
# Reset a user's password (common helpdesk task)
Set-ADAccountPassword -Identity [[FIRST_USER="a SamAccountName from your output"]] -NewPassword (ConvertTo-SecureString "NewP@ss2024!" -AsPlainText -Force) -Reset
- Verify the password was reset by checking the account's PasswordLastSet property:
Get-ADUser -Identity [[FIRST_USER="a SamAccountName from your output"]] -Properties PasswordLastSet | Select-Object Name, PasswordLastSet
The PasswordLastSet timestamp should show the current date and time, proving the reset just happened.
- Practice unlocking a locked account by running:
# Unlock a locked-out account (runs silently if the account is not locked)
Unlock-ADAccount -Identity [[FIRST_USER="a SamAccountName from your output"]]
Why did nothing happen?
Unlock-ADAccount runs silently when the account is not currently locked out. No error, no output. In production, users get locked out after too many failed login attempts, and this is the command you run to get them back in. You are building the muscle memory now.
- Disable a terminated employee's account by running:
# Disable a terminated employee's account
Disable-ADAccount -Identity [[FIRST_USER="a SamAccountName from your output"]]
- Verify the account is now disabled by running:
Get-ADUser -Identity [[FIRST_USER="a SamAccountName from your output"]] | Select-Object Name, Enabled
You should see Enabled: False. In a real environment, this is how you immediately revoke access when someone leaves the company.
- Re-enable the account so all six users are active again by running:
# Re-enable the account after practicing the disable workflow
Enable-ADAccount -Identity [[FIRST_USER="a SamAccountName from your output"]]
- Confirm the account is enabled again by running:
Get-ADUser -Identity [[FIRST_USER="a SamAccountName from your output"]] | Select-Object Name, Enabled
You should see Enabled: True. All six accounts are back to active status.
Account not re-enabling?
- Confirm you are using the same SamAccountName value you used in the Disable-ADAccount command. A typo creates a "cannot find" error instead of an enable failure.
- Why is my AD account still disabled after running Enable-ADAccount?
Verify group memberships
The last thing to confirm is that your security group memberships survived all the account changes. Enabling, disabling, and resetting passwords should not affect group memberships, but it is good practice to verify.
- Check the members of each security group by running these three commands:
# Verify IT Staff group members
Get-ADGroupMember -Identity "IT Staff" | Select-Object Name
# Verify HR Staff group members
Get-ADGroupMember -Identity "HR Staff" | Select-Object Name
# Verify Sales Staff group members
Get-ADGroupMember -Identity "Sales Staff" | Select-Object Name
What should I see?
Each command should list the two users you created in that department during Step 2. If any group is missing a member, use Add-ADGroupMember to re-add them.
Now run one final check to confirm the complete state of your domain. Before you run this, predict: how many enabled users should appear?
- Verify all six accounts are enabled across the entire domain by running:
Get-ADUser -Filter * -SearchBase "DC=corp,DC=lab" -Properties Enabled |
Where-Object { $_.Enabled -eq $true } |
Select-Object Name, Enabled
All six of your user accounts should appear with Enabled: True. Every account has a compliant password, is enabled, and will force a password change at next logon.
Your user accounts are alive and your helpdesk skills are sharp. Next up, you'll create a Group Policy Object to enforce password complexity and account lockout rules across the entire domain.
Create and Link a Group Policy for Security Policies
Your accounts are enabled and secured with passwords. But there is a gap. Nothing stops a user from changing their password to something weak like password1 at the next logon.
Group Policy is Active Directory's enforcement layer. It pushes security settings to every computer and user in the domain. In this step, you will create a Group Policy Object that sets minimum password requirements and locks out accounts after too many failed login attempts.
In this step, get ready to:
- Create and link a GPO named "Corp Security Policy" to the domain.
- Configure password complexity and account lockout policies in Group Policy Management Console.
- Force the policy to apply and verify it with gpresult.
Create the GPO and link it to the domain
A Group Policy Object (GPO) is a container that holds policy settings. Before it does anything, you need to create one and link it to the part of Active Directory you want it to apply to.
- Create a new GPO named "Corp Security Policy" by running this command:
New-GPO -Name "Corp Security Policy"
You should see output showing the new GPO with its display name, domain, and a status of AllSettingsEnabled.
What does this command do?
New-GPO creates a new Group Policy Object in the domain. At this point, the GPO exists but is not linked to anything. It holds no settings and applies to nobody.
- Link the GPO to the domain root by running this command:
New-GPLink -Name "Corp Security Policy" -Target "DC=corp,DC=lab"
You should see output confirming the link is enabled with the target dc=corp,dc=lab.
Why link at the domain level?
Password policies and account lockout policies only work when applied at the domain level. Linking this GPO to DC=corp,DC=lab means the rules will apply to every user in the domain.
Creating a custom GPO instead of editing the Default Domain Policy directly is best practice. It keeps your changes isolated and easy to troubleshoot or remove later.
- Confirm the GPO exists by running this command:
Get-GPO -Name "Corp Security Policy"
You should see the GPO listed with its display name, owner, domain, and creation time.
GPO not found?
Make sure you typed the GPO name exactly as Corp Security Policy with the same capitalization. GPO names are case-sensitive in PowerShell queries.
Help me troubleshoot why my GPO was not created.
Configure password and lockout policies in GPMC
The GPO is created and linked, but it holds no settings yet. You will configure password complexity and account lockout rules using the Group Policy Management Console editor.
- Open Server Manager from the taskbar.
- Click Tools in the top menu bar.
- Select Group Policy Management.
- In the left panel, expand Forest: corp.lab, then Domains, then corp.lab, then Group Policy Objects.
- Right-click Corp Security Policy and select Edit.
The Group Policy Management Editor opens. This is where you define the actual security rules.
- In the left panel of the editor, navigate to Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies > Password Policy.
- Double-click Minimum password length.
- Check the Define this policy setting checkbox.
- Set the value to 10 characters.
- Click OK.
- Double-click Enforce password history.
- Check Define this policy setting and set the value to 5 passwords remembered.
- Click OK.
What do these settings do?
Minimum password length of 10 means no user can set a password shorter than 10 characters.
Enforce password history of 5 means a user cannot reuse any of their last 5 passwords. This prevents cycling back to an old password.
- Double-click Password must meet complexity requirements.
- Check Define this policy setting and select Enabled.
- Click OK.
Now configure the account lockout settings.
- In the left panel, click Account Lockout Policy (directly below Password Policy).
- Double-click Account lockout threshold.
- Set the value to 5 invalid logon attempts.
- Click OK.
Windows may prompt you with suggested values for the related lockout settings.
- If prompted, click OK to accept the suggested values.
- Double-click Account lockout duration.
- Set the value to 15 minutes.
- Click OK.
What does the lockout policy do?
Account lockout threshold of 5 means an account gets locked after 5 consecutive failed password attempts. This protects against brute-force attacks.
Account lockout duration of 15 minutes means the account automatically unlocks after 15 minutes. In the meantime, a sysadmin can manually unlock it with Unlock-ADAccount if the user calls in.
You can now close the Group Policy Management Editor window.
Force the policy to apply and verify it took effect
GPO settings are applied automatically on a schedule, but you can force an immediate refresh. This is how you confirm your policy is active right now.
- Force the policy to apply immediately by running this command in PowerShell:
Invoke-GPUpdate -Force
What does this command do?
Invoke-GPUpdate triggers a Group Policy refresh on the local computer. The -Force flag runs the command without asking for confirmation. This is the PowerShell equivalent of the classic gpupdate /force command.
Before you run the next command, think about what you expect to see. Do you think your "Corp Security Policy" GPO will show up in the applied policies list?
- Verify the GPO is applied by running this command:
gpresult /r
Scroll through the output and look for the "Applied Group Policy Objects" section. You should see Corp Security Policy listed alongside the Default Domain Policy.
What does gpresult /r show?
gpresult /r displays the Resultant Set of Policy for the current computer and user. The "Applied Group Policy Objects" section lists every GPO that was successfully applied in order of processing.
If your GPO appears here, the password and lockout rules you configured are now being enforced across the entire corp.lab domain.
Don't see Corp Security Policy in the list?
Make sure you linked the GPO to the domain with the correct target. Run Get-GPO -Name "Corp Security Policy" to confirm it exists. Then re-run Invoke-GPUpdate -Force and try gpresult /r again.
Help me troubleshoot why my Corp Security Policy GPO is not appearing in gpresult.
Your domain now enforces password complexity and account lockout rules for every user. Next up, you will automate bulk user creation with a PowerShell script that provisions entire departments from a CSV file.
Automate Bulk User Creation with a PowerShell Script
Your domain is locked down with a Group Policy enforcing password complexity and account lockout rules. But so far, every user account has been created one command at a time.
That works for a handful of accounts. The hiring manager, though, wants someone who can script and "build things to make our lives easier." In this step, you'll write a PowerShell script that reads employee data from a CSV file and provisions accounts in bulk. This is exactly the kind of automation that sysadmins build for onboarding workflows.
In this step, get ready to:
- Create a CSV file with employee data for seven new hires.
- Write a PowerShell script to automate user provisioning with error handling.
- Run the script and verify all users are created with correct group memberships.
Create the scripts directory and CSV file
Before you can automate anything, you need two things: a folder to hold your scripts, and a data file listing the employees to create.
- Create the scripts directory by running this command in PowerShell:
New-Item -ItemType Directory -Path C:\Scripts
- Confirm the directory exists by running:
Test-Path C:\Scripts
You should see True in the output.
Now you need a CSV file that holds the employee data your script will read. Each row represents one new hire.
- Open Notepad to create the CSV file by running:
notepad C:\Scripts\employees.csv
Seeing a prompt about creating a new file?
Notepad will ask if you want to create a new file since employees.csv doesn't exist yet. Click Yes to continue.
- Paste the following employee data into Notepad:
FirstName,LastName,SamAccountName,Department,Title
Sarah,Johnson,sjohnson,Sales,Account Executive
Mike,Chen,mchen,Sales,Sales Manager
Lisa,Park,lpark,Sales,Sales Representative
David,Kim,dkim,HR,HR Coordinator
Emily,Roberts,eroberts,HR,Recruiter
Tom,Martinez,tmartinez,IT,Systems Administrator
Ana,Williams,awilliams,IT,Help Desk Technician
What does this CSV contain?
Each row is a new hire. The columns map directly to Active Directory user attributes your script will set.
FirstName and LastName become the display name. SamAccountName is the logon ID. Department determines which OU the account lands in.
- Save the file by pressing Ctrl+S and close Notepad.
- Back in PowerShell, verify the CSV loads correctly by running:
Import-Csv -Path C:\Scripts\employees.csv | Format-Table
You should see a neatly formatted table with all seven employees, their departments, and titles.
Seeing an empty table or an error?
- Make sure you saved the file as employees.csv and not employees.csv.txt. Notepad sometimes adds a .txt extension. In the Save As dialog, set the file type to All Files (*.*) and name it employees.csv.
- Check that the first line is exactly FirstName,LastName,SamAccountName,Department,Title with no extra spaces or characters.
- Still stuck? Help me debug my CSV file.
Write the bulk user creation script
With your employee data ready, you'll build a PowerShell script that reads the CSV and creates each user in the correct OU with the right group membership. You'll build it in three sections.
- Open Notepad to create the script file by running:
notepad C:\Scripts\New-BulkUsers.ps1
- Click Yes when Notepad asks to create the new file.
- Paste the following setup section into the empty file:
# Bulk user creation script for Active Directory
# Reads employee data from a CSV and provisions AD accounts
$domain = "DC=corp,DC=lab"
$defaultPassword = ConvertTo-SecureString "P@ssw0rd2024!" -AsPlainText -Force
$users = Import-Csv -Path "C:\Scripts\employees.csv"
What does this setup section do?
- $domain stores the domain's distinguished name so you can reuse it when building OU paths.
- $defaultPassword converts a plain-text password into a secure string that New-ADUser requires. This password meets the 10-character minimum and complexity requirements your GPO enforces.
- Import-Csv reads your CSV file and turns each row into a PowerShell object with properties matching the column headers.
- Save the file by pressing Ctrl+S to keep your progress.
- Switch to PowerShell and confirm the script file was saved by running:
Test-Path C:\Scripts\New-BulkUsers.ps1
You should see True.
- Switch back to Notepad. Add the following loop directly below the setup section. Leave one blank line between the setup and this code:
foreach ($user in $users) {
$ouPath = "OU=$($user.Department),$domain"
$displayName = "$($user.FirstName) $($user.LastName)"
$upn = "$($user.SamAccountName)@corp.lab"
try {
New-ADUser `
-Name $displayName `
-GivenName $user.FirstName `
-Surname $user.LastName `
-SamAccountName $user.SamAccountName `
-UserPrincipalName $upn `
-Path $ouPath `
-Department $user.Department `
-Title $user.Title `
-AccountPassword $defaultPassword `
-Enabled $true `
-ChangePasswordAtLogon $true
Add-ADGroupMember -Identity "$($user.Department) Staff" -Members $user.SamAccountName
Write-Host "Created user: $displayName in $($user.Department)" -ForegroundColor Green
}
catch {
Write-Host "Failed to create user: $displayName - $($_.Exception.Message)" -ForegroundColor Red
}
}
What does this loop do?
- foreach iterates through every row in the CSV. Each $user object has properties like $user.FirstName and $user.Department pulled from the column headers.
- $ouPath dynamically builds the target OU path from each user's department. A Sales employee goes to OU=Sales,DC=corp,DC=lab automatically.
- New-ADUser creates the account with all attributes in one call. Notice -Enabled $true and -AccountPassword are set together. This avoids the disabled-account gotcha you fixed in the previous step.
- Add-ADGroupMember adds the user to their department security group right after creation.
- try/catch wraps each user creation. If one user fails (duplicate name, bad OU path), the script reports the error in red and keeps going instead of stopping.
- Save the file by pressing Ctrl+S to keep your progress.
- Switch to PowerShell and confirm the file is growing by running:
Test-Path C:\Scripts\New-BulkUsers.ps1
You should see True again.
- Switch back to Notepad. Add the following summary section directly below the closing } of the foreach loop. Leave one blank line above it:
Write-Host "`nBulk user creation complete." -ForegroundColor Cyan
Write-Host "Total users processed: $($users.Count)"
Get-ADUser -Filter * -SearchBase $domain -Properties Department |
Where-Object { $_.Enabled -eq $true } |
Select-Object Name, SamAccountName, Department, Enabled |
Format-Table -AutoSize
What does this summary section do?
- The two Write-Host lines print a completion message and the total number of users the script processed.
- The Get-ADUser pipeline queries all enabled users in the domain and displays a summary table. This gives you instant confirmation that the bulk creation worked.
- Save the file by pressing Ctrl+S and close Notepad.
✔️ Awesome, I've got everything!
Great. Double check you've saved New-BulkUsers.ps1 before continuing.
ⓧ I'd like to double check the full code
Your New-BulkUsers.ps1 file should contain three sections in this exact order. Scroll up and confirm each one is present:
- Setup section (comments, $domain, $defaultPassword, and Import-Csv).
- Foreach loop (foreach with New-ADUser, Add-ADGroupMember, and try/catch error handling).
- Summary section (Write-Host messages and the Get-ADUser pipeline with Format-Table).
Run the script and verify the results
Your script is ready. Before you run it, think about what you expect to see. How many green "Created user" messages should appear?
- Navigate to the scripts directory by running:
cd C:\Scripts
- Run the bulk user creation script:
.\New-BulkUsers.ps1
You should see seven green "Created user" messages, one for each row in your CSV. The summary table at the end lists all enabled users across your domain, including both the six you created manually and the seven new ones.
Seeing red error messages?
- If you see a "file cannot be loaded" error about execution policy, run Set-ExecutionPolicy RemoteSigned -Scope CurrentUser and then try running the script again.
- If you see "An attempt was made to add an object to the directory with a name already in use," one of the CSV users has the same SamAccountName as a user you created earlier. The script's try/catch block catches this and continues with the remaining users.
- If you see "Directory object not found" errors, double check the Department column in your CSV matches your OU names exactly (IT, HR, Sales). The names are case-sensitive.
- Help me troubleshoot my bulk user script errors.
- Verify the results by listing the Sales department users with this command:
Get-ADUser -Filter * -SearchBase "OU=Sales,DC=corp,DC=lab" -Properties Department | Select-Object Name, Department, Enabled | Format-Table
You should see your two original Sales users plus the three new bulk-created users (Sarah Johnson, Mike Chen, Lisa Park), all showing Enabled: True.
- Count your total domain users by running:
(Get-ADUser -Filter *).Count
This number includes your six manually created users, seven bulk-created users, plus the built-in accounts (Administrator, Guest, krbtgt). Your domain now has a populated directory from a single script run.
- In Server Manager, click Tools in the top menu bar.
- Select Active Directory Users and Computers.
- Expand corp.lab in the left pane.
- Click on the Sales OU to confirm the bulk-created users appear alongside the original ones.
Why check ADUC after PowerShell already confirmed it?
Real sysadmins cross-verify with the GUI after running scripts. ADUC shows the same directory your script just modified, but from a visual perspective. If a manager asks you to prove the accounts exist, this is the view you show them.
Secret mission
Install and Configure DHCP with Reservations
The hiring manager also called out DHCP and reservations. In this bonus challenge, you install the DHCP Server role on your domain controller, authorize it in Active Directory, create a scope for your lab network, and reserve IP addresses for specific devices by MAC address.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely inside your Hyper-V sandbox, so there are no ongoing cloud costs. Decide whether to keep your sandbox running, pause it to come back later, or reset it entirely.
Resources you used:
- C:\Scripts directory containing employees.csv and New-BulkUsers.ps1.
- corp.lab Active Directory domain with department OUs, user accounts, security groups, and the Corp Security Policy GPO.
- DHCP Server with the CorpLAN scope and IP reservations (Secret Mission).
- Hyper-V sandbox VM running Windows Server 2022 as Domain Controller DC01.
Keep everything running
No action needed. Choose this if you are still actively building or want to practice more Active Directory administration.
- Your sandbox VM stays running with the full domain environment intact.
- All user accounts, OUs, group policies, DHCP configuration, and scripts remain in place for further experimentation.
- The VM continues to use host memory and disk space while running.
Pause - I'll come back to this later
Shut down the VM to free up host memory. Your domain configuration and scripts persist on disk and are ready when you boot the VM again.
- Inside the sandbox VM, open PowerShell and run the following command to shut down cleanly:
Stop-Computer -Force
- The VM releases host memory once it shuts down. All domain data, OUs, users, GPOs, DHCP settings, and scripts are saved to disk.
- When you are ready to resume, start the VM from Hyper-V Manager. Active Directory and DNS start automatically with the server.
Delete - I don't want to use this again
Remove all project resources and start fresh. Since everything lives inside the sandbox VM, deleting or resetting the VM removes the entire domain environment at once.
- If you want to delete just the scripts before resetting, run this command inside the sandbox VM:
Remove-Item -Recurse -Force C:\Scripts
- To remove everything (the domain, all OUs, users, groups, GPOs, and DHCP configuration), delete or reset the sandbox VM from Hyper-V Manager on your host machine.
- In Hyper-V Manager on your host, right-click the sandbox VM, select Turn Off to stop it, then right-click it again and select Delete to remove the VM configuration.
- If your sandbox platform provides a reset option (returning the VM to its original blank state), use that instead of deleting. This lets you reuse the same sandbox for future projects.
Nice Work!
Nice Work!
Nice work! You just built a fully functional Active Directory domain environment from a blank Windows Server 2022 sandbox.
You've learned how to:
- Promoted Windows Server 2022 to a Domain Controller for the corp.lab domain with integrated DNS, then built department OUs populated with user accounts and security groups managed entirely through PowerShell.
- Diagnosed the disabled-accounts gotcha, mastered day-to-day password management workflows (resets, unlocks, disables), and enforced domain-wide security by creating and linking a Group Policy Object with password complexity and account lockout policies.
- Automated bulk user provisioning by writing a PowerShell script that reads a CSV file and creates accounts with correct OU placement, group memberships, and enabled status in seconds.
- Secret Mission: Installed and configured DHCP Server with a scope and IP reservations.
Ready to quiz yourself?