【问题标题】:Powershell Remoting: using imported module cmdlets in a remote pssessionPowershell Remoting:在远程 pssession 中使用导入的模块 cmdlet
【发布时间】:2011-02-19 07:47:06
【问题描述】:

有没有办法在远程会话中使用在本地会话中导入的模块?我查看了 import-pssession,但我不知道如何获取本地会话。这是我想做的一个示例。

import-module .\MyModule\MyModule.ps1
$session = new-pssession -computerName RemoteComputer
invoke-command -session $session -scriptblock { Use-CmdletFromMyModule }

另外,我不想在远程会话中导入模块,因为 ps1 文件不在该服务器上。

【问题讨论】:

    标签: powershell powershell-remoting powershell-module


    【解决方案1】:

    所以我一直在寻找类似的东西......在我的情况下,我只需要将一个函数导出到远程会话......这就是我想出的。也许你可以遍历它来尝试一下。它不适用于内部命令,但它确实适用于自定义模块中的功能(在我所做的测试中)。

    function Export-FunctionToSession
    {
        [CmdletBinding()]
        [Alias()]
        [OutputType([int])]
        Param
        (
            [Parameter(Mandatory=$true,
                       ValueFromPipelineByPropertyName=$true,
                       Position=0)]
            $Session,
            [Parameter(Mandatory=$true,
                       ValueFromPipelineByPropertyName=$true,
                       Position=0)]
            $FunctionName
        )
        $script = "Function $functionName(){" + (Get-Command $functionName).definition + '}'
        $scriptBlock = {Invoke-Expression $using:script}
        Invoke-Command -Session $session -ScriptBlock $scriptBlock
    }
    

    【讨论】:

      【解决方案2】:

      使用 credssp 身份验证

      invoke-command -computername $localSession -Credential $Credential -Authentication Credssp
      

      【讨论】:

        【解决方案3】:

        我建议如下:

        $rs = New-PSSession -ComputerName "RemoteComputer"
        Invoke-Command -Session $rs -scriptblock {import-module ActiveDirectory}
        Import-PSSession -Session $rs -Module ActiveDirectory
        

        从那时起,您可以在会话中使用 ActiveDirectory cmdlet。

        希望这会有所帮助。

        【讨论】:

          【解决方案4】:

          如果这有帮助:

          如果您可以切换到 PowerShell 3.0,那么 Get-Module 和 Import-Module cmdlet 支持远程计算机上的模块:

          http://technet.microsoft.com/en-us/library/hh857339.aspx#BKMK_REM

          应该可以在执行 Import-Module 的远程计算机上运行 PowerShell, 远程计算机上没有任何 ps1 脚本。

          【讨论】:

          • 可能我们两端都需要 PS 3.0,不是吗?
          【解决方案5】:

          作为 Jonathan 提到的替代方案,如果您有想要通过网络推送的源模块,那么您可以毫不费力地做到这一点。如果你有二进制文件,你可能可以做类似的事情。但我想说所有的赌注都在那里。本质上,您将文件作为参数推送到哈希中,写入临时文件,然后导入。

          function Export-SourceModulesToSession
          {
              Param(
               [Management.Automation.Runspaces.PSSession]
               [ValidateNotNull()]
               $Session,
          
              [IO.FileInfo[]]
              [ValidateNotNull()]
              [ValidateScript(
              {
                (Test-Path $_) -and (!$_.PSIsContainer) -and ($_.Extension -eq '.psm1')
              })]
             $ModulePaths
            )
          
             $remoteModuleImportScript = {
               Param($Modules)
          
               Write-Host "Writing $($Modules.Count) modules to temporary disk location"
          
               $Modules |
                 % {
                   $path = ([IO.Path]::GetTempFileName()  + '.psm1')
                   $_.Contents | Out-File -FilePath $path -Force
                   "Importing module [$($_.Name)] from [$path]"
                   Import-Module $path
                 }
             }
          
            $modules = $ModulePaths | % { @{Name = $_.Name; Contents = Get-Content $_ } }
            $params = @{
              Session = $Session;
              ScriptBlock = $remoteModuleImportScript;
              Argumentlist = @(,$modules);
            }
          
            Invoke-Command @params
          }
          

          打个电话

          $session = New-PSSession -ComputerName Foo
          Export-SourceModulesToSession $session -ModulePaths '.\module.psm1','.\module2.psm1'
          

          理论上也可以,将当前的 localhost 会话导出到模块并将其推送到网络上——未经测试的伪代码。这可能行不通……

          $localSession = New-PSSession #defaults to localhost
          
          # if you don't have modules automatically loading in the profile, etc, then manually load them
          Invoke-Command -Computer $localSession -ScriptBlock { Import-Module 'foo'; Import-Module '.\module.ps1' }
          Export-PSSession $localSession -OutputModule TempLocalModule
          #now that you have TempLocalModule written out, it's possible you can send that thing across the wire in the same way
          

          【讨论】:

          • 提示:如果模块位于 PSModule 路径中或已加载,将 ModulePaths 评估更改为 (Get-Module $Module).Path 会很有用
          【解决方案6】:

          我最终破解了它来工作。我所做的是创建一个本地会话,将模块导入该会话并使用 import-pssession 将模块从创建的本地会话导入远程会话。这很慢。如果有人有更好的方法,或者如果有人知道如何获取基本会话的实例,我很乐意听取您的意见!

          Remoting.psm1

          function Export-ModuleToSession {
           Param(
            [ValidateNotNull()]
            $session,
            [ValidateNotNull()]
            $modules
           )
          
           $computername = $env:computername
          
           $modulesToImport = get-module -name $modules
          
           invoke-command -session $session -argumentlist @($computername, $modulesToImport) -scriptblock {
            Param(
             $computername,
             $modules
            )
          
            write-host ("Creating Temp Session On: " + $computername)
          
            $localSession = New-psSession -computername $computername
          
            $modules | foreach-object {
             if($_.ModuleType -ne "Binary") {
              $path = $_.path
             }
             else {
              $path = join-path (split-path $_.Path) ("{0}.psd1" -f $_.name)
             }
          
             invoke-command -session $localSession -argumentList $path -scriptblock {
              Param(
               $path
              )
          
              $initializeDefaultBTSDrive = $false
              set-executionpolicy unrestricted
          
              write-host ("Importing Module To Temp Session: " + $path)
              import-module $path
             }
            }
          
            $initializeDefaultBTSDrive = $false
          
            $modules | foreach-object { 
             write-host ("Exporting Module: " + $_.name)
             import-psSession -session $localSession -Module $_.name  | out-null 
            }
           }
          }
          

          MyModule.psm1

          function MyCmdlet {}
          

          RemotingTest.ps1

          import-module .\remoting.psm1
          import-module .\MyModule.psm1
          
          try
          {
           $remoteSession = New-PsSession -computerName "RemoteComputer"
           Export-ModuleToSession -session $remoteSession -modules "MyModule"
          
           Invoke-Command -session $remoteSession -scriptblock { MyCmdlet } -verbose -ea Stop
          }
          finally
          {
           Remove-PsSession $remoteSession -ea Continue
           Remove-Module "Remoting" -ea Continue
           Remove-Module "MyModule" -ea Continue
          }
          

          【讨论】:

          • 我的立场是正确的。 :-) 采用从远程计算机导入命令并将其转为从本地计算机导入的能力的好方法。顺便说一句,您是否因为遇到问题而基于路径(而不是模块名称)导入?
          • 如果模块文件位于默认模块位置之一,您只能按名称导入模块。如果不是,你必须给它文件路径。我遇到了从模块清单 psd1 导入的装配模块的问题。二进制模块的 PSModuleInfo.Path 属性指向 dll 而不是 psd1。如果直接从 dll 导入,那么 import-pssession 会失败。因此,所有的巫术都可以获取组装模块的 psd1 文件。
          • 你还在用这个方法还是找到了更好的方法?
          • 这不是一种不合理的方法 - 但是它需要线路的两端都具有 WinRM 侦听,这可能难以配置/允许,具体取决于您的环境。对于内部环境,没什么大不了的,但如果你的主机在 EC2 上,并且你的内部机器在防火墙后面,这将很难设置。不要轻视它的用处——这是一个很好的技巧,但请注意这些问题。我还有另一种方法,也有限制贴在下面。恕我直言,这是 Powershell 远程处理的一个痛点(没有真正的 SFTP 等价物)
          【解决方案7】:

          我不相信你可以。您可以采用另一种方式 - 将远程机器上加载的命令导入本地机器上运行的远程会话。您可以指定一个脚本来调用命令,它将将该脚本复制到远程计算机并运行它。但是,如果您需要管理单元或其他模块,则需要确保将它们安装在每台远程计算机上,然后通过命令或脚本将它们加载到远程会话中。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-11-02
            相关资源
            最近更新 更多