<< A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

–A–

access not authorized – see permissions, not authorized

active directory users, save to CSV

Get-ADUser -Filter {mail -like "*" -and enabled -eq "true" -and Surname -like "*"} | Select-Object GivenName, Surname, Name, UserPrincipalName | Export-Csv documents\ADusers4.csv

Notice this only gets users with

ACL, set

I’ve never gotten this to work. Always claims "Attempted to perform an unauthorized operation" on the last line where Set-Acl. Even though I can perform the same task through the GUI front end.

$path = "\\fs.jiminy.org\cricket"
$CurrentAcl = Get-Acl -Path $path
$fileSystemRights = "Modify"
$type = "Allow"
foreach ($identity in $users) {
    # Create new rule
    $ruleArgumentList = $identity, $fileSystemRights,"ContainerInherit, ObjectInherit", "None", $type # I think you can omit the 3rd & 4th arguments altogether to where you only supply 3 arguments
    $rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $ruleArgumentList
    # Apply new rule
    $CurrentAcl.AddAccessRule($rule)
    Set-Acl -Path $path -AclObject $CurrentAcl
}

Same error if I try $CurrentAcl.SetAccessRule($rule) instead of $CurrentAcl.AddAccessRule($rule)

“Account is sensitive and cannot be delegated”

Get-ADUser -Filter {UserAccountControl -band 0x100000} # 1048576 NOT_DELEGATED

or perhaps you have a variable $someADUsers with a bunch of Users and you want to find all users who have the NOT_DELEGATED (“Account is sensitive and cannot be delegated”) attribute

$notDelegated = $someADUsers | ? {($_.userAccountControl -band 0x100000) -eq 0x100000} # 1048576

set

$user | Set-ADAccountControl -AccountNotDelegated:$true

add property for a user – see user, update property

attribute changed last for a user – see property changed last for a user

–B–

–C–

carriage return, insert into info field for a user – see info field, insert line breaks

catch user not found – see user not found, catch, user exists or not?

change user property – see user, update property, property changed last for a user

clustered servers, list

$clusters = Get-Cluster -Domain gondor
$clusters.count
$clusters | ogv

Code above lists the clusters, but no detail on what servers comprise each cluster. For more detail on the servers comprising each cluster:

$i=0; $count = $clusters.Count
$result = @()
foreach ($cluster in $clusters) {
    $i++; $percentTxt = ($i/$count).ToString("P")
    try {
        $clusterNodes = Get-ClusterNode -cluster $cluster -ErrorAction Stop
        Write-Host "$i of $($count) ($percentTxt):$cluster - good" -ForegroundColor Green
        foreach ($clusterNode in $clusterNodes) {
            $result += New-Object -TypeName PSObject -Property @{
                cluster = $cluster
                nodeName = $clusterNode.Name
                nodeState = $clusterNode.State}
        }
    }
    catch {
        $msg = $error[0].ToString()
        $msg2 = "$cluster - $msg"
        Write-Host "$i of $($count) ($percentTxt):$msg2" -ForegroundColor Blue
        if ($msg -like "*unavailable*") {$nodeState = "unavailable"}
        elseif ($msg -like "*administrative privileges*") {$nodeState = "permission problem"}
        else {$nodeState = "unknown problem"}
        $result += New-Object -TypeName PSObject -Property @{
            cluster = $cluster
            nodeName $msg
            nodeState = $nodeState}
    }
}
$result | select cluster, nodeName, nodeState| ogv

Code above assumes you’ll run into problems such as not

But this gives at least some accounting.

common name, extract from DistinguishedName – see also OU, extract from DistinguishedName

one line

$cn = ($distinguishedName -split "(?<!\\)," | ? {$_ -match "^cn="}) -replace "cn=", ""

or

Get-ADOrganizationalUnit -Filter * | select @{n="cn";e={$cn = $_.DistinguishedName -split "(?<!\\)," | ? {$_ -match "^cn="}; ($cn | % {$_ -replace "cn=", ""}) -join "\"}}

The regular expression"(?<!\\)," is used to split a string by commas "(,)" but not when a comma is preceded by a backslash "(\)". See OU, extract from DistinguishedName for a breakdown of how this regular expression works

compare AD group membership between two users - see group membership between two users, compare

computers, list – see also computers from another domain, list

$computers = Get-ADComputer -Filter * -Properties Name, CN, IPv4Address, Enabled, OperatingSystem, OperatingSystemServicePack, OperatingSystemVersion , LastLogonDate, LogonCount, whenCreated, DNSHostName
$i=0; $count = $computers.Count
foreach ($computer in $computers) {
    $i++ ; $percentTxt = ($i/$count).ToString("P")
    # extract OU from DistinguishedName
    $OUnodes = $computer.DistinguishedName -split "," | ? {$_ -like "OU=*"} | % {$_ -replace "OU=", ""}
    if ($OUnodes.Count -gt 0) { # Check if any OUs were found and reverse the order, concatenating them with "\"
        [array]::Reverse($OUnodes)
        $OU = $OUnodes -join "\"
    } else { # Handle the case where the computer is in the "Computers" container
        $OU = "Computers"
    }
    Write-Host "$i of $($count) ($percentTxt): '$($OU)' OU has computer '$($computer.Name)'" -ForegroundColor Green
    $computer.PSObject.Properties.Add([PSNoteProperty]::new("OU", $OU))
    # keep below if you care whether online, otherwise delete
    if (Test-Connection -count 1 -computer $computer.Name -quiet){
        Write-Host "$($computer.Name) online, last logged in $($computer.LastLogonDate)" -ForegroundColor Green
        $computers | Add-Member NoteProperty -Name "OnOrOff" -Value "on"
    }
    else {
        Write-Host "$($computer.Name) offline, last logged in $($computer.LastLogonDate)" -ForegroundColor Red
        $computers | Add-Member NoteProperty -Name "OnOrOff" -Value "off"
    }
    # keep above if you care whether online, otherwise delete #>
}
$computers | sort OU, Name | select OU, Name, enabled, DistinguishedName, OperatingSystem, OperatingSystemVersion, LastLogonDate, LogonCount, whenCreated, IPv4Address, DisplayName, DNSHostName, onOrOff | ogv

Caveat: treat the "LastLogonDate" with a grain of salt. It’s possible a laptop mostly lives behind a Wi-Fi router whose DNS entries only include those for a local ISP but don’t include entries for any of your DCs - which means it can’t find your DCs.

computers from another domain, list

$dc = Get-ADDomainController -DomainName galaxyfar.faraway.com -Discover -NextClosestSite
$computersOtherDomain = Get-ADComputer -Server $dc.HostName[0] -property networkAddress, IPv4Address, CN -Filter * | select CN , SamAccountName, networkAddress, IPv4Address

computers recently deleted, show from recycle bin - see recycle bin, show recently deleted computers

connectivity to a bunch of PCs in an OU, test

Get-ADComputer -Filter * -Server ad11 -SearchBase "OU=IT,OU=yourOU,DC=yourDomain,DC=com" | Where {Test-Connection $_.Name -count 1 -Quiet} | Select @{Name = "Computername";Expression ={$_.Name}}

contacts, list alongside users

This example combines contacts and users, sorting by OU, name

Get-ADObject -Filter {(objectclass -eq "contact" ) -or (objectclass -eq "user")} -Properties ObjectClass, Name, canonicalname | Where-Object {$_.ObjectClass -eq "user" -or $_.ObjectClass -eq "contact"} | sort name | select name, @{Label = "OU";Expression = {($_.canonicalname -Split "/")[-2]}}, ObjectClass | sort OU, name | ft

Must we specify users and contacts twice? Once in the -Filter and then again in the Where-Object? Isn’t that redundant? You would think so. But if I don’t specify Where-Object, I also get computers thrown in along with contacts and users. Not sure why.

contacts, create from CSV

This example includes processing a language column which has special characters

$UserDomain = "yourDomain.com"
$OU = "OU=YourOU,DC=yourDomain,DC=com"
$dir = [environment]::getfolderpath("mydocuments") + "\"
$fileSuffix = ".csv"
$fileBase = "someFileName"
$file = $dir + $fileBase + $fileSuffix
$fileUTF8 = $dir + $fileBase + "_utf8" + $fileSuffix
$i = 0
# to get special foreign characters, we must go through this bass-ackwards way of import/export/import below
# See https://www.ilikesharepoint.de/2015/02/powershell-import-data-from-csv-with-special-characters/
#Convert CSV to UTF-8 with special characters
Get-Content $file | Out-File $fileUTF8 -Encoding utf8
# Only now can we import using Unicode
$csv = Import-CSV $fileUTF8 -Encoding Unicode
foreach($item in $csv)
{
    $i++
    if (($null -eq $item.LastName) -or ($item.LastName -eq '')){break} # some files have lots of empty junk rows at the end
    $FirstName = $item.FirstName
    $LastName = $item.LastName
    $Email = $item.Email
    $displayName = "$FirstName $LastName"
    $UserName = "$FirstName $LastName"
    if ((Get-ADObject -LDAPFilter "(mail=*$Email)") -or (Get-ADObject -LDAPFilter "(displayName=*$displayName)"))
    {
        if (($null -eq $Email) -or ('' -eq $Email))
        {
           Write-Warning "$i contact for $displayName has no email at all.  So we won’t create a contact for him."
        }
        else
        {
           Write-Warning "$i contact for $displayName ($Email) already exists"
        }
    }
    else
    {
        "$i contact for $displayName  ($Email) doesn’t exist, will create"
        $sAMAccountName = "$FirstName.$LastName"
        $localProxyEmail = "$sAMAccountName@$UserDomain"
        if ($item.Language -eq "Français"){"language is French for $displayName"; $language="fr-BE"}
        elseif ($item.Language -eq "Néerlandais"){"language is Netherlands for $displayName"; $language="nl-NL"}
        Else {"no language ($($item.Language) for $displayName, default to Netherlands"; $language = "nl-NL"}
        $proxyAddresses = @("SMTP:$Email","smtp:$localProxyEmail") # this first array will be included in the "other attributes" array below
        $OtherAttributes = @{
           'displayName'=$displayName
           'mail'=$item.Email
           'proxyAddresses'=$proxyAddresses
           'givenName'=$item.FirstName
           'sn'=$item.LastName
             'c'='BE'
           'Title'=$item.JobTitle
           'company' = "Your Company"
           'language' = $language}
        $NewContactParams = @{
           'Type' = "Contact"
           'Name' = $UserName
           'OtherAttributes' = $OtherAttributes
           'Path' = "$OU"}
        New-ADObject @NewContactParams
    }
 }

contacts, list

Get-ADObject -filter {objectclass -eq "contact"}

contacts, show for a group - see group members, show

contacts, list all for an OU - see OU, list all contacts for an OU

contact, set property of - unlike users, many properties don’t already exist. Instead, you must explicitly add them. For example, you can’t simply set a language to a user who doesn’t already have one specified:

update just one contact

Get-ADObject -LDAPFilter "(displayName=Jack Smith)" -Properties name, language | Set-ADObject -language "fr-BE"

because it will fail with

Set-ADObject : A parameter cannot be found that matches parameter name 'language'.

even though it looks like there’s an empty slot for it all ready to be filled when you look at it in something like ADUC. Instead of trying to modify a property you think ought to already exist, explicitly add it instead. It will probably work better:

Get-ADObject -LDAPFilter "(displayName= Jack Smith)" -Properties name, language | Set-ADObject -Add @{language='fr-BE'}

update bulk contacts

if you want to update a whole bunch of contacts at once, make sure to include distinguishedName in the properties:

$contacts = Get-ADObject -filter {objectclass -eq "contact"} `
    -Properties distinguishedName, name, givenName, sn, mail, displayName, co, c, countryCode | `
    where-object {$_.distinguishedName -like "*OU=yourOU*"} | `
    Select-Object @{n="Dom";e={$_.mail.split("@")[1]}}, distinguishedName, name, givenName, sn, mail, displayName, company, co, c, countryCode | `
    Sort-Object Dom, sn, givenName

refer to each contact by distinguishedName as you Set-ADObject:

$contacts | % {Set-ADObject $_.distinguishedName -Add @{countryCode=56}}

verify by re-running the query above to re-populate the $contacts variable and then:

$contacts | ogv

country code, update – see also user, update property

assume you want to update the country code for all users in any OU that contains the string UK to GB (only if it’s not already GB)

Get-ADUser -filter * -Properties name, givenName, middleName, sn, mail, co, c, country  | `
    where-object {($_.distinguishedname -like "*UK*") -and ($_.c -ne "GB")} | % {Set-ADUser -Identity $_ -replace @{c="GB"}}

verify

Get-ADUser -filter * -Properties name, givenName, middleName, sn, mail, co, c, country | `
  where-object {$_.distinguishedname -like "*UK*"} | Sort-Object co, sn, givenName | select name, co, c, country, givenName, middleName, sn, mail | ft

create user - see user, create

cross over to another domain to find info or do stuff – see domain, foreign

–D–

deleted computers - see recycle bin, show recently deleted computers

delete group member from group, see group member, delete

directory permissions, do child folders have permissions parent directory does not? – see folder identity permissions, do any child folders have identity permissions the parent does not?

disable user

$ID = "houdini"
(Get-ADUser -Identity $ID).enabled
Disable-ADAccount -Identity $ID
Enable-ADAccount -Identity $ID

display name, find user by - see user, find by DisplayName

distinct file permissions within folder – See permissions, unique file permissions in a folder

distinguishedName, extract common name from – see common name, extract from DistinguishedName

distinguishedName, extract OU from – see OU, extract from DistinguishedName, also see common name, extract from DistinguishedName

distribution group, count how many in see group, count how many in

distribution group, show members - see group members, show

distribution group, find

find by name

Get-ADGroup -Filter { (GroupCategory -eq "Distribution") -and (Name -like "Accounting*")} -Properties name, mail, distinguishedName | ft name, mail, distinguishedName

or, to find distribution group corresponding to a certain email

Get-ADGroup -Filter {(GroupCategory -eq "Distribution") -and (mail -like "Accounting*")} -Properties name, mail, distinguishedName | ft name, mail, distinguishedName

DNS name servers, list - see domain name servers, list

does a user exist - see user exists or not?

domain administrators, list

list domain admins …

$DomainAdmins = Get-ADGroupMember -Server "dc1.hardknocks.edu" -Identity "Domain Admins" -Recursive

… and go further to expand each user to get selected attributes for each user

$users = @()
foreach ($member in $DomainAdmins) {
    $user = Get-ADUser $member -Properties DisplayName, Name, CanonicalName, Department, Description, Created, whenChanged, LastLogonDate, PasswordLastSet, PasswordNeverExpires PasswordNotRequired, Enabled, extensionAttribute2
    $CanonicalName = $user.CanonicalName
    $domain, $contentArray = $CanonicalName -split "/"
    $content = ($replace | % {$contentArray}) -join '/'
    $content.Split("/")[-1]
    $OU = $content.Substring(0,$content.Length-$content.Split("/")[-1].Length-1)
    $users += New-Object -TypeName PSObject -Property @{
        DisplayName = $user.DisplayName
        Name = $user.Name
        OU = $OU
        Department = $user.Department
        Description = $user.Description
        Created = $user.Created
        Changed = $user.whenChanged
        LastLogon = $user.LastLogonDate
        PasswdLastSet = $user.PasswordLastSet
        NeverExpires = $user.PasswordNeverExpires
        PasswdNotReqd = $user.PasswordNotRequired
        Enabled = $user.Enabled
        extAttr2 = $user.extensionAttribute2
    }
}
$users = $users | sort DisplayName | select DisplayName, Name, OU, Department, Description, Created, Changed, LastLogon, PasswdLastSet, NeverExpires, PasswdNotReqd, Enabled, extAttr2
$users | ogv
$users| Export-CSV -Path "DomainControllers$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -NoTypeInformation -Encoding UTF8

domain controller, nearest

(Get-ADDomainController -Discover).Hostname

or

$DC = Get-ADDomainController -Discover

$DCName = $DC.Hostname

write-host $DCName

domain computers, list all - see computers, list

domain controller, replicate - see also domain replication status

Repadmin /replicate $Destination $Source 'dc=yourDomain,dc=com'

or

Repadmin /replicate "DC1" "DC2" 'dc=yourDomain,dc=com'

to replicate all DCs:

(Get-ADDomainController -Filter *).Name | Foreach-Object {repadmin /syncall $_ (Get-ADDomain).DistinguishedName /e /A | Out-Null}; Start-Sleep 10; Get-ADReplicationPartnerMetadata -Target "$env:userdnsdomain" -Scope Domain | Select-Object Server, LastReplicationSuccess

To replicate from one DC (DC1 below) to all its replication partners

Repadmin /syncall DC1

The Repadmin command above isn’t really a PowerShell command and for some reason, doesn’t always work for me - even from the old CMD prompt. Unfortunately, there isn’t really any single PowerShell command that does this. Someone did, however, write a script (module, actually) to do this: SyncADAdmin Note: this is a module which really should be imported and then invoked. To use, navigate to the directory where you put this:

Import-Module .\Sync-ADDomain.psm1
Sync-ADDomain

See recent syncs:

Get-ADReplicationPartnerMetadata -Target DC1,DC2 | select-object Server, LastReplicationAttempt, LastReplicationSuccess, partner | out-gridview

domain controllers, list all for domain you’re in

$DomainName = (Get-ADDomain).DNSRoot
$DCList = Get-ADDomainController -Filter * -Server $DomainName | sort HostName

domain, cross to another – see domain, foreign

domain, delete group member belonging to one domain from group belonging to another domain, see delete a member belonging to one domain from a group belonging to another domain,. Especially if you get an error like:

ResourceUnavailable: (be9adff36-ffec-4bdb-9f4b-add78fc78dab:ADGroup)

domain, foreign – see

computers from another domain, list

delete a member belonging to one domain from a group belonging to another domain

user, get from another domain

group members, show including any members belonging to a domain other than our default, local domain

domain name servers, list

Resolve-DnsName -Name yourDomain.com -Type NS -DnsOnly

or

Get-DnsServerResourceRecord -ComputerName someDC -ZoneName yourDomain.com -RRType NS

Haven’t had any luck filtering on the name (to feed into a piped command). This works to display.

Get-DnsServerResourceRecord -ComputerName ad11 -ZoneName yourDomain.com-RRType NS | %{$_.RecordData.NameServer}

But if I try to filter on a specific server value that’s displayed by the command above, no records returned

Get-DnsServerResourceRecord -ComputerName ad11 -ZoneName yourDomain.com-RRType NS | ?{$_.RecordData.NameServer-eq"someDC.yourDomain"}

According to this, Only zonename and zonescope are valid optional parameters when using pipeline.

domain replication status - see also domain controller, replicate

Get-ADReplicationPartnerMetadata -Target * -Partition * | Select-Object Server,@{Label = "Partnr";Expression = {(($_.Partner -Split ",")[1] -Split "=")[1]}},PartnerType,Partition,ConsecutiveReplicationFailures,LastReplicationAttempt, LastReplicationSuccess,LastReplicationResult | ogv

just to find errors

Get-ADReplicationPartnerMetadata -Target * -Partition * | ?{($_.ConsecutiveReplicationFailures -gt 0)} | Select-Object Server,@{Label = "Partnr";Expression = {(($_.Partner -Split ",")[1] -Split "=")[1]}},PartnerType,Partition,ConsecutiveReplicationFailures,LastReplicationAttempt,LastReplicationSuccess,LastReplicationResult | ogv

shorter & sweeter and also shows elapsed time since last success

repadmin /replsum

which is short version of

repadmin /replsummary

failure count, first failure time and error code for one particular DC

Get-ADReplicationFailure someDCServer

forest-wide replication health report - puts results into a sortable, filterable grid view. You can also hide columns. I often hide Destination DSA Site, showrepl_COLUMNS, Source DSA Site, Transport Type.

Repadmin /showrepl * /csv | ConvertFrom-Csv | Out-GridView

this shows a little more detail like the last time. Or this:

Repadmin /showrepl * /csv | ConvertFrom-Csv | select "Source DSA", "Destination DSA", "Last Success Time", "Number of Failures", "Last Failure Time", "Last Failure Status" | sort @{expression="Source DSA";Ascending=$true}, @{expression="Destination DSA";Ascending=$true}, @{expression="Last Success Time";Descending=$true}, @{expression="LastReplicationSuccess";Descending=$true} | ogv

I don’t think this command works anymore:

repadmin /showreps

domain, which one you are in

$DomainName = (Get-ADDomain).DNSRoot

domains in a forest, list – see forest domains, list

–E–

email, find AD Object using - see

employeeType, add – see also user, update property

find users whose title does not contain the word "contractor" and make their employeeType = "employee"

Get-ADUser -SearchBase "OU=yourOU,DC=yourDomain,DC=com" `
    -Filter '(title -ne "*") -and (title -notlike "*contractor*")' -SearchScope OneLevel | `
 &   Set-ADUser -Add @{employeeType='employee'}

contacts in an OU

Get-ADObject -filter {objectclass -eq "contact"} `
    -SearchBase "OU=yourOU,DC=yourDomain,DC=com" `
    -SearchScope OneLevel | `
    Set-ADObject -Add @{employeeType='employee'}

enable user – see disable user

error, access not authorized – see permissions, not authorized

exist, does a user exist - see user exists or not?, groups, delete several in an array but check if they exist first

exist, does a group exist - see groups, delete several in an array but check if they exist first

–F–

filter users – see also user, find by display name wildcard, userAccountControl, filter by

Get-ADUser -Filter {employeeType -eq "tst"}

recently created users

$when = $((Get-Date).Date.AddHours(-8))
Get-ADUser -Filter {whenCreated -ge $when} -Properties whenCreated

handle checking for nulls differently

Get-ADUser -Filter {-not(employeeType -like "*")}

find group by display name wildcard - see group, find by display name wildcard

find user by display name wildcard - see user, find by display name wildcard, filter users, userAccountControl, filter by, user not found, catch, user exists or not?

find where some entity might reside whether user/group/contact/alias - when I want to search exhaustively through AD, I run the following 5 commands in PowerShell:

$SearchUser = "someone";
Get-ADObject -LDAPFilter "objectClass=Contact" -Properties Name,mail | Where-Object{$_.mail -like "$($SearchUser)*"} | ft Name, mail, distinguishedName;
Get-ADGroup -Filter {(GroupCategory -eq "Distribution") -and (mail -like "$($SearchUser)*")} -Properties name, mail, distinguishedName | ft name, mail, distinguishedName;
Get-ADGroup -Filter {(GroupCategory -eq "Security") -and (mail -like "$($SearchUser)*")} -Properties name, mail, distinguishedName | Sort-Object mail | ft name, mail, distinguishedName;
Get-ADUser -Filter {mail -like "$($SearchUser)*"} -Properties UserPrincipalName, mail, distinguishedName | ft UserPrincipalName, mail, distinguishedName;
Get-ADUser -filter * | where-Object {$_.ProxyAddresses -match "$($SearchUser)" } | fl;

To look for:

Respectively

folder, distinct file permissions within – See permissions, unique file permissions in a folder

folder, file permissions within (unique) – See permissions, unique file permissions in a folder

folder identity permissions, do any child folders have identity permissions the parent does not?

The script below checks whether any child folders have security identities (users/groups) which the parent does not as part of their security permissions. It will not let you know if both the parent and child contain the same identities but the permissions aren’t the same. For example, if Sam is in the child folder’s security list but Sam is not in the parent’s security list, this program will alert you by setting the IdentityReferenceFoundInParent property to $false. But if Sam appears as an identity in both parent and child but Sam can modify the parent but can only read the child, it will not alert.

$result = @()
# gather parent folder permissions
$IdentityReferencesParent = @()
$pathParent "\\fs.shire.com\Residency"
$CurrentAcl = Get-Acl -Path $pathParent
foreach ($permission in $CurrentAcl.Access) {
    $IdentityReferencesParent += $permission.IdentityReference
    $result += New-Object -TypeName PSObject -Property @{
        parent = $null
        folder = $null
        IdentityReference = $permission.IdentityReference
        FileSystemRights = $permission.FileSystemRights
        AccessControlType = $permission.AccessControlType
        IsInherited = $permission.IsInherited
        IdentityReferenceFoundInParent = $null
    }
}
# gather each child folder’s permissions...
$folders = @()
# only get child if it’s a folder; ignore files
Get-ChildItem $pathParent -r -Depth 0 | % {if ($_.PsIsContainer) { $folders += $_.FullName}}
foreach ($folder in $folders) {
    $IdentityReferenceFoundInParent = $null
    $CurrentAcl = Get-Acl -Path $folder
    # ... and check whether the child folder has an identity the parent doesn’t
    foreach ($permission in $CurrentAcl.Access) {
        if ($IdentityReferencesParent.contains($permission.IdentityReference)) {
            $IdentityReferenceFoundInParent = $true
        }
        else {
            $IdentityReferenceFoundInParent = $false
        }
        $result += New-Object -TypeName PSObject -Property @{
           
parent = $pathParent
            # don’t duplicate the parent portion of the child folder’s path
            folder = $folder.Substring($pathParent.Length+1, $folder.Length-$pathParent.Length-1)
            IdentityReference = $permission.IdentityReference
            FileSystemRights = $permission.FileSystemRights
            AccessControlType = $permission.AccessControlType
            IsInherited = $permission.IsInherited
            IdentityReferenceFoundInParent = $IdentityReferenceFoundInParent
        }
    }
}
$result | select parent, folder, IdentityReference, FileSystemRights, AccessControlType, IsInherited, IdentityReferenceFoundInParent | ogv

Each folder will show many rows in the OGV above: one for each IdentityReference

Look in the last “IdentityReferenceFoundInParent” column in the ogv above for differences.

A different, less granular approach below ignores files with permissions identical to parent and only lists folders with different permission than parent and gives hint about type of difference. It might server better to quickly spot differences without having to delve into details like above.

$path = "\\server\somepath\test"
$parentAcl = Get-Acl $path
 
Get-ChildItem $path -Directory -Recurse | % {
  $folderPath = $_.FullName
  $folderAcl = Get-Acl $folderPath
  $folderPathShort = $folderPath.Substring($path.Length+1, $folderPath.Length-$path.Length-1)
 
  # Check for explicitly blocked inheritance
  if ($folderAcl.AreAccessRulesProtected) {
    Write-Host "$folderPathShort has explicitly blocked inheritance." -ForegroundColor Red
    continue}
  # Compare IdentityReference, FileSystemRights and AccessControlType
  $diff = $parentAcl.Access | ? {
    $matchingChild = $folderAcl.Access | ? {$_.IdentityReference -eq $_.IdentityReference}
    # This “? {$_.IdentityReference -eq $_.IdentityReference}” comparison above might seem confusing at first.
    # Are we just comparing $_.IdentityReference property to itself above? That would be pretty dumb. No.
    # We’re really asking: does the IdentityReference property of each access rule match the IdentityReference property of the parent folder’s ACL?
    if ($matchingChild) {
      # If $matchingChild is null (i.e., no matching child access rule), it indicates that the child folder inherits permissions from its parent.
      # Now check whether FileSystemRights or AccessControlType differ.
      $_.FileSystemRights -ne $matchingChild.FileSystemRights -or
      $_.AccessControlType -ne $matchingChild.AccessControlType
    } else {
      # If $matchingChild is not null (i.e., a matching child access rule exists), it means the user/group has specific permissions in the child folder.
      $true
    } # IdentityReference not found in child - potential difference
  }
  if ($diff) {Write-Host "$folderPathShort has different permissions than its parent." -ForegroundColor Red}
  else {Write-Host "$folderPathShort inherits permissions from its parent." -ForegroundColor Green}
}

folder, unique file permissions within – See permissions, unique file permissions in a folder

foreign domain – see domain, foreign

foreign domain user, get – see user, get from another domain

forest domains, list

for the current user (you):

(Get-ADForest -Current LoggedOnUser).domains

found, user not – see user not found, catch, user exists or not?

FSMO roles, list

for Primary Domain Controller (PDC), RID Master, Infrastructure Master

Get-ADDomainController -Filter * | Select Name, Domain, Forest, OperationMasterRoles | ? {$_.OperationMasterRoles} | Format-Table -AutoSize

or

Get-ADDomain | Select-Object InfrastructureMaster, RIDMaster, PDCEmulator

for DomainNamingMaster, SchemaMaster

Get-ADForest | Select-Object DomainNamingMaster, SchemaMaster

FSMO roles, move

Move-ADDirectoryServerOperationMasterRole -Identity someServer PDCEmulator, RIDMaster, InfrastructureMaster

–G–

Get-ADGroupMember problems – see group members size limit exceeded

The solution isn’t specific to size limit exceeded; it works to solve other problems, too.

use this:

(Get-ADGroup MoronsWithStrongOpinions -Properties Member).Member

instead of this:

Get-ADGroupMember MoronsWithStrongOpinions

Unfortunately, this only returns DistinguishedName property instead of whole user objects.

Extract the CommonName (aka cn) from the DistinguishedName and then filter by cn in users and groups successively to try to find the member.

$group = "MoronsWithStrongOpinions"
$members = (Get-ADGroup $group -Properties Member).Member
$j=0; $count = $members.Count
foreach ($member in $members) {
  $j++; $percentTxt = ($j/$count).ToString("P")
  $cn = $member.Substring(3,$member.IndexOf(",")-3) # CommonName component of DistinguishedName
  $user = Get-ADUser -Filter {cn -eq $cn} -Properties DisplayName, samAccountName, cn
  if ($null -ne $user) {Write-Host "$j of $($count) ($percentTxt): '$($user.samAccountName)' ($($user.DisplayName)) found as user"}
  else {
    $group = Get-ADGroup -Filter {cn -eq $cn} -Properties DisplayName, samAccountName, cn
    if ($null -ne $group) {Write-Host "$j of $($count) ($percentTxt): '$cn' ($($group.DisplayName)) found as group"}
    else {Write-Host "$j of $($count) ($percentTxt): '$cn' user/group not found"}
  }
}

}

Get-ADUser, all properties - see user, all properties

Get-ADUser, filter on a property to be null - see null, filter on property

groups, copy with members – see also group members, show group members, show whether members are users or computers,

you have several groups which you want to copy exactly as they are (same types, members, etc.) except with different names and to a different OU

$groupNames = ("Garbage-Collectors", "Swamps", "Dumps")
$newGroupNames = ("Sanitary-Engineers", "Wetlands", "Landfills")
$newOU = "OU=Hifalutin,DC=whitewash,DC=com"
 
$i=0
foreach ($groupName in $groupNames) {
    $group = Get-ADGroup $groupName -Properties DisplayName, Description, DistinguishedName
    Write-Host "$($i): name: $($group.Name), DisplayName: $($group.DisplayName), SamAccountName: $($group.SamAccountName), GroupScope: $($group.GroupScope), Description: $($group.Description), DistinguishedName: $($group.DistinguishedName), GroupCategory: $($group.GroupCategory)" -ForegroundColor Cyan
    $j=0
    New-ADGroup -Name $newGroupNames[$i] -SamAccountName $newGroupNames[$i] -GroupCategory $group.GroupCategory -GroupScope $group.GroupScope -DisplayName $newGroupNames[$i] -Path $newOU -Description $group.Description
    Start-Sleep -Seconds 1
    $groupMembers = Get-ADGroupMember -Identity $groupName
    foreach ($member in $groupMembers) {
        #Add the user to the destination group
        Write-Host ("  $($j): Adding {0} to group '$($newGroupNames[$i])'" -f $member.SamAccountName) -ForegroundColor Blue
        Add-ADGroupMember -Identity $newGroupNames[$i] -Members $member.SamAccountName
        $j++
    }
    $i++
}

If you include IDs from a different domain, this will fail for those, because SamAccountName alone isn’t enough. – see also , group members, show including any members belonging to a domain other than our default, local domain

I don’t know that you really need the Start-Sleep command, but I usually like to get the system time to finish creating a group before I add Members right away.

Increment $i and $j at the end instead of the customary beginning of each loop so the arrays won’t get pushed over 1 and get mixed up.

group, count how many in – see also group members, show group members, show whether members are users or computers,

finds users but omits contacts

(Get-ADGroupMember -Identity "someGroup").Count

this includes contacts as well as members

(Get-ADGroup someGroup -Properties member | Select-Object -ExpandProperty member | Get-ADObject).Count

this does not work in local AD, only in AAD

(Get-DistributionGroupMember someDistGrp).Count

groups, delete several in an array but check if they exist first – see also group members, show group members, show whether members are users or computers,

foreach ($group in $groups){
    try {
        $groupLookFor = Get-ADGroup $group -ErrorAction SilentlyContinue
        If ($Null -ne $groupLookFor) {
            Write-Host "'$group' exists in AD" -ForegroundColor Green
            Remove-ADGroup $group -confirm:$false
        }
        Else {Write-Host "$group  not found in AD" -ForegroundColor Yellow}
    }
    catch {switch ($_.CategoryInfo.Category) {
            "ObjectNotFound" {Write-Host "'$group' not found in AD" -ForegroundColor Cyan}
            default {Write-Host "some other error occurred trying to find '$($group)': $($_.CategoryInfo.Category)" -ForegroundColor Magenta} # Catch any other types of errors
        }
    }
}

groups, delete several in an array and store that information in a CSV (including member information) in case you need to recreate groups – see also group members, show group members, show whether members are users or computers,

$groupNames = (Get-ADGroup -SearchBase "OU=Operations,DC=acquiredCompany,DC=com" -Filter * -SearchScope Subtree | ? {$_.DistinguishedName -like "*Purgem*"}).("DistinguishedName")
$i=0
$result = @()
foreach ($groupName in $groupNames) {
    $i++
    $group = Get-ADGroup -Identity $groupName -Properties DisplayName, Description, DistinguishedName
    Write-Host "$($i): name: $($group.Name), SamAccountName: $($group.SamAccountName), DisplayName: $($group.DisplayName), Descr: $($group.Description), GroupScope: $($group.GroupScope), GroupCategory: $($group.GroupCategory)" -ForegroundColor Cyan
    $j=0
    $groupMembers = Get-ADGroupMember -Identity $groupName # = Get-ADGroup $group.DistinguishedName -Properties Member).Member
    foreach ($member in $groupMembers) {
        $j++
        switch ($member.ObjectClass) {"user" {$color="Green"}; "group" {$color="Blue"}; "computer" {$color="Magenta"}; default {$color="Gray"}}
        Write-Host "    $($j): $($member.SamAccountName) - $($member.ObjectClass) - $($member.DistinguishedName)" -ForegroundColor $color
        $result += New-Object -TypeName PSObject -Property @{
            groupCount = $i
            groupName = $groupName
            groupDisplayName = $group.DisplayName
            groupSamAccountName = $group.SamAccountName
            groupDistinguishedName = $group.DistinguishedName
            groupGroupScope = $group.GroupScope
            groupDescription = $group.Description
            groupGroupCategory = $group.GroupCategory
            memberCount = $j
            memberSamAccountName = $member.SamAccountName
            memberDistinguishedName = $member.DistinguishedName
            memberObjectClass = $member.ObjectClass
        }
    }
    Remove-ADGroup - Identity$group.SamAccountName -Confirm:$false
}
$result= $result | select groupCount, groupName, groupDisplayName,groupSamAccountName, groupDistinguishedName, groupGroupScope, groupGroupCategory, groupDescription, memberCount,memberSamAccountName, memberObjectClass, memberDistinguishedName
$result | ogv
$result | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\$((Get-Date).ToString('yyyy-MM-dd_hh-mm'))DeletedGroups.csv" -NoTypeInformation -Encoding UTF8

group, find by display name wildcard – see also group members, show group members, show whether members are users or computers,

Get-ADGroup -Filter {DisplayName -like "*seminar*"} -Properties Name, DisplayName

group member, delete – see also groups, delete several in an array and store that information in a CSV, group members, show group members, show whether members are users or computers,

there are two approaches: from the user’s perspective and from the group’s perspective

from user’s perspective

Remove-ADPrincipalGroupMembership -Identity $user.ObjectGUID -MemberOf $group.ObjectGUID -confirm:$false

from group’s perspective

Remove-ADGroupMember -Identity $group.ObjectGUID -Members $user.ObjectGUID -confirm:$false

You don’t have to just restrict yourself to the ObjectGUID property; sAMAccountName, name, DistinguishedName also work. But if you’re going across domains which have users with identical names and samAccountNames, then specifying ObjectGUID or DistinguishedName is probably a good idea to make sure you don’t delete the user belonging to an unintended domain from a group. Speaking of working across domains …

… if you’re trying to delete a member belonging to one domain from a group belonging to another domain, you might get an error:

ResourceUnavailable: (be9adff36-ffec-4bdb-9f4b-add78fc78dab:ADGroup)

In that case:

Set-ADObject -Identity $($group.DistinguishedName) -Remove @{member="$($user.DistinguishedName)"}

You might think you’d also need to tack on:

-server $DomainController

But that seems to just make things worse. Probably because you actually end up having to use controller servers from both domains: one for the user and the other for the group. If you don’t bother to specify a domain controller server, the system seems to be smart enough to figure it out all by itself (as long as you have permissions on both domains).

group member information, store before deleting groups – see groups, delete several in an array and store that information in a CSV, – see also group members, show group members, show whether members are users or computers,

group membership between two users, compare – see also group members, show group members, show whether members are users or computers,

find membership count of each

(Get-AdPrincipalGroupMembership snowwhite).Count
(Get-AdPrincipalGroupMembership princecharming).Count

view membership difference between the two users

Compare-Object -ReferenceObject (Get-AdPrincipalGroupMembership snowwhite | select name | sort-object -Property name) -DifferenceObject (Get-AdPrincipalGroupMembership princecharming | select name | sort-object -Property name) -property name -passthru

store results into variable

$comparedGroups = Compare-Object -ReferenceObject (Get-AdPrincipalGroupMembership snowwhite | select name | sort-object -Property name) -DifferenceObject (Get-AdPrincipalGroupMembership princecharming | select name | sort-object -Property name) -property name -passthru

store groups which the second different user is a member but which the first reference user is not into a variable

$GroupsWhichDifferentUserHasThatReferenceUserDoesNot = $comparedGroups | ? {$_.SideIndicator -eq "=>"} | select name

group members, show – see also groups, to which does a user belong?, domain administrators, list, group members, show whether members are users or computers, group members size limit exceeded for an example which also goes on to show selected attributes of each member

this finds users but omits contacts

Get-ADGroupMember -Identity "someGroup" | ft

fancier: recursive, gets DisplayName, sorts by Name, puts Excel-ready output to clipboard

Get-ADGroupMember -Identity otherGroup -Recursive | Get-ADUser -Property DisplayName | Select Name, DisplayName | sort name | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | clip

includes contacts as well as members

Get-ADGroup someGroup -Properties member | Select-Object -ExpandProperty member | Get-ADObject

contacts and members with email

Get-ADGroup someGroup -Properties member | Select-Object -ExpandProperty member | Get-ADObject -Properties name, mail | select name, mail

gets all domains except one

Get-ADGroup someGroup -Properties member | Select-Object -ExpandProperty member | Get-ADObject -Properties name, mail | select name, mail | ? {$_.mail -notlike "*someDomain.com"}

group members, show whether members are users or computers – see also group members, show

# use Get-ADGroupMember to list group members and determine whether each member is a user or a workstation
$groupName = "SPM-Users"
$groupMembers = Get-ADGroupMember -Identity $groupName # Get group members
$memberDetails = @() # Create array to hold the custom objects
foreach ($member in $groupMembers) { # Loop through each member and create a custom object
    $memberDetails += [PSCustomObject]@{
        Name = $member.Name
        Type = $member.objectClass
    }
}
$memberDetails | sort type, Name | Out-GridView

group members size limit exceeded – see also group members, show group members, show whether members are users or computers,

Trying to find members of a group with too many members

Get-ADGroupMember MoronsWithStrongOpinions

returns error:

Get-ADGroupMember: The size limit for this request was exceeded.

use

(Get-ADGroup MoronsWithStrongOpinions -Properties Member).Member

instead

group members, show including any members belonging to a domain other than our default, local domain – see also groups, copy with members, domain, foreign

Useful if you normally only encounter users in your local Domain but occasionally run into a user from another domain in the same forest

$groupNames = ("Earthlings", "Americans", "StarAcademy")
$i=0
$alternateDomain = "vulcan.planet.com"
foreach ($groupName in $groupNames) {
    $group = Get-ADGroup $groupName -Properties DisplayName, Description, DistinguishedName
    Write-Host "$($i): name: $($group.Name), DisplayName: $($group.DisplayName), SamAccountName: $($group.SamAccountName), GroupScope: $($group.GroupScope), Description: $($group.Description), DistinguishedName: $($group.DistinguishedName), GroupCategory: $($group.GroupCategory)" -ForegroundColor Cyan
    $j=0
    $groupMembers = Get-ADGroupMember -Identity $groupName
    foreach ($member in $groupMembers) {
        try {
            $user = Get-ADUser -Identity $member.objectGUID -Properties DisplayName -ErrorAction Stop
            Write-Host "  $($j): $($member.SamAccountName) - $($user.DisplayName)" -ForegroundColor Green
        }
        catch {
            $msg = $error[0].exception.gettype().fullname
            Write-Host "    error: $msg when looking for user in default domain" -ForegroundColor Magenta
            $dc = Get-ADDomainController -DomainName $alternateDomain -Discover -NextClosestSite
            $user = Get-ADUser -Server $dc.HostName[0] $member.objectGUID
            Write-Host "   $($j): $($member.SamAccountName) - $($user.DisplayName) found in alternate domain $alternateDomain" -ForegroundColor Blue
        }
        $j++
    }
    $i++
}

Increment $i and $j at the end instead of the customary beginning of each loop so the arrays won’t get pushed over 1 and get mixed up.

group, rename

renames the "Name" property which can’t do using GUI

Rename-ADObject -Identity (Get-ADGroup -Identity "oldName").ObjectGUID -NewName "newName"

group or user?

Given a samAccountName, is it a group or a user?

Beware that $samAccountName below cannot be in the form of $user.samAccountName or it will fail.

$samAccountName = "Domain Admins"
$ObjectClass = (Get-ADObject -Filter {SamAccountName -eq $samAccountName}).ObjectClass
if ($ObjectClass -eq "user") {Write-Host "$SamAccountName is a $ObjectClass" -ForegroundColor Green}
elseif ($ObjectClass -eq "group") {Write-Host "$SamAccountName is a $ObjectClass" -ForegroundColor Blue}

groups, find empty

$groupsEmpty = Get-ADGroup -Filter * -Properties * | ? {($_.members.count -eq 0) -And ($_.isCriticalSystemObject -ne "True")}
# (Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime # the command above may take some time, run this immediately after to find out how long
$i = 0; $count = $groupsEmpty.Count
$result = @()
foreach ($group in $groupsEmpty) {
    $i++; $percentTxt = ($i/$count).ToString("P")
    if ($group.MemberOf.Count -ge 1) {
        $color = "Blue"
        $memberNameArray = @()
        $MemberOUJoined = $group.MemberOf -join '; '
        $j=0
        foreach ($member in $group.MemberOf) {
            $j++
            try {
                $memberName = (Get-ADGroup -Identity $member -ErrorAction SilentlyContinue).Name
            }
            catch {$memberName
                $memberName = "can’t find $j"
            }
            $memberNameArray += $memberName
            Write-Host "  $i of $($count) $member $memberName" -ForegroundColor Yellow
        }
        $memberNameJoined = $memberNameArray -join '; '
    }
    else {
        $color = "Green"
        $MemberOUJoined = $null
        $memberNameJoined = $null
    }
    $result += New-Object -TypeName PSObject -Property @{
        "order" = $i
        "SamAccountName" = $group.SamAccountName
        "DisplayName" = $group.DisplayName
        "distinguishedName" = $group.DistinguishedName
        "GroupCategory" = $group.GroupCategory
        "GroupScope" = $group.GroupScope
        "Created" = $group.Created
        "whenChanged" = $group.whenChanged
        "membersOfCount" = $group.MemberOf.Count
        "MemberOfOU" = $MemberOUJoined
        "MemberOfName" = $memberNameJoined
        "ObjectGUID" = $group.ObjectGUID
    }
        Write-Host "$i of $($count) ($percentTxt): $group.SamAccountName" -ForegroundColor $color
}
$result = $result | select SamAccountName, DisplayName, DistinguishedName, GroupCategory, GroupScope, Created, whenChanged, membersOfCount, MemberOfOU, MemberOfName, ObjectGUID
$result | ogv
$result | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\EmptyGroups$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -Encoding UTF8 -NoTypeInformation

groups, to which does a user belong? – see also group members, show; group members, show whether members are users or computers

Get-ADPrincipalGroupMembership someUser | select Name, GroupCategory, GroupScope

current user (list groups by distinguished name)

(New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$($env:username)))")).FindOne().GetDirectoryEntry().memberOf

current user (list groups by canonical name)

(New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$($env:username)))")).FindOne().GetDirectoryEntry().memberOf | Get-AdGroup -Properties CanonicalName | % {$CN = ($_.CanonicalName -Split "/"); "{0}\{1}" -f $CN[-2],$CN[-1]}

for a user in a foreign domain

$dc = Get-ADDomainController -DomainName foreign.org -Discover -NextClosestSite
Get-ADPrincipalGroupMembership foreignUser -Server $dc.HostName[0]

if you get error

Get-ADPrincipalGroupMembership: The operation being requested was not performed because the user has not been authenticated.

then try

Get-ADUser foreignUser -Server $dc.HostName[0] -Properties MemberOf | Select-Object -ExpandProperty MemberOf | Get-ADGroup -Server $dc.HostName[0] | Select-Object Name

groups for a department

# this just sets up the file to be in a directory we know we have permission: "My Documents"
$outputfile = "yourOutPutFile.txt"
$mytemp= [environment]::getfolderpath("mydocuments")
$outputfile = $mytemp + "\" + $outputfile
 
# this one, multi-piped line does everything we want
Get-ADUser -filter {mail -like "*yourdomain.com"} -Properties DisplayName, mail, memberof | % {
  $email = $_.mail
  $Name = $_.DisplayName
  $_.memberof | Get-ADGroup | Select @{N="User";E={$Name}},@{N="email";E={$email}}, Name
} | Export-Csv $outputfile -nti

nti means no type information which suppresses the (almost always unwanted) first line

groups, delete a user from all but one

We don’t want to remove this user from “Domain Users” just yet - especially if we’re going to keep his ID around for a while as a shared mailbox accessible by his successor.

There’s no provider filter parameter for Get-ADPrincipalGroupMemebership, so we must use late filtering:

Get-ADPrincipalGroupMembership someUser | Where-Object {$_.name -ne "Domain Users"} | select name, GroupCategory, GroupScope

Remove users from all groups in AD.  Go to their ID in ADUC and look what’s in “member of”.  To remove his membership in all groups except “Domain Users”.  Or, with PowerShell

Get-ADPrincipalGroupMembership someUser | Where-Object {$_.name -ne "Domain Users"} | % {Remove-ADPrincipalGroupMembership -Identity someUser -MemberOf $_ -confirm:$false}

groups in an OU, display

Get-ADGroup -Filter "*" | select-object * | where -object {$_.distinguishedname -like "*,OU=yourOU,*"} | sort-Object groupCategory,GroupScope,name | ft name,groupCategory,GroupScope, DistinguishedName

or

Get-ADGroup -Filter * -SearchBase "OU=yourOU,DC=yourdomain,DC=com" | sort-Object SearchBase,groupCategory,GroupScope,name | ft name,groupCategory,GroupScope, DistinguishedName

groups, list by type

Get-ADGroup -filter * | Sort-Object GroupCategory,GroupScope,Name | ft Name,GroupCategory,GroupScope, DistinguishedName

or

$allGroups = Get-ADGroup -filter *
$allGroups | group GroupCategory | select Name, Count # Security, Distribution
$allGroups | group GroupScope | select Name , Count # Universal, DomainLocal, Global

groups with no mail field

$groupsNoMail = Get-ADGroup -LDAPFilter "(!mail=*)"

–H–

–I–

Import-Module ActiveDirectory returns 'ActiveDirectory' was not loaded because no valid module file was found in any module directory - see RSAT (Remote Server Administration Tools)

info field, insert line breaks

If you try to insert text with line breaks into the info field, it will truncate everything after the first line break. Only way I”ve found to do this is by replacing carriage returns with “`r`n”:

Set-AdUser -Identity DuncanDonuts -Replace @{Info="Internal Contact:`r`nJoe Bagadonitz"}

inherit

–J–

join a PC to the domain - see rejoin a PC to the domain

–K–

–L–

last change of a user attribute / property – see property changed last for a user

list all computers in the domain, see computers, list

list name servers - see domain name servers, list

local group policy

gpedit.msc

local security polity

secpol.msc

local users and groups

lusrmgr.msc

local user list

Get-LocalUser

local user locked? - see determine whether local users are locked

lock out user – see also unlock local user

There’s no setting where you can simply flip a switch to lock out Active Directory user accounts. So what is one to do if you need some locked out accounts to do testing with? This script requires the RSAT tools to be installed on the workstation that it is being run from, specifically the Active Directory and Group Policy modules. First, you may want to verify that the user you want to lock out is not already among the users locked out:

Search-ADAccount -LockedOut -UsersOnly | Select-Object Name, SamAccountName

lock the user:

$dc = (Get-ADDomainController -Discover).Hostname
$ID = "houdini"
$user= Get-ADUser -Identity $ID
$Password = ConvertTo-SecureString "NotMyPassword" -AsPlainText -Force
$i=0
Do {
    $i++
    Write-Host "$i"
    Invoke-Command -ComputerName $dc {Get-Process
    } -Credential (New-Object System.Management.Automation.PSCredential ($($user.UserPrincipalName), $Password)) -ErrorAction SilentlyContinue
}
Until ((Get-ADUser -Identity $user.SamAccountName -Properties LockedOut).LockedOut)

unlock if you want after you just locked him out:

Unlock-ADAccount -Identity $ID

lockout status

Get-ADUser clint -properties lockedout | select name, lockedout

lockout status tool available to download from Microsoft

installs at C:\Program Files (x86)\Windows Resource Kits\Tools\

Find all events in last hour

Get-WinEvent -Logname Security -FilterXPath "*[System[EventID=4740 and TimeCreated[timediff(@SystemTime) <= 3600000]] and EventData[Data[@Name='TargetUserName']='someUser']]" | Select-Object TimeCreated,@{Name="User Name";Expression={$_.Properties[0].Value}},@{Name="Source Host";Expression={$_.Properties[1].Value}}

determine whether local users are locked

actually, whenever I tried to search how to find whether a local user was locked, some posts kept insisting that "Enabled" suffices as such an indicator. I remain unconvinced. Nevertheless, here is a command to determine if enabled:

Get-LocalUser -Name "Plebian" | fl Enabled

or (not really a PowerShell command) which if you look at the "Active" property returned should give you an indication

net user "Plebian"

unlock:

Unlock-ADAccount -Identity houdini

also might work to unlock:

net user "Plebian" /active=yes

logon, last across all DCs

$userSamAccountName = "waldo"
$domainControllers = "dc1", "dc2", "dc3", "dc4"
foreach ($dc in $domainControllers) {
    $user = Get-ADUser -Identity $userSamAccountName -Server $dc -Properties DisplayName, samAccountName, Enabled, LockedOut, LastLogonDate, whenCreated, LastBadPasswordAttempt
    Write-Host "$($dc) - $($user.SamAccountName) ($($user.DisplayName)) created $($user.whenCreated):" -ForegroundColor Cyan -NoNewline
    Write-Host " | locked $($user.LockedOut)" -ForegroundColor $(if ($($user.LockedOut)) {"Red"} else {"Green"}) -NoNewline
    Write-Host " | enabled $($user.Enabled)" -ForegroundColor $(if ($($user.Enabled)) {"Green"} else {"Red"}) -NoNewline
    Write-Host " | LastLogonDate $($user.LastLogonDate)" -ForegroundColor $(if ($null -eq $($user.LastLogonDate)) { "Red"} else {"Green"}) -NoNewline
    Write-Host " | Last LastBadPasswordAttempt: $($user.LastBadPasswordAttempt)" -ForegroundColor $(if ($null -ne $($user.LastBadPasswordAttempt)) {"Red"} else {"Green"})
}

–M–

mail

see groups with no mail field

see users with no mail field

see also users with no user principal name field

managers

Get-AdUser -Filter * -Properties SamAccountName, DisplayName, manager | Select-Object -Property SamAccountName, Displayname, @{Name="manager";Expression={(Get-ADUser $_.manager -Properties DisplayName).DisplayName}}

members of a group - see group members, show, group members, show whether users or computers

membership of AD groups between two users, compare - see group membership between two users, compare

modified user attribute, when? – see property changed last for a user

–N–

name servers, list - see domain name servers, list

name wildcard - see sAMAccountName, find all objects containing a substring of a sAMAccountName (for users, contacts, groups, etc.)

nearest domain controller - see domain controller, nearest

network connectivity for PCs - see connectivity to a bunch of PCs in an OU, test

new line, insert into info field for a user – see info field, insert line breaks

new user - see user, create

not found, user – see user not found, catch, user exists or not?

null, filter on property

In this example, we want to find all ADUsers whose msExchHideFromAddressLists property is not set. So we quite reasonably attempt to filter on that filter not equal to the $null variable:

Get-ADuser -filter {msExchHideFromAddressLists -eq $null} -Properties msExchHideFromAddressLists | ft Name, msExchHideFromAddressLists

But that fails with:

Get-ADuser : Variable: 'null' found in expression: $null is not defined.

So, instead filter on -notlike "*":

Get-ADuser -filter {msExchHideFromAddressLists -notlike "*"} -properties msExchHideFromAddressLists | ft Name, msExchHideFromAddressLists

You can actually still filter on the $null variable. Just not in the very first part of the command where you’re using the -filter. Instead, use later after a pipe:

Get-ADuser -filter * -properties msExchHideFromAddressLists | ? {$_.msExchHideFromAddressLists-eq$null} | ft Name, msExchHideFromAddressLists

I like to think that the first method of filtering on -notlike "*" is more efficient and elegant.

–O–

operating system versions of all computers, see also computers, list

$windowsServersBaseOS = Get-ADComputer -Properties OperatingSystem -Filter {OperatingSystem -like "Windows Server*"} |select OperatingSystem, @{n="OS";e={if ($_.OperatingSystem -like "*R2*"){$_.OperatingSystem.Substring(0,22)} else {$_.OperatingSystem.replace("`u{00AE}","").Substring(0,19)}}}
$windowsServersBaseOS | group OS | sort Name | select Name, Count

Using substring to begin with is to crunch down the various flavors such as Enterprise, Standard, etc.

Jockeying between string length of 19 and 20 in the substring is to deal with 2012 R2.

The $_.OperatingSystem.replace("`u{00AE}","") is to get rid of the extra ® symbol that comes along with Windows 2008 so the result sorts right.

OU, extract from CanonicalName

Easiest way. This also adds an OU field to the object you get when you fetch some users.

$users = Get-ADUser -SearchBase "OU=Users,DC=africa,DC=com" -Filter * -Properties DisplayName, CanonicalName

Note the properties…

$users | Get-Member

…because after the step below, we should have one more property.

foreach ($obj in $srvUsers) {
    $obj.PSObject.Properties.Add([PSNoteProperty]::new("OU", (($obj.CanonicalName -split "/")[1..(($obj.CanonicalName -split "/").Length - 2)] -join "/")))
}

Again, get the properties. Now there should be one more than before.

$users | Get-Member

A somewhat more roundabout way. Let’s say we want to extract the Organizational Unit from a user’s CanonicalName name. That is, Forest/Dwarves/Mine in this case

$CanonicalName = "MagicKingom.com/Forest/Dwarves/Mine/Sneezy"

We don’t care about the domain out front and only want its Organizational Unit. Start by stripping off the domain.

first

$domain, $contentArray = $CanonicalName -split "/"

This assigns the first element of the array resulting from the split to the $domain variable and the remaining array elements to the $contentArray variable.

everything except the first

everything except the first goes to the $contentArray variable which we can concatenate back together:

$content = ($replace | % {$contentArray}) -join "/"

last

but now we still have the user name at the end we don’t want.

This gets the string at the end (the user), which we may want.

$content.Split("/")[-1]

everything except the last

But to get the OU, we want everything except the last element of the array:

$content.Substring(0,$content.Length-$content.Split("/")[-1].Length-1)

OU, extract from DistinguishedName – also see common name, extract from DistinguishedName

one-liner:

Get-ADOrganizationalUnit -Filter * | select @{n="OU";e={$OU = $_.DistinguishedName -split "(?<!\\)," | ? {$_ -match "^OU="}; [array]::Reverse($OU); ($OU | % {$_ -replace "OU=", ""}) -join "\"}} | sort OU

The regular expression "(?<!\\)," is used to split a string by commas "(,)" but not when a comma is preceded by a backslash "(\)". Here’s a breakdown of how it works:

  1. "(?<!\\),": This is a negative lookbehind assertion. It checks that there is no backslash "(\)" immediately before the comma "(,)". In other words, it ensures that the comma is not preceded by a backslash.
  2. "(,)": This part of the regular expression matches a comma.

When combined, "(?<!\\)," effectively splits a string by commas unless the comma is escaped with a backslash. This is useful in scenarios where you have a string containing comma-separated values, and you want to split it while ignoring escaped commas.

For example, if you have a string like this:

OU=Sales,OU=North\,America,OU=Users,DC=example,DC=com

Using "(?<!\\)," as the delimiter in a split operation will correctly split it into the following parts:

  1. OU=Sales
  2. OU=North,America
  3. OU=Users
  4. DC=example
  5. DC=com

It treats the comma inside "OU=North,America" as part of the value and doesn’t split it.

a less compact one-liner:

$servers | select Name, @{n="OU";e={$OU = ($_.DistinguishedName.Substring($_.DistinguishedName.IndexOf(",OU=")+1).Substring(0,$_.DistinguishedName.Substring($_.DistinguishedName.IndexOf(",OU=")+1).IndexOf(",DC=")) -replace "OU=", "").Split(",");[array]::Reverse($OU);$OU -join "/"}} | ogv

or even more drawn out:

$group = Get-ADGroup "sadhus"
$distinguishedName = $group.DistinguishedName
$pos = $distinguishedName.IndexOf(",OU=")
$withoutSamName = $distinguishedName.Substring($pos+1)
$pos = $withoutSamName.IndexOf(",DC=")
$importantPart = $withoutSamName.Substring(0, $pos)
$importantPart = $importantPart -replace "OU=", ""
$importantPart = $importantPart -replace "CN=", ""
$OU = $importantPart.Split(",")
[array]::Reverse($OU)
$OU = $OU -join "/"

as a function

function GetOUfromDistinguishedName { param ($distinguishedName)
    $pos = $distinguishedName.IndexOf(",OU=")
    $withoutSamName = $distinguishedName.Substring($pos+1)
    $pos = $withoutSamName.IndexOf(",DC=")
    $importantPart = $withoutSamName.Substring(0, $pos)
    $importantPart = $importantPart -replace "OU=", ""
    $importantPart = $importantPart -replace "CN=", ""
    $OU = $importantPart.Split(",")
    [array]::Reverse($OU)
    $OU = $OU -join "/"
    return $OU
}

$groupOU = GetOUfromDistinguishedName ($group.DistinguishedName)

OU, extract from DistinguishedName using SQL – also see common name, extract from DistinguishedName

select REPLACE(SUBSTRING(DistinguishedName, CHARINDEX('OU=', DistinguishedName) + 3, LEN(DistinguishedName) - CHARINDEX('OU=', DistinguishedName) - LEN(',DC=healthcare,DC=uiowa,DC=edu') -2), ',OU=', '\') as OU
from computers

OU, list all contacts for an OU

Get-ADObject -filter {objectclass -eq "contact"} -Properties name, givenName, middleName, sn, mail | `
    where-object {$_.distinguishedname -like "*yourOU*"} | Sort-Object sn, givenName | select name, givenName, middleName, sn, mail | ft

Maybe more efficient to limit up front using the -SearchBase parameter below rather than after the fact using the where-object parameter like what we do above:

Get-ADObject -filter {objectclass -eq "contact"} -SearchBase "OU=yourOu,DC=yourDomain,DC=com" -Properties name, givenName, middleName, sn, mail | `
    Sort-Object sn, givenName | select name, givenName, middleName, sn, mail | ft

And perhaps also sort first by email domain

Get-ADObject -filter {objectclass -eq "contact"} -Properties name, givenName, middleName, sn, mail | `
    where-object {$_.distinguishedname -like "*yourOU*"} | `
    Select-Object @{n="Dom";e={$_.mail.split("@")[1]}}, name, givenName, middleName, sn, mail | `
    Sort-Object Dom, sn, givenName | ft

list emails

Get-ADObject -SearchBase "OU=MyOu,DC=myDomain,DC=com" -Filter {objectclass -eq "contact" } -Properties mail | Select-Object Name, mail

OU, list all users sorted by their OU

Get-ADUser -filter * -Properties name, EmailAddress, canonicalname | select name, EmailAddress, @{Label = "Group";Expression = {($_.canonicalname -Split "/")[-2]}} | sort Group, name

OU, list all users for an OU

this level and all levels below that, specify -SearchScope Subtree (or just leave that parameter out and it will search all levels below by default)

Get-ADUser -SearchBase "OU=yourOU,DC=yourDomain,DC=com" -Filter * -SearchScope Subtree | ft

to just list the highest level, specify -SearchScope OneLevel

Get-ADUser -SearchBase "OU=yourOU,DC=yourDomain,DC=com" -Filter * -SearchScope OneLevel | ft

to filter users

Get-ADUser -SearchBase $OU -filter {((employeeType -eq "prs" -or extensionAttribute2 -eq "prs") -and (enabled -eq $true))}

if you mix “-or” with “-and” like above, make sure to enclose each with separate parentheses! If you leave off, say, the parentheses around what’s after the “-and”, you’ll get an error.

you can do the same thing above this way instead:

Get-ADUser -SearchBase $OU -Filter "(employeeType -eq 'prs' -or extensionAttribute2 -eq 'prs') -and enabled -eq `"$true`""

OU permissions

groups or users with permissions

$ACL = Get-Acl "AD:OU=DeathStarLaserBeam,DC=minions,DC=DarthVader,DC=org"
$ACL.Access | group IdentityReference | select Name | sort Name | ogv

groups or users with permissions with their permissions

$ACL.Access | select IdentityReference, IsInherited, InheritanceFlags, ActiveDirectoryRights | ogv

but sometimes above doesn’t give enough information. For instance, when I delegate sometimes I get a bunch of identical rows from command above where the InheritanceFlags all show ContainerInherit and ActiveDirectoryRights all show WriteProperty I have not been able to decipher ".objectType"

Import-Module ActiveDirectory
$OUTarget = "OU=Users,OU=Mandolorian,DC=empire,DC=org"
$aclEntries = (Get-ACL-Path "AD:\$OUTarget").Access | ? {$_.identityReference -like "empire\OUA-*"}

foreach ($entry in $aclEntries) {
    $identity = $entry.ObjectType
    try {
        $object = Get-ADObject -Identity $identity
        if ($object) {
            Write-Host "ObjectType: $($object.objectClass)"
            Write-Host "InheritedObjectType: $($object.objectClass | Join-String ,)"
        } else {
            Write-Host "Object not found for $($entry.ObjectType)" -ForegroundColor DarkYellow
        }
    } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
        Write-Host "$($entry.IdentityReference): Object not found for $($entry.ObjectType)" -ForegroundColor Red
    }
}

OU, users inherit permissions? – see user inherits permissions from parent OU

OUs (Organizational Units), list

Get-ADOrganizationalUnit -filter * | ft Name, DistinguishedName

But just getting the name and distinguishedName is hard for humans to parse. That is, with the jumble of extra letters, = signs and semicolons, it’s hard to see how deep the levels go. It’s backwards from where you want the top level to the left and deepest level to the right. With the order being backwards, sorting as is is pretty worthless. So better display:

Get-ADOrganizationalUnit -Filter * | select @{n="OU";e={$OU = $_.DistinguishedName -split "(?<!\\)," | ? {$_ -match "^OU="}; [array]::Reverse($OU); ($OU | % {$_ -replace "OU=", ""}) -join "\"}} | sort OU

The regular expression"(?<!\\)," is used to split a string by commas "(,)" but not when a comma is preceded by a backslash "(\)". See OU, extract from DistinguishedName for a breakdown of how this regular expression works

to just list the OUs one level down in a specific OU, specify -SearchScope OneLevel

Get-ADOrganizationalUnit -Searchbase "OU=yourOU,DC=yourDomain,DC=com" -SearchScope OneLevel -Filter * | ft

OUs (Organizational Units), list empty

$OUs = Get-ADOrganizationalUnit -Searchbase "DC=PumpkinPatch,DC=Dogpatch,DC=gov" -SearchScope Subtree -Filter * -Properties Description
$i = 0; $count = $OUs.Count
$result = @()
foreach ($ou in $OUs) {
    $color = $null
    $i++; $percentTxt = ($i/$count).ToString("P")
    $ouName = $ou.Name
    $distinguishedName = $ou.DistinguishedName
    $depth = $distinguishedName -split "OU" | measure | select -exp count
    $depth = $depth - 1
    $children = Get-ADObject -filter * -SearchBase $ou.distinguishedname | ? {$_.distinguishedname -ne $ou.distinguishedname} | Measure-Object | Select -ExpandProperty Count
    if ($children -gt 0) {$color = "Green"} else {$color = "Red"}
    $result += New-Object -TypeName PSObject -Property @{
        "order" = $i
        "ouName" = $ouName
        "children" = $children
        "distinguishedName" = $distinguishedName
        "depth" = $depth
        "description" = $ou.description
    }
    Write-Host "$i of $($count) ($percentTxt): '$ouName' has $children children ($distinguishedName)" -ForegroundColor $color
}
$result = $result | select order, ouName, description, children, depth, distinguishedName
$result | ogv
$result | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\OUs$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -Encoding UTF8 -NoTypeInformation

OUs for contacts (just the lowest level)

Get-ADObject -filter {objectclass -eq "contact" } -Properties targetaddress,distinguishedName | Sort-Object {((($_.DistinguishedName.Split(',', 2))[1]).Split(',', 2))[0]},name | select name, targetaddress,@{Name="OU";Expression={((($_.DistinguishedName.Split(',', 2))[1]).Split(',', 2))[0]}} | ogv

–P–

password expiration date

Get-AdUser -Filter * -Properties SamAccountName, DisplayName, "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property SamAccountName, Displayname, @{Name="PasswordExpires";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}

password never expires, list all such users (which are also enabled) sorted by OU, name

$neverExpired = Get-ADUser -filter {(PassWordNeverExpires -eq "True") -and (Enabled -eq "True")} -Properties name, EmailAddress, canonicalname
$nvExp = $neverExpired | select name, EmailAddress, @{Label = "Group";Expression = {($_.canonicalname -Split "/")[-2]}} | sort Group, name
$nvExp | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\PasswordNeverExpires$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -Encoding UTF8

or if you prefer just one command:

Get-ADUser -filter {(PassWordNeverExpires -eq "True") -and (Enabled -eq "True")} -Properties name, EmailAddress, canonicalname | select name, EmailAddress, @{Label = "Group";Expression = {($_.canonicalname -Split "/")[-2]}} | sort Group, name | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\PasswordNeverExpires$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -Encoding UTF8

It’d be nice if we could exclude shared mailboxes & system users...

password not required

Get-ADUser -Filter {UserAccountControl -band 0x20} # 32 PASSWD_NOTREQD

password policy resulting from GPO

Get-ADUserResultantPasswordPolicy StevieWonder

password, test if correct

$Username="NapoleonBoneparte"
$Password="TopSecret"
$context=New-ObjectSystem.DirectoryServices.AccountManagement.PrincipalContext("Domain")
if ($context.ValidateCredentials($Username,$Password)) {Write-Host"Password is correct." -ForegroundColor Green}
else {Write-Host"Password is incorrect." -ForegroundColor Red}

permissions, file: how many distinct file permissions within a folder

If a department has permissions set for a folder, people moving files into this folder may retain permissions associated with the source folder and then department users can’t see these new files.

permissions, folder, do child folders have permissions parent folder does not? – see folder identity permissions, do any child folders have identity permissions the parent does not?

permissions, list for an OU – see OU permissions

permissions, list for a user

(Get-ACL "AD:$((Get-ADUser someUser).distinguishedname)").access | select objectType, IdentityReference, inheritedObjectType, ActiveDirectoryRights

haven’t found this to be too useful

permissions, not authorized

catch [System.UnauthorizedAccessException]

permissions, set for file or folder - see ACL, set

below will find every subdirectory in a directory whose subdirectory matches users belonging to the an OU and restrict permissions to that directory to only that user. Useful if that’s the way it was but it got messed up.

$inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
$propagation = [system.security.accesscontrol.PropagationFlags]"None"
$ou = "OU=minions,DC=gru,DC=com"
$users = Get-ADUser -SearchBase $ou -Filter * -Properties Name,SamAccountName,DistinguishedName
ForEach($user in $users) {
   $username = $user.Name
   #Write-Host $username
   $path = "\\fs.gru.com\minions\" + $username
   $acl = Get-ACL -Path $path
   # take ownership
   $admins = New-Object Security.Principal.NTAccount("Builtin", "Administrators")
   $acl.SetOwner($admins)
   #Remove the inheritance and remove inherited access rules
   #https://docs.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.objectsecurity.setaccessruleprotection?view=netframework-4.8
   $acl.SetAccessRuleProtection($True, $False)
   $acl.Access | % {$acl.RemoveAccessRule($_)}
   $AccessRule1 = New-Object System.Security.AccessControl.FileSystemAccessRule("gru\Isilon File Server Admins","FullControl",$inherit, $propagation,"Allow")
   $acl.SetAccessRule($AccessRule1)
   $DomainPlusUserName = "HEALTHCARE\" + $USERNAME
   $AccessRule2 = New-Object System.Security.AccessControl.FileSystemAccessRule($DomainPlusUserName,"Modify",$inherit, $propagation,"Allow")
   $acl.SetAccessRule($AccessRule2)
   #Set the ACL to the folder so its done
   Set-Acl -Path $path -AclObject $acl
}

permissions, unique file permissions in a folder

$FolderPath = "\\department\Fiscal Services"

# Get all the files in the folder
$files = Get-ChildItem -Path $FolderPath -File

# Initialize a hashtable to store the unique permission combinations
$permissions = @{}

# Loop through each file
foreach ($file in $files) {
    # Get the ACL of the file
    $ACL = Get-Acl -Path $File.FullName
 
    # Convert the ACL to a string
    $ACLString = $ACL.Access | Out-String
    # if you don’t expand permissions, the "Name" value will be unreadable
    # and only show up as ellipses/3 dots
    $permissionList = $permissions | Format-List
 
    # Check if the ACL string already exists in the hashtable
    if ($permissions.ContainsKey($ACLString)) {
        # Increment the count of the existing permission combination
        $permissions[$ACLString]++
    }
    else {
        # Add a new entry to the hashtable with a count of 1
        $permissions[$ACLString] = 1
    }
}
 
# Display the results both ways (with and without expanded permissions)
$permissionList # detailed permissions show up, but no count for each unique file permission
$permissions # count for each unique file permission, but name shows up as ellipses

permissions, users inherit permissions from OU? – see user inherits permissions from parent OU

picture, add – see also user, update property

$ADphoto = [byte[]](Get-Content C:\Users\elvis\Pictures\elvis.png -Encoding byte)
Set-ADUser elvis -Replace @{thumbnailPhoto=$ADphoto}

If you get

Set-ADUser : 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.

It’s probably not because you can’t connect to any server. You can test by

Get-ADDomainController -Discover -Service ADWS

or

Get-ADDomainController -ForceDiscover -Discover -Service ADWS –NextClosestSite

More likely, the picture was too big. Needs to be under 100K.

property, add to collection of objects

let’s say you have group members

$oranges = Get-ADGroupMember oranges

add whether they’re enabled.

foreach ($user in $oranges) {
    $user | Add-Member -MemberType NoteProperty -Name "Enabled" -Value (Get-ADUser $user.SamAccountName).Enabled -Force
}

properties, see all - sometimes by default, when you do a get "-" even with a "fl" appended, you don’t get all the properties

Get-ADUser somauser -Properties *

properties, see users and contacts with a some properties which are filled in (not null)

This example finds all users and contacts whose 1st or 2nd extensionAttributes are set and then sorts by OU, name

Get-ADObject -filter {(objectclass -eq "contact") -or (objectclass -eq "user")} -Properties ObjectClass, Name, canonicalname, extensionAttribute1, extensionAttribute2 | Where-Object {$null -ne $_.extensionAttribute1 -or $null -ne $_.extensionAttribute2} | sort name | select name, @{Label = "OU";Expression = {($_.canonicalname -Split "/")[-2]}}, extensionAttribute1, extensionAttribute2, ObjectClass | sort OU, name | ft

property for a user, change – see user, update property

property changed last for a user

(Get-ADReplicationAttributeMetadata -Server dc1 -Object (Get-AdUser chuckgrassley) | ? {$_.AttributeName -eq "mail"}).LastOriginatingChangeTime.ToString("M/d/yy h:mm:ss tt")

property missing for a user?

You might think this might work

if (($contact.$property -eq $null) -or ($contact.$property -eq ""))

But it doesn’t. Use this instead.

if (-not($contact.$property))

–Q–

–R–

recently created users – see users created recently

recycle bin, show recently deleted computers

This only works if you’ve enabled the Active Directory recycle bin.

This example finds all computers deleted after a certain date for a certain OU and sorts by date

$computers = Get-ADObject -Filter 'ObjectClass -eq "computer" -AND IsDeleted -eq $True' -IncludeDeletedObjects -Properties IsDeleted,LastKnownParent,WhenChanged | ? {($_.WhenChanged -ge "8/8/19")} | Select-Object @{n="ComputerName";e={$_.Name.split("$([Environment]::NewLine)")[0]}},@{n="OU";e={$_.LastKnownParent.split(",")[0]}},WhenChanged | ? {$_.OU -like "*someOU"} | sort ComputerName

You could probably get fancier displaying the OU; this only shows the outer-most leaf of the OU

rejoin a PC to the domain

Test whether it’s already properly joined:

Test-ComputerSecureChannel –credential yourDomain.com\AdminUser

If result is false, re-run same command with -repair appended

rename a group – see group, rename – renames the "Name" property which can’t do using GUI

rename a user – see also user, update property

Seems like this ought to be simple, right? But problem: it seems that you need to use the Rename-ADObject and that command wants an identity. And all you might have is a name. So you have to pipe the Get-ADuser into a Set-ADuser (in order to get an object with an identity) and then finally pipe that into Rename-ADObject. The first two commands are probably superfluous; included here in case you already had $DepartingUserIdentity as a variable earlier in a script. The last command is what you really need.

$DepartingUserIdentity = "someUser";
$DepartingUserName = (Get-ADUser $DepartingUserIdentity).Name
Get-ADUser $DepartingUserIdentity| Set-ADUser-PassThru | Rename-ADObject -NewName "departed $DepartingUserName" -PassThru

make sure display name matches

Change the display name.  Otherwise, will retain the old name when looking at shared mailboxes in Exchange Online

Get-ADUser $DepartingUserIdentity -Properties DisplayName | select name, DisplayName

It’s kind of weird having to invoke "Foreach-Object" (%) for just one user.  But doesn’t work with merely "| Set-ADUser -DisplayName $_.name" - puts in a null

Get-ADUser $DepartingUserIdentity -Properties DisplayName | Set-ADUser -DisplayName $_.name

so invoke "Foreach-Object" (%)  - even if we’re doing this for just one user

Get-ADUser $DepartingUserIdentity -Properties DisplayName | % {Set-ADUser -Identity $_ -DisplayName $_.name}

replicate domain controller - see domain controller, replicate

replication status of domains - see domain replication status

RSAT (Remote Server Administration Tools)

For Windows 10 version 1903 and later, need to go to Deploy RSAT (Remote Server Administration Tools) for Windows 10 v1903 using SCCM (System Center Configuration Manager) and Powershell and run Install-RSATv1809v1903.ps1 (download)

–S–

sAMAccountName, find all objects containing a substring of a sAMAccountName (for users, contacts, groups, etc.)

Get-ADObject -Filter "SamAccountName -like '*marketing*'" -Properties DisplayName, sAMAccountName, mail | Select-Object DisplayName, Name, sAMAccountName, mail, objectClass | ft

to update one property (extensionAttribute2) in this case whose value is null for a bunch found by wildcard on another property (SamAccountName) in this case

Get-ADObject -Filter "SamAccountName -like 'Srv-C*'" -Properties SamAccountName, extensionAttribute2 | ? {$null -eq $_.extensionAttribute2 } | % {Set-ADUser -Identity $_ -Add @{extensionAttribute2="srv"}}

sAMAccountName wildcard - see sAMAccountName, find all objects containing a substring of a sAMAccountName (for users, contacts, groups, etc.)

search for where some entity might reside whether user/group/contact/alias - see find where some entity might reside whether user/group/contact

set time for a PDC - see ntp time, set for PDC

security group, find email-enabled

Get-ADGroup -Filter {(GroupCategory -eq "Security") -and (mail -like "*")} -Properties name, mail, distinguishedName | Sort-Object mail | ft name, mail, distinguishedName

SID, find name for

$objSID = New-Object System.Security.Principal.SecurityIdentifier ("S-1-5-21-898656534-286731432-926709055-10765");
$objUser = $objSID.Translate([System.Security.Principal.NTAccount]);
$objUser.Value

sync domain controllers, see domain controller, replicate

sync time among domain controllers - see

sync time among domain controllers, report on

–T–

test network connectivity for PCs - see connectivity to a bunch of PCs in an OU, test

test for user not found – see user not found, catch, user exists or not?

time - none of the w32tm commands below are really "PowerShell" commands. But they work OK in PowerShell console.

This mainly has to do with setting and syncing time among domain controllers

sync time among domain controllers, report on

w32tm /monitor

time difference between 2 domain controllers. If you’re on DC1 and want to see how DC2’s time differs from yours:

w32tm /stripchart /computer:DC2 /packetinfo /samples:1

source where this server gets its time

w32tm /query /peers

or

w32tm /query /status

and look at the "Source" record

ntp time, set for PDC

w32tm /config /manualpeerlist:"time.nist.gov,0x1 0.ntp.pool.org,0x1 1.ntp.pool.org,0x1 2.ntp.pool.org,0x1" /syncfromflags:manual /reliable:yes /update

which I usually follow immediately by

w32tm /query /peers

in order to verify. This may show something like this:

State: Pending
Time Remaining: 214.2158447s

at least at first. Even if you wait the number of seconds, it simply resets to something like 1800 (half an hour).

registry settings

w32tm /dumpreg

w32tm /dumpreg /subkey:Config

when you look at w32tm /dumpreg /subkey:Config, above pay attention to the value of AnnounceFlags

w32tm /query /configuration can also return this info

w32tm /dumpreg /subkey:Parameters

when you look at w32tm /dumpreg /subkey:Parameters, above pay attention to the value of NtpServer.

title, find users who don’t have one like

so invoke "Foreach-Object" (%)  - even if we’re doing this for just one user

Get-ADUser -SearchBase "OU=yourOU,DC=yourDomain,DC=com" -Filter '(title -ne "*") -and (title -notlike "contractor")' -SearchScope OneLevel | ft

title, change all contacts in an OU (that has nothing but contacts)

Get-ADObject -filter {objectclass -eq "contact"} -SearchBase "OU=yourOU,DC=yourDomain,DC=com" `
    -Properties name, givenName, middleName, sn, mail, employeeType, title | `
    Set-ADObject -Add @{title="inspector"}

trust relationship broken

Test-ComputerSecureChannel -credential yourdomain\someadmin -Repair

two users, compare membership of AD groups between - see group membership between two users, compare

–U–

unique file permissions within folder – See permissions, unique file permissions in a folder

unlock local user – see also determine whether local users are locked, lock out user

Unlock-ADAccount -Identity houdini

also might work to unlock:

net user "Plebian" /active=yes

update user property – see user, update property

user, all properties

if you try to get a full list of all the properties for a user, you’ll end up with a rather disappointingly small list:

Get-ADUser someuser

You know there’s more stuff buried in there! So use this instead:

Get-ADUser someuser -Properties *

user, compare all properties for a list

("user1", "user2") | %{Get-ADUser $_ -Properties *} | export-csv "c:SomeFile.csv"

user, create

$UserName = "$FirstName $LastName"
$sAMAccountName = "$FirstName.$LastName"
$DefaultPassword = "topSecret"
$UPN = "$sAMAccountName@$UserDomain"
$NewUserParams = @{
    'UserPrincipalName' = $UPN
    'Name' = $UserName
    'DisplayName' = $UserName
    'GivenName' = $FirstName
    'Surname' = $LastName
    'Title' = $Title
    'Department' = $Department
    'SamAccountName' = $sAMAccountName
    'AccountPassword' = (ConvertTo-SecureString $DefaultPassword -AsPlainText -Force)
    'Enabled' = $true
    'Initials' = $MiddleInitial
    'Path' = "$OU"
    'ChangePasswordAtLogon' = $false
    'EmailAddress' = $UPN
}
New-ADUser @NewUserParams

user, disable or enable – see disable user

user exists or not? – see also user not found, catch

$User = Get-MsolUser -UserPrincipalName $upn -ErrorAction SilentlyContinue
If ($Null -ne $User) {"$upn exists in Azure AD"}

Else {"$upn not found in Azure AD"}

users, filter to find – see filter users, user, find by display name wildcard, userAccountControl, filter by, user not found, catch, user exists or not?

user, find by DisplayName – see also filter users, user, find by display name wildcard, userAccountControl, filter by, user not found, catch, user exists or not?

Get-ADUser -Filter {DisplayName -eq "Fred Flintstone"} -Properties Name, DisplayName

find a bunch by name

$displayNames = @("Duck, Huey", "Duck, Dewey", "Duck, Louie", "Duck, Donald")
$i=0; $count = $displayNames.Count
$users = @()
foreach ($displayName in $displayNames) {
    $i++; $percentTxt = ($i/$count).ToString("P")
    $user = Get-ADUser -Filter {DisplayName -eq $displayName} -Properties SamAccountName
    if ($null -ne $user) {
        Write-Host "$i of $($count) ($percentTxt): '$($user.SamAccountName)' found for '$displayName'" -ForegroundColor Green
        $users += New-Object -TypeName PSObject -Property @{
            "SamAccountName" = $user.SamAccountName
        }
    }
    else {
        Write-Host "$i of $($count) ($percentTxt): no SamAccountName found for '$displayName'" -ForegroundColor Yellow
    }
}
$users | ogv

user, find by display name wildcard – see also filter users, userAccountControl, filter by

Get-ADUser -Filter {DisplayName -like "*room*"} -Properties Name, DisplayName

below might work better for a variable

$displName = 'Fred Flint'
Get-ADUser -Filter "DisplayName -like '$displName*'" -Properties DisplayName, sn, givenName

user, find by wildcard (and other objects as well) - see sAMAccountName, find all objects containing a substring of a sAMAccountName (for users, contacts, groups, etc.)

user, get from another domain – see also domain, foreign

find the nearest domain controller for the other domain

$dc = Get-ADDomainController -DomainName tattoine.galaxyfarfaraway.com -Discover -NextClosestSite

specify that nearest domain controller for the other domain when searching for the user

Get-ADUser -Server $dc.HostName[0] "Luke"

user inherits permissions from parent OU – see also users inheriting permissions from parent OU

are permissions inherited?

Get-ADUser Maverick -Properties nTSecurityDescriptor | select Name, @{n="Inherits";e={$_.nTSecurityDescriptor.AreAccessRulesProtected}}

remove inheritance

Get-ADUser Maverick -Properties nTSecurityDescriptor | % {
    $_.ntSecurityDescriptor.SetAccessRuleProtection($false, $true)
    $_ | Set-ADUser -Replace @{ntSecurityDescriptor = $_.ntSecurityDescriptor}
}

opposite from above: add inheritance

Get-ADUser Maverick -Properties nTSecurityDescriptor | % {
    $_.ntSecurityDescriptor.SetAccessRuleProtection($true, $true)
    $_ | Set-ADUser -Replace @{ntSecurityDescriptor = $_.ntSecurityDescriptor}
}

either of these changes takes maybe 10 seconds

user or group – see group or user?

users created recently – see also filter users

users created since 4 pm yesterday

$when = $((Get-Date).Date.AddHours(-8))
Get-ADUser -Filter {whenCreated -ge $when} -Properties whenCreated

users inheriting permissions from parent OU, count both ways – see also user inherits permissions from parent OU

how many users both inherit and do not inherit parent OU permissions?

$OUPath = "OU=Administrators,OU=Operations,DC=minions,DC=com"
 
# Get all the users in the OU with the nTSecurityDescriptor property
$Users = Get-ADUser -Filter * -SearchBase $OUPath -Properties nTSecurityDescriptor
 
# Group the users by the inheritance status
$Groups = $Users | Group-Object -Property {$_.nTSecurityDescriptor.AreAccessRulesProtected}
 
# Loop through each group and display the count
foreach ($Group in $Groups) {
    # Check the inheritance status
    if ($Group.Name -eq "True") {
        # Inheritance is disabled
        Write-Output "Number of users in the $OUPath OU that do not inherit permissions from the parent OU: $($Group.Count)"
    }
    else {
        # Inheritance is enabled
        Write-Output "Number of users in the $OUPath OU that inherit permissions from the parent OU: $($Group.Count)"
    }
}

users, list

Get-ADUser -Filter * | ft

Or only those with emails, sorted by OU and name

Get-ADUser -Properties * -Filter {(Enabled -eq 'True') -and (mail -like '*')} | select name, EmailAddress, @{Label = "Group";Expression = {($_.canonicalname -Split "/")[-2]}} | sort Group, name | ft

users, list all sorted by their OU - see OU, list all users sorted by their OU

users, list all along with contacts, sorted by their OU - see contacts, list alongside users

users, list all for an OU – see OU, list all users for an OU

users, recently created – see users created recently

user locked – see unlock local user, lock out user

user not found, catch – see also user exists or not?, groups, delete several in an array but check if they exist first

try {$user = Get-ADUser -Identity wraith; Write-Host "wraith found" -ForegroundColor Blue}
catch {switch ($_.CategoryInfo.Category) {
  "ObjectNotFound" {Write-Host "wraith not found" -ForegroundColor Red}
  default {Write-Host "some other error occurred: $($_.CategoryInfo.Category)" -ForegroundColor Red} # Catch any other types of errors
  }
}

user, update property

Updating many common attributes can be updated this way…

Set-ADUser -Identity SnowWhite -Surname "White"

However, attempting to update some other attributes this way…

Set-ADUser -Identity SnowWhite -extensionAttribute2 "innocent"

…may give error:

Set-ADUser: A parameter cannot be found that matches parameter name 'extensionAttribute2'.

For such attributes that are empty, “Add”:

Set-ADUser -Identity SnowWhite -Add @{extensionAttribute2="innocent"}

for a bunch found by wildcard

Get-ADObject -Filter "SamAccountName -like 'Srv-C*'" -Properties SamAccountName, extensionAttribute2 | ? {$null -eq $_.extensionAttribute2 } | % {Set-ADUser -Identity $_ -Add @{extensionAttribute2="srv"}}

To change such attributes that already have a value, “Replace”:

Set-ADUser -Identity SnowWhite -Replace @{extensionAttribute2="innocent"}

To delete or clear such attributes that already have a value, “Clear”:

Set-ADUser -Identity "UserName" -Clear "employeeType", "employeeID"

To process many users, some of whose attributes may either be

$users = "tweedleDum", "tweedleDee"
foreach ($user in $users) {
    $userObj = Get-ADUser $user -Properties DisplayName, employeetype
    if ($userObj.employeetype -ne "prs") {
        if ($userObj.employeetype-eq $null) {
            Set-ADUser $user -Add @{employeetype = "prs"}
        } else {
            Set-ADUser $user -Replace @{employeetype = "prs"}
        }
    }
}

userAccountControl attribute – See UserAccountControl attribute: Checking and configuring security settings for Active Directory accounts

userAccountControl, filter by

Get-ADUser -Filter {UserAccountControl -band 0x100000} # 1048576 NOT_DELEGATED

or perhaps you have a variable $someADUsers with a bunch of Users and you want to find all users who have the NOT_DELEGATED (“Account is sensitive and cannot be delegated”) attribute

$notDelegated = $someADUsers | ? {($_.userAccountControl -band 0x100000) -eq 0x100000} # 1048576

userParameters, find users whose userParameters is not null

Get-ADUser -Filter * -Properties samAccountName, userParameters | where {$_.userParameters -ne $null} | Sort-Object samAccountName | fl samAccountName, userParameters

UserPrincipalName

see users with no user principal name field

see also groups with no mail field

see also users with no mail field

users with no mail field

$usersNoMail = Get-ADUser -LDAPFilter "(!mail=*)"

users with no user principal name field

$usersNoUPN = Get-ADUser -LDAPFilter "(!userPrincipalName=*)"

–V–

–W–

wildcard for users, contacts, groups, etc. – see

–X–

–Y–

–Z–