Move-ADObject

Eine Einmal konfigurierte Domänen- und OU-Struktur mit Objekten ist nicht statisch. Es gibt immer Änderungen und es stellt sich die Frage, wie sie diese Reorganisation unter Berücksichtigung der Abhängigkeiten hinbekommen. Zu NT4-Zeiten gab es keine OUs oder Forests aber auch schon Domänen und mit  Active Directory Migration Toolkit und NETMON konnten Objekte verschoben werden. Mittlerweile gibt es mit Move-ADObject ein leistungsfähiges PowerShell-Commandlet, dem ich etwas auf die Finger schauen will.

Was bedeutet "Objekt verschieben"?

Sie können sich das Verlagern von AD-Objekten sehr gut auch an einem Dateisystem vorstellen. Sogar der Begriff der "Partition" gibt es bei Festplatten als auch im Active Directory.

Aktion Gleiche Partition Andere Partition

Dateisystem

Die Datei wird gar nicht bewegt sondern im Verzeichnis wird einfach der Eintrag umgehängt. Das geht schnell und problemlos.

  • Verzeichniseintrag wird "umgehängt"
  • Es werden keine Daten kopiert
  • NTFS-Rechte bleiben unverändert

Die Datei wird von der Quelle tatsächlich ins Ziel kopiert und dann in der Quelle gelöscht

  • Neuer Eintrag im Verzeichnis wird angelegt
  • Daten werden kopiert
  • Berechtigungen werden vom Verzeichnis übernommen

Active Directory

Ein AD-Objekte kann auch einfach innerhalb einer Domain (=Partition) umstrukturiert werden

  • Verzeichniseintrag wird umgehängt
    Der distinguishedname ändert sich aber GUID/SID bleibt
  • Properties und Unterobjekte bleiben erhalten
  • Berechtigungen werden XXX

Der Umzug in eine andere Domain oder sogar einen anderen Forest stellte neue Herausforderungen. Im Hintergrund landet das Objekt in einer neuen Partition

  • Objekt wird im Ziel neu angelegt.
    XXX bekommt es eine neue GUID/SID?
  • Bestehende Properties des Quellobjekts werden kopiert
    Kommen auch Custom-Properties einer eigenen Schema-Erweiterung mit?
  • Quellobjekt wird gelöscht

Die Detailfrage ist natürlich, ob die Quelle erst am Ende gelöscht wird, denn einige Feldwerte dürfen in einem Active Directory ja nur einmal vorliegen.

Die Analogien zwischen einem Dateisystem und Active Directory sind schon frappierend.

Testserie

Es ist aber nicht nur das "Verschieben" des Objekts alleine. Das Objekt selbst kann ja von anderen Objekten referenziert werden, z.B. als Mitglied einer Gruppe oder als Manager eines anderen Objekts. Es kann auch über die SID auf Objekte berechtigt sein und es kann selbst z.B. einen Manager o.ä. haben. Also habe ich mir eine Testumgebung aufgebaut und ein Musterobjekt mit vielen Feldern gefüllt und dann mit Move-ADObject verschoben. Drei Szenarien sind dabei möglich:

  • Innerhalb der Domain
  • Innerhalb eines Forest
  • Zwischen zwei Forests

Also brauchte ich mindestens einen Forest mit zwei Domains und einen zweiten Forest. Move-ADObject bedient sich wohl immer dem RID-Master

The Move-ADObject cmdlet moves an object or a container of objects from one container to another or from one domain to another. When an object is moved between domains, both the source DC and the target DC need to be the RID Master of their domains
Quelle: https://docs.microsoft.com/en-us/powershell/module/addsadministration/move-adobject?view=win10-ps

Was im Hintergrund passiert ist, habe ich mit meinem Tool GET-ADChanges verfolgt, welches sich als "Domain Controller" ausgibt und über eine Replikationsanfrage die geänderten Felder bekommt.

Den Befehl habe ich immer auf einem DC der Quelldomäne mit DomainAdmin-Rechten gestartet. Zudem habe ich die Credentials eines Domain-Administrators in der Ziel-Domäne angegeben.

Aktion Veränderungen

Same Domain

Die Migration eines Objekte zwischen zwei OUs innerhalb einer Domäne hat keine Überraschungen gezeigt. Es wurde eigentlich der "ParentDN" und die "ParentGUID" des Objekts geändert.

Move-ADObject `
   -Identity "CN=MoveUser1,OU=OU1,OU=movetest,DC=msxfaq,DC=de" `
   -TargetPath "OU=OU2,OU=movetest,DC=msxfaq,DC=de"

timestamp : 13.02.2021 19:49:22
objectguid : e34fdd4b-3895-43d3-97d1-82e45cac0e86
identity : CN=MoveUser1,OU=OU2,OU=movetest,DC=msxfaq,DC=de
action : NewOrMove
field : parentguid
value : System.Byte[]

timestamp : 13.02.2021 19:49:22
objectguid : e34fdd4b-3895-43d3-97d1-82e45cac0e86
identity : CN=MoveUser1,OU=OU2,OU=movetest,DC=msxfaq,DC=de
action : NewOrMove
field : parentdn
value : OU=OU2,OU=movetest,DC=msxfaq,DC=de

Man könnte einfach davon ausgehen, dass das AD eine relativ einfache Datenbank ist, deren "Hierarchie" durch die Verknüpfungen dieser Felder hergestellt wird. Das Replikationsvolumen bei einem Umhängen ist daher überschaubar. Bei allen anderen Objekten wie "Gruppen", Manager etc. hat sich nichts geändert. Ich gehe davon aus, dass intern das AD diese Mitgliedschaften nicht über den DN verwaltet, sondern über die ObjectGUID, welche hier gleich geblieben ist.

Same Forest

Hier wird es etwas aufwändiger, da ich zwei DCs zu überwachen habe.

Move-ADObject `
   -Identity "CN=MoveUser1,OU=OU1,OU=movetest,DC=msxfaq,DC=de" `
   -TargetPath "OU=movetest,DC=sub,DC=msxfaq,DC=de" `
   -TargetServer subdc.sub.msxfaq.de

In der Quelle wurde das Objekt einfach gelöscht.

 223142! identity       ! action    ! field          ! value
-------------------------------------------------------------------------------
 232512! CN=3565404b37f1! Delete    ! lastknownparent! CN=Infrastructure,DC
 232512! CN=3565404b37f1! Modify    ! isdeleted      ! True
 232512! CN=3565404b37f1! Modify    ! proxiedobjectna! B:16:000000010000000
 232512! CN=3565404b37f1! Modify    ! showinadvancedv! True
 232512! CN=3565404b37f1! Modify    ! ntsecuritydescr! System.Byte[]
 232512! CN=3565404b37f1! Modify    ! objectcategory !
 232512! CN=3565404b37f1! Modify    ! msds-lastknownr! 3565404b37f1764b9b7a
 232512! CN=3565404b37f1! Modify    ! whencreated    ! 02/13/2021 22:25:04
 232512! CN=3565404b37f1! Modify    ! lastknownparent! CN=Infrastructure,DC
 232512! CN=3565404b37f1! Modify    ! objectclass    ! top infrastructureUp
 232512! CN=3565404b37f1! Modify    ! systemflags    ! 234881024

Das Objekt wird in die versteckte OU "CN=Infrastructure,DC=msxfaq,DC=de verschoben und erscheint nicht im AD-Papierkorb.

Zusätzlich hat Move-ADObject aber noch die Mitgliedschaft in Gruppen "korrigiert", in denen das Quellobjekt Mitglied war:

 232512! CN=ADGroupLD,OU! MemberAdd ! Member         ! CN=MoveUser1\0ACNF:e
 232513! CN=MoveUser1\0A! MemberOfAd! MemberOf       ! CN=ADGroupLD,OU=Firm
 232513! CN=ADGroupUS,OU! MemberAdd ! Member         ! CN=MoveUser1\0ACNF:e
 232513! CN=MoveUser1\0A! MemberOfAd! MemberOf       ! CN=ADGroupUS,OU=Firm
 232513! CN=ADGroupUD,OU! MemberAdd ! Member         ! CN=MoveUser1\0ACNF:e
 232513! CN=MoveUser1\0A! MemberOfAd! MemberOf       ! CN=ADGroupUD,OU=Firm
 232513! CN=ADGroupLS,OU! MemberAdd ! Member         ! CN=MoveUser1\0ACNF:e
 232513! CN=MoveUser1\0A! MemberOfAd! MemberOf       ! CN=ADGroupLS,OU=Firm

Der DN des Objekts verweist auf die GUID im Ziel in der Form CN=MoveUser1\0ACNF:e34fdd4b-3895-43d3-97d1-82e45cac0e86,OU=movetest,DC=sub,DC=msxfaq,DC=de.

Interessanterweise kann ich diese Änderung von "Member/MemberOf" nur beim Verschieben aus der Domäne mit den Gruppen sehen. Wenn ich den Benutzer in die Domäne hinschiebe, in der die Gruppen liegen, ist nichts zu sehen.

In der Ziel-Domäne wurde ein neues Objekte angelegt. Das "whenCreated"-Feld ist zumindest die aktuelle Uhrzeit und nicht das Datum des Quellobjekts.

 224851! identity       ! action    ! field          ! value
-------------------------------------------------------------------------------
 232543! CN=MoveUser1,OU! NewOrMove ! parentguid     ! System.Byte[]
 232543! CN=MoveUser1,OU! NewOrMove ! parentdn       ! OU=movetest,DC=sub,D
 232543! CN=MoveUser1,OU! Modify    ! departmentnumbe! DepNr
 232543! CN=MoveUser1,OU! Modify    ! codepage       ! 0
 232543! CN=MoveUser1,OU! Modify    ! ntpwdhistory   !
 232543! CN=MoveUser1,OU! Modify    ! objectcategory ! CN=Person,CN=Schema,
 232543! CN=MoveUser1,OU! Modify    ! department     ! Department
 232543! CN=MoveUser1,OU! Modify    ! description    ! Description
 232543! CN=MoveUser1,OU! Modify    ! ntsecuritydescr! System.Byte[]
 232543! CN=MoveUser1,OU! Modify    ! pwdlastset     ! 132577287040285259
 232543! CN=MoveUser1,OU! Modify    ! dbcspwd        !
 232543! CN=MoveUser1,OU! Modify    ! objectclass    ! top person organizat
 232543! CN=MoveUser1,OU! Modify    ! samaccounttype ! 805306368
 232543! CN=MoveUser1,OU! Modify    ! company        ! Company
 232543! CN=MoveUser1,OU! Modify    ! userprincipalna! MoveUser1@msxfaq.net
 232543! CN=MoveUser1,OU! Modify    ! proxiedobjectna! B:16:000000000000000
 232543! CN=MoveUser1,OU! Modify    ! unicodepwd     !
 232543! CN=MoveUser1,OU! Modify    ! comment        ! Comment
 232543! CN=MoveUser1,OU! Modify    ! useraccountcont! 512
 232543! CN=MoveUser1,OU! Modify    ! countrycode    ! 0
 232543! CN=MoveUser1,OU! Modify    ! primarygroupid ! 513
 232543! CN=MoveUser1,OU! Modify    ! ms-ds-consisten! System.Byte[]
 232543! CN=MoveUser1,OU! Modify    ! lmpwdhistory   !
 232543! CN=MoveUser1,OU! Modify    ! sidhistory     ! System.Byte[] System
 232543! CN=MoveUser1,OU! Modify    ! logonhours     !
 232543! CN=MoveUser1,OU! Modify    ! samaccountname ! MoveUser1
 232543! CN=MoveUser1,OU! Modify    ! objectsid      ! System.Byte[]
 232543! CN=MoveUser1,OU! Modify    ! displayname    ! MoveUser1
 232544! CN=MoveUser1,OU! Modify    ! whencreated    ! 02/13/2021 22:25:04
 232544! CN=MoveUser1,OU! Modify    ! supplementalcre!
 232544! CN=MoveUser1,OU! Modify    ! accountexpires ! 9223372036854775807
 232544! CN=MoveUser1,OU! Add       ! manager        ! CN=ADUser1,OU=Firma,

Die ObjectGUID sieht man hier interessanterweise nicht.

Interessant sind hier aber einige Felder:

  • ObjectGUID wird übernommen (nicht sichtbar)
    d.h. es wurde nicht die GUID der Quelldomäne übernommen sondern im Ziel eine neue GUID angelegt. Wenn ich das Objekt mehrfach schiebe, wird aber die frühere ObjectGUID des Objekt in der jeweiligen Domain beibehalten.
  • Manager wurde übernommen
    Sie verweisen nun auf das Konto in der anderen OU
  • SID-History wurde gefüllt
    Damit hat der neue Benutzer die gleichen Berechtigungen, die auf seinem Benutzer basieren, Er kann weiter sein Heimatlaufwerk verwenden und sein Windows Profil
  • ms-DS-ConsistencyGuid wird kopiert
    Damit dürfte auch ADSync bei halbwegs aktueller Konfiguration zufrieden sein.

Ich habe dann noch in der Quelle den Manager eines Benutzers kontrolliert. Hier stand nun CN=MoveUser1,OU=movetest,DC=sub,DC=msxfaq,DC=de drin.

Aber im Trace sehen Sie keine Änderung. Der "Link" scheint über ein internes Feld zu gehen, welches aber nicht per LDAP-Replikation sichtbar wird. Allerdings bin ich nicht sicher, welches Feld es denn sein sollte, denn der DN, die ObjectGUID und die SID haben sich ja geändert.

Ziel

Soweit ist das ganze Verfahren unspektakulär.

Objekte und Abhängigkeiten

Interessant wird es, wenn das Objekt noch Abhängigkeiten zu anderen Objekten hat. Folgende Sonderfälle habe ich geprüft

Thema

Beschreibung

Status

Blatt oder Container

Es ist einfacher nur ein Objekt zu verschieben. Aber manchmal gibt es unter einem Objekte noch Unterobjekte. Das gilt nicht nur für OUs sondern auch Benutzer können z.B. ActiveSync-Partnerschaften haben.

Bei einer Verlagerung innerhalb einer Domain ist das noch einfach aber über Domaingrenzen hinweg müssen die dann mehrere Objekte verschieben. Das Unterstützt Move-ADObject nicht und liefert folgende Fehlermeldung:

Move-ADObject : The operation cannot be performed because child objects exist. 
This operation can only be performed on a leaf object

Manuell zu lösen

"Manager"

Sie können an einen Benutzer einen "Manager" zuweisen. Das Feld "manager" enthält dann den DN zum Manager. Wird der Manager verschoben, müssten genaugenommen auch alle betroffenen Objekte aktualisiert werden, die auf den verschobenen Manager verweisen. Es gibt weitere Felder wie z.B. Assistant. Laut Microsoft Dokumentation enthält das Feld den "distinguishedname"

Allerdings ist das nicht das interne Speicherformat, denn bei einem Move des Managers in eine andere Domäne wird die Anzeige aktualisiert aber mein Skript erkennt keine replikationsrelevante Änderung an diesem Objekt. Ich vermute daher, dass intern eine "objectID" oder ein Verweis auf ein Datenbankfeld genutzt wird, welches beim Move nicht verändert wird. Es ist aber wohl nicht die ObjectGUID, die sich beim Manager durch den Move verändert.

OK

Member/MemberOf

Wenn ein Benutzer Mitglied einer Gruppe ist, dann wird bei der Gruppe das Feld "Member" mit dem DistinguishedName gepflegt. Beim Benutzer selbst gibt es das Feld "MemberOf", welches aber ein BackLink-Attribute ist. Wird das Objekt verschoben, muss der Eintrag bei der Gruppe auf den neuen Ziel-DN aktualisiert werden. Innerhalb einer Domain ist das noch einfach aber über Domaingrenzen schon eine Herausforderung. Zumal nicht alle Gruppen (DomainLocal, DomainGlobal, Universal) auch Objekte aus anderen Domänen oder gar Forests enthalten können. Aber der erste Move wurde abgebrochen, weil das Objekt noch Mitglied in Gruppen war.

Move-ADObject `
   -Identity "CN=MoveUser1,OU=OU1,OU=movetest,DC=msxfaq,DC=de" `
   -TargetPath "OU=movetest,DC=sub,DC=msxfaq,DC=de" `
   -TargetServer subdc.sub.msxfaq.de

Move-ADObject : Can't move objects with memberships across domain boundaries as once moved, this would violate the
membership conditions of the account group. Remove the object from any account group memberships and retry

Ich habe in dann nur aus den "DomainGlobalen" Gruppen entfernt und dann konnte das Objekt verschoben werden.

  • Anzeige vor dem Verschieben ohne "Domainglobale" Gruppen
  • Mitgliedschaften nach dem Verschieben.
    Sichtbar sind nur die universellen Gruppen. In den "Domain lokalen" Gruppen ist er aber auch noch Mitglied

Beachten Sie, dass die "Domain Users" die "Default Gruppe" ist und nicht zählt. Die Gruppe "Domain Users" sollte nie in einer anderen gruppe Mitglied sein, da dann Move-ADObject auch nicht mehr funktioniert

Manuell zu lösen

Computer

Computerkonten können innerhalb einer Domäne einfach verschoben werden. Sie bekommen dann die neuen Gruppenrichtlinien. Über Domaingrenzen hinweg reicht es aber nicht das Computerobjekt zu verschieben sondern sie müssen auch auf dem Computer die Domainzugehörigkeit anpassen. Das ist ein Fall, den ich nicht mit Move-ADObject umsetzen kann

Möglich aber nicht sinvoll.

SID / SID History

Der "Securityidentifier (SID)" ist der primäre Schlüssel, über den Berechtigungen auf Objekte (ACLs) vergeben werden. Die SID enthält einen Domain-Teil, so dass bei einem Umzug in andere Domänen oder Forests das Zielobjekt eine neue SID bekommt. Damit der Benutzer seine früheren Berechtigungen nicht verliert, kann die frühere SID als "SIDHistory" mitgeführt werden. Denken Sie dabei aber auch an SIDFilterung

SIDHistory wird gepflegt

ObjectGUID

Diese Feld wird durch das AD bei der Anlage des Objekts vergeben und ist im Forest eindeutig. Beim Move innerhalb der Domain wird sie beibehalten werden aber zwischen Domänen und über Grenzen eines Forest hinaus wird es sich ändern.

Interessant ist hier aber das Verhalten, dass die ObjectGUID beim Zurückschieben des Objekts an den alten Ort wieder den alten Wert einnimmt. Irgendwo muss sich das AD diese Information also merken.

Ändert sich, d.h. Programme müssen damit umgehen können.

SAMAccoutName

Das Active Directory erlaubt nicht, dass zwei Objekte in einer Domain den gleichen SAMAccountnamen haben. Ich habe also im Ziel einem anderen Benutzer den gleichen SAMAccountName geben und den Move versucht. Wie erwartet ist er gescheitert.

Move-ADObject : The specified account already exists

Eindeutigkeit wird erzwungen

Berechtigungen

Auf ein AD-Objekt können Berechtigungen vererbt und explizit zugewiesen werden. Daher wollte ich wissen, wie es sich damit verhält:

  • Verschieben innerhalb der gleichen Domain
    Das Objekt bekommt die vererbten Berechtigungen im Ziel und die vererbten Berechtigungen der Quelle entfallen. Explizit auf das Objekt vergebene Berechtigungen bleiben erhalten.
  • Verschieben in andere Domain
    In meinen Test wurden im Ziel nur die vererbten Rechte angewendet. Explizit auf das Objekt vergebene Rechte sind gelöscht wurden

Wenn ich es genau nehme, ist das Verhalten beim Verlagern in eine andere Domäne mit einem anderen Admin sinnvoll, um konsistente Berechtigungen zu erhalten. Sie müssen dennoch dran denken.

Beachten

Ich bin sicher, dass ich nicht alle Sonderfälle erfasst habe. Eine Testumgebung aus zwei DCs in zwei Domänen lässt sich aber ja schnell wieder aufbauen.

Gruppen

Natürlich habe ich auch noch eine Gruppe verschoben. In der universellen Security-Gruppe waren zwei Benutzer aus der Quelldomain.

 HHmmss! identity       ! action    ! field          ! value
-------------------------------------------------------------------------------
 011612! CN=154758819b59! Delete    ! lastknownparent! CN=Infrastructure,DC=msxfaq,DC=de
 011612! CN=154758819b59! Modify    ! isdeleted      ! True
 011612! CN=154758819b59! Modify    ! proxiedobjectna! B:16:0000000100000000:CN=Movegroup\0ACN
 011612! CN=154758819b59! Modify    ! showinadvancedv! True
 011612! CN=154758819b59! Modify    ! ntsecuritydescr! System.Byte[]
 011612! CN=154758819b59! Modify    ! objectcategory !
 011612! CN=154758819b59! Modify    ! msds-lastknownr! 154758819b59e2449a2cfa6cdc26a22b
 011612! CN=154758819b59! Modify    ! whencreated    ! 02/14/2021 00:16:11
 011612! CN=154758819b59! Modify    ! lastknownparent! CN=Infrastructure,DC=msxfaq,DC=de
 011612! CN=154758819b59! Modify    ! objectclass    ! top infrastructureUpdate
 011612! CN=154758819b59! Modify    ! systemflags    ! 234881024

Beim Löschen ist keine Besonderheit zu sehen. Wobei die gelöschte Gruppe anscheinend auch unter "cn=infrastructure" eingelagert wird.

Die Protokollierung im Ziel zeigt, dass die Gruppe neu angelegt und mit Werten ausgestattet wird.

 HHmmss! identity       ! action    ! field          ! value
-------------------------------------------------------------------------------
 011612! CN=Movegroup,OU! NewOrMove ! parentguid     ! 01 2e a3 ec ae 40 56 48 a0 21 86 92 d2
 011612! CN=Movegroup,OU! NewOrMove ! parentdn       ! OU=movetest,DC=sub,DC=msxfaq,DC=de
 011612! CN=Movegroup,OU! Modify    ! proxiedobjectna! B:16:0000000000000001:DC=msxfaq,DC=de
 011612! CN=Movegroup,OU! Modify    ! grouptype      ! -2147483640
 011612! CN=Movegroup,OU! Modify    ! whencreated    ! 02/14/2021 00:16:11
 011612! CN=Movegroup,OU! Modify    ! samaccountname ! Movegroup
 011612! CN=Movegroup,OU! Modify    ! ntsecuritydescr! System.Byte[]
 011612! CN=Movegroup,OU! Modify    ! objectsid      ! System.Byte[]
 011612! CN=Movegroup,OU! Modify    ! samaccounttype ! 268435456
 011612! CN=Movegroup,OU! Modify    ! sidhistory     ! System.Byte[]
 011612! CN=Movegroup,OU! Modify    ! objectcategory ! CN=Group,CN=Schema,CN=Configuration,DC=
 011612! CN=Movegroup,OU! Modify    ! objectclass    ! top group
 011612! CN=Movegroup,OU! MemberAdd ! Member         ! CN=MoveUser2,OU=OU1,OU=movetest,DC=msxf
 011612! CN=MoveUser2,OU! MemberOfAd! MemberOf       ! CN=Movegroup,OU=movetest,DC=sub,DC=msxf
 011612! CN=Movegroup,OU! MemberAdd ! Member         ! CN=MoveUser1,OU=OU1,OU=movetest,DC=msxf
 011612! CN=MoveUser1,OU! MemberOfAd! MemberOf       ! CN=Movegroup,OU=movetest,DC=sub,DC=msxf

Hier ist auch zu sehen, dass die Mitglieder aus der abgebenden Domäne ebenfalls eingetragen werden. Auch die SID der alten Gruppe wird als "SIDHistory" mitgeführt. Eine Verschiebung von Gruppen zwischen den Domänen ist also auch möglich.

Cross Forest - Nicht möglich

Natürlich wollte ich wissen, ob mit Move-ADObject auch eine Migration über die Grenzen eines Forest hinweg möglich sind. Es gibt diverse Hinweise und Antworten in Foren, die so eine Funktion suggerieren. Die Online-Hilfe hier ist aber eindeutig:

Move-ADObject
Moves an Active Directory object or a container of objects to a different container or domain.
Quelle: https://docs.microsoft.com/en-us/powershell/module/addsadministration/move-adobject?view=win10-ps

Theoretisch wäre es schon möglich, ein Object aus einem Forest in einem anderen Forest anzulegen und mit einem Trust könnte sogar die SID-History mit übertragen werden. Aber es gibt auch noch viele weitere Punkte wie:

  • Manager
    Das Feld verweist dann ja auf einen anderen Forest. Ohne Trust kann das nicht gehen aber merkt Move-ADObject das und verhindert den Move?
  • MemberOf
    Die gleichen Überlegungen gelten für die Mitgliedschaft in Gruppen
  • SIDHistory
    Die SID kann sicherlich mit übernommen werden. Aber "wirken" kann sie natürlich nur mit einem Trust und geeigneter SIDHistory-Filterung auf dem Trust
  • Schema-Felder
    Was passiert, wenn im Zielforest einige Felder fehlen, weil dort die entsprechenden Schemaerweiterungen, z.B. Exchange und SfB, nicht erfolgt sind?

Ich habe dennoch in meinem Lab einen weiteren Forest mit Domaincontroller aufgebaut und versucht ein Objekt zu verschieben und erst mal jede Menge Fehlermeldungen produziert

  • DNS-Fehler
    Natürlich sollten sich die Server korrekt finden können. Dazu reicht nicht nur der Hostname sondern auch die msdcs-Einträge müssen erreichbar sein

Move-ADObject : The naming context could not be found

  • Falsche Namen
    Zuerst habe ich mich plump beim Servernamen vertippt. Die Fehlermeldung ist leider nicht hilfreich

Move-ADObject : The server has rejected the client credentials.

  • Falsche Anmeldenamen
    Für dien Zugriff auf den Target-Server muss ich mit "-Credential" gültige Anmeldedaten mitliefern. Ungültige Anmeldedaten liefern natürlich einen Fehler

Move-ADObject : Either the target name is incorrect or the server has rejected the client credentials

  • Kein/Falscher Server
    Liegt das Ziel in einer anderen Domain, dann sollten sie den RID-Master im Ziel als TargetServer angeben. Nicht immer findet Mov-ADObjkect über die ZielOU einen passenden Server. Der Fehler leitet dann:

Move-ADObject : The operation could not be performed because the object's parent is either uninstantiated or deleted

  • Kein Trust, kein Login
    Nachdem ich aber alles angegeben hatte, bekam ich immer noch einen "The server has rejected the client credentials". Mit WireShark habe ich dann gesehen, dass der Client ein Ticket von der anderen Seite bekommen möchte.

    Das wird so ohne Vertrauensstellung nicht gehen.

Also habe ich einen Trust zwischen den beiden Forests eingerichtet und mich auf die "Minimalfunktion" beschränkt.

This domain: carius.de
Specified domain: msxfaq.net

Direction:
Two-way: Users in the local domain can authenticate in the specified domain and users 
in the specified domain can authenticate in the local domain.

Trust type: External

Transitive: No

Outgoing trust authentication level: Domain-wide authentication in local and specified forests.

Sides of trust: Create the trust for both this domain and the specified domain.

Das hat aber noch nicht gereicht, denn ich habe trotz der Angabe korrekter Daten den Fehler bekommen während WireShark gar keine Verbindung aufgezeichnet hat.

Move-ADObject : Access is denied

Also habe ich den Trust auf einen "Forest Trust" angepasst.

This domain: carius.de
Specified domain: msxfaq.net

Direction:
Two-way: Users in the local domain can authenticate in the specified domain and users 
in the specified domain can authenticate in the local domain.

Trust type: Forest trust

Transitive: Yes

Outgoing trust authentication level: Forest-wide authentication.

Sides of trust: Create the trust for this domain only.

Diesmal bekam ich auch die Warnung über einen UPN-Konflikt. Den habe ich ja provoziert, denn schließlich kann ich ja auch den UPN ins Ziel umziehen.

Ich hoffe also, dass Move-ADObject den UPN eines Benutzers beibehalten kann, auch wenn er die Rechte über den Trust dann nur nach der Bereinigung nutzen kann.

Wenn ich über "-Server" den lokalen DC angegeben habe, bekam ich folgenden Fehler.

Move-ADObject : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.

Aber folgendes liefert schon Daten:

PS C:\> Get-ADDomainController -Discover -Service “ADWS”

Domain      : carius.de
Forest      : carius.de
HostName    : {DC01.carius.de}
IPv4Address : 192.168.178.216
IPv6Address : 2a00:6020:403d:bb00:a547:132f:4cac:442f
Name        : DC01
Site        : SITE1

Vielleicht stört er sich per "loopback" auf dem Server selbst aber ohne Server kommt kein Fehler

Die folgenden Voraussetzungen waren bei mir natürlich erfüllt:

  • FSMO-Master
    Move-ADObject : The requested operation could not be performed because the directory service is not the master for that type of operation

Note: A cross-domain move requires a fully qualified server name and the use of the RID Master in both domains.
Quelle Move-ADOject https://docs.microsoft.com/en-us/powershell/module/addsadministration/move-adobject?view=win10-ps

  • Enterprise Admin-Rechte
    "To move objects between two domains requires Enterprise Admins."

Move-ADObject : The naming context could not be found

Nach meinem aktuellen Wissenstand ist eine "Cross Forest"-Migration mit dem PowerShell-Commandlet "MoveADObject" nicht möglich. Für diese Fälle ist dann ADMT -Active Directory Migration Toolkit oder eine 3rd Party Software erforderlich.

Es gibt hier schon noch einige Herausforderungen, die ich aber zu einem späteren Zeitpunkt analysieren werden, wenn mal wieder eine "Cross Forest"-Migration ohne 3rd Party Tools ansteht.

Move-ADObject und ADSync

Parallel zu meinen Tests mit Move-ADObject habe ich auch noch mit ADSync und dem Source Anchor (Siehe SourceAnchor Details) experimentiert. Mit Move-ADObject kann ich ja recht einfach ein Objekt zwischen Domains verschieben und ADSync sollte dabei ja nicht aus dem Tritt kommen. Das gilt zumindest, wenn ADSync für bestehende Objekte das Feld "ms-DS-ConsistencyGUID" nutzt und dieses kopiert wird. Das Feld gibt es leider nicht für Kontakte und auch bei Gruppen liest ADSync ab Version 1.5.18.0 () das Feld nur aber schreibt es nicht selbst. Das bedeutet aber, dass die Verlagerung einer Gruppe von einer Domäne in eine andere Domäne nur korrekt funktionieren dürfte, wenn Sie vorher die ms-DS-ConsistenyGUID gesetzt haben. Ich habe eine Gruppe daher von einer Root-Domain in eine Sub-Domain verschoben, ohne dass diese die einen Wert in "ms-DS-ConsistenyGUID" hatte.

Mich hat es dann aber doch etwas überascht, dass ADSync mit dieser Situation auch ohne Inhalte in "ms-DS-ConsistenyGUID" zurecht gekommen ist. Für ADSync war das ein "Rename"

Und auch in den anstehenden Export-Aktionen ist zu sehen, dass in die Cloud nur die tatsächlich geänderten Felder übertragen werden.

Die Gruppe im AzureAD bleibt aber bestehen. Das ist auch logisch, da die ObjectGUID der Gruppe unverändert geblieben ist und entsprechend auch der "sourceAnchor" sich nicht ändert.

Interessant ist auch, dass laut ADSync in das AzureAD durchaus die Felder "netBiosName" und "dnsDomainName" geschrieben werden. Diese sind aber weder über die MSOnline-PowerShell noch die AzureAD-Powershell in der Cloud zu sehen.

PS C:\> Get-AzureADgroup -SearchString Movegroup | fl *

DeletionTimestamp            :
ObjectId                     : 9cc3b6ef-dcac-403f-916f-a2ca52d02423
ObjectType                   : Group
Description                  :
DirSyncEnabled               : True
DisplayName                  : Movegroup
LastDirSyncTime              : 18.02.2021 22:16:44
Mail                         :
MailEnabled                  : False
MailNickName                 : Movegroup
OnPremisesSecurityIdentifier : S-1-5-21-3945891503-181675860-1499227176-1116
ProvisioningErrors           : {}
ProxyAddresses               : {}
SecurityEnabled              : True


PS C:\> Get-AzureADgroup -SearchString Movegroup | fl *

DeletionTimestamp            :
ObjectId                     : 9cc3b6ef-dcac-403f-916f-a2ca52d02423
ObjectType                   : Group
Description                  :
DirSyncEnabled               : True
DisplayName                  : Movegroup
LastDirSyncTime              : 18.02.2021 23:38:47
Mail                         :
MailEnabled                  : False
MailNickName                 : Movegroup
OnPremisesSecurityIdentifier : S-1-5-21-3945891503-181675860-1499227176-1117
ProvisioningErrors           : {}
ProxyAddresses               : {}
SecurityEnabled              : True

Auch über Microsoft Graph (https://graph.microsoft.com/v1.0/groups) gibt es nur folgende Liste

{
            "id": "9cc3b6ef-dcac-403f-916f-a2ca52d02423",
            "deletedDateTime": null,
            "classification": null,
            "createdDateTime": "2021-02-18T22:16:44Z",
            "creationOptions": [],
            "description": null,
            "displayName": "Movegroup",
            "expirationDateTime": null,
            "groupTypes": [],
            "isAssignableToRole": null,
            "mail": null,
            "mailEnabled": false,
            "mailNickname": "Movegroup",
            "membershipRule": null,
            "membershipRuleProcessingState": null,
            "onPremisesDomainName": "carius.de",
            "onPremisesLastSyncDateTime": "2021-02-18T23:46:38Z",
            "onPremisesNetBiosName": "CARIUS",
            "onPremisesSamAccountName": "Movegroup",
            "onPremisesSecurityIdentifier": "S-1-5-21-1343410112-xxxxxxxx-xxxxxxx-1168",
            "onPremisesSyncEnabled": true,
            "preferredDataLocation": null,
            "preferredLanguage": null,
            "proxyAddresses": [],
            "renewedDateTime": "2021-02-18T22:16:44Z",
            "resourceBehaviorOptions": [],
            "resourceProvisioningOptions": [],
            "securityEnabled": true,
            "securityIdentifier": "S-1-12-1-2630072047-xxxxxxxx-xxxxxxxx-xxxxxxx",
            "theme": null,
            "visibility": null,
            "onPremisesProvisioningErrors": []
        },

Sonderfall: ADSync Cross Domain

Bei den Verschiebungen zwischen Domänen eines Forest habe ich eher per Zufall noch einen Sonderfall entdeckt:

  1. Das Quellobjekt liegt in Domain1 und wird durch ADSync ins AzureAD repliziert.
  2. Die Ziel-OU liegt in einer anderen Domäne
  3. Die Ziel-OU ist nicht durch ADSync betreut
  4. Das Benutzerobjekt wird durch Move-ADObject fehlerfrei mit allen Feldern verschoben

Ich hätte nun erwartet, dass ADSync das "gelöschte Objekt" in der Quelle erkennt und da ADSync das Ziel nicht repliziert, müsste das Objekt auch in AzureAD gelöscht werden.

Aber das Objekt wurde nicht gelöscht.

Die Art, wie Move-ADObject das Objekt verlagert, führt dazu, dass ADSync keinen "Delete" beim nächsten "DeltaImport" erkennt. Es fehlt ihm das "DeletedItem" in der OU und das alte Objekt ist ja unter "cn=Infrastruktur,dc=<domain>,dc=<tld>" weiterhin vorhanden. Diesen Container kann aber ADSync nicht sehen.

Wir haben hier eine schlafende Inkonsistenz mit einem Benutzer in AzureAD samt aller Microsoft 365-Funktionen, ohne dass es ein korrespondierendes lokales Objekt gibt.
Die Lösung ist einfach: Einmal "FullSync" ausführen

# Full Sync auf ADSync ausführen
start-ADSyncCycle -policy initial

Mit dem FullSync vergleiche ADSync noch einmal alle lokalen Objekte mit seinem Connectorspace und hier erkennt er dann auch das fehlende Objekt.

Zusammenfassung

Hinter "Move-ADObject" steckt keine Geheimwissenschaft aber es kann die Arbeit einer Reorganisation deutlich vereinfachen. Technisch legt das Commandlet im Ziel das gleiche Objekte an und kopiert alle Felder, die ich bislang getestet habe. Es ist sogar in der Lage die bisherige SID des Objekts auch im Ziel anzufügen, was ansonsten nur mit ADMT oder Programmierung mit Windows-DLLs möglich ist. Mit abgesehen von der Mitgliedschaft in "Domain-Gruppen", die keine Mitglieder aus anderen Domänen enthalten können, bleiben sogar die Mitgliedschaften in lokalen Gruppen und universellen Gruppen erhalten. Mit Mitnahme von ms-DS-ConsistencyGUID erlaubt die weitere Nutzung von Office 365 mit ADSync.

Allerdings müssen die Ausgangsvoraussetzungen natürlich ebenso einfach und überschaubar sein. Untercontainer, wie sie ActiveSync gerne mal anlegt, verhindern die Verschiebung. Auch kommt Move-ADObject natürlich nicht an die Leistung von ADMT oder NETDOM/MOVEDOM heran, wenn es um die Migration von Computerkonten geht.

Etwas unsicher bin ich noch bei dem Verhalten in einigen Sonderfällen. So scheint ein verschobenes Objekt in der Quelle zumindest noch einige Zeit unter "cn=infrastructure" zu liegen, denn beim Zurückmoven kommt die alte ObjectGUID wieder zum Einsatz.

Dennoch ist Move-ADObject mit den wenigen Einschränkungen ein sehr effektives und leistungsfähiges Commandlet zur Migration von AD-Objekten innerhalb eines Forest.

Weitere Links