Windows Server for beginners. Part 13: Managing Active Directory from PowerShell
All parts of the series “Windows Server for beginners”We've been using the ActiveDirectory module since part 4, and so far it has simply been a set of commands that do what their names say. It's time to take it apart as a tool: what it uses to talk to a controller, how its filters work, why -Properties * is a bad habit, and what to do with directory objects that have no dedicated cmdlet. This part is a reference worth coming back to; most of the examples in the following parts will rely on it.
ADWS
The module doesn't speak LDAP. It talks to Active Directory Web Services — the ADWS service on the controller, TCP port 9389, which accepts requests over the WS-Transfer and WS-Enumeration protocols (SOAP over the .NET net.tcp transport) and reads and writes the directory itself. The service appeared in Windows Server 2008 R2 together with the module, and on older controllers it was installed separately as the Active Directory Management Gateway Service.
Three consequences follow. -Server in the module's cmdlets must point to a controller with ADWS running; if the service isn't there or is stopped, the answer is "Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.", and if -Server isn't given and DC Locator found no controller with ADWS, it's "Unable to find a default server with Active Directory Web Services running". The module can't work with LDAP servers that aren't Active Directory (OpenLDAP, 389 Directory Server): for those there are the System.DirectoryServices classes in .NET; AD LDS instances it does serve, they have their own ADWS. And the module's requests aren't visible in an LDAP capture: you have to look at them either on port 9389, where they're encrypted, or through event 1644 on the controller, as in part 5 — inside the controller ADWS still runs an ordinary LDAP search.
PS C:\> Get-Service ADWS | Select-Object Status, StartType # on dc1
Status StartType
------ ---------
Running Automatic
PS C:\> (Get-Command -Module ActiveDirectory).Count
151
PS C:\> Get-Command -Module ActiveDirectory -Noun ADObject, ADServiceAccount, ADAccount, ADUser, ADGroupMember | Group-Object Noun | Sort-Object Count -Descending | Select-Object Count, Name, @{n='Verbs'; e={$_.Group.Verb -join ','}}
Count Name Verbs
----- ---- -----
8 ADObject Get,Move,New,Remove,Rename,Restore,Set,Sync
7 ADServiceAccount Get,Install,New,Remove,Set,Test,Uninstall
4 ADAccount Disable,Enable,Search,Unlock
4 ADUser Get,New,Remove,Set
3 ADGroupMember Add,Get,Remove
Get-Service here was run on the controller itself: in PowerShell 7 it has no -ComputerName parameter, and how to run commands on another server is the subject of the next part. The module in Windows Server 2025 has 151 cmdlets, and the number grows from version to version: older systems have fewer.
The module is installed with the role tools (Install-WindowsFeature RSAT-AD-PowerShell on a server) or with RSAT on a workstation, which part 15 covers. Since Windows Server 2019 and Windows 10 1809 it loads in PowerShell 7 natively — its manifest lists both Desktop and Core in CompatiblePSEditions. On older systems PowerShell 7 loads it through the Windows PowerShell compatibility layer, and objects arrive deserialized; you can turn that mode on explicitly with Import-Module ActiveDirectory -UseWindowsPowerShell.
Identity
Every Get-, Set- and Remove- has an -Identity parameter, the first positional one, and it accepts any of the four names from part 3:
Get-ADUser alice # sAMAccountName
Get-ADUser 'CN=Alice Smith,OU=Sales,OU=Departments,DC=corp,DC=example,DC=com' # DN
Get-ADUser 9c3f1a2b-7d4e-4f60-8a1b-2c3d4e5f6a7b # objectGUID
Get-ADUser S-1-5-21-3623811015-3361044348-30300820-1104 # objectSid
A UPN isn't accepted in -Identity: Get-ADUser alice@corp.example.com answers "Cannot find an object with identity: 'alice@corp.example.com' under: 'DC=corp,DC=example,DC=com'.", while Get-ADUser -Filter 'UserPrincipalName -eq "alice@corp.example.com"' finds the user. For computers -Identity accepts the name both without the dollar sign and with it: Get-ADComputer ws1 and Get-ADComputer 'ws1$' find the same account. And -Identity takes an object from the pipeline, so Get-ADUser alice | Set-ADUser -Title 'Engineer' and Get-ADGroupMember Sales | Disable-ADAccount work without intermediate variables.
Filters
-Filter is the main way to find several objects. Its language looks like PowerShell, but it isn't PowerShell: the module parses the string and translates it into an LDAP filter before sending it.
Get-ADUser -Filter 'Enabled -eq $true -and Department -eq "Sales"'
Get-ADComputer -Filter 'OperatingSystem -like "*Server*" -and Enabled -eq $true'
Get-ADUser -Filter 'PasswordNeverExpires -eq $true'
Get-ADUser -Filter 'LastLogonDate -lt $cutoff' -Properties LastLogonDate
Get-ADGroup -Filter 'GroupScope -eq "Universal"'
Get-ADUser -Filter *
Operators: -eq, -ne, -like, -notlike (with *, no other wildcards), -gt, -ge, -lt, -le, -approx, -and, -or, -not, plus -bor and -band for bit fields and -recursivematch for nested membership. There are no regular expressions: -Filter 'Name -match "smith"' answers "Error parsing query: 'Name -match "smith"' Error Message: 'Operator Not supported: -match' at position: '6'.". Three rules people trip over:
The module looks up variables itself, but not all of them. A filter in single quotes with $cutoff inside works because the module looks the variable up in the caller's scope; a property of the module's own object — $user.SamAccountName on the result of Get-ADUser — works too. A property of a row from Import-Csv or of a hashtable doesn't: -Filter 'SamAccountName -eq $_.Login' in a loop over a CSV answers "Property: 'Login' not found in object of type: 'System.Management.Automation.PSCustomObject'.", and indexes ($list[0]) and expressions ($((Get-Date).AddDays(-90))) aren't parsed at all. It's safer to build the string: -Filter "Name -like '$prefix*'", or to put the value into a plain variable first.
Property names are the module's, not always LDAP's. Enabled and PasswordNeverExpires are computed from userAccountControl, and the module translates them into bitwise LDAP rules. But not every computed property works in a filter: -Filter 'LockedOut -eq $true' answers "Searching on extended attribute 'LockedOut' is not supported with this cmdlet. Use Search-ADAccount instead.", and CannotChangePassword is refused the same way. LastLogonDate is lastLogonTimestamp converted to DateTime; PasswordLastSet is pwdLastSet; Created and Modified are whenCreated and whenChanged. Any LDAP attribute can be written directly too: -Filter 'pwdLastSet -eq 0'.
Complex things go into -LDAPFilter. A search by a FILETIME date, a membership chain, ANR, a bit comparison without a named property — all of this is easier to write as an LDAP filter from part 5 than to coax out of the module's syntax:
Get-ADUser -LDAPFilter '(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=CN=Domain Admins,CN=Users,DC=corp,DC=example,DC=com))'
Get-ADObject -LDAPFilter '(anr=ali)'
Search scope: -SearchBase (the DN to start from; without it, the domain root) and -SearchScope (Base, OneLevel, Subtree). Paging is always on, the page size is -ResultPageSize, 256 by default; -ResultSetSize limits the total number of results when you need "the first ten". ADWS keeps an open enumeration context for no longer than 30 minutes: a very long pipeline that processes each object slowly can break off in the middle, and then the results are collected into a variable first.
Properties
A cmdlet returns not all attributes but a small default set — Get-ADUser returns ten: DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName. Everything else has to be requested:
PS C:\> Get-ADUser alice | Get-Member -MemberType Property | Measure-Object | Select-Object -ExpandProperty Count
10
PS C:\> (Get-ADUser alice -Properties *).PropertyCount
106
PS C:\> Get-ADUser alice -Properties Mail, Department, PasswordLastSet, LastLogonDate, MemberOf | Select-Object Mail, Department, PasswordLastSet, LastLogonDate
Mail Department PasswordLastSet LastLogonDate
---- ---------- --------------- -------------
alice@example.com Sales 10/15/2026 9:30:11 AM 10/15/2026 9:02:11 AM
-Properties * on one object is harmless; on ten thousand it's ten thousand objects with a hundred attributes each, photos and certificates included, over SOAP. The rule: list what you need. The difference is measurable and grows with the domain; on a few thousand accounts it looks like this:
PS C:\> (Measure-Command { Get-ADUser -Filter * -Properties * }).TotalSeconds
14.8
PS C:\> (Measure-Command { Get-ADUser -Filter * -Properties Mail, Department }).TotalSeconds
1.9
Server
Without -Server the module gets a controller from DC Locator — the nearest one in the site with ADWS — and remembers it for the session. With -Server you can name a controller (dc2, dc2.corp.example.com), a domain (corp.example.com — the choice is again Locator's, but within that domain) or a global catalog (corp.example.com:3268 — a search across the whole forest with the partial attribute set).
When this matters. Reading after writing: an object created on dc1 appears on dc2 after 15 seconds, and a script that creates a user with one command and adds it to a group with another can land on different controllers and get "object not found". Scripts that write pin the controller — most often the PDC emulator:
$dc = (Get-ADDomain).PDCEmulator
New-ADUser -Server $dc ...
Add-ADGroupMember -Server $dc ...
Non-replicated attributes: lastLogon and badPwdCount have to be asked of every controller, as in part 5. Lockouts: Search-ADAccount -LockedOut is more reliably asked of the PDC, to which lockouts replicate urgently. And another domain or forest: -Server partner.example.net -Credential (Get-Credential).
Creating and editing
PS C:\> $params = @{
Name = 'Carol White'
GivenName = 'Carol'
Surname = 'White'
SamAccountName = 'carol'
UserPrincipalName = 'carol@corp.example.com'
Path = 'OU=Sales,OU=Departments,DC=corp,DC=example,DC=com'
Department = 'Sales'
AccountPassword = (Read-Host -AsSecureString 'Password')
ChangePasswordAtLogon = $true
Enabled = $true
OtherAttributes = @{ extensionAttribute1 = 'EMP-1042' }
}
PS C:\> New-ADUser @params -PassThru | Select-Object DistinguishedName, Enabled
DistinguishedName Enabled
----------------- -------
CN=Carol White,OU=Sales,OU=Departments,DC=corp,DC=example,DC=com True
A hashtable with @params (splatting) is the standard way to pass two dozen parameters without a line three screens long. -OtherAttributes takes any LDAP attributes that have no named parameter. Without -AccountPassword the account is created disabled, and with -Enabled $true the command fails with "The password does not meet the length, complexity, or history requirement of the domain." and doesn't create the account: an empty password violates the policy.
Bulk creation — from a CSV through the pipeline:
Import-Csv .\users.csv -Encoding UTF8 | ForEach-Object {
New-ADUser -Server $dc -Name "$($_.First) $($_.Last)" -GivenName $_.First -Surname $_.Last -SamAccountName $_.Login `
-UserPrincipalName "$($_.Login)@corp.example.com" -Path $_.OU -Department $_.Dept `
-AccountPassword (ConvertTo-SecureString $_.Password -AsPlainText -Force) -ChangePasswordAtLogon $true -Enabled $true
}
Editing is Set-ADUser with named parameters for common attributes (-Title, -Department, -Manager, -EmailAddress, -Enabled, -PasswordNeverExpires) and four parameters for the rest, the same as Set-ADObject in part 5: -Replace, -Add, -Remove, -Clear:
Set-ADUser carol -Title 'Account Manager' -Manager alice
Set-ADUser carol -Replace @{ extensionAttribute1 = 'EMP-1043'; info = 'Transferred 2026-10' }
Set-ADUser carol -Add @{ otherTelephone = '+1 555 0102' }
Set-ADUser carol -Clear info
Get-ADUser -Filter 'Department -eq "Sales"' | Set-ADUser -Office 'Building A, floor 3'
Moving and renaming are Move-ADObject -TargetPath and Rename-ADObject -NewName (it changes the CN; the logon name is Set-ADUser -SamAccountName). Deleting is Remove-ADUser, which asks for confirmation. Objects protected from accidental deletion first need Set-ADObject -ProtectedFromAccidentalDeletion $false, otherwise the deletion answers "Access is denied."; New-ADOrganizationalUnit protects every OU, so before Remove-ADOrganizationalUnit -Recursive the protection is removed from all nested OUs too: Get-ADOrganizationalUnit -SearchBase $ou -Filter * | Set-ADObject -ProtectedFromAccidentalDeletion $false.
Groups and passwords
Add-ADGroupMember -Identity Sales -Members carol, bob
Add-ADGroupMember -Identity Sales -Members (Get-ADUser -Filter 'Department -eq "Sales"')
Remove-ADGroupMember -Identity Sales -Members bob -Confirm:$false
Get-ADGroupMember -Identity Sales -Recursive | Select-Object Name, ObjectClass
Get-ADPrincipalGroupMembership carol | Select-Object Name, GroupScope
-Members takes a list: adding a hundred users in one call is faster than a hundred calls. The list just has to be uniform: names mixed with the result of Get-ADUser in one call (-Members carol, bob, (Get-ADUser …)) give "Cannot convert 'System.Object[]' to the type 'Microsoft.ActiveDirectory.Management.ADPrincipal' required by parameter 'Members'.". Get-ADGroupMember -Recursive expands nesting, but ADWS has a limit on the response size (5000 members by default, MaxGroupOrMemberEntries in the service configuration; Get-ADPrincipalGroupMembership has the same limit); for larger groups the member attribute is read directly: (Get-ADGroup Sales -Properties member).member. For "which groups is this user in, nested ones included" there's tokenGroups from part 5 or an LDAP filter with a chain.
Passwords and states:
Set-ADAccountPassword carol -Reset -NewPassword (Read-Host -AsSecureString) # reset without knowing the old one
Set-ADAccountPassword carol -OldPassword $old -NewPassword $new # change knowing the old one: the user's own right
Set-ADUser carol -ChangePasswordAtLogon $true
Unlock-ADAccount carol
Disable-ADAccount carol; Enable-ADAccount carol
Search-ADAccount -LockedOut | Select-Object Name, LockedOut, LastLogonDate
Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly | Select-Object Name, LastLogonDate
Search-ADAccount -PasswordExpired
Search-ADAccount -AccountExpiring -TimeSpan 7.00:00:00
A change with -OldPassword is subject to the whole password policy: before the minimum password age has passed, the server rejects it with the same error as a weak password — "The password does not meet the length, complexity, or history requirement of the domain.".
Search-ADAccount is the cmdlet for questions like "who is locked out, who hasn't logged on for three months, whose password has expired", and it covers what you'd otherwise have to write as FILETIME filters; -AccountInactive counts as inactive those who have never logged on, too — their LastLogonDate is empty. The domain password policy is Get-ADDefaultDomainPasswordPolicy; fine-grained policies for specific groups (stricter for administrators, softer for service accounts) are New-ADFineGrainedPasswordPolicy with a precedence and Add-ADFineGrainedPasswordPolicySubject; what finally applies to a user is Get-ADUserResultantPasswordPolicy carol. If no fine-grained policy applies to the user, this command outputs nothing: the domain policy applies.
The AD: drive
The module adds a provider, and the directory becomes a file system:
PS C:\> Set-Location 'AD:\DC=corp,DC=example,DC=com'
PS AD:\DC=corp,DC=example,DC=com> Get-ChildItem | Select-Object Name, ObjectClass
Name ObjectClass
---- -----------
Builtin builtinDomain
Computers container
Departments organizationalUnit
Domain Controllers organizationalUnit
...
PS AD:\DC=corp,DC=example,DC=com> Get-ItemProperty 'OU=Sales,OU=Departments' -Name description, whenCreated
Paths are DNs; the root of the drive, Set-Location AD:\, shows the partitions: the domain, Configuration, Schema, ForestDnsZones and DomainDnsZones. The main use of the provider is **permissions**: Get-Acl and Set-Acl work with the security descriptors of directory objects, and delegation is done through them. Delegating password resets in a branch OU to the Branch Admins group:
PS C:\> $ou = 'AD:\OU=Branch,OU=Departments,DC=corp,DC=example,DC=com'
PS C:\> $acl = Get-Acl $ou
PS C:\> $sid = (Get-ADGroup 'Branch Admins').SID
PS C:\> $resetPassword = [Guid]'00299570-246d-11d0-a768-00aa006e0529' # Reset Password extended right
PS C:\> $userClass = [Guid]'bf967aba-0de6-11d0-a285-00aa003049e2' # user class
PS C:\> $acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule($sid, 'ExtendedRight', 'Allow', $resetPassword, 'Descendents', $userClass)))
PS C:\> Set-Acl $ou -AclObject $acl
PS C:\> (Get-Acl $ou).Access | Where-Object IdentityReference -like '*Branch Admins*' | Select-Object ActiveDirectoryRights, ObjectType, InheritanceType
ActiveDirectoryRights ObjectType InheritanceType
--------------------- ---------- ---------------
ExtendedRight 00299570-246d-11d0-a768-00aa006e0529 Descendents
The GUIDs of extended rights live in CN=Extended-Rights,CN=Configuration (the rightsGuid attribute), the GUIDs of classes and attributes in the schema (schemaIDGUID). This is the same operation as the Delegation of Control wizard in the snap-in, and the same result as dsacls "OU=Branch,…" /I:S /G "CORP\Branch Admins:CA;Reset Password;user", only reproducible.
Get-ADObject
Users, computers, groups, OUs, controllers, sites, subnets, site links, trusts, password policies and managed accounts have cmdlets of their own in the module. For everything else there are Get-ADObject, New-ADObject, Set-ADObject and Remove-ADObject, which work with any class by DN and filter:
Get-ADObject -SearchBase 'CN=Policies,CN=System,DC=corp,DC=example,DC=com' -Filter 'objectClass -eq "groupPolicyContainer"' -Properties displayName, versionNumber
Get-ADObject -SearchBase (Get-ADRootDSE).configurationNamingContext -LDAPFilter '(objectClass=nTDSDSA)' -Properties options # NTDS Settings objects of all controllers
Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -Filter 'lDAPDisplayName -eq "mail"' -Properties *
New-ADObject -Name 'Printers' -Type container -Path 'OU=Branch,OU=Departments,DC=corp,DC=example,DC=com'
Get-ADObject -Filter 'isDeleted -eq $true -and Name -like "Bob*"' -IncludeDeletedObjects | Restore-ADObject
The last line is a restore from the AD Recycle Bin from part 5: the deleted object returns to its former place with all its attributes and memberships. Restore-ADObject -TargetPath puts it into another container if the old one is gone.
Managed service accounts
In part 6 SQL Server ran as svc-sql with a password that somebody knows and that never changes. The module can do better: group managed service accounts (gMSA, Windows Server 2012): a 240-byte password is generated and changed every 30 days by the controller itself, and only the computers allowed to can retrieve it. No human ever knows the password.
PS C:\> Add-KdsRootKey -EffectiveImmediately # once per forest; the Key Distribution Service root key (Kds module)
PS C:\> New-ADServiceAccount -Name svc-web -DNSHostName svc-web.corp.example.com -PrincipalsAllowedToRetrieveManagedPassword web1$ -ServicePrincipalNames 'HTTP/web.corp.example.com'
PS C:\> Install-ADServiceAccount svc-web # on web1
PS C:\> Test-ADServiceAccount svc-web # on web1
True
-EffectiveImmediately makes the key effective at once only on the controller where it was created: the others get it through replication, and controllers wait up to 10 hours from the key's creation before working with gMSAs — a margin for that replication. In a lab with a single controller the date is set in the past: Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)). After that a service, an IIS pool or a scheduled task is run as CORP\svc-web$ with an empty password, and web1 gets the current password from the controller by itself. An SPN on a gMSA is registered the same way as on an ordinary account, and everything from the Kerberos part works unchanged.
How not to bring a controller down
A controller serves the module's requests on a par with user logons. A few rules that separate an administrator's script from an incident:
- Filter on the server, not in PowerShell.
Get-ADUser -Filter * | Where-Object Department -eq Salespulls the whole domain to keep forty people;-Filter 'Department -eq "Sales"'returns forty. Indexed attributes (sAMAccountName,objectGUID,objectSid,displayName,mail,userPrincipalName, anything with bit 1 insearchFlags) are fast; a search with a leading wildcard (-like "*smith") on a non-indexed attribute walks through every object, and event 1644 from part 5 will show it. -Propertiesas a list, not*.- Write operations on one controller, with
-Server. -WhatIfbefore a bulkSet-orRemove-:Get-ADUser -Filter 'Department -eq "Sales"' | Remove-ADUser -WhatIfprints what would be deleted, and it's the only way to find out there's a typo in the filter before it takes effect.- Run as an ordinary account with
-Credentialfor privileged commands, rather than as a domain admin all day: the password is asked once in$cred = Get-Credential, and then-Credential $credwherever rights are needed.
Looking with our own eyes
What the module sends and where:
PS C:\> Get-ADUser carol | Out-Null
PS C:\> Get-NetTCPConnection -RemotePort 9389 | Select-Object LocalAddress, RemoteAddress, State, OwningProcess
LocalAddress RemoteAddress State OwningProcess
------------ ------------- ----- -------------
192.168.1.100 192.168.1.10 Established 5124
192.168.1.100 192.168.1.10 Established 5124
192.168.1.100 192.168.1.10 Established 5124
192.168.1.100 192.168.1.10 Established 5124
Four connections to dc1 on 9389 from the PowerShell process: the module opens them on the first command and reuses them — after more Get-ADUser calls in the same session the same four remain, with the same local ports. In Wireshark this is .NET Message Framing over TCP with Negotiate authentication — SOAP inside, and you can't read it in a capture. On the other hand, on a controller with event 1644 enabled you can see the LDAP query the filter turned into:
Filter:
( & (objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=corp,DC=example,DC=com) (objectClass=user) (department=Sales) )
Search scope:
subtree
Attribute selection:
distinguishedName,name,objectClass,objectGUID,objectSid,sAMAccountName,userPrincipalName,givenName,sn,userAccountControl,department
The module added objectCategory=person and objectClass=user by itself — that's exactly why Get-ADUser doesn't return computers, even though the computer class inherits from user. It also shows that -Properties Department became one attribute in the request's list, not all of them.
What comes back:
PS C:\> Get-ADUser carol | Get-Member | Select-Object -First 4 TypeName, Name, MemberType
TypeName Name MemberType
-------- ---- ----------
Microsoft.ActiveDirectory.Management.ADUser Contains Method
Microsoft.ActiveDirectory.Management.ADUser Equals Method
Microsoft.ActiveDirectory.Management.ADUser GetEnumerator Method
Microsoft.ActiveDirectory.Management.ADUser GetHashCode Method
ADUser is an object with a dictionary of attributes inside: $u.Department returns the attribute's value, $u['department'] the same value in an ADPropertyValueCollection (for multi-valued attributes that collection holds the whole list), and $u.PropertyNames lists everything that was requested. ADUser and ADComputer inherit from ADAccount, which together with ADGroup inherits from ADPrincipal, and all of them and ADOrganizationalUnit inherit from the common ADObject; that's why any of them can be passed to Set-ADObject or Move-ADObject.
And finally, a script example that puts it all together: a report on inactive users with the last logon across all controllers, without -Properties *, with the filter on the server:
$dcs = (Get-ADDomainController -Filter *).HostName
$cutoff = (Get-Date).AddDays(-90)
Get-ADUser -Filter 'Enabled -eq $true -and LastLogonDate -lt $cutoff' -Properties LastLogonDate, Department |
ForEach-Object {
$u = $_
$last = ($dcs | ForEach-Object { (Get-ADUser $u -Server $_ -Properties lastLogon).lastLogon } | Measure-Object -Maximum).Maximum
[PSCustomObject]@{ Name = $u.Name; Department = $u.Department; LastLogon = [DateTime]::FromFileTime($last) }
} | Sort-Object LastLogon | Export-Csv .\inactive.csv -NoTypeInformation -Encoding UTF8
The first filter cuts by the replicated LastLogonDate, accurate to two weeks, and only for the remaining accounts does the script ask each controller for the exact lastLogon. Accounts that have never logged on won't make it into the report: they have no lastLogonTimestamp attribute, and in LDAP a comparison with a missing attribute is false. They're found separately — Get-ADUser -Filter 'LastLogonDate -notlike "*"' — or with Search-ADAccount -AccountInactive, which includes them.
Sources
- ActiveDirectory module — the reference for all the module's cmdlets;
- Active Directory Web Services — the ADWS service, port 9389, the Active Directory Management Gateway Service and the service parameters:
MaxGroupOrMemberEntries,MaxEnumContextExpiration; - MS-ADDM: Endpoints and MC-NMF: .NET Message Framing Protocol — ADWS endpoints, the net.tcp binding and the frame format in a capture;
- PowerShell 7 module compatibility — the ActiveDirectory module works in PowerShell 7 natively since Windows Server 2019 and Windows 10 1809;
- about_ActiveDirectory_Filter and Get-ADUser — the
-Filterlanguage, operators and their LDAP equivalents,-Identityforms,-ResultPageSize,-SearchBase,-Server; - Search Filter Syntax — LDAP filters and the
LDAP_MATCHING_RULE_IN_CHAINrule; - Last-Logon-Timestamp and Search-Flags — where
LastLogonDatecomes from and how an attribute becomes indexed; - New-ADUser, Set-ADUser, Remove-ADOrganizationalUnit and about_Splatting — creating and editing accounts, protection from deletion, passing parameters as a hashtable;
- Add-ADGroupMember, Get-ADGroupMember and Get-ADPrincipalGroupMembership — group membership;
- Set-ADAccountPassword, Search-ADAccount, New-ADFineGrainedPasswordPolicy and Get-ADUserResultantPasswordPolicy — passwords, finding accounts by state, fine-grained policies;
- ActiveDirectoryAccessRule, Reset Password, User class and Dsacls — the access rule, the GUIDs of the extended right and of the class, the same result through
dsacls; - Get-ADObject, Restore-ADObject and Active Directory Recycle Bin — objects of any class and restoring deleted ones;
- Group Managed Service Accounts overview, Secure group managed service accounts, Create a Key Distribution Service (KDS) Root Key and New-ADServiceAccount — gMSA, the password length and change interval, the KDS root key and its 10 hours;
- Use Event1644Reader.ps1 to analyze LDAP query performance — event 1644 and expensive queries;
- Get-NetTCPConnection — connections to ADWS.
We ran everything in this part from a workstation, and the module found a controller and knew how to reach it on its own. The other modules — DnsServer, DhcpServer, Storage, NetTCPIP — have no built-in transport: their -ComputerName and -CimSession go through WinRM, and an ordinary Get-Process or Restart-Service on another server can't be run without it at all.
Next — part 14: WinRM and PowerShell Remoting. What WS-Management is and how a listener works; Enable-PSRemoting and what it really changes; Enter-PSSession and Invoke-Command, sessions and parallel execution on dozens of servers; Kerberos authentication and why TrustedHosts is needed outside a domain; an HTTPS listener with a certificate; the second hop problem and its solutions; and JEA — endpoints where only permitted commands can be run.
Only registered users can leave a comment.
Sign in or register to leave a comment.