1 Forest

MSDN: Forest-Klasse

Da es schon kilometerweise Literatur über die Bedeutung von Forests und Domains im ActiveDirectory gibt, wil ich mich nicht groß mit der Theorie aufhalten und gleich mit Beispielen loslegen..
Auf den Forest muss man sich beispielsweise verbinden, wenn man mehrere Domänen besitzt und diese einzeln nach bestimmten Kriterien durchsuchen will. Befindet man sich in einer Single-Domainumgebung kann man diesen Schritt übergehen:
 

2 Domains

 

Beispiel 1: Mehrere Varianten zum Ermitteln der aktuellen Domäne und aller Domaincontroller

"$('=' * 20) getcurrentdomain $('=' * 20)"
$dom=[System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$dom

"$('=' * 20) Alle DCs der Domäne, Methode 1 $('=' * 20)"
$dom.findalldomaincontrollers() | select name,ipaddress,sitename

"$('=' * 20) Alle DCs der Domäne, Methode 2 $('=' * 20)"
$dom.domaincontrollers | select name,ipaddress,sitename

"$('=' * 20) Alle DCs in ein Array $('=' * 20)"
$DCs=$dom.domaincontrollers
foreach ($DC in $DCs){$DC.Name}

DomainController Properties zeigt die möglichen Eigenschaften

 

Beispiel 2: Auflisten aller GlobalCatalogserver eines Forests

$MyForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DCGCs = $MyForest.FindallGlobalCatalogs()
$DCGCs | Format-Table Name, IPAddress, Domain, OsVersion, Roles, Sitename

DomainController Properties zeigt die möglichen Eigenschaften

 

Beispiel 3: Auflisten aller DCs eines Forests

Set-StrictMode -Version "2.0"
Clear-Host
 
$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
 
$AllOutput = @()
$Forest.Domains | ForEach{
  [PsObject]$OutPut = "" | Select-Object DomainName,DCName,OSVersion,IPAddress,IsGlobalCatalog
  $Output.DomainName = $_.Name
  $DirectoryContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$_.Name)
  $([System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DirectoryContext).DomainControllers) | ForEach{
     $Output.DCName = $_.Name
     
     $Output.IpAddress = $($_.IpAddress)
     $OutPut.IsGlobalCatalog = $($_.IsGlobalCatalog())
     $Output.OsVersion = $($_.OSVersion)
     $Output
     $AllOutput += $Output
  }
}    
$AllOutput | Format-Table -AutoSize

DomainController Properties zeigt die möglichen Eigenschaften

isglobalcatalog() ist eine Methode der DomainControllerClass DomainController Methods

 
Beispiel 4: Auflisten aller DCs einer beliebigen Domäne des Forests mit IPAdresse und Sitezugehörigkeit
Set-StrictMode -Version "2.0"
Clear-Host

$Context = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain","Subdom.Dom1.Intern")
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)

foreach ($DomainController in $Domain.DomainControllers){
  $Name = $DomainController.Name
  $SiteName = $DomainController.SiteName
  $IPAddress =  $DomainController.IPAddress
  $ServerSite = $DomainController.SiteName
 
  "{0}  {1} {2}" -f $Name,$IPAddress,$ServerSite  
}
#mögliche Ausgabe

DC01.Subdom.Dom1.Intern  192.125.38.81 Site1
DC02.Subdom.Dom1.Intern  192.125.38.92 Site1
DC06.Subdom.Dom1.Intern  192.168.86.78 Site2
DC07.Subdom.Dom1.Intern  192.168.86.39 Site2
 
 
Beispiel 5: Bestimmen des DistinguishedName und der GUID eines Servers
Im obigen Beispiel habe ich mir alle Domaincontroller aus der Domain-Klasse besorgt. Viele, aber nicht alle Eigenschaften sind in den Properties der FindOne / FindAll Objekte enthalten. Man muss dann, wie hier gezeigt, ein extra ADSI-Objekt erzeugen und abfragen.
Set-StrictMode -Version "2.0"
Clear-Host

$CommonName = "DC01"

$DirectorySearcher = ([ADSISearcher]"LDAP://")
$Filter = "(&(objectCategory=computer)(cn=$DCName))"
$DirectorySearcher.Filter = $Filter

$DN = $DirectorySearcher.FindOne()
$DirectorySearcher.FindOne().Properties.distinguishedname
$DirectorySearcher.FindOne().Properties.operatingsystem
""
#weitere Eigenschaften über die ADSI-Klasse (DirectoryEntry) auslesen
$DC = [ADSI]"LDAP://$DN"
$DC.GUID
#mögliche Ausgabe

CN=DC01,OU=Domain Controllers,DC=domain01,DC=forest,DC=intern
Windows Server 2008 R2 Standard

c6244f5315b6147a8de000f5606bcfc5
 

3 Das ActiveDirectory Schema 

Hey, Scripting Guy!: How to Find Active Directory Schema Update History by Using PowerShell

Beispiel 1: Ermitteln der Schemaversion

Set-StrictMode -Version "2.0"
Clear-Host
 
#by LDAPQuery
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$Pdce = $Domain.PdcRoleOwner.Name
$DomainDN = ([ADSI]"LDAP://rootDSE").DefaultNamingContext
$SchemaContext = "LDAP://$PDCe/cn=schema,cn=configuration,$domainDN"
$([ADSI]$SchemaContext).ObjectVersion
 
#by cmdlets
$(Get-ADObject (Get-ADRootDSE).schemaNamingContext  -Properties objectVersion).objectVersion
in beiden Fällen sollte euch die Schemaversion des Forests angezeigt werden, die ihr dann mit Hilfe des oben verlinkten Artikels der Scripting Guys einer Windowsversion zuordnen könnt.
 
Weitere Scripte für das AD-Schema findet ihr hier: Schema - Queries
 
Noch ein kurzes Wort zu Schemaupdates:
Bekanntlich gibt es nach einem Schemaupdate keinen Weg zurück. Fehlerhafte Schemaupdates können daher zumindest theoretisch einen ganzen Forest lahmlegen und ein Desaster Recovery erforderlich machen. Deswegen plant und testet hoffentlich jeder von Euch anstehende Schemaupdates entsprechend sorgfältig in Test- und Prestagingumgebungen.
Es gibt noch einen weiteren, vielleicht etwas weniger bekannten Punkt, den man zumindest kennen sollte: Wie ihr in der letzten Ausgabe von Beispiel 1b  seht, fügen Schemaupdates meist neue ObjektKlassen mit Eigenschaften und Indexes in das bestehende Schema ein. Das bedeutet, dass jeder(!) Domaincontroller den Datenbankindex der ActiveDirectory-Datenbank (ntds.dit) nach Erhalt des Updates lokal neu berechnen muss. Ältere Hardware kann dabei an ihre Grenzen kommen und der DC kann aufgrund hoher CPU-Last vorübergehend beispielsweise keine Anmeldungen verarbeiten.  
Im Systemlog des DCs seht ihr übrigens die entsprechenden Events, die die Indexerstellung anzeigen. 
 

3.1 Unterbinden der Replikation von und zu einem DC

Zur Durchführung eines Schemaupdates ist es aus oben genannten Gründen sinnvoll, den ersten Domaincontroller, der das Schemaupdate erhält, replikationstechnisch zu isolieren. Wenn das Schemaupdate auf einem DC fehlerfrei durch gelaufen ist, kann man die Replikation auf die übrigen DCs freigeben. Dafür gibt es einen relativ einfachen Trick

Zusammengefasst beschreibt dieser Artikel, dass nur solche Domaincontroller untereinander replizieren, deren Attribut "ms-DS-ReplicationEpoch" Attribute des Objekts "NTDS Settings" gleich sind. Default ist dieses Attribut nicht gesetzt. Umgekehrt bedeutet das Setzen von "ms-DS-ReplicationEpoch" auf einen beliebigen Wert (zum Beispiel "5"), dass dieser DC nicht mehr repliziert. Im "Directory Service" Eventlog zeigen die Events 1875 und 1876 auf unterschiedliche Epoch-Versionen zwischen den Domaincontrollern hin. 
msDS-Replication kann man natürlich auch über ADSI-Edit oder LDP.exe setzen
CN=NTDS Site Settings,CN=<SiteName>,CN=Sites,CN=Configuration,DC=dom1,DC=intern
 
Nach dem Entfernen des Attributs repliziert der DC sofort wieder.