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
- email has to be present. That is: not null: (
mail -like "*"
) - enabled (
-and enabled -eq "true"
) - last name has to be present. That is: not null: (
-and Surname -like "*"
)
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
catch user not found – see user not found, catch, user exists or not?
change user property – see user, update property
$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
- having permission to look into the cluster or
- not even being able to find it.
But this gives at least some accounting.
compare AD group membership between two users - see group membership between two users, compare
computers, list – see also computers from another domain, list
Get-ADComputer -Filter * -Property * | Sort-Object Name | Select-Object Name,CN,DisplayName,IPv4Address,Enabled,OperatingSystem,OperatingSystemServicePack,OperatingSystemVersion,LastLogonDate, LogonCount,whenCreated,DistinguishedName,DNSHostName
Are they online?
$computers
=
Get-ADComputer
-Filter * -Property * |
Sort-ObjectName
foreach
($computer
in
$computers)
{
if
(Test-Connection
-count
1
-computer
$computer.Name
-quiet){
Write-Host
"$($computer.Name) online, last logged in $($computer.LastLogonDate)"
-ForegroundColor
Green}
else
{Write-Host
"$($computer.Name) offline, last logged in $($computer.LastLogonDate)"
-ForegroundColor Red}
}
a more complete report that combines various properties - including the lowest leaf of the PC's OU - along with whether each computer is online or offline:
$report
=
@()
$computers
=
Get-ADComputer
-Filter * -Property * |
Sort-Object
whenCreated |
Select-Object
Name,CN,DisplayName,IPv4Address,Enabled,OperatingSystem,OperatingSystemServicePack,OperatingSystemVersion,LastLogonDate,
LogonCount,whenCreated,@{n="OU";e={$_.DistinguishedName.split(",")[1]}},DistinguishedName,DNSHostName
foreach
($computer
in
$computers)
{
$thisComputer
=
New-Object
PSObject
if
(Test-Connection
-count
1
-computer
$computer.Name
-quiet){
Write-Host
"$($computer.Name) online, last logged in $($computer.LastLogonDate)"
-ForegroundColor Green
$thisComputer
|
Add-Member
NoteProperty -Name
"OnOrOff"
-Value
"on"
}
else
{
Write-Host
"$($computer.Name) offline, last logged in $($computer.LastLogonDate)"
-ForegroundColor Red
$thisComputer
|
Add-Member
NoteProperty -Name
"OnOrOff"
-Value
"off"
}
$thisComputer
|
Add-Member
NoteProperty -Name
"LastLogonDate"
-Value
$computer.LastLogonDate
$thisComputer
|
Add-Member
NoteProperty -Name
"DisplayName"
-Value
$computer.DisplayName
$thisComputer
|
Add-Member
NoteProperty -Name
"Name"
-Value
$computer.Name
$thisComputer
|
Add-Member
NoteProperty -Name
"IPv4Address"
-Value
$computer.IPv4Address
$thisComputer
|
Add-Member
NoteProperty -Name
"Enabled"
-Value
$computer.Enabled
$thisComputer
|
Add-Member
NoteProperty -Name
"OperatingSystem"
-Value
$computer.OperatingSystem
$thisComputer
|
Add-Member
NoteProperty -Name
"OperatingSystemVersion"
-Value
$computer.OperatingSystemVersion
$thisComputer
|
Add-Member
NoteProperty -Name
"LogonCount"
-Value
$computer.LogonCount
$thisComputer
|
Add-Member
NoteProperty -Name
"whenCreated"
-Value
$computer.whenCreated
$thisComputer
|
Add-Member
NoteProperty -Name
"OU"
-Value
$computer.OU.split("=")[1]
$thisComputer
|
Add-Member
NoteProperty -Name
"DistinguishedName"
-Value
$computer.DistinguishedName
$thisComputer
|
Add-Member
NoteProperty -Name
"DNSHostName"
-Value
$computer.DNSHostName
$report
+=
$thisComputer
}
$report
|
Export-CSV
-Path
"$([environment]::getfolderpath("mydocuments"))\ADComputers$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"
-NoTypeInformation -Encoding UTF8
$report | 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"
color:#CE9178'>"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
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
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?
$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
distribution group, count how many in see group, count how many in
distribution group, show members - see group members, show
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?
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
(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
group members, show including any members belonging to a domain other than our default, local domain
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
repadmin /showreps
$DomainName
= (Get-ADDomain).DNSRoot
domains in a forest, list – see forest domains, list
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?
filter users – see also user, find by display name wildcard, userAccountControl, filter by
Get-ADUser -Filter {employeeType -eq "tst"}
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:
- Contacts
- Distribution groups
- Email-enabled security groups
- Users
- Email aliases
Respectively
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
Same 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
Same 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
foreign domain – see domain, foreign
for the current user (you):
(Get-ADForest -Current LoggedOnUser).domains
found, user not – see user not found, catch, user exists or not?
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
Move-ADDirectoryServerOperationMasterRole -Identity someServer PDCEmulator, RIDMaster, InfrastructureMaster
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
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.
this 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 and store that information in a CSV (including member information) in case you need to recreate groups
$groupNames
= ("Orc-Owners",
"Orc-Infantry",
"Orc-Officers)
$i=0
$result
=
@()
$alternateDomain
=
"isengard.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
}
$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
userCount
=
$j
memberSamAccountName
=
$member.SamAccountName
userDisplayName
=
$user.DisplayName
}
$j++
}
Remove-ADGroup
-Identity
$group.SamAccountName
-Confirm:$true
$i++
}
$result=
$result
| select
groupCount, groupName, groupDisplayName, groupSamAccountName,
groupDistinguishedName, groupGroupScope, groupDescription, groupGroupCategory,
userCount, memberSamAccountName, userDisplayName
$result | ogv
$result
|
Export-Csv
-Path
"$([environment]::getfolderpath("mydocuments"))\DeletedGroupsIowaEyeBank1719809$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"
-NoTypeInformation -Encoding UTF8
group, find by display name wildcard
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
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
group membership between two users, compare
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 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
this 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 size limit exceeded
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.
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}
$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
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
$groupsNoMail = Get-ADGroup -LDAPFilter "(!mail=*)"
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)
join a PC to the domain - see rejoin a PC to the domain
list all computers in the domain, see computers, list
list name servers - see domain name servers, list
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
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
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 group - see group members, show
membership of AD groups between two users, compare - see group membership between two users, compare
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 user - see user, create
not found, user – see user not found, catch, user exists or not?
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.
operating system versions of all computers, see computers, list
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
$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
"/"
or as a one-liner with a select
statement:
$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
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
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
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
OU, users inherit permissions? – see user inherits permissions from parent OU
OUs (Organizational Units), list
Get-ADOrganizationalUnit -filter * | ft Name, DistinguishedName
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
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...
Get-ADUser -Filter {UserAccountControl -band 0x20} # 32 PASSWD_NOTREQD
password policy resulting from GPO
Get-ADUserResultantPasswordPolicy StevieWonder
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
catch [System.UnauthorizedAccessException]
permissions, set for file or folder - see ACL, set
permissions, users inherit permissionsn 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.
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 - is a 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))
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
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 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)
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
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
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
- For the PDC, should be set to something like
time.nist.gov
- For the other DCs, should be set to the IP of the 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 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:Parameters when you look at 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
Time Remaining: 214.2158447s
w32tm /dumpreg /subkey:Config
, above pay attention
to the value of AnnounceFlags
w32tm /query /configuration
can also return this infow32tm /dumpreg /subkey:Parameters
, above pay attention
to the value of NtpServer
.
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
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
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"
$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
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, 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
user locked – see unlock local user, lock out user
user not found, catch – see also user exists or not?
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
}
}
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 such attributes that already have a value, replace:
Set-ADUser -Identity SnowWhite -Replace @{extensionAttribute2="innocent"}
userAccountControl attribute – See UserAccountControl attribute: Checking and configuring security settings for Active Directory accounts
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
see users with no user principal name field
see also groups with no mail field
see also users with no mail field
$usersNoMail = Get-ADUser -LDAPFilter "(!mail=*)"
users with no user principal name field
$usersNoUPN = Get-ADUser -LDAPFilter "(!userPrincipalName=*)"
wildcard for users, contacts, groups, etc. - see sAMAccountName, find all objects containing a substring of a sAMAccountName