Programmatisch beitreten Windows-Rechner zu AD-Domäne

Dies ist ähnlich, aber kein dupe, diese Frage - jedoch, wo es versucht, Informationen auf manuell Beitritt eines Servers zu einer Domäne (und wurde zu Recht Weiterleitung) ich bin auf der Suche nach Hilfe mit irgendeinem code, der programmatisch reiht sich in eine Maschine zu einer Domäne.

Szenario ist, dass wir ein launcher-Dienst instanziiert Amazon EC2 Server2008R1 VMs, Optional ist übergabe einer Maschine Namens durch den Nutzer-Datenstrom. Ein Prozess ist eingebettet in unsere Bilder, die Kontrollen der User-Daten für einen Namen auf Booten - Falls keiner vorhanden ist, dann der VM bleibt außerhalb unserer Cloud domain, aber wenn der name vorhanden ist, dann ist die Maschine umbenannt wie angegeben und automatisch mit der Domäne verknüpft.

Hier ist das problem - wenn ich diesen Prozess manuell jederzeit nach Instanz zu starten, es funktioniert genau wie beschrieben; der Computername geändert wird, und die VM der Domäne beigetreten ist (wir haben einen Neustart zu erzwingen, damit dies geschieht).

Aber bei der Ausführung als Geplanter Task (ausgelöst beim Start) der Maschine umbenennen passiert, wie erwartet, aber der nachfolgende Aufruf JoinDomainOrWorkgroup (siehe unten) nimmt die alte randomisierten Maschine name der VM von EC2-statt mit dem neuen Namen hat es gerade zugewiesen wurde.

Diese Ergebnisse in WMI-return-code von 8525, wir bekommen ein getrenntes irreführend Eintrag in der AD-repository (der, die randomisierte name) und die Maschine ist nicht mit der Domäne verbunden. Die VM startet dann neu, und einen zweiten Durchgang durch die startup-Prozess (ungewöhnlich ausgelöst, da gibt es Inhalte, die im User-Daten, aber die Maschine ist noch nicht in der Domäne) führt alle die gleichen Schritte und gelingt.

Wie es aussieht ist die Maschine name wird im ersten Durchgang aber nicht 'abgeschlossen', und JoinDomainOrWorkgroup sieht noch den ursprünglichen Namen. Auf dem zweiten pass, der Rechnername ist schon richtig eingestellt, und so JoinDomainOrWorkgroup funktioniert wie erwartet. Ganz, weshalb das Verfahren auf diese Weise verhält, während des Startvorgangs, aber funktioniert perfekt, wenn manuell ausgeführt auf eine bereits gestartete VM, ist denke ich der Kern des Problems.

Habe ich versucht, das einfügen einer Verzögerung zwischen dem umbenennen und join Schritte im Falle der Aufruf JoinDomainOrWorkgroup geschah vor dem umbenennen ging hinter die kulissen, aber das hat nicht geholfen - und ich habe nicht wirklich erwarten, dass es, da der gesamte Prozess funktioniert perfekt, wenn manuell ausgeführt. Es ist also wahrscheinlich eine Kombination aus feiner Unterschied in der Zustandsmaschine während dem Booten und etwas dummes in den code.

Vielleicht mit System.Environment.MachineName im SetDomainMembership Methode nicht empfehlenswert ist? Aber es stil schlägt fehl, selbst wenn ich den pass der neue name als string, wie ich für SetMachineName. So bin ich überfragt.

Hier ist der WMI code, benennt der Maschine:

///<summary>
///Set Machine Name
///</summary>
public static bool SetMachineName(string newName)
{
  _lh.Log(LogHandler.LogType.Debug, string.Format("Setting Machine Name to '{0}'...", newName));

  //Invoke WMI to populate the machine name
  using (ManagementObject wmiObject = new ManagementObject(new ManagementPath("Win32_ComputerSystem.Name='" + System.Environment.MachineName + "'")))
  {
    ManagementBaseObject inputArgs = wmiObject.GetMethodParameters("Rename");
    inputArgs["Name"] = newName;

    //Set the name
    ManagementBaseObject outParams = wmiObject.InvokeMethod("Rename", inputArgs, null);

    //Weird WMI shennanigans to get a return code (is there no better way to do this??)
    uint ret = (uint)(outParams.Properties["ReturnValue"].Value);
    if (ret == 0)
    {
      //It worked
      return true;
    }
    else
    {
      //It didn't work
      _lh.Log(LogHandler.LogType.Fatal, string.Format("Unable to change Machine Name from '{0}' to '{1}'", System.Environment.MachineName, newName));
      return false;
    }
  }
}

Und hier ist der WMI code, verbindet es die domain:

///<summary>
///Set domain membership
///</summary>
public static bool SetDomainMembership()
{
  _lh.Log(LogHandler.LogType.Debug, string.Format("Setting domain membership of '{0}' to '{1}'...", System.Environment.MachineName, _targetDomain));

  //Invoke WMI to join the domain
  using (ManagementObject wmiObject = new ManagementObject(new ManagementPath("Win32_ComputerSystem.Name='" + System.Environment.MachineName + "'")))
  {
    try
    {
      //Obtain in-parameters for the method
      ManagementBaseObject inParams = wmiObject.GetMethodParameters("JoinDomainOrWorkgroup");

      inParams["Name"] = "*****";
      inParams["Password"] = "*****";
      inParams["UserName"] = "*****";
      inParams["FJoinOptions"] = 3; //Magic number: 3 = join to domain and create computer account

      //Execute the method and obtain the return values.
      ManagementBaseObject outParams = wmiObject.InvokeMethod("JoinDomainOrWorkgroup", inParams, null);
      _lh.Log(LogHandler.LogType.Debug, string.Format("JoinDomainOrWorkgroup return code: '{0}'", outParams["ReturnValue"]));

      //Did it work?  ** disabled so we restart later even if it fails
      //uint ret = (uint)(outParams.Properties["ReturnValue"].Value);
      //if (ret != 0)
      //{
      // //Nope
      // _lh.Log(LogHandler.LogType.Fatal, string.Format("JoinDomainOrWorkgroup failed with return code: '{0}'", outParams["ReturnValue"]));
      // return false;
      //}

      return true;
    }
    catch (ManagementException e)
    {
      //It didn't work
      _lh.Log(LogHandler.LogType.Fatal, string.Format("Unable to join domain '{0}'", _targetDomain), e);
      return false;
    }
  }
}

Entschuldigt, wenn dieser code sieht Geist-betäubend dumm - ich bin neu auf WMI, und dies ist im wesentlichen abgekupfert von Beispielen, die ich gefunden habe, auf der interwebs; wenn es ein schlauer/eleganter Weg, dies zu tun, dann mit allen Mitteln zeigen. Wenn Sie heilen kann, das problem in der gleichen Zeit, bonus-Punkte!

  • Weitere Informationen: der Aufruf SetMachineName funktioniert, aber der name ändert sich nicht, sofort - ipconfig zeigt immer noch den alten Namen, und suchen auf System-Eigenschaften zeigt die alten Namen gefolgt von "(wird sich ändern, um XXXXXXX nach Neustart)". Wenn SetDomainMembership bekommt eine management-Pfad zu System.Umwelt.MachineName, ist dies immer noch die alten Namen und ist falsch (führt zu einem gebrochenen AD-Eintrag und einer gescheiterten join). Wenn ich stattdessen den pass der neue name als parameter, die WMI-Aufruf schlägt fehl mit einem "Nicht Gefunden" - exception, vermutlich, weil es nicht noch eine Maschine mit diesem neuen Namen fest.
Schreibe einen Kommentar