我正在开发一个自定义的PowerShell的模块,我想在远程会话的上下文中使用到不同的计算机哪个。 下面的代码(这显然是行不通的)解释了什么是我想要实现:
import-module .\MyCustomModule.psm1
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
<# use function defined in MyCustomModule here #>
}
第一个问题是,它是否在所有可能实现这个场景? 我的意思是我只想我的自定义模块在物理上存在我的机器上,而不是远程服务器上。
我发现这个线程 ,但我没有管理它的工作-它不允许建立与远程计算机的会话回本地之一。 也许,我面临着在评论该线程某处提到的配置限制......此外,笔者提到的对性能的影响这是我的解决方案的关键...
如果可能的话,再怎么样?
PowerShell中的版本是目前不是约束 - 如果解决方案仅适用于PS 3.0可用 - 我可以这样生活。
有这个问题一些伟大的意见,我已经花了一些时间来调查各种方式来解决这个问题。
首先,我所最初要求是不可能的。 我的意思是,如果你去的模块方式,那么该模块应该是物理存在在目标机器上要能够Import-Module
到远程会话。
抽象我的问题进一步,我想为产品创建部署可重复使用的基于PowerShell的框架。 这将是一个推动的方式部署,这意味着我们鼓励人们在本地机器上运行一些脚本来部署到一些远程服务器。 据我调查方面,有两种可能的方式,在平等互利的常理。
模块方法
该过程中遵循:
- 每个逻辑上不同的一块的功能放入PowerShell的模块(
*.psm1
) - 所述模块分配给远程机器并延长
PSModulePath
变量,以包括新的模块位置 - 在客户机上,创建一个新的会话到远程服务器,并使用
Invoke-Command -Session $s -ScriptBlock {...}
- 从脚本块开始
Import-Module CustomModule
-它会搜索CustomModule
在远程机器上,显然会发现它
好处
以下是爱这种方法的原因:
- 传统的模块作用的结果 - 促进可重用的库的创建
- 根据伟大的书的Windows PowerShell在行动 ,“模块可以用来创建特定领域的应用。” 据我明白,它可以通过组合模块嵌套和混合脚本/二进制模块以暴露特定于某个域的直观的界面来实现。 基本上,这是一个我最看重的基于PowerShell的部署框架的目标
缺点
考虑到以下事项:
- 你必须找到一种方法来定制模块提供到远程计算机。 我曾经玩过的NuGet ,我不知道它很相称的任务,但也有其他选择,例如,MSI安装程序或纯
xcopy
从共享文件夹。 此外,传送机制应该支持升级/降级和(最好)的多实例安装,但是这是我的任务,而不是一般的问题,更关系
脚本办法
该过程中遵循:
- 将每个逻辑上不同的一块的功能在一个单独的PowerShell脚本(*的.ps1)
- 在客户机上,创建一个新的会话到远程服务器,并使用
Invoke-Command -Session $s -FilePath .\myscript.ps1
加载在脚本中定义的功能,远程会话 - 使用另一个
Invoke-Command -Session $s -ScriptBlock {...}
并参阅您的自定义功能-他们将有一个会议
好处
以下是这种方法的长处:
- 这是简单的 - 你不必知道模块的特点。 只要写简单的PowerShell脚本,这就是它
- 你没有提供任何远程机器 - 这使得解决方案更简单和更不容易出错维修
缺点
当然,它的效果并不理想:
- 有过解决方案的控制较少:例如,如果“进口”的一组功能的会话,个个都是“进口”和看得见的用户,所以没有“封装”,等等。 我敢肯定,许多解决方案可以与此居住,所以基于这一点不只是决定
- 在每个文件的功能必须是自包含的 - 任何点采购或进口模块从那里将搜索远程机器,而不是当地的一个
最后,我应该说,远程机器仍然需要远程处理做好准备。 这就是我的意思是:
- 执行策略应该改变的东西,因为它是默认的限制:
Set-ExecutionPolicy Unrestricted
- PowerShell远程应启用:
Enable-PSRemoting
- 该帐户的脚本运行作为应该被添加到远程服务器的本地管理员
- 如果你计划访问文件共享的远程会话,请确保您知道关于多跳的认证和采取适当的行动
- 确保你的杀毒软件是你的朋友,并且不把你送到PowerShell的地狱
这里的另一种方法:重新在远程会话模块,而不复制任何文件。
我没有尝试,以应付模块之间的依赖关系,但这似乎工作正常进行简单的自包含的模块。 它依赖模块中的本地会话是可用的,因为这使得确定出口更容易,但有一些额外的工作,它也将与模块文件的工作。
function Import-ModuleRemotely([string] $moduleName,[System.Management.Automation.Runspaces.PSSession] $session)
{
$localModule = get-module $moduleName;
if (! $localModule)
{
write-warning "No local module by that name exists";
return;
}
function Exports([string] $paramName, $dictionary)
{
if ($dictionary.Keys.Count -gt 0)
{
$keys = $dictionary.Keys -join ",";
return " -$paramName $keys"
}
}
$fns = Exports "Function" $localModule.ExportedFunctions;
$aliases = Exports "Alias" $localModule.ExportedAliases;
$cmdlets = Exports "Cmdlet" $localModule.ExportedCmdlets;
$vars = Exports "Variable" $localModule.ExportedVariables;
$exports = "Export-ModuleMember $fns $aliases $cmdlets $vars;";
$moduleString= @"
if (get-module $moduleName)
{
remove-module $moduleName;
}
New-Module -name $moduleName {
$($localModule.Definition)
$exports;
} | import-module
"@
$script = [ScriptBlock]::Create($moduleString);
invoke-command -session $session -scriptblock $script;
}
我不相信这是支持框的右侧没有任何“黑客”。 智能此举很可能是把模块上的公共场所如文件服务器,并导入到服务器上,当你需要它。 例如:
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
#Set executionpolicy to bypass warnings IN THIS SESSION ONLY
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
#Import module from public location
Import-Module \\fileserver\folders\modulelocation...
<# use function defined in MyCustomModule here #>
}
有关使脚本块了您的自定义功能和使用发送其关闭,以terget服务器什么Invoke-command
Import-module YourModule
$s = [scriptblock]::Create($(get-item Function:\Your-ModuleFunction).Definition)
Invoke-Command -ScriptBlock $s -Computername s1,s2,sn
感谢这个线程是有益的......。
不过我却改写了功能。
要知道,幽冥原有功能在这个岗位或该改写功能包括模块清单数据。 所以,你不能依靠模块版本检查。
function Import-ModuleRemotely {
Param (
[string] $moduleName,
[System.Management.Automation.Runspaces.PSSession] $session
)
Import-Module $moduleName
$Script = @"
if (get-module $moduleName)
{
remove-module $moduleName;
}
New-Module -Name $moduleName { $($(Get-Module $moduleName).Definition) } | Import-Module
"@
Invoke-Command -Session $Session -ScriptBlock {
Param($Script)
. ([ScriptBlock]::Create($Script))
Get-Module
} -ArgumentList $Script
}