Как я могу запустить функцию PowerShell удаленно?

Используя PowerShell, я планирую запустить много функций на удаленном хосте для сбора информации.

Вот пример для извлечения содержимого файла удаленно, просто запустив функцию getcontentfile с параметром в качестве имени удаленного хоста:

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

Эта функция должна возвращать информацию об удаленном хосте в локальный экземпляр PowerShell. Как я могу изменить этот скрипт, чтобы сделать это?

4 ответа

Вы можете запустить локальную загруженную функцию на удаленном компьютере:

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

Во-первых, для возврата информации не используйте Write-Host (это верно всегда, если только вы на самом деле не хотите иметь оба цвета и работать только в интерактивном режиме локально).

Сделайте вывод возвращаемым значением функции:

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

Во-вторых: включите удаленное взаимодействие PSH на целевых системах: см. Справку для Enable-PSRemoting,

В-третьих: выполните команду удаленно:

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

Это вернет содержимое файла на двух компьютерах, чтобы отделить результаты добавления -AsJob вернет объекты задания, которые затем могут быть запрошены отдельно с помощью Job командлеты (см. gcm -noun job для списка, обратите внимание Receive-Job чтобы получить результаты работы).

Ваш первый вариант - включить Powershell 2.0 Remoting.

Лично я не очень интересовался удаленным взаимодействием, хотя он и мощный, поэтому я написал сценарий для использования WMI, создания процесса с помощью cmd.exe, а затем направил stdout и stderr в файл журнала, который затем можно прочитать.

Сценарий оставляет свой файл журнала на удаленном компьютере, поэтому вы можете просто: get-content \\remotecomputer\c$\remoteExec.log читать это.

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

РЕДАКТИРОВАТЬ: В этом примере сценарий называется remoteExec.ps1, и я использую его для создания удаленного процесса powershell и запуска команды (что пытается сделать запрашивающий):

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

Я мог бы тогда прочитать журнал с:

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

Короткий ответ: ты не можешь.

Обычно вы используете Invoke-Command запустить команду на удаленном компьютере. Эта команда может быть блоком сценария или сценарием PowerShell. Ни один из этих подходов не может охватить и использовать переменные или функции, которые существуют на вашем локальном компьютере, то есть вы не можете загружать свои функции заранее, чтобы сделать их доступными на удаленном компьютере.

Что вам нужно сделать, это получить их на удаленном компьютере, а затем загрузить их оттуда. Мы создаем общий ресурс и размещаем на нем наши скрипты PowerShell.

Другие вопросы по тегам