Wie kann ich eine PowerShell-Funktion remote ausführen?

7

Mit Powershell möchte ich viele Funktionen auf einem Remote-Host ausführen, um Informationen zu sammeln.

Hier ist ein Beispiel zum Remote-Abrufen des Dateiinhalts, indem Sie einfach eine Funktion namens getcontentfile mit dem Parameter als Namen des Remote-Hosts ausführen:

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

Diese Funktion sollte Informationen zum Remote-Host an die lokale Instanz von PowerShell zurückgeben. Wie kann ich dieses Skript dazu ändern?

Aimar
quelle
1
Haben Sie die PSH-Hilfe zum Remoting gelesen? about_remote
Richard

Antworten:

4

Erstens, um Informationen zurückzugeben, nicht verwenden Write-Host(dies gilt immer, es sei denn, Sie möchten wirklich nur beide Farben haben und nur lokal interaktiv arbeiten).

Machen Sie die Ausgabe zum Rückgabewert der Funktion:

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

Zweitens: enable PSH Remoting auf den Zielsystemen: siehe Hilfe für Enable-PSRemoting.

Drittens: Führen Sie den Befehl remote aus:

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

Dadurch wird der Inhalt der Datei auf den beiden Computern zurückgegeben. Um die Ergebnisse zu trennen, werden beim Hinzufügen von Jobobjekten Jobobjekte zurückgegeben, -AsJobdie dann separat mit den JobCmdlets abgefragt werden können (siehe gcm -noun jobListe, Hinweis Receive-Jobzum Abrufen der Ergebnisse eines Jobs).

Richard
quelle
Hallo Richard, danke für die Antwort. Tatsächlich habe ich diesen Befehl ausprobiert, aber ich muss eine Funktion aus der Ferne ausführen, nicht nur einen einfachen Befehl. Ich erweitere die Funktion, um größer zu werden, mit vielen Befehlen wie dem Abrufen des Inhalts vieler Dateien, Zeichenfolgenoperationen und dem Anfordern von hyperV (get-VM) usw. Ich muss eine Befehlszeile ausführen, die die Funktion ausführt, nicht die Skriptdatei den Remote-Host und erhalten nur Informationen als Ergebnis.
Aimar
1
@Aimar Es gibt zwei (relevante) Formen von Invoke-Comment. Man nimmt einen Skriptblock: Fügen Sie das gesamte Skript dort ein. Dies kann Funktionen, Lademodule usw. umfassen. Oder Sie können -FilePatheine (Skript-) Datei benennen. Wenn Sie Skripte / Module laden, müssen Sie die Ausführungsrichtlinie berücksichtigen.
Richard
Vielen Dank für die Antwort: Sie meinen Invoke-Command (nicht Comment). Ich habe versucht, Module für Hyperv zu laden, indem ich die Skriptdatei auf dem lokalen Computer aufgerufen habe als: Import-Module C: /module/hyperv.psd1
Aimar
@Aimar Richtige Stelle auf dem Tippfehler, danke, aber jetzt zu spät, um einen Kommentar zu bearbeiten :-(. Gab es ein Problem beim Aufrufen Import-Module? (Scheint ein seltsamer Pfad zu sein, aber das HV-Modul ist Teil von Windows und würde erwarten, dass es in der Standardeinstellung ist env:PSModulePath.)
Richard
4

Sie können eine lokal geladene Funktion auf einem Remotecomputer ausführen:

Invoke-Command -ComputerName Comp1 -cred $cred -ScriptBlock ${function:get-contentfile } -argumentlist "ParameterA", "ParameterB"
icnivad
quelle
1
Das funktioniert - danke! - aber ich bin mit der Syntax nicht vertraut und habe keine Ahnung, wie oder warum es funktioniert. Haben Sie einen Link zu den entsprechenden Dokumenten oder weitere Informationen zu dieser Syntax für den Remotefunktionsaufruf?
Dylan Beattie
3

Ihre erste Option ist das Aktivieren von Powershell 2.0 Remoting .

Persönlich war ich nicht wirklich an Remoting interessiert, obwohl es leistungsstark ist. Deshalb habe ich ein Skript zur Verwendung von WMI geschrieben, einen Prozess mit cmd.exe erstellt und dann stdout und stderr an eine Protokolldatei weitergeleitet, die Sie dann lesen können.

Das Skript belässt seine Protokolldatei auf dem Remotecomputer, sodass Sie sie einfach get-content \\remotecomputer\c$\remoteExec.log lesen können.

<#
.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)
}

BEARBEITEN: In diesem Beispiel heißt das Skript remoteExec.ps1 und ich verwende es, um einen Remote-Powershell-Prozess zu erstellen und einen Befehl auszuführen (was der Fragesteller versucht):

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

Ich könnte dann das Protokoll lesen mit:

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

Sean C.
quelle
1
Obwohl Sie möglicherweise nicht "wirklich interessiert" sind, eröffnet das Remoting von PSH mehr Optionen, einschließlich der Tatsache, dass Sie nicht von DCOM abhängig sind (mit all seinen Auswirkungen auf die Firewall) und in der Lage sind, denselben Vorgang auf vielen Servern gleichzeitig auszuführen.
Richard
Vielen Dank für die schnelle Antwort. Tatsächlich habe ich dieses Skript auf dem lokalen Host ausgeführt und das Programmargument wie dir oder 'comamnd line' geändert, aber es war dieselbe Ausgabe wie die leere: Erfolgreicher Trigger für 'machine_name'; zurückgegeben: 0
Aimar
Ich habe versucht, in die Protokolldatei auf dem Remote-Host zu schauen, und es war wie folgt: 'Get-Acl' wird nicht als interner oder externer Befehl, bedienbares Programm oder Batch-Datei erkannt.
Aimar
1
Aimar: .\remoteExec.ps1 -program "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -verifyPath -computerName "computer1"-args "-command Get-ChildItem C:\"Da das Skript CMD.EXE aufruft, muss es die Powershell öffnen und den Befehl angeben, den Sie ausführen möchten.
Sean C.
1
Sean, wenn die Installation von PSH keine Option ist, warum nicht die Dinge einfach halten und verwenden psexec? (Besser wäre es, die Politik zu verbessern). PS. PSH v2 kann bei Bedarf und Erlaubnis unter WinXP und 2003 installiert werden.
Richard
0

Die kurze Antwort lautet: Sie können nicht.

Normalerweise führen Sie Invoke-Commandeinen Befehl auf einem Remotecomputer aus. Dieser Befehl kann ein Skriptblock oder ein PowerShell-Skript sein. Keiner dieser Ansätze kann Variablen oder Funktionen, die auf Ihrem lokalen Computer vorhanden sind, erreichen und verwenden, dh Sie können Ihre Funktionen nicht im Voraus laden, um sie auf dem Remotecomputer zugänglich zu machen.

Sie müssen sie nur auf den Remotecomputer laden und von dort laden. Wir erstellen eine gemeinsame Freigabe und stellen unsere PowerShell-Skripts für diese Freigabe bereit.

bespritzte Bits
quelle