Manage Windows AD with PowerShell


Making Changes

You can modify users of a certain OU with a one-liner so that they all have a certain attribute value, allowing other programs (e.g., AADConnect for synchronization to the cloud) to find and process them:

Get-ADUser -Filter * -SearchBase "OU=Externals,DC=corp,DC=frickelsoft,DC=net" | Set-ADUser -Add @{extensionAttribute4 = "M365"}

An imported CSV file lets you edit multiple users:

Import-CSV 'C:\temp\csv\users.csv' | % { if($_. mail-like '*') { Set-ADUser $_.sAMAccountName -Add @{extensionAttribute4  ="M365"}}}

This command imports a CSV file that contains user definitions and parses it line by line. Two columns in the CSV are inspected more closely: mail and sAMAccountName (Figure 2). If the mail address ends with , extensionAttribute4 of the user in AD is set to M365. Nothing happens for the other users found in the CSV file.

Figure 2: PowerShell parsing users from an Excel or CSV file and editing their accounts in AD.

To transfer the value of the region column to an AD attribute (e.g., preferredDataLocation for Office 365), you need to modify the command

Import-CSV '.\Downloads\users.csv' | % { Set-ADUser -Identity $_.sAMAccountName-Add @{preferredDataLocation  =$_.region }}

to take the cell value from the CSV file instead of using a fixed value.

Managing Special Accounts

Of course, you will not only want to manage normal user accounts, but also accounts belonging to external partners and suppliers or service accounts. You can simply disable accounts that are no longer needed:

Get-ADUser -Identity svc_low_SQL3 | Disable-ADAccount

This method also works with accounts belonging to external identities that are grouped in an OU. To block people or service accounts that have not logged in for 120 days or more, use:

$lastLogonCutOff = (Get-Date). AddDays(-120)
Get-ADUser -Filter { LastLogonDate -lt $lastLogonCutOff -and Enabled -eq $true } -SearchBase "OU=Externals,DC=corp,DC=frickelsoft,DC=net" | Disable-ADAccount

In the best case, the service accounts that you create as normal user accounts and not as group-managed service accounts (gMSA) are restricted to the extent that the logon can only take place on certain machines to avoid misuse. To define this case, use the LogonWorkstations parameter:

Set-ADUser svc_low_SQL3 -LogonWorkstations "SQL3"

This attribute expects a comma-separated list of machine names. For example, you can create a new service account that you want to log on to all SQL servers with:

$sqlServers = Get-ADComputer -Filter "Name -like 'SQL*'" -SearchBase "OU=Servers,OU=Tier1,DC=corp,DC=frickelsoft,DC=net" | SELECT sAMAccountName |%{$_.sAMAccountName.Trim("$")}
$sqlServers = $sqlServers -join ","
Set-ADUser svc_high_SQL3 -LogonWorkstations $sqlServers

If you only want the service account to be valid for a time-limited project, or if the owner of the account is required to come back and renew the account within 90 days at the latest, you can set an expiration date:

Set-ADAccountExpiration -Identity svc_low_SQL3 -TimeSpan 90.00:00:00

You will certainly want to minimize the number of accounts whose passwords never expire. In fact, apart from service accounts, there should be no accounts in AD whose passwords do not expire:

Search-ADAccount -PasswordNeverExpires | Export-CSV C:\temp\csv\neverexpires.csv

Alternatively, you can move these accounts to a group for delegated administration:

Search-ADAccount -PasswordNeverExpires | %{Add-ADGroupMember -Identity "PWDNeverExpires" -Members $_.sAMAccountName }

If you specifically need to harden certain accounts against hijacking and ensure that the passwords used are appropriately complex, you can attach custom password policies to these accounts. For example, with a few lines of PowerShell, you can create a new password settings object that contains custom password policies and assign it to a group of service accounts. First, create the password policy object that enforces manual unlocking and long, complex passwords (Listing 1).

Listing 1

Enforcing Complex Passwords

New-ADFineGrainedPasswordPolicy -Name "HighSecServiceAccountsPolicy" -Precedence 500 -ComplexityEnabled $true -Description "Password Policy for High Sec Service Accts" -DisplayName "High Sec Service Accs PassPolicy" -LockoutDuration "00:00:00" -LockoutObservationWindow "00:00:00" -LockoutThreshold 7 -MinPasswordAge "01:00:00" -PasswordHistoryCount 20 -MinPasswordLength 16

After that, define a new AD group to which you then add the service accounts as members before assigning the policy (Listing 2).

Listing 2

Defining New AD Group

New-ADGroup -Name "High Sec Service Accts" -SamAccountName HighSecSer-viceAccts -GroupCategory Security -GroupScope Global -DisplayName "High Sec Service Accts" -Path "OU=Groups,OU=Service Accounts, DC=corp,DC=frickelsoft,DC=net" -Description "Members of this group are High Security Service Accounts"
Add-ADFineGrainedPasswordPolicySubject -Identity HighSecServiceAccountsPolicy -Subjects 'HighSecServiceAccts'

Finally, search and find the service accounts to be protected in AD:

Get-ADUser -Filter 'DisplayName -like "SVC_HIGH_*"' -SearchBase "OU=Service Accounts,DC= corp,DC=frickelsoft,DC=net" | % { Add-ADGroupMember "High Sec Service Accounts" -Members $_ }

The next time the password is changed, the service accounts – or the admin who resets and changes the passwords – has to comply with the new password policy.

Managing Forests and AD Services

PowerShell lets you inspect the AD service itself, as well as manage the data in the directory. Cmdlets let you create new domain controllers, domains, AD objects, and partitions and inspect existing objects:

$forest = Get-ADForest -Server ""
foreach($domain in $forest.Domains) { Get-ADDomainController -Filter * -Server $Domain }

The following two cmdlets show you the flexible single master operation (FSMO) role holders:

Get-ADForest | SELECT DomainNamingMaster, SchemaMaster
Get -ADDomain -Name | SELECT InfrastructureMaster, PDCEmulator, RIDMaster

The Get-ADDomain and Get-ADForest cmdlets have additional properties that you can use for an inventory or check: The DomainFunctionalLevel can be found in DomainMode for each domain, and the ForestFunctionalLevel is found in ForestMode for forest objects.

If you want to provision devices that have been added to the domain to an Azure AD, you need to configure a hybrid Azure AD join. One step in the configuration is to create the service connection object manually or automatically in the configuration partition of the AD. To check whether the object has been created, use:

configPartition = (Get-ADRootDSE).configurationNamingContext
Get-ADObject -Filter * -SearchBase "LDAP://CN=62a0ff2e-97b9-4513-943f-0d221bd30080,CN=Device Registration Configuration,CN=Services,$($configPartition)"

You can check the AD schema version with PowerShell with:

Get-ADObject (Get-ADRootDSE).schemaNamingContext -Property objectVersion

Output of version 88 means Windows Server 2019, 87 means Windows Server 2016, and 69 means Windows Server 2012 R2.

If you use Exchange, you can find the schema version for Exchange with:

Get-ADObject -Identity "CN=ms-Exch-Schema-Version-Pt,$((Get-ADRootDSE).schemaNamingContext)" -Properties rangeUpper | SELECT rangeUpper

Exchange Server 2019 has version numbers starting from 17000, whereas Exchange version 2016 is in the range of 15317 to 15333.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs

Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>


		<div class=