7 votes

Comment puis-je exécuter une fonction PowerShell à distance ?

À l'aide de powershell, je prévois d'exécuter plusieurs fonctions sur un hôte distant pour recueillir des informations.

Voici un exemple pour récupérer le contenu d'un fichier à distance en exécutant simplement une fonction appelée getcontentfile avec comme paramètre le nom de l'hôte distant :

function getcontentfile 
{
    [CmdletBinding()]
    param($hostname)
    $info = Get-Content "C:\fileinfo.xml"
    write-host $info
}

Cette fonction doit renvoyer des informations sur l'hôte distant à l'instance locale de PowerShell. Comment puis-je modifier ce script pour faire cela ?

1 votes

Avez-vous lu l'aide de PSH sur le remoting ? about_remote

4voto

Richard Points 5289

Premièrement, pour retourner l'information, n'utilisez pas Write-Host (c'est toujours vrai, à moins que vous ne souhaitiez vraiment que les deux aient des couleurs). et ne fonctionnent que localement de manière interactive).

Faites de la sortie la valeur de retour de la fonction :

function getcontentfile 
{
    [CmdletBinding()]
    param($hostname)
    $info = Get-Content "C:\fileinfo.xml"
    $info
}

Deuxièmement : activez le remoting PSH sur les systèmes cibles : voir la page d'accueil du site Web de la Commission européenne. aide para Enable-PSRemoting .

Troisièmement : exécutez la commande à distance :

Invoke-Command -computer comp1,comp2 -ScriptBlock { Get-Content "C:\fileinfo.xml"  }

Cela renverra le contenu du fichier sur les deux ordinateurs, pour séparer les résultats en ajoutant -AsJob renverra des objets de travail qui pourront ensuite être interrogés séparément avec la fonction Job cmdlets (voir gcm -noun job pour une liste, notez Receive-Job pour obtenir les résultats d'un travail).

0 votes

Bonjour Richard, merci pour votre réponse. En fait, j'ai essayé cette commande mais j'ai besoin d'exécuter une fonction à distance et pas seulement une simple commande. Je suis en train d'étendre la fonction pour qu'elle soit plus large avec de nombreuses commandes comme obtenir le contenu de nombreux fichiers, des opérations sur les chaînes de caractères et hyperV qui demande également (get-VM) etc... J'ai besoin de lancer une ligne de commande qui exécute la fonction et non le fichier script sur l'hôte distant et d'obtenir seulement des informations comme résultat.

0 votes

J'ai essayé de charger le module pour hyperv en appelant le fichier script sur la machine locale en tant que : Import-Module C:/module/hyperv.psd1

0 votes

@Aimar Correct pour la faute de frappe, merci, mais il est maintenant trop tard pour éditer un commentaire :-(. Y a-t-il eu un problème en appelant Import-Module ? (Cela semble être un chemin étrange, cependant, le module H-V fait partie de Windows, donc on s'attendrait à ce qu'il soit par défaut). env:PSModulePath .)

4voto

Robbot78910 Points 31

Vous pouvez exécuter une fonction chargée localement sur une machine distante :

Invoke-Command -ComputerName Comp1 -cred $cred -ScriptBlock ${function:get-contentfile } -argumentlist "ParameterA", "ParameterB"

1 votes

Cela fonctionne - merci ! - mais je ne suis pas familier avec la syntaxe et je n'ai aucune idée de comment ou pourquoi cela fonctionne. Avez-vous un lien vers la documentation appropriée ou plus d'informations sur cette syntaxe pour l'invocation de fonctions à distance ?

3voto

Sarav anan Points 1

Votre première option est d'activer Powershell 2.0 Remoting .

Personnellement, je n'étais pas vraiment intéressé par le remoting bien qu'il soit puissant, j'ai donc écrit un script pour utiliser WMI, créer un processus avec cmd.exe et ensuite diriger le stdout et le stderr vers un fichier journal que vous pouvez ensuite lire.

Le script laisse son fichier journal sur l'ordinateur distant, donc vous pourriez simplement : get-content \\remotecomputer\c$\remoteExec.log pour le lire.

<#
.SYNOPSIS
    Remotely executes a command and logs the stdout and stderr to a file on the
    remote computer.
.DESCRIPTION
    This script accepts three parameters (one optional) and executes a program on
    a remote computer.  It will verify connectivity and optionally (verifyPath) the
    existence of the program to be executed.  If either verifications fail, it will
    not attempt to create the process on the remote computer.
.EXAMPLE
    .\remoteExec.ps1 -program "dir" -args "c:\" -computerName "SEANC"
.EXAMPLE
    .\remoteExec "C:\Windows\SysWOW64\msiexec.exe" "/i c:\a.msi /passive /log c:\a-install.log" SEANC C:\Windows\Temp\remote.log -verifyPath
.PARAMETER computerName
    The name of the computer on which to create the process.
.PARAMETER program
    The command to run on the remote computer.
.PARAMETER args
    The command arguments.
.PARAMETER log
    The file to which the stderr and stdout generated by the command will be redirected.
    This is a local path on the remote computer.
.PARAMETER verifyPath
    Switch to enforce path verification.
#>
param(
    [parameter(Mandatory=$true)] [string]$program,
    [parameter(Mandatory=$false)][string]$args = "",
    [parameter(Mandatory=$true)] [string]$computerName,
    [parameter(Mandatory=$false)][string]$log = "C:\remoteExec.log",
    [parameter(Mandatory=$false)][switch]$verifyPath = $false
)

if (-not (Test-Connection $computerName -Quiet -Count 1))
{
    return Write-Error "Unable to connect to $computerName."
}

if ($verifyPath -and (-not (Test-Path \\$computerName\$($program.replace(":","$")) -PathType Leaf))) {
    return Write-Error "Path $program does not exist on $computerName."
}

try {
    $remoteWmiProcess = [wmiclass]"\\$computerName\root\cimv2:win32_process"
    $remoteProcess = $remoteWmiProcess.create(
        "cmd.exe /c `"$program $args > $log 2>&1`""
    )
} catch {
    return Write-Error ("Unable to create process through WMI.");
}

if ($remoteProcess.returnValue -ne 0) {
    return Write-Error ("FAILED on $computerName with return code: " + $remoteProcess.returnValue)
} else {
    return ("Successful trigger on $computerName; returned: " + $remoteProcess.returnValue)
}

EDIT: Dans cet exemple, le script s'appelle remoteExec.ps1 et je l'utilise pour créer un processus powershell distant et exécuter une commande (ce que le demandeur tente de faire) :

.\remoteExec.ps1 -program "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -verifyPath -computerName "computer1" -args "-command Get-ChildItem C:\"

Je pourrais alors lire le journal avec :

Get-Content \\computer1\C$\remoteExec.log

1 votes

Même si vous n'êtes pas "vraiment intéressé", le remoting de PSH offre davantage d'options, notamment le fait de ne pas dépendre de DCOM (avec toutes ses implications en termes de pare-feu) et de pouvoir effectuer la même opération sur plusieurs serveurs simultanément.

0 votes

Merci pour la rapidité de votre réponse. En fait, j'ai exécuté ce script sur l'hôte local et j'ai changé l'argument du programme comme dir ou 'comamnd line' mais c'était la même sortie que celle vide:Successful trigger on 'machine_name' ; returned : 0

0 votes

J'ai essayé de consulter le fichier journal de l'hôte distant et j'ai obtenu le résultat suivant : 'Get-Acl' n'est pas reconnu comme une commande interne ou externe, un programme opérationnel ou un fichier batch.

0voto

Haresh Points 3

La réponse courte est que vous ne pouvez pas.

Habituellement, vous utilisez Invoke-Command pour exécuter une commande sur un ordinateur distant. Cette commande peut être un bloc script ou un script PowerShell. Aucune de ces approches ne peut atteindre et utiliser des variables ou des fonctions qui existent sur votre ordinateur local, c'est-à-dire que vous ne pouvez pas charger vos fonctions à l'avance pour les rendre accessibles sur l'ordinateur distant.

Ce que vous devez faire, c'est les installer sur l'ordinateur distant, puis les charger à partir de là. Nous créons un partage commun et déployons nos scripts PowerShell sur ce partage.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X