Como posso usar funções compartilhadas em uma sessão remota do Powershell?

3

Eu tenho alguns scripts do Powershell para configurar aplicativos web do IIS, filas de mensagens, etc.

Eles usam um conjunto de bibliotecas de funções compartilhadas que criamos - então cada script começa com a linha

. .\common.ps1

para referenciar a biblioteca compartilhada. A biblioteca compartilhada contém um conjunto de funções como Create-IisApplicationPool , Create-MessageQueue e similares, que são então chamadas a partir do script real. O problema com esses scripts é que você precisa fazer logon via Remote Desktop e executá-los localmente, portanto, estou escrevendo alguns novos scripts para implantar código em uma instância do Amazon EC2 e usando a comunicação remota do Powershell para invocá-los localmente.

O que não consigo descobrir é como disponibilizar essa biblioteca compartilhada em uma sessão remota do Powershell.

Aqui está um exemplo simples:

functions.ps1

function Add-Title([string] $name) {
    "Mr. $name"
}

function Say-HelloWorld([string] $name = "World") {
    $computerName = $env:COMPUTERNAME
    $greeting = Add-Title($name)
    Write-Host "Hello, $greeting ($computerName)"
}

example.ps1

. ./functions.ps1


$remoteUsername = "username"
$remotePassword = "password"
$remoteHostname = "172.16.0.100"

$securePassword = ConvertTo-SecureString -AsPlainText -Force $remotePassword
$cred = New-Object System.Management.Automation.PSCredential $remoteUsername, $securePassword


Say-HelloWorld("Spolsky")

Rodando localmente, isso funciona muito bem - e diz "Olá, Sr. Spolsky (DYLAN_PC)" como esperado.

Agora, se eu substituir a chamada Say-HelloWorld por essa chamada de script remoto:

Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock {
    Say-HelloWorld("Spolsky")
}

Eu recebo o erro do Powershell:

The term 'Say-HelloWorld' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is co rrect and try again. + CategoryInfo : ObjectNotFound: (Say-HelloWorld:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

Claramente, a sessão remota não pode ver as funções que foram importadas localmente.

Para funções simples, esta sintaxe funciona:

Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock ${function:Add-Title } -argumentlist "Spolsky"

mas isto falha para qualquer função que dependa de outras funções.

Eu tentei várias coisas usando PS-ExportSession e tentando passar um argumento -Session para Invoke-Command, mas não consigo encontrar nenhuma maneira de capturar funções locais e suas dependências em um módulo que pode ser importado para um sessão remota. Qualquer ajuda recebida com gratidão!

    
por Dylan Beattie 03.12.2012 / 18:19

4 respostas

4

Este é um tópico antigo, mas todas as respostas são mais redondas do que isso.

Import-Module .\Common.ps1 -Force
# Now you can call common functions locally

$commonFunctions = (Get-Command .\Common.ps1).ScriptContents
Invoke-Command -Session $session -ArgumentList $commonFunctions -ScriptBlock {
    param($commonFunctions)
    Invoke-Expression $commonFunctions

    # Now you can call common functions on the remote computer
}
    
por 13.10.2016 / 23:46
1

Você diz que cada script começa com . .\common.ps1 , mas não aparece em seu script de exemplo. Independentemente disso, se você precisar usar as funções em common.ps1, terá que colocá-lo em algum lugar que a máquina remota possa acessar.

Você pode usar as unidades redirecionadas no Powershell como faria em uma sessão RDP:

New-PSSession SERVER1 -Cred $creds | Enter-PSSession
. \tsclient\c\common.ps1

Ou você pode colocar common.ps1 em um compartilhamento de rede:

. \Server1\share\common.ps1

Ou você pode simplesmente colar o conteúdo em common.ps1 em cada script.

Ou você pode colocar common.ps1 no sistema de arquivos local da máquina remota.

Quando o analisador Powershell na máquina remota vê ".. \ common.ps1" ele está tentando carregar common.ps1 do diretório de trabalho atual, que é provavelmente o diretório home de qualquer usuário que tenha estabelecido a sessão PS remota. / p>     

por 03.12.2012 / 18:36
1

Eu esperaria que você precisasse copiar functions.ps1 antes de fazer o sourcing do ponto. Na verdade, eu provavelmente copiaria os dois scripts para o mesmo diretório (por exemplo, através do compartilhamento admin do C $ para \server\C$\foo ) e, em seguida, invocaria remotamente C:\foo\example.ps1 usando Invoke-Command .

    
por 03.12.2012 / 19:59
0

Eu tive exatamente o mesmo problema. Eu suponho que é fazer com invocações remotas em execução no contexto do chamador remoto. Consegui contornar o problema fornecendo um caminho local completo para a biblioteca de destino como uma variável e, em seguida, obtendo o ponto de origem da biblioteca por meio da variável:

function Get-ScriptDirectory
{
    return Split-Path $script:MyInvocation.MyCommand.Path
}

function GetLocalFileName
{
    param([string]$filename)    
    return [system.io.path]::Combine((Get-ScriptDirectory),$filename)
}

# dot-source the library using full local name to get round problem with remote invocation
$MYLIBRARY = GetLocalFileName "mylibrary.ps1"
. $MYLIBRARY 
    
por 20.06.2013 / 17:47