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
attribute changed last for a user – see property changed last for a user
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
$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.
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
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
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
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. 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
$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?, 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
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:
- Contacts
- Distribution groups
- Email-enabled security groups
- Users
- Email aliases
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
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
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.
renames the "Name" property which can’t do using GUI
Rename-ADObject -Identity (Get-ADGroup -Identity "oldName").ObjectGUID -NewName "newName"
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; 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
$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)
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"}
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?
- OU permissions – groups or users with permissions with their permissions
- user inherits permissions from parent OU?
- users inheriting permissions from parent OU, count both ways
join a PC to the domain - see rejoin a PC to the domain
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
gpedit.msc
secpol.msc
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
$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"})
}
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
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?
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 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:
"(?<!\\),"
: 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."(,)"
: 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:
- OU=Sales
- OU=North,America
- OU=Users
- DC=example
- 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
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`""
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
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
$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
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))
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
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)
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
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
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
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 – 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
}
}
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
- already OK
- something other than what it should
- null
$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
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