How can I run a PowerShell function remotely?
Solution 1:
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).
Solution 2:
You can run a local loaded function on a remote Machine:
Invoke-Command -ComputerName Comp1 -cred $cred -ScriptBlock ${function:get-contentfile } -argumentlist "ParameterA", "ParameterB"
Solution 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