I think I've figured it out by combining my searcher template with the script from the Soon-To-Expire Passwords report script. I'm getting an error with line 89 and the msDS-ResultantPSO property however. Here is my current script.
# Get parameter values
$days = 14 # TO DO: Modify Me - How soon password expires
$now = Get-Date
$nowInt64 = $now.ToFileTime()
$threshold = $now.AddDays($days)
$thresholdInt64 = $threshold.ToFileTime()
$commandID = "{d8ff58b9-8131-4041-9861-2b73a02983e1}" # TO DO: Modify Me
# List of OUs to search
$ouDNs = @("OU=User OU 1,DC=domain,DC=com")
$ouDNs += "OU=User OU 2,DC=domain,DC=com"
$ouDNs += "OU=User OU 3,DC=domain,DC=com"
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
# Connect to the Adaxes service
$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")
Function FindUsers ($ouPath, $officesInfo) {
$searcher = New-Object "Softerra.Adaxes.Adsi.Search.DirectorySearcher" $NULL, $False
$searcher.SearchParameters.PageSize = 500
$searcher.SearchParameters.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.SearchParameters.BaseObjectPath = "$ouPath"
### Build search filter ###
# We filter out user accounts whose password never expires or must be changed at next logon,
# as well as interdomain trust accounts and accounts required to use smart cards
$filterUsers = "(sAMAccountType=805306368)"
$filterPasswordLastSet = "(!(pwdLastSet=0))"
$filterPasswordNeverExpires = "(!(userAccountControl:1.2.840.113556.1.4.803:=65536))"
$filterSmartCardLogon = "(!(userAccountControl:1.2.840.113556.1.4.803:=262144))"
$filterInterdomainTrust = "(!(userAccountControl:1.2.840.113556.1.4.803:=2048))"
$filterDisableUsers = "(!(userAccountControl:1.2.840.113556.1.4.803:=2))"
$filter = "(&" + $filterUsers + $filterPasswordLastSet + $filterPasswordNeverExpires + $filterSmartCardLogon + $filterInterdomainTrust + $filterDisableUsers +")"
$searcher.SearchParameters.Filter = $filter
$searcher.SearchParameters.ReferralChasing = "ADS_CHASE_REFERRALS_NEVER"
# Load these properties
$searcher.SetPropertiesToLoad(@("msDS-UserPasswordExpiryTimeComputed","msDS-ResultantPSO","pwdLastSet","distinguishedName","userPrincipalName"))
$result = $searcher.ExecuteSearch()
$users = $result.FetchAll()
$result.Dispose()
# Map domain names to maximum password age specified in the default domain password policy
$domainToMaxPwdAge = @{}
# Map policy DN to its name
$policyDnToName = @{}
# Custom column identifiers
$effectivePolicyColumnID = "{a9cc0207-e218-4392-aff2-01222f74b001}"
$passwordExpiresColumnID = "{41055ea7-4c35-4025-ba3a-5d65871b4a59}"
# Find users with soon-to-expire passwords
ForEach ($user in $users) {
$username = $user.Properties["userPrincipalName"].Value
$dn = $user.Properties["distinguishedName"].Value
$expiryTime = $user.GetPropertyByName("msDS-UserPasswordExpiryTimeComputed").Values[0]
If ($expiryTime -eq $NULL) # Fine-Grained Password Policies not supported
{
# Get the maximum password age from the default domain password policy
$domain = $Context.GetObjectDomain($user.AdsPath.DN)
If (-not $domainToMaxPwdAge.Contains($domain))
{
# Bind to the default naming context
$nc = $Context.BindToObjectEx("Adaxes://$domain", $False)
# Get the value of the maxPwdAge property
$maxPwdAgeLargeInt = $nc.Get("maxPwdAge")
# Remember the value
$domainToMaxPwdAge[$domain] =
[Softerra.Adaxes.Adsi.AdsLargeInteger]::ToInt64($maxPwdAgeLargeInt)
}
$maxPwdAge = $domainToMaxPwdAge[$domain]
If ($maxPwdAge -eq 0x8000000000000000) # no maximum password age
{
$expiryTime = $maxPwdAge
}
Else
{
$passwordLastSet = $user.GetPropertyByName("pwdLastSet").Values[0]
$expiryTime = $passwordLastSet - $maxPwdAge
}
}
If (($expiryTime -gt $nowInt64) -and ($expiryTime -lt $thresholdInt64))
{
# Get effective policy name
#$policyDN = $user.GetPropertyByName("msDS-ResultantPSO").Values[0]
$policyDN = $NULL
If ([String]::IsNullOrEmpty($policyDN))
{
$policyName = "<Default Domain Policy>"
}
Else
{
If (-not $policyDnToName.Contains($policyDN))
{
$policyDNObj = New-Object Softerra.Adaxes.LDAP.DN $policyDN
$policyDnToName[$policyDN] = $policyDNObj.Leaf.Value
}
$policyName = $policyDnToName[$policyDN]
}
$columnValues = @{ $effectivePolicyColumnID=$policyName; $passwordExpiresColumnID=$expiryTime }
#$Context.Items.Add($user, $columnValues, $NULL)
# Bind to the user
$userObj = $admService.OpenObject("Adaxes://$dn", $NULL, $NULL, 0)
# Execute Custom Command
$userObj.ExecuteCustomCommand($commandID)
}
}
}
ForEach ($ouDN in $ouDNs)
{
# Bind to OU
$ou = $Context.BindToObjectByDN($ouDN)
# Build report part for current OU
$ouName = [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($ou, 'IncludeParentPath')
# Add users
$ouMatches = $NULL
$ouMatches = FindUsers $ou.ADsPath $ouName
}