Hey, Scripting Guy!Durchsuchen von Active Directory

Die Scripting Guys von Microsoft

Codedownload verfügbar unter: HeyScriptingGuy2009_02.exe(151 KB)

Inhalt

Bereitstellen von Hilfe
Das Wesentliche
Hilfsfunktionen

Wie Sie vielleicht wissen, sind der Skripting Editor und ich seit kurzem die neuen hauptamtlichen Scripting Guys von Microsoft. Einen großen Teil unserer Arbeitszeit haben wir unlängst darauf verwendet, die Tausenden von E-Mails durchzusehen, die an scripter@microsoft.com geschickt werden. Wir haben zwar keine diesbezügliche Studie in Auftrag gegeben, würden aber behaupten, dass die am häufigsten per E-Mail gestellte Frage die folgende ist: „Wo bekomme ich den Active Directory Browser?“ Aber wissen Sie was? Wir haben diesen Browser nie gesehen. Wir haben lange gesucht, konnten ihn aber nicht finden.

Nach dem Posten einiger geheimer Beiträge in einem Diskussionsforum im Internet erhielten wir schließlich eine codierte Antwort, die uns nach der Entschlüsselung verriet, dass ADSI Scriptomatic der Active Directory Browser ist. Da das Programm nicht Active Directory Browser heißt und sein Zweck eigentlich auch nicht darin besteht, Active Directory zu durchsuchen (es erleichtert Ihnen das Erstellen von ADSI-Skripts), habe ich beschlossen, ein Windows PowerShell-Skript zu schreiben, mit dessen Hilfe Sie das Active Directory-Schema durchsuchen können. Dieses Schema trägt den Namen „BrowseActiveDirectorySchema.ps1“ (siehe Abbildung 1).

Abbildung 1 BrowseActiveDirectorySchema.ps1

Param($action,$class, [switch]$help)

Function GetHelp()
{
  $helpText= '
@"
 DESCRIPTION:
 NAME: BrowseActiveDirectorySchema.ps1
 Browse Active Directory Schema. Lists Classes, and properties. 

 PARAMETERS: 
 -Action <L(ist all classes), M(andatory), O(ptional), F(ind)>
 -Class class to search: user, computer, person, contact etc
 -Help displays this help topic

 SYNTAX:
 BrowseActiveDirectorySchema.ps1 -A L
 Lists the name of each class defined in the AD schema

 BrowseActiveDirectorySchema.ps1 -A M -c user
 Lists the mandatory properties of the user class

 BrowseActiveDirectorySchema.ps1 -A O -c computer
 Lists the optional properties of the computer class

 BrowseActiveDirectorySchema.ps1 -A F -c user
 Lists all Active Directory Classes that contain the word user 
 in the actual class name

 BrowseActiveDirectorySchema.ps1 -Action Find -c user
 Lists all Active Directory Classes that contain the word user 
 in the actual class name

 BrowseActiveDirectorySchema.ps1 -help
 Prints the help topic for the script
"@ #end helpText
  $helpText
} #end GetHelp
Function GetADSchema($Action, $class)
{
 $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
 Switch ($Action)
  {
   "classes" { 
              $schema.FindAllClasses() | 
              Select-Object -Property Name 
             }
   "Mandatory" 
             {
              "Mandatory Properties of $class object"
              ($schema.FindClass("$class")).MandatoryProperties | 
               Format-Table -Property Name, Syntax, IsSingleValued -AutoSize 
             }
   "Optional" 
             {
              "Optional Properties of $class object"


              "This might take a few seconds ..."
              ($schema.FindClass("$class")).OptionalProperties | 
              Format-Table -Property Name, Syntax, IsSingleValued -AutoSize 
             }
   "Find" 
             {
              $schema.FindAllClasses() | 
              Where-Object { $_.name -match "$class" } |
              Select-Object -property name
             }
   DEFAULT {"$action is not a valid action." ; GetHelp ; Exit}
  }
} #end GetADSchema

Function GetAllClasses()
{
 GetAdSchema("classes")
} #end GetAllClasses

Function GetMandatory($class)
{
 GetAdSchema -action "Mandatory"  -class $class 
} #end GetMandatory

Function GetOptional($class)
{
 GetAdSchema -action "Optional"  -class $class 
} #end GetOptional

Function FindClasses($class)
{
 GetAdSchema -action "Find" -class $class
} #end FindClasses
# *** Entry Point to Script ***
if($help) { GetHelp ; Exit }

Switch ($action)
{
 "L" {GetAllClasses ; Exit}
 "M" {GetMandatory($class) ; Exit}
 "O" {GetOptional($class) ; Exit}
 "F" {FindClasses($class) ; Exit}
 DEFAULT { "$action is not a valid action." ; GetHelp ; Exit} 
}

Wie Sie sehen, beginnt das Skript mit der Param-Anweisung. Sie dient der Erstellung dreier Befehlszeilenparameter, die Ihnen ermöglichen, das Skript durch Ausführen zu ändern, statt es bearbeiten zu müssen, um unterschiedliches Verhalten zu beobachten. Dies ist ziemlich hilfreich:

Param($action,$class, [switch]$help)

Wenn Sie beispielsweise die erforderlichen Eigenschaften der user-Klasse in Active Directory-Domänendiensten (AD DS) sehen möchten, geben Sie die Parameter „–action M“ und „–class user“ an (siehe Abbildung 2).

fig02.gif

Abbildung 2 Anzeigen der erforderlichen Eigenschaften der user-Klasse

Ebenso problemlos könnten Sie die optionalen Eigenschaften der group-Klasse auswählen. Dies ist der Vorteil bei der Verwendung von Befehlszeilenparametern: Sie können das Verhalten eines Skripts zur Laufzeit ändern, statt noch einmal von vorn anfangen zu müssen. Dies ist eine bewährte Methode beim Schreiben von Skripts, die Sie als Dienstprogramme einsetzen möchten, im Unterschied zu jenen, die Sie nur einmal verwenden.

Bereitstellen von Hilfe

Im nächsten Abschnitt des Skripts in Abbildung 1 wird die GetHelp-Funktion gezeigt. Wenn Sie ein Skript schreiben, das Befehlszeilenparameter verfügbar macht, wird als bewährte Methode empfohlen, eine Funktion aufzunehmen, die Hilfe zum Verwenden des Skripts anzeigt. Schließlich wollen Sie vermeiden, dass die Benutzer Ihres Skripts das Skript öffnen und den gesamten Text durchgehen müssen, um herauszufinden, wozu es dient. Zwar gilt beim Skriptentwurf der Leitsatz, dass ein Skript gut lesbar sein sollte, aber wenn Sie eine Hilfefunktion aufnehmen, erleichtern Sie den Benutzern die Arbeit.

Die GetHelp-Funktion zeigt Informationen auf ganz ähnliche Weise an wie das Cmdlet „Get-Help“. Es werden drei Textabschnitte angezeigt: DESCRIPTION, PARAMETERS und SYNTAX. GetHelp führt zwei Aufgaben aus. Die Funktion erstellt ein Heredoc, das den anzuzeigenden Text enthält, und zeigt dann den Inhalt der Variablen an, die das Heredoc enthält (in diesem Fall ist dies $helpText).

Ein Heredoc ist ein Windows PowerShell-Konstrukt, das Ihnen ermöglicht, Informationen einzugeben und Ihre Ausgabe zu formatieren, ohne sich um entsprechende Textausgaberegeln kümmern zu müssen. Alles, was Sie im Heredoc eingeben, wird als Text behandelt. GetHelp wird aufgerufen, wenn das Skript mit dem Switch „–help“ ausgeführt oder ein falscher Parameter eingegeben wird. Abbildung 3 zeigt das Ergebnis nach dem Aufrufen des Skripts mit dem Switch „–help“.

fig03.gif

Abbildung 3 Aufrufen des Skripts mit dem Switch „–help“

Das Wesentliche

Als Nächstes betrachten wir die GetADSchema-Funktion, die die eigentliche Arbeit für das Skript in Abbildung 1 ausführt. Der here-Schlüssel verwendet die DirectoryServices.ActiveDirectory.ActiveDirectorySchema-Klasse in Microsoft .NET Framework. Durch Einschließen der Klasse in eckige Klammern, gefolgt von zwei Doppelpunkten, können Sie auf die statischen Methoden der Klasse zugreifen (in diesem Fall GetSchema und GetCurrentSchema).

Die statische Methode „GetCurrentSchema“ gibt eine Instanz einer ActiveDirectorySchema-Klasse zurück, die das Schema repräsentiert, mit dem Sie derzeit verbunden sind. Abbildung 4 zeigt die ActiveDirectorySchema-Klassenmember.

fig04.gif

Nach dem Erstellen einer Instanz der DirectoryServices.ActiveDirectory.ActiveSchema-.NET Framework-Klasse und dem Speichern des resultierenden Schemaobjekts in der Variablen „$schema“ müssen Sie entscheiden, welche Aktion durchgeführt werden soll. Hierzu evaluiert eine Switch-Anweisung den Wert, der von der Variablen „$action“ an sie übergeben wird.

In Abhängigkeit von der erfüllten Bedingung findet die Funktion alle Klassen in AD DS, zeigt erforderliche oder optionale Eigenschaften einer bestimmten Klasse an oder sucht eine Klasse, die die angegebenen Kriterien erfüllt. Bei Verwendung der Switch-Anweisung empfiehlt es sich als bewährte Methode, immer eine Standardbedingung aufzunehmen.

Hilfsfunktionen

Um den Code zu entflechten und die Erweiterung des Skripts zu erleichtern, habe ich einige Hilfsfunktionen aufgenommen. Diese Funktionen werden in Abhängigkeit von den Parametern aufgerufen, die bei Ausführung des Skripts an dieses übergeben werden. Jede der Hilfsfunktionen ruft GetADSchema auf und übergibt einen anderen Satz von Parametern in Abhängigkeit vom Wert, der in der Befehlszeile für den Parameter „–action“ angegeben wurde.

Die erste Hilfsfunktion ist GetAllClasses, die GetADSchema aufruft und das Wort „classes“ übergibt. Wenn die Switch-Anweisung in der GetADSchema-Funktion der Zeichenfolge „classes“ entspricht, wird die FindAllClasses-Methode aus der ActiveDirectorySchema-Klasse aufgerufen. Hier der Code, der von der Switch-Anweisung aufgerufen wird:

"classes" { 
              $schema.FindAllClasses() | 
              Select-Object -Property Name'

Hier ist die GetAllClasses-Funktion:

Function GetAllClasses()
{
GetADSchema("classes")
} #end GetAllClasses

Die nächste Hilfsfunktion ist GetMandatory. Ihr Zweck besteht darin, bei Ausführung des Skripts erforderliche Eigenschaften des Objekts zurückzugeben, das im Parameter „–class“ angegeben wurde. Die GetMandatory-Funktion empfängt den Wert für $class von der Befehlszeile über den Parameter „–class“. Wenn GetMandatory die GetADSchema-Funktion aufruft, werden zwei Parameter übergeben. Weil zwei Parameter übergeben werden, betrachte ich es als bewährte Methode, den vollständigen Parameternamen für beide anzugeben. So lässt sich der Code leichter lesen und verstehen. In der GetAllClasses-Funktion haben wir hingegen beim Aufruf der GetADSchema-Funktion nicht den Namen des Parameters „–action“ verwendet. In diesem Fall wurde der Wert „classes“ der Position nach übergeben.

Die GetADSchema-Funktion verwendet bei ihrem Aufruf die FindClass-Methode aus der ActiveDirectorySchema-Klasse, um die Klasse abzurufen, die in der Variablen „$class“ angegeben wurde. Sie gibt eine Instanz einer ActiveDirectorySchemaClass-Klasse zurück. Die Member dieser Klasse werden in Abbildung 5 gezeigt.

fig05.gif

Als Nächstes fragt die GetADSchema-Funktion die MandatoryProperties-Eigenschaft des Objekts ab und leitet die Ergebnisse an das Cmdlet „Format-Table“ weiter, wo die Eigenschaften „Name“, „Syntax“ und „IsSingleValued“ ausgewählt werden. Der Parameter „–Autosize“ des Cmdlets „Format-Table“ passt die Größe der Spalten automatisch an, um wenn möglich zu vermeiden, dass Eigenschaftswerte abgeschnitten werden. Folgender Code wird bei Übereinstimmung mit der Zeichenfolge „Mandatory“ ausgeführt:

"Mandatory" 
       {
       "Mandatory Properties of $class object"
       ($schema.FindClass("$class")).MandatoryProperties | 
       Format-Table -Property Name, Syntax, IsSingleValued -AutoSize 
       }

Hier ist die GetMandatory-Funktion:

Function GetMandatory($class)
{
 GetAdSchema -action "Mandatory" -class $class 
} #end GetMandatory

Schauen wir uns nun an, wie die GetOptional-Funktion die optionalen Eigenschaften einer AD DS-Klasse anzeigen kann. GetOptional übernimmt den $class-Wert, der von der Befehlszeile über den Parameter „–class“ empfangen wurde, und übergibt dann den $class-Wert zusammen mit der Aktion namens „Optional“ an die GetADSchema-Funktion.

Bei einer Übereinstimmung mit der Zeichenfolge „Optional“ in der Switch-Anweisung wird eine Meldung auf dem Bildschirm angezeigt, aus der hervorgeht, dass die Anzeige optionaler Eigenschaften einige Sekunden dauern könnte. Anschließend wird die FindClass-Methode aus der ActiveDirectorySchema-Klasse aufgerufen. Die FindClass-Methode gibt eine Instanz einer ActiveDirectorySchemaClass-Klasse zurück. Bei Abfrage der OptionalProperties-Eigenschaft der ActiveDirectorySchema­Class-Klasse würden die optionalen Eigenschaften zurückgegeben, die für die ausgewählte Klasse in AD DS definiert wurden.

Die Ergebnisse werden an das Cmdlet „Format-Table“ weitergeleitet, das die Informationen in derselben Weise anzeigt wie bei den erforderlichen Eigenschaften. Hier der betreffende Abschnitt des Codes:

"Optional" 
      {
      "Optional Properties of $class object"
      "This might take a few seconds ..."
      ($schema.FindClass("$class")).OptionalProperties | 
      Format-Table -Property Name, Syntax, IsSingleValued -AutoSize 
      }

Der folgende Code beschreibt die vollständige GetOptional-Funktion:

Function GetOptional($class)
{
 GetAdSchema -action "Optional"  -class $class 
} #end GetOptional

Die letzte Hilfsfunktion ist „FindClasses“. Diese Funktion ruft die GetADSchema-Funktion auf und übergibt zwei Werte. Der erste ist die Aktion „Find“, und der zweite ist die zu suchende Klasse. Der Zweck dieser Funktion besteht darin, dem Benutzer die Identifizierung von Klassen im AD DS-Schema zu erleichtern, die eine nähere Untersuchung verdienen.

Angenommen, Sie interessieren sich für die Arbeit mit E-Mails. Im diesem Fall möchten Sie sehen, welche Klassen auf E-Mail bezogen sind und welche Eigenschaften für eine bestimmte Klasse existieren. Wie Abbildung 6 zeigt, wird das Skript zuerst mit den Parametern „–action f“ und „–class mail“ ausgeführt. Hierdurch werden alle Klassen zurückgegeben, deren Namen die Zeichenfolge „mail“ enthalten. Wenn Sie eine Klasse gefunden haben, die für Sie interessant ist, untersuchen Sie die Eigenschaften der Klasse. Hierzu wählen Sie den Parameter „action m“ aus (m steht für „mandatory“) und geben den Parameter „–c“ (class) an, gefolgt vom genauen Namen der Klasse.

fig06.gif

Abbildung 6 Suchen einer Klasse im AD DS-Schema

Beim Aufruf von GetADSchema durch die FindClasses-Funktion wird die FindAllClasses-Methode aufgerufen, und die sich ergebende Auflistung von ActiveDirectorySchemaClass-Klassen wird über die Pipeline gesendet. Where-Object verwendet eine Musterübereinstimmung für einen regulären Ausdruck, um nach Klassen zu suchen, die dem in der Variablen „$class“ gespeicherten Wert entsprechen. Der Code lautet wie folgt:

"Find" 
    {
    $schema.FindAllClasses() | 
    Where-Object { $_.name -match "$class" } |
    Select-Object -property name

Dies ist die FindClasses-Funktion:

Function FindClasses($class)
{
 GetAdSchema -action "Find" -class $class
} #end FindClasses

Nach Abschluss der Definition aller Hilfsfunktionen gelangen Sie nun an den Einstiegspunkt für das Skript. Der Einstiegspunkt hat nur eine Aufgabe: Er untersucht die Befehlszeile und bestimmt, welche Funktion aufgerufen wird. Als Erstes wird die Anwesenheit des Parameters „–help“ überprüft. Wenn das Skript mit „–h“ oder „–help“ ausgeführt wird, ruft es die GetHelp-Funktion auf, um die Hilfe anzuzeigen, und wird dann beendet:

if($help) { GetHelp ; Exit }

Da als Erstes nach dem Parameter „–help“ gesucht wird, übertrumpft dessen Anwesenheit in der Befehlszeile alles andere. Wurde der Parameter „–help“ nicht verwendet, muss das Skript den für den Parameter „–action“ (den Standardparameter) angegebenen Wert auswerten. Jede Eingabe in der Befehlszeile wird als Wert für „–action“ interpretiert, wenn nichts anderes verwendet wird. Hieraus ergibt sich der zusätzliche Vorteil, dass falsche Eingaben in das Skript erfasst werden können.

Die Switch-Anweisung ist ein natürliches Tool zum Auswerten der Werte, die für „–action“ angegeben werden. Jede der vier definierten Aktionen ruft die entsprechende Funktion auf. Die fünfte Bedingung, die definiert wird, ist die Standardaktion. Sie zeigt eine Meldung an, aus der hervorgeht, dass die Aktion nicht zulässig ist, woraufhin die GetHelp-Funktion aufgerufen wird.

Bei der Switch-Anweisung sollten Sie bedenken, dass damit mehrere Übereinstimmungen gefunden werden könnten. Aus diesem Grund wird nach jedem Aufruf der Funktionen die Exit-Anweisung verwendet. Den Code für die Switch-Anweisung finden Sie hier:

Switch ($action)
{
 "L" {GetAllClasses ; Exit}
 "M" {GetMandatory($class) ; Exit}
 "O" {GetOptional($class) ; Exit}
 "F" {FindClasses($class) ; Exit}
 DEFAULT { "$action is not a valid action." ; GetHelp ; Exit} 
}

Das ist schon alles. Es gibt keinen Active Directory Browser außer ADSI Scriptomatic. Das Skript „BrowseActiveDirectorySchema.ps1“ dürfte Ihnen jedoch vorerst gute Dienste erweisen. Weitere Informationen zur Skripterstellung für Active Directory finden Sie im Active Directory-Skriptinghub. Darüber hinaus stehen wir Ihnen im Skriptcenter rund um die Uhr mit Rat und Tat zur Seite.

Ed Wilson ist leitender Berater bei Microsoft und ein bekannter Skriptexperte. Er ist ein Microsoft-zertifizierter Schulungsleiter, der für Microsoft Premier-Kunden weltweit einen beliebten Workshop zu Windows PowerShell anbietet. Ed Wilson ist Autor von acht Büchern, einschließlich mehrerer Bücher zum Thema Windows-Skripterstellung, und hat an fast einem Dutzend weiterer Bücher mitgearbeitet. Er besitzt mehr als 20 Branchenzertifizierungen.

Craig Liebendorfer ist ein Wortschmied und ein langjähriger Microsoft-Webredakteur. Er kann immer noch nicht glauben, dass es einen Job gibt, bei dem er dafür bezahlt wird, täglich mit Wörtern zu arbeiten. Respektloser Humor steht bei Craig Liebendorfer ganz oben auf der Liste, und daher ist er hier gut aufgehoben. Als größte Leistung in seinem Leben betrachtet er seine wunderbare Tochter.