Comment importer le module PowerShell personnalisé dans la session distante?
je développe un module PowerShell personnalisé, que j'aimerais utiliser dans le contexte d'une session à distance vers un autre ordinateur. Le code suivant (qui évidemment ne fonctionne pas) explique ce que j'essaie de réaliser:
import-module .MyCustomModule.psm1
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
<# use function defined in MyCustomModule here #>
}
la première question Est de savoir s'il est possible de réaliser ce scénario? je veux dire que je voudrais seulement que mon module personnalisé soit physiquement présent sur ma machine, pas sur un serveur distant.
j'ai trouvé ce thread , mais je n'ai pas réussi à le faire fonctionner - il ne permet pas de créer une session depuis la machine distante vers la machine locale. Probablement, j'ai fait face aux limitations de configuration mentionnées quelque part dans les commentaires sur ce thread... En outre, l'auteur a mentionné les implications de performance qui est critique pour ma solution...
Si c'est possible, alors comment?
la version de PowerShell est actuellement pas une contrainte - si la solution n'est disponible qu'en PS 3.0 - je peux m'en accommoder.
4 réponses
il y avait quelques grands commentaires à la question, et j'ai passé quelque temps à étudier diverses façons d'aborder le problème.
pour commencer, ce que j'ai initialement demandé n'est pas possible. Je veux dire, si vous allez dans le sens du module, alors le module devrait être physiquement présent sur une machine cible pour pouvoir Import-Module
dans la session à distance.
pour résumer davantage ma question, j'essaie de créer une PowerShell réutilisable cadre pour le produit déploiements. Il va s'agir de déploiements poussés, c'est-à-dire que nous encourageons les gens à exécuter des scripts sur une machine locale pour les déployer sur un serveur distant. Pour autant que j'ai examiné la zone, Il ya deux façons possibles qui sont favorables au bon sens.
Modules approche
Le processus à suivre:
- placez chaque élément de fonctionnalité logiquement différent dans le Module PowerShell (
*.psm1
) - distribuer le module à la machine distante et étendre la variable
PSModulePath
pour inclure l'emplacement des nouveaux modules - sur une machine client, créer une nouvelle session pour le serveur distant, et utiliser
Invoke-Command -Session $s -ScriptBlock {...}
- dans le bloc script démarrer à partir de
Import-Module CustomModule
- il va chercher leCustomModule
sur une machine distante et évidemment le trouver
Avantages
les éléments suivants sont Les raisons d'aimer cette approche:
- la conséquence du rôle traditionnel du module-faciliter la création de bibliothèques réutilisables
- selon le grand livre Windows PowerShell in Action , "les modules peuvent être utilisés pour créer des applications spécifiques au domaine". Pour autant que je comprenne, cela peut être réalisé en combinant le module d'imbrication et de mélange script / modules binaires pour exposer l'interface intuitive spécifique à un certain domaine. Fondamentalement, c'est celui que j'apprécie le plus pour l'Objectif du cadre de déploiement basé sur PowerShell
désavantages
il est important de tenir compte de ce qui suit:
- Vous devez trouver un moyen de délivrer les modules personnalisés à la machine distante. J'ai joué avec NuGet , et Je ne suis pas sûr que cela convienne à la tâche, mais il y a d'autres options, par exemple, MSI installer ou simple
xcopy
à partir du dossier partagé. En outre, le mécanisme de livraison devrait prendre en charge la mise à niveau / déclassement et (de préférence) les installations multi-instances, mais c'est plus lié à ma tâche qu'au problème en général
Scripts approche
Le processus à suivre:
- la place de chacun une fonctionnalité logiquement différente dans un script PowerShell séparé (*.ps1)
- sur une machine client, créer une nouvelle session sur le serveur distant, et utiliser
Invoke-Command -Session $s -FilePath .\myscript.ps1
pour charger les fonctions définies dans un script vers la session distant - utilisez un autre
Invoke-Command -Session $s -ScriptBlock {...}
et référez - vous à vos fonctions personnalisées-elles seront là dans une session
avantages
ce qui suit sont de bons points de cette approche:
- , c'est simple - vous n'avez pas à connaître module particularités. Il suffit d'écrire des scripts PowerShell simples et c'est tout
- vous n'avez pas à livrer quoi que ce soit à la machine distante - cela rend la solution encore plus simple et moins sujette à erreur dans la maintenance
désavantages
bien sûr, ce n'est pas idéal:
- il y a moins contrôle de la solution: par exemple, si vous "importez" un ensemble de fonctions à la session, toutes sont "importées" et visibles à l'utilisateur, donc pas d ' "encapsulation", etc. je suis sûr que beaucoup de solutions peuvent vivre avec cela, alors ne décidez pas sur la base de ce point seulement
- la fonctionnalité dans chaque fichier doit être autonome - tout point-sourcing ou d'importation de module à partir de là va rechercher la machine distante ,pas la locale
enfin, je dois dire que la machine distante doit encore être préparée pour la remoting. C'est ce que je veux dire:
- la Politique d'exécution doit être changée en quelque chose, car elle est restreinte par défaut:
Set-ExecutionPolicy Unrestricted
- remoting PowerShell devrait être activé:
Enable-PSRemoting
- le compte que le script exécute comme doit être ajouté aux administrateurs locaux du serveur distant
- si vous prévoyez d'accéder à des partages de fichiers dans la session distante, assurez-vous que vous êtes au courant de authentification multi-hop et de prendre les mesures appropriées
- assurez-vous que votre antivirus est votre ami et ne vous envoie pas à la PowerShell hell
voici une autre approche: recréer le module dans une session à distance, sans copier de fichiers.
Je n'ai pas essayé de gérer les dépendances entre les modules, mais cela semble bien fonctionner pour les modules autonomes simples. Il s'appuie sur le fait que le module est disponible dans la session locale, car cela rend la détermination des exportations plus facile, mais avec un peu de travail supplémentaire, il fonctionnerait aussi avec un fichier de module.
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;
}
Je ne crois pas que cela soit supporté à droite de la boîte sans aucun "hacks". Le plus intelligent serait probablement de placer le module sur un emplacement public comme un serveur de fichiers et de l'importer sur le serveur lorsque vous en avez besoin. 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 #>
}
Qu'en est-il de sortir scriptblock de votre fonction personnalisée et de l'envoyer aux serveurs terget en utilisant Invoke-command
Import-module YourModule
$s = [scriptblock]::Create($(get-item Function:\Your-ModuleFunction).Definition)
Invoke-Command -ScriptBlock $s -Computername s1,s2,sn