¿Cómo importar el módulo personalizado de PowerShell en la sesión remota?


Estoy desarrollando un módulo personalizado de PowerShell, que me gustaría usar en el contexto de una sesión remota en un equipo diferente. El siguiente código (que obviamente no funciona) explica lo que estoy tratando de lograr:

import-module .\MyCustomModule.psm1
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock { 
  <# use function defined in MyCustomModule here #> 
}

La primera pregunta es si es posible lograr este escenario. Quiero decir que solo me gustaría que mi módulo personalizado estuviera físicamente presente en mi máquina, no en el servidor remoto.

He encontrado este hilo, pero no he logrado que para trabajar: no permite crear una sesión desde una máquina remota a la local. Probablemente, me enfrenté a las limitaciones de configuración mencionadas en algún lugar de los comentarios a ese hilo... Además, el autor mencionó las implicaciones de rendimiento que es crítico para mi solución...

Si eso es posible, ¿entonces cómo?

La versión de PowerShell no es actualmente una restricción - si la solución solo está disponible en PS 3.0 - puedo vivir con esto.

Author: Community, 2013-01-21

4 answers

Hubo algunos grandes comentarios a la pregunta, y he pasado algún tiempo investigando varias maneras de abordar el problema.

Para empezar, lo que he pedido inicialmente no es posible. Quiero decir, si vas por el camino del módulo, entonces el módulo debe estar físicamente presente en una máquina de destino para poder Import-Module en la sesión remota.

Para resumir aún más mi pregunta, estoy tratando de crear un marco basado en PowerShell reutilizable para las implementaciones de productos. Va a ser implementaciones de tipo push, lo que significa que alentamos a las personas a ejecutar algunos scripts en una máquina local para implementarlos en algún servidor remoto. Por lo que investigué el área, hay dos maneras posibles que son amigables con el sentido común.

Enfoque por módulos

El proceso a seguir:

  • coloque cada pieza de funcionalidad lógicamente diferente en el módulo de PowerShell (*.psm1)
  • distribuya el módulo a la máquina remota y extienda la variable PSModulePath para incluir los nuevos módulos ubicación
  • en un equipo cliente, cree una nueva sesión en el servidor remoto y use Invoke-Command -Session $s -ScriptBlock {...}
  • en el bloque de script start from Import-Module CustomModule - buscará el CustomModule en una máquina remota y obviamente lo encontrará

Ventajas

Las siguientes son las razones para amar este enfoque para:

  • la consecuencia del rol del módulo tradicional-facilitar la creación de bibliotecas reutilizables
  • de acuerdo con la great book Windows PowerShell en Action, "los módulos se pueden usar para crear aplicaciones específicas de dominio". Por lo que entiendo, se puede lograr combinando el anidamiento del módulo y la mezcla de módulos script / binarios para exponer la interfaz intuitiva específica de un dominio determinado. Básicamente, este es el que más valoro para el objetivo del marco de implementación basado en PowerShell

Desventajas

Lo siguiente es importante tener en cuenta consideración:

  • Tiene que encontrar una manera de entregar los módulos personalizados a la máquina remota. He jugado con NuGet , y no estoy seguro de que se adapte bien a la tarea, pero también hay otras opciones, por ejemplo, MSI installer o plain xcopy desde la carpeta compartida. Además, el mecanismo de entrega debería soportar upgrade / downgrade y (preferiblemente) instalaciones de múltiples instancias, pero eso está más relacionado con mi tarea que con el problema en generalidades

Enfoque de scripts

El proceso a seguir:

  • coloque cada pieza de funcionalidad lógicamente diferente en un script de PowerShell separado (*.ps1)
  • en un equipo cliente, cree una nueva sesión en el servidor remoto y use Invoke-Command -Session $s -FilePath .\myscript.ps1 para cargar las funciones definidas en un script en la sesión remota
  • use otro Invoke-Command -Session $s -ScriptBlock {...} y refiérase a sus funciones personalizadas-estarán allí en una sesión

Ventajas

El los siguientes son buenos puntos de este enfoque:

  • es simple - usted no tiene que saber acerca de las peculiaridades del módulo. Simplemente escriba scripts de PowerShell simples y eso es todo
  • no tiene que entregar nada a la máquina remota, esto hace que la solución sea aún más simple y menos propensa a errores en el mantenimiento

Desventajas

Claro, no es ideal:{[12]]}

  • hay menos control sobre la solución: por ejemplo, si "importa" un conjunto de funciones a la sesión, todas ellas son " importadas "y visibles para el usuario, por lo que no hay" encapsulación", etc. Estoy seguro de que muchas soluciones pueden vivir con esto, así que no decida basándose solo en este punto{[82]]}
  • la funcionalidad en cada archivo tiene que ser independiente: cualquier fuente de puntos o importación de módulos desde allí buscará en la máquina remota, no en la local

Finalmente, debo decir que la máquina remota todavía necesita estar preparada para la comunicación remota. Esto es lo que media:

  • la política de ejecución debe cambiarse a algo, porque está restringida por defecto: Set-ExecutionPolicy Unrestricted
  • La comunicación remota de PowerShell debe estar habilitada: Enable-PSRemoting
  • la cuenta en la que se ejecuta el script debe añadirse a los administradores locales del servidor remoto
  • si planea acceder a recursos compartidos de archivos en la sesión remota, asegúrese de estar al tanto de la autenticación de múltiples saltos y tome las acciones adecuadas
  • asegúrese de que su antivirus es su amigo y no te envía al infierno de PowerShell
 38
Author: Yan Sklyarenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-15 06:39:06

Aquí hay otro enfoque: Recrear el módulo en una sesión remota, sin copiar ningún archivo.

No he hecho ningún intento de hacer frente a las dependencias entre módulos, pero esto parece funcionar bien para módulos autónomos simples. Se basa en que el módulo esté disponible en la sesión local, ya que esto facilita la determinación de las exportaciones, pero con un poco de trabajo adicional también funcionaría con un archivo de módulo.

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;
}
 7
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-19 11:07:49

No creo que esto sea soportado a la derecha de la caja sin ningún "hacks". El movimiento inteligente probablemente sería poner el módulo en una ubicación pública como un servidor de archivos e importarlo en el servidor cuando lo necesite. Ex:

$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 #> 
}
 1
Author: Frode F.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-21 15:53:18

¿Qué hay de hacer scriptblock de su función personalizada y enviarla a los servidores terget usando Invoke-command

Import-module YourModule
$s = [scriptblock]::Create($(get-item Function:\Your-ModuleFunction).Definition)

Invoke-Command -ScriptBlock $s -Computername s1,s2,sn
 0
Author: Jiří Soyka Domin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-21 16:05:13