Par programmation joindre à Windows de la machine à un domaine AD

C'est similaire, mais pas dupe, cette question - toutefois, lorsqu'il a demandé des informations sur manuellement rejoindre un serveur à un domaine (et a juste titre redirigé) je suis à la recherche pour obtenir de l'aide avec un peu de code de programme pour les jointures d'une machine à un domaine.

Le scénario, c'est que nous avons un service de lancement qui instancie Amazon EC2 Server2008R1 VMs, éventuellement en passant un Nom de Machine par l'Utilisateur-flux de Données. Un processus est ancré dans nos images qui vérifie les Données d'Utilisateur pour un nom au démarrage - Si aucun n'est présent, alors la machine virtuelle reste en dehors de notre Nuage de domaine, mais si le nom est présent, alors la machine est renommé comme prévu, et l'auto-joint au domaine.

Ici, est le problème - si j'exécute ce processus manuellement à tout moment après l'instance de départ, il fonctionne exactement comme décrit; le nom de la machine est modifié, et la VM est joint au domaine (nous forcer un redémarrage pour que cela se produise).

Cependant, lors de l'exécution d'une Tâche Planifiée (déclenchement au démarrage), la machine renommer se passe comme prévu, mais l'appel suivant à JoinDomainOrWorkgroup (voir ci-dessous) reprend le vieux randomisés machine nom donné à la VM par EC2 au lieu de le nouveau nom a été attribué.

Il en résulte une WMI code de retour de 8525, nous obtenons un déconnecté mal nommée entrée dans l'ANNONCE du dépôt (de l'étude randomisée de nom) et la machine n'est pas joint au domaine. La machine virtuelle redémarre, et une seconde fois par le processus de démarrage (anormalement déclenchée car il est contenu dans les Données Utilisateur, mais la machine n'est pas encore dans le domaine) exécute toutes les étapes et réussit.

On dirait le nom de la machine est définie dans la première passe, mais pas "finalisé", et JoinDomainOrWorkgroup voit encore le nom d'origine. Lors de la deuxième passe, le nom de la machine est déjà réglée correctement, et donc JoinDomainOrWorkgroup fonctionne comme prévu. Tout à fait pourquoi le processus se comporte de cette façon, lors du démarrage, mais fonctionne parfaitement lorsqu'il est exécuté manuellement sur un déjà commencé VM, c'est que je pense que le nœud du problème.

J'ai essayé d'insérer un délai entre le renommer et de le rejoindre étapes dans le cas où l'appel à JoinDomainOrWorkgroup qui se passait avant le changement de nom a été finalisé en coulisses, mais cela n'a pas aidé et je n'ai pas vraiment s'y attendre, puisque l'ensemble du processus fonctionne parfaitement lorsqu'il est exécuté manuellement. Donc c'est probablement une combinaison d'une subtile différence dans l'état de la machine pendant le démarrage et quelque chose de stupide dans le code.

Peut-être à l'aide de System.Environment.MachineName dans le SetDomainMembership méthode est déconseillée? Mais il stil échoue, même si je passe le nouveau nom dans une chaîne de caractères comme je le fais pour SetMachineName. Donc je suis perplexe.

Voici le code WMI qui renomme la machine:

///<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;
    }
  }
}

Et voici le code WMI qui ajoute au domaine:

///<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;
    }
  }
}

Excuses si ce code est l'esprit numbingly stupide - je suis nouveau sur WMI, et c'est en grande partie chipé par les exemples que j'ai trouvé sur les interwebs; si il y a de plus intelligent/propre façon de le faire, puis par tous les moyens de démontrer. Si vous pouvez guérir le problème dans le même temps, des points bonus!

Plus d'informations: l'appel à SetMachineName fonctionne, mais le nom ne change pas instantanément ipconfig affiche toujours l'ancien nom, et en regardant les Propriétés du Système indique l'ancien nom suivi de "(qui va changer à XXXXXXX après redémarrage)". Si SetDomainMembership devient une voie de la gestion du Système.De l'environnement.MachineName, c'est toujours l'ancien nom et est incorrect (conduisant à un bris ANNONCE d'entrée et de l'échec d'une jointure). Si je plutôt passer le nouveau nom en tant que paramètre, le WMI appel échoue avec un 'introuvable' exception, sans doute parce qu'il n'y a pas encore une machine avec ce nouveau nom fermement fixé.

OriginalL'auteur Eight-Bit Guru | 2010-11-15