0 Einleitung

Auch WMI hat einige sehr interessante Klassen im Angebot, um im AD vielfältige Aufgaben zu erfüllen. Für einige wichtige Aufgaben  rund um die AD-Replikation stellen WMI-Klassen sogar meines Erachten die besten Methoden bereit.

Ebenso lohnt sich auch ein Blick auf die DNS-Klassen innerhalb von WMI, auf die ich im zweiten Teil dieses Kapitels eingehen werde.

 

1 MSAD - Klassen

MSDN: WMI Provider Classes in Active Directory Domain Services

Insbesondere sind die Klassen interessant, wenn man ein eigenes Monitoring aufbauen oder erweitern möchte,

 

1.1 MSAD_ReplNeighbor

MSDN: MSAD_ReplNeighbor

Mit dieser Klasse kann man

  • viel über den Zustand der Replikation der Domaincontroller einer Umgebung erfahren, ähnlich "Repadmin /Showrepl" (Beispiele 1 und2)
  • die Replikationspartner eines Domaincontrollers auslesen (Beispiel 3)
  • die Replikationstopologie vom KCC neu berechnen lassen, ähnlich "Repadmin /KCC" (Beispiel 4)

Wie immer bei WMI Klassen lassen sich alle Abfragen über den Positionsparameter -Computer auch remote durchführen

 

Beispiel 1: Übersicht über den Replikationsstatus eines Domaincontrollers erstellen

Set-StrictMode -Version "2.0"
Clear-Host

$ReplInfo = Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class MSAD_ReplNeighbor `
            | ft SourceDsaCN, NamingContextDN, LastSyncResult,
@{N="NumSyncFailures"; E={$_.NumConsecutiveSyncFailures}},
@{N="LastSyncAttempt"; E={$_.ConvertToDateTime($_.TimeOfLastSyncAttempt)}},
@{N="LastSyncSuccess"; E={$_.ConvertToDateTime($_.TimeOfLastSyncSuccess)}} -auto

$ReplInfo
#mögliche Ausgabe

SourceDsaCN NamingContextDN                          LastSyncResult NumSyncFailures LastSyncAttempt     LastSyncSuccess    
----------- ---------------                          -------------- --------------- ---------------     ---------------    
DC1 DC=dom1,DC=intern                                0               0              02.04.2013 02:13:26 02.04.2013 02:13:26
DC2 CN=Configuration,DC=dom1,DC=intern               0               0              02.04.2013 00:55:10 02.04.2013 00:55:10
DC1 CN=Configuration,DC=dom1,DC=intern               0               0              02.04.2013 01:55:10 02.04.2013 01:55:10
DC2 CN=Schema,CN=Configuration,DC=dom1,DC=intern     0               0              02.04.2013 00:55:10 02.04.2013 00:55:10
DC1 CN=Schema,CN=Configuration,DC=dom1,DC=intern     0               0              02.04.2013 01:55:10 02.04.2013 01:55:10
DC1 DC=DomainDnsZones,DC=dom1,DC=intern              0               0              02.04.2013 01:55:10 02.04.2013 01:55:10
DC2 DC=ForestDnsZones,DC=dom1,DC=intern              0               0              02.04.2013 00:55:10 02.04.2013 00:55:10
DC1 DC=ForestDnsZones,DC=dom1,DC=intern              0               0              02.04.2013 01:55:10 02.04.2013 01:55:10
DC2 DC=Dom2,DC=dom1,DC=intern                        0               0              02.04.2013 00:55:10 02.04.2013 00:55:10
DC1 DC=Dom2,DC=dom1,DC=intern                        0               0              02.04.2013 01:55:10 02.04.2013 01:55:10
DC2 DC=dom3,DC=dom1,DC=intern                        0               0              02.04.2013 00:55:10 02.04.2013 00:55:10
DC1 DC=dom3,DC=dom1,DC=intern                        0               0              02.04.2013 01:55:10 02.04.2013 01:55:10

Dieses Skript liefert ähnliche Informationen wie "Repadmin -Showreps", allerdings um einiges übersichtlicher

Das Skript oder besser die Klasse hat leider den Nachteil, dass die angegebenen Zeiten nicht der lokalen Zeit entsprechen. Dies liegt daran, dass die Eigenschaften den falschen "BIAS", also den Zeitversatz zurückgeben. Anstelle der lolalen Zeit im WMI-Format "20130402003235.982000+120" (+120 steht für MESZ) erhält man "20130402003235.982000+000" zurück. Die Methode ConvertToDateTime meint nun, dieses 2 Stunden dazuzählen zu müssen, um die richtige Zeit auszugeben. Das scheint mir an dieser Stelle ein Fehler dieser Klasse zu sein, da die Umrechnung sonst immer einwandfrei funktioniert, wie beispielsweise im folgenden Link. Scripting Guys: Berechnen der Serverbetriebszeit

 

Beispiel 2: Fehlgeschlagenen Replikationen ermitteln

Set-StrictMode -Version "2.0"
Clear-Host

$ReplErrors =@()
$ReplNeighbors = Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class MSAD_ReplNeighbor
$ReplNeighbors | Foreach {
  If(($_.LastSyncResult -eq 0) -or ($_.NumConsecutiveSyncFailures -ne 0)) {
  $ReplErrors += `
   "{0} {1} {2} {3} {4} {5}" -f $_.SourceDsaCN, $_.NamingContextDN, $_.LastSyncResult , `
     $_.NumConsecutiveSyncFailures,$($_.ConvertToDateTime($_.TimeOfLastSyncAttempt))  ,  `
     $($_.ConvertToDateTime($_.TimeOfLastSyncSuccess))
    }#If
  }#Foreach #>
 
  If($ReplErrors.Count -eq 0){
   "Aktuell keine Replikationsfehler auf diesem DC"
  }Else{
   Write-Host "SourceDsaCN NamingContextDN LastSyncResult NumSyncFailures LastSyncAttempt LastSyncSuccess" -BackGroundColor Yellow
   $ReplErrors

  }
#mögliche Ausgabe bei Replikationsproblemen

SourceDsaCN NamingContextDN LastSyncResult NumSyncFailures LastSyncAttempt LastSyncSuccess
DC01 CN=Configuration,DC=dom1,DC=intern 8418 0 13.04.2013 18:50:15 12.04.2013 20:50:09
DC02 CN=Configuration,DC=dom1,DC=intern418 0 13.04.2013 18:50:29 12.04.2013 20:50:31

                                                                                                                                               
Besipiel 3: Auslesen der Replikationspartner eines Domaincontrollers (Hostname / DNSHostname)

Set-StrictMode -Version "2.0"
Clear-Host

$HostNames = $(Get-WmiObject -Namespace Root\MicrosoftActiveDirectory -Class MSAD_ReplNeighbor) `
    | ForEach {$_.SourceDsaCN} | Select -unique
$HostNames
""

#[Enum]::GetValues([System.DirectoryServices.AuthenticationTypes])
$AuthenticationType = [System.DirectoryServices.AuthenticationTypes]::Serverbind

$DNSHostnames = $
HostNames | Foreach{
  $LDAPString = [String]::Concat("LDAP://",$Hostname,":389/RootDSE")
  $RootDSE = New-Object System.DirectoryServices.DirectoryEntry($LDAPString,$Null,$Null,$AuthenticationType)
  $RootDSE.DNSHostname
  }
$DNSHostnames
#mögliche Ausgabe

DC1
DC2

dc1.dom1.root.intern
dc2.root.intern

Als Hostnamen erhält man genau die Namen zurück, die man auch in der GUI von "Sites and Services" erhält.

Um den DNSHOstname zu erhalten, stelle ich eine LDAP-Verbindung über den einfachen Hostname zur RootDSE her. Die RootDSE liefert auch noch andere interessante Eigenschaften, wie etwa den Domainlevel.
Auf den richtigen AuthenicationType sollte man hierbei achten, da sonst der LDAP-Verbindungsaufbau ungewöhnlich lange dauern kann:

If your ADsPath includes a server name, specify the AuthenticationTypes.ServerBind flag when using the LDAP provider. Do not use this flag for paths that include a domain name or for serverless paths. Specifying a server name without also specifying this flag results in unnecessary network traffic.

Example:
DirectoryEntry ent = new DirectoryEntry("LDAP://server01",null,null,AuthenticationTypes.ServerBind);


Über die RootDSE kann man übrigens noch eine ganze Reihe interessanter Eigenschaften eines Domaincontrollers auslesen, ohne selbst Domainadministrator sein zu müssen:

MSDN: RootDSE

 

Beispiel 4: Replikations vom KCC überprüfen und berechnen lassen

$WMI = Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class MSAD_DomainController
$WMI.ExecuteKCC(0,0)

Dieses Skript als Admin ausführen

MSDN: ExecuteKCC method of the MSAD_DomainController class

 

1.2 MSAD_DomainController

MSDN: MSAD_DomainController

Mit dieser Klasse lassen sich folgende Prüfungen an einem Domaincontroller durchführen

  • IsAdvertisingToLocator
  • IsGC
  • IsRegisteredInDNS
  • IsSysVolReady
  • PercentOfRIDsLeft

Ich halte diese Informationen für durchaus wichtig. Wenn die Rückgabewerte vom Standard abweichen, sollte ein Monitorsystem Fehler ausgeben.                                                                                                                        

Set-StrictMode -Version "2.0"
Clear-Host

$Query = "Select IsAdvertisingToLocator,IsGC,IsRegisteredInDNS,IsSysVolReady,PercentOfRIDsLeft `
         from MSAD_DomainController"
$WMI = Get-WMIObject -query $Query -NameSpace "root/MicrosoftActiveDirectory" -Computer "."

If ($($WMI.IsAdvertisingToLocator) -eq $True){
     "OK: IsAdvertisingToLocator is $True"
  }Else{
     "Error - $($WMI.$Property)"
  }
       
If ($($WMI.IsGC) -eq $True){      
     "OK: IsGC is $True"
   }Else{
      "This could be an error: IsGC is $False"
   }
         
If ($($WMI.IsRegisteredInDNS) -eq $True){      
      "OK: IsRegisteredInDNS is $True"
   }Else{
      "This could be an error: IsRegisteredInDNS is $False"
   }
         
If ($($WMI.IsSysvolReady) -eq $True){      
       "OK: IsSysvolReady is $True"
   }Else{
       "Error: IsSysvolReady is $False"
   }
     
If ($($WMI.PercentOfRIDsLeft) -gt 20){  
      "OK: $($WMI.PercentOfRIDsLeft)% of RIDs are available"
   }Else{
      "probably an error: $($WMI.PercentOfRIDsLeft)% of RIDs are available"
      "20% are normally minimum"
   }
#mögliche Ausgabe

OK: IsAdvertisingToLocator is True
OK: IsGC is True
OK: IsRegisteredInDNS is True
OK: IsSysvolReady is True
OK: 80% of RIDs are available

(Sehr) kurze Erklärungen zu den einzelnen Eigenschaften findet man im oben genannten MSDN-Link dieser Klasse.

Ob die jeweiligen Fehlerbedingungen wie im Skriptzutreffen, muss man indivuduell pro Umgebung entscheiden.


1.3 MSAD_NamingContext

MSDN: MSAD_NamingContext

Der Wert der von dieser Klasse zurückgegebenen Informationen ist eher überschaubar.

Set-StrictMode -Version "2.0"
Clear-Host

Get-WMIObject -class MSAD_NamingContext -computer "." -namespace root/MicrosoftActiveDirectory `
             | ft DistinguishedName,IsFullReplica -auto
#mögliche Rückgabe

DistinguishedName                                        IsFullReplica
-----------------                                        -------------
DC=ForestDnsZones,DC=RootDom,DC=intern                   True
DC=DomainDnsZones,DC=RootDom,DC=intern                   True
CN=Schema,CN=Configuration,DC=RootDom,DC=intern          True
CN=Configuration,DC=RootDom,DC=intern                    True
DC=RootDom,DC=intern                                     True
DC=SubDom1,DC=RootDom,DC=intern                          False
DC=SubDom2,DC=RootDom,DC=intern                          False

Man könnte also mit diesem Skript prüfen, welche DNs auf einem Domaincontroller vorhanden sind. Allerdings kann man sich diese Information über die unter "1.1 MSAD-ReplNeighbor" beschriebenen Klasse ebenso besorgen, erhält aber zusätzlich noch Hinweise, ob die Replikation dieser DistinguishedNames fehlerfrei läuft.

 

1.4 MSAD_ReplCursor

MSDN: MSAD_ReplCursor

Set-StrictMode -Version "2.0"
Clear-Host

Get-WMIObject -class MSAD_ReplCursor -namespace root/MicrosoftActiveDirectory | `
     ft NamingContextDN,SourceDsaDN, `
     @{N="LastSyncSuccess"; E={$_.ConvertToDateTime($_.TimeOfLastSuccessfulSync)}} -auto

Mit dieser Klasse hat man nocheinmal ein Werkzeug, um die Replikation zu überwachen. Anhand der Eigenschaft "TimeOfLastSuccessfulSync" kann man durch einen Vergleich zur aktuellen Zeit Replikationsprobleme erkennen. Auch hier halte ich die unter "1.1 MSAD-ReplNeighbor" Klasse durch die zusätzlichen Informationen für geeigneter.

 

1.5 MSAD_PendingOp

MSDN: MSAD_PendingOp

Mit dieser Klasse kann man recht einfach prüfen, ob es hängende Replikationsjobs gibt

Set-StrictMode -Version "2.0"
Clear-Host

$PendingOps = @(Get-WMIObject -class MSAD_ReplPendingOp -namespace root/MicrosoftActiveDirectory)

If($PendingOps.Count -eq 0){
   "There are no pending replication jobs"
   }else{
   "There are some replication jobs in delay"
   $PendingOps | ft * -auto
   }
#mögliche Ausgabe

There are no pending replicationjobs

 

2 User und Gruppenverwaltung mit WMI

Es ist nicht allzu üblich, aber mit WMI kann man auch recht gut ADObjekte wie User und Gruppen administrieren. Da aber dieser Weg nicht optimiert ist,  siehe: WMI Win32_Group ASSOCIATORS Queries Are Not Optimized nur ein paar kurze Beispiele

 

Beispiel 1: Auslesen aller AD-Gruppen

$Query = "ASSOCIATORS OF {Win32_NTDomain.Name='Domain: DOM1'} WHERE assocClass=Win32_GroupInDomain"
Get-WmiObject -Query $query | select Name,description
#Ausgabe gekürzt
name                                         description                                
----                                         -----------                                
Zertifikatherausgeber                        Mitglieder dieser Gruppe dürfen Zertifik...
RAS- und IAS-Server                          Server in dieser Gruppe können auf die R...
Zulässige RODC-Kennwortreplikationsgruppe    Mitglieder dieser Gruppe können Kennwört...
Abgelehnte RODC-Kennwortreplikationsgruppe   Mitglieder dieser Gruppe können Kennwört...
DnsAdmins                                    Gruppe "DNS-Administratoren" 

     

Beispiel 2: Ermitteln aller an einem Computer angemeldeten Useraccounts (Domaincontroller oder Client)

$Computer = "dc1"
$SessionIDs=get-wmiObject -class "win32_logonsession" -namespace "root\CIMV2" -computer $Computer


$SessionIDs | %{
$Query="Associators of {win32_logonsession.LogonID=$($_.LogonID)}"
Get-Wmiobject -query $Query -computer $Computer |?{$_.__class -eq "Win32_UserAccount"} |select  caption}
#Ausgabe

caption
-------
DOM1\Admin2
DOM1\User1
DOM1\Administrator