我有一个 powershell 脚本,当新电脑安装了 Windows 7 时,我们会用它来做几件事。我们也在 Windows 10 上使用它,而且它运行良好。它在第一次登录时运行,然后技术人员决定是否必须将电脑加入域。但我们需要找到一种方法来在脚本中实现检查,以查看计算机名称是否已存在于技术人员将加入的特定 OU 中。我们不想将 Active Directory 模块添加到所有新的 Windows 7 PC 中,因为这只需要一次。
我们如何在 powershell 脚本中实现这样的检查,该脚本必须能够在未连接的 Windows 7 PC 上运行,并使用技术人员在脚本首次运行时已经输入的凭据?
更新:
在我们开始部署 Windows 10(以及 Windows 7)后,我们以前的 Visual Basic 脚本的行为有所不同。因此,我们决定在 Powershell 中重写它以适应 Windows 7 和 10。我们还设法找到了一种方法来在同一会话中重命名和加入域(= 只需重新启动 1 次)。为了管理这一点,我们在加入域或工作组从Win32_计算机系统,强制计算机对象加入所选 OU,即使该对象已经存在。如果用户收到一台新计算机,并且必须为其指定相同的名称,就会发生这种情况。这就是为什么我需要能够检查它是否已经存在于该特定 OU 中,并在继续加入之前询问技术人员这是否可以。
新的 powershell 脚本有很多非英语内容,并且给使用该脚本的技术人员带来很多问题 (read-host)。因此,我决定删除与此问题相关的脚本片段。
# $computername, $ou and $credentials is set before this runs
$domain = "our.domain.com"
$computer = get-wmiobject Win32_ComputerSystem
$ret = $computer.rename($computername,$credentials.getnetworkcredential()).password,$credentials.username)
if ($ret.ReturnValue -eq 0)
{
$ret = $computer.JoinDomainOrWorkGroup($domain,($credentials.GetNetworkCredential()).Password, $credentials.UserName, $OU, 0x1 + 0x2 + 0x20 + 0x400)
Switch ($ret.ReturnValue)
{
"2224" {
$ret = $computer.JoinDomainOrWorkGroup($domain,$pass,$user,$OU,33)
if ($ret.ReturnValue -eq 1332) { write-host "Computer already exist in another OU. Either delete or move it before joining" -foregroundcolor red -backgroundcolor yellow}
}
"1326" { Write-Host "Wrong username or password" -foregroundcolor red -backgroundcolor yellow }
"2691" { Write-Host "Computer is already joined to this OU" -foregroundcolor red -backgroundcolor yellow }
"0" { Write-Host "Computer was joined"-foregroundcolor Green }
default { Write-Host "Undetermined error: $ret" }
}
}
else { write-host "Computer was not renamed. Try again ($counter/3)" }
更新2: 我也尝试过这样做,但是失败了。无论如何它都返回 False。
$user = $credentials.username
$pass = ($credentials.getnetworkcredential()).password
$searchdomain = New-Object DirectoryServices.DirectoryEntry("LDAP://OUR.DOMAIN.COM", $user, $pass)
$searchdomain.Path = "LDAP://< OU string >"
$ComputerName = gc env:computername
$searcher = New-Object System.DirectoryServices.DirectorySearcher($searchdomain)
$searcher.filter = "(cn=$ComputerName)"
$searchparm = $searcher.FindOne()
if (!($searchparm))
{ Write-Host "Doesn't exist - proceed joining this OU" }
else
{ Write-Host "Already exist - Ask to overwrite existing object" }
答案1
我能够使用本地/非域帐户重现 Update 2 中的问题。LDAP 不起作用,GC 起作用。我不确定为什么。如果只有这个查询失败,也许使用 GC 是一种可接受的解决方法。
使用常规.NET 应用程序的相同查询不会失败。
我确实注意到 Netlogon.log 中存在以下内容,但我认为我的测试环境中的 DNS 没有任何问题:
06/26 18:29:19 [CRITICAL] [3672] NetpDcGetNameIp: <ComputerName>: No data returned from DnsQuery.
06/26 18:29:19 [CRITICAL] [3672] NlBrowserSendDatagram: No transports available
06/26 18:29:19 [CRITICAL] [3672] NetpDcGetNameNetbios: <ComputerName>: Cannot NlBrowserSendDatagram. (ALT) 53
06/26 18:29:19 [CRITICAL] [3672] NetpDcGetName: <ComputerName>: IP and Netbios are both done.
$credentials = Get-Credential
$user = $credentials.username
$pass = ($credentials.getnetworkcredential()).password
$authType = ([System.DirectoryServices.AuthenticationTypes]::Secure -bor [System.DirectoryServices.AuthenticationTypes]::Sealing)
$searchdomain = New-Object System.DirectoryServices.DirectoryEntry("GC://contoso.com", $user, $pass, $authType)
$searchdomain.Path = "GC://OU=Computers,OU=HQ,DC=contoso,DC=com"
$ComputerName = gc env:computername
$searchScope = [System.DirectoryServices.SearchScope]::OneLevel
$searcher = New-Object System.DirectoryServices.DirectorySearcher($searchdomain, $null, $null, $searchScope)
$searcher.filter = "(cn=$ComputerName)"
# FindOne() fails with "The specified domain either does not exist or could not be contacted" if using LDAP instead of GC
$searchparm = $searcher.FindOne()
# Write-Host $searchparm.Path
if (!($searchparm)) { Write-Host "Doesn't exist - proceed joining this OU" } else { Write-Host "Already exist - Ask to overwrite existing object" }
我在装有 Windows Management Framework 5.1/PowerShell 5.1 的 Windows Server 2016 TP5 上进行了测试,没有发现此问题。我推测这是 PowerShell 5.0 的问题,可能会在未来的版本/修补程序中得到解决。
答案2
也许您可以创建一个 Web 服务,然后从您想要的任何地方查询它......
例如:您创建一个 PHP 脚本,它需要一个参数(computername)并返回 true(如果computername已经加入到域)或 false。
然后您可以从 PowerShell 脚本中查询此页面,如下所示:(New-Object Net.WebClient).DownloadString("http://url?计算机名称=xxxxx“)