Public/Schema/Get-ADSchemaClassPossibleChildren.ps1
|
<#
.SYNOPSIS List the classes that can be created directly under an instance of an Active Directory class. .DESCRIPTION Reads the 'possibleInferiors' attribute of the class definition in the schema. Active Directory calculates that attribute itself, from the possSuperiors and systemPossSuperiors of every other class, so the answer already accounts for inheritance and needs no walking of the schema. Useful when designing an OU structure, or when a creation fails with a naming violation and you want to know what the container will actually accept. Note this is what the schema allows, not what the current user is allowed to do. Permissions are not taken into account here, and the answer does not depend on the rights of the account running the query. Reference: https://learn.microsoft.com/windows/win32/adschema/a-possibleinferiors .PARAMETER ClassName LDAP display name of the class, such as 'user', 'organizationalUnit' or 'container'. .PARAMETER Server Domain controller or domain to query. Defaults to the one selected by the ActiveDirectory module. .EXAMPLE Get-ADSchemaClassPossibleChildren -ClassName 'organizationalUnit' Lists everything that can be created inside an OU. .EXAMPLE Get-ADSchemaClassPossibleChildren -ClassName 'computer' Lists what can live under a computer object, which is where the printQueue and the LAPS related objects show up. .EXAMPLE Get-ADSchemaClassPossibleChildren -ClassName 'user' -Server 'dc01.contoso.com' Queries a specific domain controller. .OUTPUTS System.String, one per class, sorted. .NOTES Version : 2.0 - August 2026. Migrated from the ActiveDirectory-Toolbox repository. The original built the distinguished name as "CN=$ClassName,$schemaNC", which assumes the common name of the class equals its LDAP display name. That holds for 'user' but not for most classes: the LDAP display name 'organizationalUnit' has 'Organizational-Unit' as its common name, so the lookup failed. The class is now resolved on its lDAPDisplayName, which is what the parameter has always been documented to take. Author : Bastien Perez - ITPro-Tips (https://itpro-tips.com) .LINK https://itpro-tips.com #> function Get-ADSchemaClassPossibleChildren { [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory, Position = 0)] [string]$ClassName, [string]$Server ) $ErrorActionPreference = 'Stop' # Common parameters forwarded to every ActiveDirectory cmdlet call $adParameters = @{ ErrorAction = 'Stop' } if ($PSBoundParameters.ContainsKey('Server')) { $adParameters.Add('Server', $Server) } try { $schemaNamingContext = (Get-ADRootDSE @adParameters).schemaNamingContext } catch { Write-Error "Unable to read the RootDSE: $($_.Exception.Message)" return } $getADObjectParams = $adParameters.Clone() $getADObjectParams.SearchBase = $schemaNamingContext $getADObjectParams.LDAPFilter = "(&(objectClass=classSchema)(lDAPDisplayName=$ClassName))" $getADObjectParams.Properties = 'possibleInferiors' # Wrapped in an array, an ADObject implements IDictionary so 'Count' on a single object would return its # number of properties rather than 1 $classesFound = @() try { $classesFound = @(Get-ADObject @getADObjectParams) } catch { Write-Error "Unable to query the schema partition: $($_.Exception.Message)" return } if ($classesFound.Count -eq 0) { Write-Error "Class '$ClassName' not found in the schema" return } $possibleChildren = @($classesFound[0].possibleInferiors) if ($possibleChildren.Count -eq 0) { Write-Warning "The class '$ClassName' cannot contain any object" return } return ($possibleChildren | Sort-Object) } |