我之前涵盖了如何 默默地安装msi。管理员要做的下一件事就是在远程系统上安装它。这是逻辑下一步。这对Po​​werShell新的人来说并不总是最简单的任务。

指数

介绍

To keep these samples cleaner, I am going to use an imaginary installer that is not an MSI but the approach is the same. The main way to execute remote commands is with PowerShell remoting using the Enter-PSSession or Invoke-Command cmdlets. I am assuming that you already have PSRemoting working in your environment. If you need help with that, consult the Powershell Remoting的秘密 ebook.

I am also using Invoke-Command in all my examples because that is what you would use in your scripts.

远程运行安装人员

If you already have the file on the remote system, we can run it with Invoke-Command.

Invoke-Command -ComputerName server01 -ScriptBlock {
    c:\software\installer.exe /silent
}

有两个重要的细节可以立即意识到。

第一个详细信息是您需要在安装程序运行时维护远程会话。如果安装程序不会阻止执行(它在执行时将控件返回给shell),则脚本可以在安装程序完成之前完成。只要关闭远程会话,这将取消安装。

You will need to call Start-Process -Wait if you are having that issue.

Invoke-Command -ComputerName server01 -ScriptBlock { 
    Start-Process c:\windows\temp\installer.exe -ArgumentList '/silent' -Wait
}

这为我们带来了我们的第二个重要细节。安装需要真正沉默。远程会话是非交互式的。这意味着它们无法弹出或显示窗口。这将导致程序失败,因为它无法显示窗口,否则它会导致安装程序挂起,因为它希望有人单击您无法单击的按钮。

从远程位置安装

大多数时间如果在远程系统上运行安装程序,则您可以在网络共享(UNC路径)上安装安装程序。乍一看,这看起来应该有效:

# Incorrect approach
Invoke-Command -ComputerName server01 -ScriptBlock {
    \\fileserver\share\installer.exe /silent
}

这可能是很多头痛的来源。理想情况下,您想从UNC路径运行安装程序,但您发现它不起作用。

尝试复制remote命令中的文件给您同样的问题。

# Incorrect approach
Invoke-Command -ComputerName server01 -ScriptBlock {
    Copy-Item \\fileserver\share\installer.exe c:\windows\temp\
}

# Access denied or file does not exist

一切都告诉你文件要么不存在,或者您对文件没有权限。这是一个错误的消息,因为它确实存在,并且您有文件访问权限。问题是您的远程会话没有相同的权利。

双跳问题

This is the double hop problem. The credential used to authenticate with server01 cannot be used by server01 to authenticate to fileserver. Or any other network resources for that matter. That second hop is anything that requires authentication that is not on the first remote system.

我们可以预先复制文件或在远程端重新验证。

我将在其余示例中使用这些位置持有者变量。

$file = '\\fileserver\share\installer.exe'
$computerName = 'server01'

使用管理员共享的预复制文件

显而易见的第一个方法是使用远程系统的管理员共享将内容推向我们可以访问的位置。在这里,我将它放在Windows Temp文件夹中,然后远程执行它。

Copy-Item -Path $file -Destination "\\$computername\c$\windows\temp\installer.exe"
Invoke-Command -ComputerName $computerName -ScriptBlock {
    c:\windows\temp\installer.exe /silent
}

使用PSSession预拷贝(PS 5.0)

电源外壳 5.0中添加了一个新功能,允许您使用PSSession复制文件。因此,使用下面的语法创建PSSession并将文件复制到它上面。关于这种方法的一个很酷的事情就是通过PowerShell 5.0,您可以通过VM总线(而不是网络)将PSSession over over Guest VM创建到Guest VM,并且您仍然可以将文件复制到它。

$session = New-PSSession -ComputerName $computerName
Copy-Item -Path $file -ToSession $session -Destination 'c:\windows\temp\installer.exe'

Invoke-Command -Session $session -ScriptBlock {
    c:\windows\temp\installer.exe /silent
}
Remove-PSSession $session

While you can run Invoke-Command on multiple computers at once, be aware that Copy-Item -ToSession only works on a single session.

PowerCli Copy-VMGUEST

您可以使用PowerCli将文件复制到vSphere Guest Copy-VMGUEST. CmdLet.

$VM = Get-VM $computername
Copy-VMGuest -Source $file -Destination 'c:\windows\temp\installer.exe' -VM $VM

从会话重新验证

It actually is easy to re-authenticate in the remote session. Create a credential object and pass it into your Invoke-Command. Then use that credential to create a New-PSDrive. Even if you don’t use that new drive mapping, it will establish authentication for your UNC path to work.

$credential = Get-Credential
$psdrive = @{
    Name = "PSDrive"
    PSProvider = "FileSystem"
    Root = "\\fileserver\share"
    Credential = $credential
}

Invoke-Command -ComputerName $computerName -ScriptBlock {
    New-PSDrive @using:psdrive
    \\fileserver\share\installer.exe /silent 
} 

我在这个例子中使用了两个技巧,我需要指出你之前还没有看到它们。第一是 拆分 where I place arguments into a hashtable and use the @ operator to pass them to the CmdLet. The second is the $using: 范围 to get a variable from my local session into that remote scriptblock. I combine both of them when I execute this command New-PSDrive @using:psdrive.

不要使用Credssp.

我无法谈论双跳问题而不提及信用证。如果您谷歌双跳问题,您将在线找到最常见的解决方案是启用CredSSP。即使是Jeffery Snover也有一个推荐的旧文章。普通社区已将其作为解决方案迁移,因为它将您的环境造成风险。使用CredSSP的问题是您的管理员凭证以允许攻击者轻松访问它的方式缓存在远程系统上。

有关更多详细信息,请参阅此伟大的写作: 意外破坏:谨防信用证

基于资源的Kerberos约束委派

但是有一个更好的解决方案称为基于资源的Kerberos约束委派。 Server 2012中的约束委派介绍了使用安全描述符控制服务票证委托的概念,而不是允许SPN列表。此更改通过启用资源来确定允许代表其他用户请求票证的安全主体来简化委派。看 Powershell Remoting Kerberos双跳安全地解决了 for the details.

这是一个快速剪辑,用于显示它的工作原理。

# For ServerC in Contoso domain and ServerB in other domain
$ServerB = Get-ADComputer -Identity ServerB -Server dc1.alpineskihouse.com
$ServerC = Get-ADComputer -Identity ServerC
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB

#To undo the configuration, reset ServerC’s attribute to null.
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $null

其他考虑的方法

这涵盖了管理员采取解决这个问题的最常见方法。我确实有一些想法要考虑的想法。这些方法超出了这篇文章的范围,以进入实施细节,但我希望您要意识到它们。

期望的状态配置

您可以使用DSC部署和安装软件。 DSC中的简单内容非常简单,您会学到这条路径的很多。对于此,您需要一个拉动服务器(易于设置)。

决定如何将安装程序获取到目标系统是DSC的硬部分。如果您设置了证书,则可以向“直线文件副本的文件共享”提供凭据。或者您可以创建自定义DSC资源并将文件放入其中。目标系统将从其他资源中下载它从拉动服务器下载。

您可以将其与其中一个接下来的想法结合起来。

网络下载

您可以在安装之前将文件从外部或内部Web服务器中拉出。

Invoke-WebRequest $url -OutFile 'c:\windows\temp\installer.exe' -UseBasicParsing

安装包管理

Windows介绍了 Pakage Management. 进入Windows,可用于从在线存储库安装包。

Install-Package $PackageName

使用chocholatey安装

或者你可以使用 chocholatey.org. package manager. The Microsoft package manager supports Chocholatey as a source but I have found the occasional installer that needs to be ran with choco install instead.

choco install $PackageName

内部存储库

您可以设置Nuget存储库并使用新的软件包管理命令部署应用程序。如果您有内部开发团队,这是他们可能已经设置的东西。

Install-Package $PackageName -Source MyRepoName

在结束时

这篇文章的上半场回答了为什么你可能正在努力让软件才能远程安装的问题。

如果您的问题是“我应该如何安装软件?”然后您的焦点应该转移到包管理。它仍然是Windows生态系统的新功能,但这就是Windows朝向的方向。

您有充足的选择可供选择。选择最适合您当前情况的作品。