gpt4 book ai didi

c# - 以编程方式将 Windows 机器加入 AD 域

转载 作者:太空狗 更新时间:2023-10-29 20:18:29 25 4
gpt4 key购买 nike

这类似于但不是 this question 的欺骗 - 然而,它在其中寻找有关手动将服务器加入域的信息(并且被正确重定向)我正在寻找一些代码的帮助,这些代码以编程方式将机器加入到一个域。

场景是我们有一个启动程序服务来实例化 Amazon EC2 Server2008R1 VM,可选择通过用户数据流传递机器名称。我们的图像中嵌入了一个进程,用于在启动时检查用户数据中的名称——如果不存在,则 VM 仍然在我们的云域之外,但如果存在该名称,则机器将按指定重命名并自动加入到域。

这就是问题所在——如果我在实例启动后的任何时候手动运行这个过程,它就会完全按照描述工作;机器名称已更改,VM 已加入域(我们强制重启以实现此目的)。

但是,当作为计划任务运行时(在启动时触发),机器重命名会按预期发生,但随后调用 JoinDomainOrWorkgroup(见下文)会选择旧的随机机器名称VM 由 EC2 而不是刚刚分配的新名称。

这导致 WMI 返回代码 8525,我们在 AD 存储库(具有该随机名称)中得到一个断开连接的错误命名条目,并且机器未加入域。 VM 然后重新启动,第二次通过启动过程(异常触发,因为用户数据中有内容但机器尚未在域中)执行所有相同的步骤并成功。

看起来机器名称是在第一遍中设置的,但没有“最终确定”,JoinDomainOrWorkgroup 仍然看到原始名称。在第二遍中,机器名称已经正确设置,因此 JoinDomainOrWorkgroup 可以按预期工作。正是这个过程在启动期间以这种方式运行,但在已经启动的 VM 上手动运行时却完美运行的原因,我认为是问题的症结所在。

我已经尝试在重命名和加入步骤之间插入延迟,以防在重命名在幕后完成之前调用 JoinDomainOrWorkgroup,但这没有帮助 - 我没有真的很期待它,因为整个过程在手动运行时运行完美。所以这可能是启动期间机器状态的细微差异和代码中的一些愚蠢行为的结合。

也许在 SetDomainMembership 方法中使用 System.Environment.MachineName 是不可取的?但即使我将新名称作为字符串传递给 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;
}
}
}

如果这段代码看起来愚蠢得令人 NumPy ,我深表歉意 - 我是 WMI 的新手,这主要是从我在互联网上找到的示例中抄袭的;如果有更聪明/更简洁的方法来做到这一点,那么一定要证明。如果能同时解决问题,加分!

最佳答案

好的,给你。

首先,系统属性中字段的顺序有点误导 - 您首先看到机器名称,然后是域/工作组。这下意识地影响了我的想法,意味着我的代码通过尝试先设置名称来复制该顺序,然后将机器加入域。虽然这在某些情况下确实有效,但它不一致或不可靠。所以这里学到的最大教训是......

Join the domain first - then change the machine name.

是的,实际上就是这样。经过无数次的测试迭代,我终于明白,如​​果我以这种方式尝试它可能会更好。我在第一次通过更改名称时被绊倒了,但很快意识到它仍在使用本地系统凭据 - 但现在机器此时已加入域,它需要与使用的相同的域凭据加入域本身。稍后快速调整代码,我们现在有一个始终可靠的 WMI 例程,它加入域然后更改名称。

它可能不是最简洁的实现(请随意评论改进)但它确实有效。享受吧。

/// <summary>
/// Join domain and set Machine Name
/// </summary>
public static bool JoinAndSetName(string newName)
{
_lh.Log(LogHandler.LogType.Debug, string.Format("Joining domain and changing Machine Name from '{0}' to '{1}'...", Environment.MachineName, newName));

// Get WMI object for this machine
using (ManagementObject wmiObject = new ManagementObject(new ManagementPath("Win32_ComputerSystem.Name='" + Environment.MachineName + "'")))
{
try
{
// Obtain in-parameters for the method
ManagementBaseObject inParams = wmiObject.GetMethodParameters("JoinDomainOrWorkgroup");
inParams["Name"] = "domain_name";
inParams["Password"] = "domain_account_password";
inParams["UserName"] = "domain_account";
inParams["FJoinOptions"] = 3; // Magic number: 3 = join to domain and create computer account

_lh.Log(LogHandler.LogType.Debug, string.Format("Joining machine to domain under name '{0}'...", inParams["Name"]));

// Execute the method and obtain the return values.
ManagementBaseObject joinParams = wmiObject.InvokeMethod("JoinDomainOrWorkgroup", inParams, null);

_lh.Log(LogHandler.LogType.Debug, string.Format("JoinDomainOrWorkgroup return code: '{0}'", joinParams["ReturnValue"]));

// Did it work?
if ((uint)(joinParams.Properties["ReturnValue"].Value) != 0)
{
// Join to domain didn't work
_lh.Log(LogHandler.LogType.Fatal, string.Format("JoinDomainOrWorkgroup failed with return code: '{0}'", joinParams["ReturnValue"]));
return false;
}
}
catch (ManagementException e)
{
// Join to domain didn't work
_lh.Log(LogHandler.LogType.Fatal, string.Format("Unable to join domain '{0}'", _targetDomain), e);
return false;
}

// Join to domain worked - now change name
ManagementBaseObject inputArgs = wmiObject.GetMethodParameters("Rename");
inputArgs["Name"] = newName;
inputArgs["Password"] = "domain_account_password";
inputArgs["UserName"] = "domain_account";

// Set the name
ManagementBaseObject nameParams = wmiObject.InvokeMethod("Rename", inputArgs, null);
_lh.Log(LogHandler.LogType.Debug, string.Format("Machine Rename return code: '{0}'", nameParams["ReturnValue"]));

if ((uint)(nameParams.Properties["ReturnValue"].Value) != 0)
{
// Name change didn't work
_lh.Log(LogHandler.LogType.Fatal, string.Format("Unable to change Machine Name from '{0}' to '{1}'", Environment.MachineName, newName));
return false;
}

// All ok
return true;
}
}

关于c# - 以编程方式将 Windows 机器加入 AD 域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4183759/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com