7

Using powershell, I plan to run many functions on a remote host to gather information.

Here is an example to retrieve the content of file remotely just by running a function called getcontentfile with the parameter as the name of the remote host:

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

This function should return information about the remote host to the local instance of PowerShell. How can I modify this script to do that?

1

4 Answers 4

4

Firstly to return information don't use Write-Host (this is true always, unless you really only want to both have colours and only operate interactively locally).

Make the output the return value of the function:

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

Secondly: enable PSH remoting on the target systems: see the help for Enable-PSRemoting.

Thirdly: run the command remotely:

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

This will return the contents of the file on the two computers, to separate the results adding -AsJob will return job objects which can then be queried separately with the Job cmdlets (see gcm -noun job for a list, note Receive-Job to get the results of a job).

4
  • Hi Richard, thanks for response. In fact , I tried this command but what I need is to execute a function remotely not only simple command. I am expanding the function to be larger with many commands like get-content of many files, string operations and hyperV also requesting (get-VM) etc...I need to run a command line that executes the function not the script file on the remote host and get only informations as result.
    – Aimar
    Jul 9, 2012 at 14:06
  • 1
    @Aimar There are two (relevant) forms of Invoke-Comment. One takes a script block: put the whole script in there, this can include functions, load modules, etc. Or you can use -FilePath to name a (script) file. If you are loading scripts/modules then you need to consider execution policy.
    – Richard
    Jul 9, 2012 at 14:38
  • thanks for response: you mean Invoke-Command (not Comment)..I tried to load Module for hyperv by calling in script file in local machine as : Import-Module C:/module/hyperv.psd1
    – Aimar
    Jul 10, 2012 at 8:05
  • @Aimar Correct spot on the typo, thanks, but now too late to edit a comment :-(. Was there a problem with calling Import-Module? (Seems an odd path however, H-V module is part of Windows so would expect it to be in default env:PSModulePath.)
    – Richard
    Jul 10, 2012 at 8:48
4

You can run a local loaded function on a remote Machine:

Invoke-Command -ComputerName Comp1 -cred $cred -ScriptBlock ${function:get-contentfile } -argumentlist "ParameterA", "ParameterB"
1
  • 1
    This works - thanks! - but I'm unfamiliar with the syntax and have no idea how, or why, it works. Do you have a link to the appropriate docs or more information about this syntax for remote function invocation? Dec 3, 2012 at 16:35
3

Your first option is to enable Powershell 2.0 Remoting.

Personally, I wasn't really interesting in remoting although it is powerful, so I wrote a script to use WMI, create a process with cmd.exe and then pipe the stdout and stderr to a log file which you can then read.

The script leaves its log file on the remote computer, so you could simply: get-content \\remotecomputer\c$\remoteExec.log to read it.

<#
.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: In this example, the script is called remoteExec.ps1 and I use it to create a remote powershell process and run a command (what the asker is attempting to do):

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

I could then read the log with:

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

9
  • 1
    While you might not be "really interested", PSH's remoting opens up more options, including not being dependent on DCOM (with all its firewall implications) and be able to perform the same operation on many servers concurrently.
    – Richard
    Jul 9, 2012 at 13:48
  • Thank you for the rapid response. In fact, I ran this script on the local host and changed the program argument like dir or 'comamnd line' but it was the same output as empty one:Successful trigger on 'machine_name'; returned: 0
    – Aimar
    Jul 9, 2012 at 13:50
  • I tried to look into the log file in the remote host and it was like: 'Get-Acl' is not recognized as an internal or external command, operable program or batch file.
    – Aimar
    Jul 9, 2012 at 14:01
  • 1
    Aimar: .\remoteExec.ps1 -program "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -verifyPath -computerName "computer1"-args "-command Get-ChildItem C:\" Because the script is calling CMD.EXE, you need to have it open powershell and specify the command you want to run.
    – Sean C.
    Jul 9, 2012 at 14:28
  • 1
    Sean, if installing PSH is not option, why not keep things simple and use psexec? (Better would be to improve the policy). PS. PSH v2 can be installed on WinXP and 2003 if required and allowed.
    – Richard
    Jul 9, 2012 at 14:40
0

The short answer is you can't.

Usually, you use Invoke-Command to run a command on a remote computer. That command can be a script block or a PowerShell script. Neither of these approaches can reach out and use variables or functions that exist on your local computer, i.e. you can't load your functions ahead of time to make them accessible on the remote computer.

What you have to do is get them on the remote computer, then load them from there. We create a common share and deploy our PowerShell scripts to that share.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .