通过 Invoke-Command 远程执行 Powershell Add-Computer

通过 Invoke-Command 远程执行 Powershell Add-Computer

设想:

在 Azure VM 上本地执行时,成功将机器添加到 AD,然后重新启动。

$DomainName = "test.local"
$AdminUserName = "sysadmin"
$Password = <mypass>
$SecurePassword = ConvertTo-SecureString $Password -asplaintext -force
$Credential = New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $AdminUserName, $SecurePassword
$Credential

Add-Computer -DomainName $DomainName -Credential $Credential -Restart -Passthru -Verbose

问题:

使用相同的变量,但现在通过远程 Powershell 在我的计算机上运行脚本,以另一个 Azure VM 作为目标:

$ScriptBlockContent = { 
Param ($Arg1,$Arg2)
Add-Computer -DomainName $Arg1 -Credential $Arg2 -Restart -Passthru -Verbose}

$Session = New-PSSession -ConnectionUri $Uri -Credential $Credential
Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList ($DomainName,$Credential)

远程执行时会失败。为什么?

PS C:\> Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList $DomainName, $Credential
VERBOSE: Performing the operation "Join in domain 'test.local'" on target "testvm2".
Computer 'rzlab1sql1' failed to join domain 'test.local' from its current workgroup 'WORKGROUP' with following error
message: Unable to update the password. The value provided as the current password is incorrect.
    + CategoryInfo          : OperationStopped: (testvm2:String) [Add-Computer], InvalidOperationException
    + FullyQualifiedErrorId : FailToJoinDomainFromWorkgroup,Microsoft.PowerShell.Commands.AddComputerCommand
    + PSComputerName        : mylab.cloudapp.net

然而,一些更基本的、没有参数的东西,远程运行没有问题,所以我的$Uri、$Credential 和一般语法看起来没问题,会话启动并运行我的代码:

$Path = "C:\"
$Attribute = "d"

$ScriptBlockContent = { 
Param ($Arg1,$Arg2)
Get-ChildItem -Path $Arg1 -Attributes $Arg2}

$Session = New-PSSession -ConnectionUri $Uri -Credential $Credential
Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList $Path, $Attribute

Invoke-Command 和我存储凭据的方式有问题吗?还有其他选项可以完成此操作(从 PS 脚本将新 VM 添加到域)吗?

解决方案

使用测试.local\sysadmin而不是系统管理员用户连接到 AD。

$DomainName = "test.local"
$AdminUserName = "sysadmin"
$DomainUserName = $DomainName+"\"+$AdminUserName
$Password = <mypass>
$SecurePassword = ConvertTo-SecureString $Password -asplaintext -force
$Credential = New-Object -Typename System.Management.Automation.PSCredential -Argumentlist ($AdminUserName, $SecurePassword)
$DomainCredential = New-Object -Typename System.Management.Automation.PSCredential -Argumentlist ($DomainUserName, $SecurePassword)

$ScriptBlockContent = { 
Param ($Arg1,$Arg2)
Add-Computer -DomainName $Arg1 -Credential $Arg2 -Restart -Passthru -Verbose}

$Session = New-PSSession -ConnectionUri $Uri -Credential $Credential
Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList ($DomainName, $DomainCredential)

另一个解决方案(不太安全)是将纯文本用户和密码发送到远程会话,并在那里创建凭证:

$ScriptBlockContent = { 
Param ($Arg1,$Arg2,$Arg3,$Arg4)
Add-Computer -ComputerName $Arg4 -DomainName $Arg1 -Credential (New-Object -Typename System.Management.Automation.PSCredential -Argumentlist ($Arg1+"\"+$Arg2), (ConvertTo-SecureString $Arg3 -asplaintext -force)) -Restart -Passthru -Verbose}

$Session = New-PSSession -ConnectionUri $Uri -Credential $Credential
Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList ($DomainName,$AdminUserName,$Password,$VMName)

答案1

我认为问题可能出在您使用 生成凭据的方式上ConvertTo-SecureString。默认情况下,该 cmdlet 使用特定于当前主机的加密密钥(我认为)除非您通过参数提供显式加密密钥-Key。在远程端,它需要使用其没有的相同加密密钥来解密字符串(因为主机密钥不同)。

首先,我会尝试将纯文本用户名和密码作为另一个参数传递给调用,并在脚本块中创建凭据。这至少可以证明这是否确实是您的问题。

*编辑:这是文档的链接转换为安全字符串

答案2

取自:http://www.gi-architects.co.uk/2017/01/powershell-add-computer-error-when-executed-remotely/

问题的根源在于(假设您的密码正确)在交互运行时,域是预先附加的,因此您只需提供用户。但在非交互式环境中,域是未知的。确保您包含短域名contoso\DMAdmin或完整的 FQDN [email protected]

如果您通过 Azure 自动化安全地将用户名和密码作为变量传递,则可以使用以下 PowerShell 脚本:

$PasswordSec = ConvertTo-SecureString $Password -AsPlainText -Force $djuser = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $PasswordSec Add-Computer -DomainName "contoso.com" -Credential $djuser -Restart

相关内容