Это похоже на этот вопрос , но не похоже на него. Однако, где он запрашивал информацию о ручном присоединении сервера к домену (и был правильно перенаправлен), я ищу помощь с некоторымикод, который программно присоединяет машину к домену.
Сценарий состоит в том, что у нас есть служба запуска, которая создает экземпляры виртуальных машин Amazon EC2 Server2008R1, дополнительно передавая имя компьютера через поток пользовательских данных.Процесс запекается в наших изображениях, который проверяет пользовательские данные на наличие имени при загрузке. Если его нет, виртуальная машина остается за пределами нашего облачного домена, но если имя присутствует, то машина переименовывается, как указано, и автоматически присоединяется кдомен.
Вот в чем проблема - если я запускаю этот процесс вручную в любое время после запуска экземпляра, он работает точно так, как описано;имя машины изменяется, и виртуальная машина присоединяется к домену (для этого требуется перезапуск).
Однако при запуске в виде запланированной задачи (запускается при запуске) переименование машины происходит, как ожидается, но последующий вызов JoinDomainOrWorkgroup
(см. ниже) извлекает старое рандомизированное имя машины, присвоенное виртуальной машине EC2, вместо нового имени, которое было только что назначено.
Это приводит к возврату WMIкод 8525 , мы получаем отключенную ошибочно названную запись в репозитории AD (с этим рандомизированным именем), и машина не присоединяется к домену.Затем виртуальная машина перезапускается, и второй проход через процесс запуска (ненормально инициированный, поскольку в пользовательских данных есть контент, но машина еще не находится в домене), выполняет все те же шаги и успешно.
Это выглядитнапример, имя машины задается при первом проходе, но не «завершается», а JoinDomainOrWorkgroup
все еще видит исходное имя.На втором проходе имя машины уже установлено правильно, поэтому JoinDomainOrWorkgroup
работает как положено.Я думаю, суть проблемы во время запуска, но она прекрасно работает при запуске вручную на уже запущенной виртуальной машине, -
Я попытался вставить задержку между переименованием и соединениемшаги в случае, если вызов JoinDomainOrWorkgroup
происходил до того, как переименование было завершено за кулисами, но это не помогло - и я действительно не ожидал этого, так как весь процесс отлично работает при запуске вручную.Так что это, вероятно, сочетание тонкой разницы в состоянии компьютера во время загрузки и чего-то глупого в коде.
Может быть, использование System.Environment.MachineName
в методе SetDomainMembership
нецелесообразно?Но он по-прежнему не работает, даже если я передаю новое имя в виде строки, как для SetMachineName
.Поэтому я в тупике.
Вот код WMI, который переименовывает машину:
/// <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;
}
}
}
А вот код WMI, который присоединяет его к домену:
/// <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;
}
}
}
Извиняюсь, если этот код выглядит глупо - я новичок в WMI, и это в основном написано на примерах, которые я нашел на веб-сайтах;если есть более умный / аккуратный способ сделать это, то непременно продемонстрируйте.Если вы можете решить проблему одновременно, начисляйте бонусные баллы!