I have a script that connects to a remote machine using Invoke-Command and then runs a script block. This all works fine, however I would like to know if its possible to write a log file on to the parent machine. Due to firewalling on the servers the parent can connect to the child, but the child cannot connect to the parent.
At the moment when I use Out-File it creates that file on the server that I am connected to. I would like to find a way to create that file, and append to it on the server that I am connecting from.
Output in the scriptblock is returned to the caller. Simply pipe or redirect the output of Invoke-Command to a file.
Invoke-Command -Computer ... -ScriptBlock {...} > 'C:\path\to\out.txt'
or
Invoke-Command -Computer ... -ScriptBlock {...} | Out-File 'C:\path\to\out.txt'
Related
Editing to be clear with the issue
I am running the below code from a local computer which should run the script Test.ps1 placed on $server at C:\Temp to collect data from $server and other servers.
When i perform this, the script runs but i only get data for the $server and not the others. While if i run the C:\Temp\Test.ps1 script sitting on the $server, i get the desired output for all servers.
I am using this code
$s = New-PSSession -ComputerName $server -Credential $credential
Invoke-Command -Session $s -Command {C:\Temp\Test.ps1}
I am getting the output for the remote server on which the code is placed (localhost for the script), buti am not getting any output for the other servers.
While if I run the script locally on the remote server i get output from all the servers
The script does not have to be on the remote host. PowerShell allows you to run local PS1 scripts on remote computers.
Running Remote Commands
https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7.1
Run a Script
To run a script on one or many remote computers, use the FilePath
parameter of the Invoke-Command cmdlet. The script must be on or
accessible to your local computer. The results are returned to your
local computer.
For example, the following command runs the DiskCollect.ps1 script on
the remote computers, Server01 and Server02.
Invoke-Command -ComputerName Server01, Server02 -FilePath 'c:\Scripts\DiskCollect.ps1'
As for this...
'My requirement is to run that script from the remote host per
security protocols'
... just use a script block as shown via the same MS Docs link
Run a Remote Command
To run a command on one or more computers, use the Invoke-Command
cmdlet. For example, to run a Get-UICulture command on the Server01
and Server02 remote computers, type:
Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {& .c:\Scripts\DiskCollect.ps1}
Of course, I just removed Get-UICulture cmdlet in the docs command, with a script to use.
It depends on how your remote script uses credentials to access other servers. This should classify as a double hop issue.
If you cannot use CredSPP, you can use Resource-Based Kerberos Constrained Delegation
or use credentials inside the Invoke-Command scriptblock i.e. you can define a credential object on the local computer to be used in the -credentials parameter, and refer to it with $using:cred in your scriptblock.
The article does a good job of summarizing all your options.
I am trying to upgrade a server with a particular application from a client by PowerShell remote:
Invoke-Command -ComputerName $server -Credential $mycreds {Start-Process -FilePath "C:\temp\xxx.exe" -ArgumentList "-default", "-acceptEULA" -wait }
Whatever I try, I get messages like "Can't find the file specified..." what do I do wrong?
FilePath is on the local (client) computer.
Your C:\temp\xxx.exe executable must be present on the server (the remote machine) for your command to work, because that is where your script block ({ ... }) executes.
Note: By contrast, if you use Invoke-Command with the -FilePath parameter in order to run a locally present script file (.ps1) remotely, PowerShell automatically copies it to the remote machine; from the docs: "When you use this parameter, PowerShell converts the contents of the specified script file to a script block, transmits the script block to the remote computer, and runs it on the remote computer."
To copy the executable there from your local (client-side) machine, you need a 4-step approach (PSv5+, due to use of Copy-Item -ToSession[1]):
Create a remoting session to $server explicitly, using New-PSSession
Copy the local (client-side) executable to that session (the remote computer) with Copy-Item and its -ToSession parameter
Run your Invoke-Command command with the -Session parameter (rather than -ComputerName) in order to run in the explicitly created session (this isn't strictly necessary, but there's no need to create another (ad hoc) session).
Run Remove-PSSession to close the remote session.
Important: In a PowerShell remoting session, you cannot run external programs that require interactive user input:
While you can launch GUI applications, they invariably run invisibly.
Similarly, interactive console applications aren't supported (although output from console applications is received by the client).
However, interactive prompts from PowerShell commands are supported.
To put it all together:
# Specify the target server(s)
$server = 'w764' # '.'
# Establish a remoting session with the target server(s).
$session = New-PSSession -ComputerName $server
# Copy the local executable to the remote machine.
# Note: Make sure that the target directory exists on the remote machine.
Copy-Item C:\temp\xxx.exe -ToSession $session -Destination C:\temp
# Now invoke the excutable on the remote machine.
Invoke-Command -Session $session {
# Invoke *synchronously*, with -Wait.
# Note: If the program is a *console* application,
# you can just invoke it *directly* - no need for Start-Process.
Start-Process -Wait -FilePath C:\temp\xxx.exe -ArgumentList "-default", "-acceptEULA"
}
# Close the remote session.
# Note: This will terminate any programs that still
# run in the remote session, if any.
Remove-PSSession $session
[1] If you're running Powershell v4 or below, consider downloading psexec.
I have a executable that resides on a remote station that I am trying to run from a central server, but running into issues. I am able to stop the Process on the remote station from the server using
Invoke-Command -ComputerName $name {Stop-Process -Name "ProcessName"
But when I try and run the executable, using
Invoke-Command -ComputerName $Args Start-Process "C:\Process\Process.exe"
it returns an error
This command cannot be run due to the error: The system cannot find the file
I have tried many variations of Invoke-Command, Start-Process, along with specifying the UNC path using the $name variable, but it will not run the executable stored on the remote computer.
You should run it like this:
Invoke-Command -ComputerName $name -ScriptBlock {
Set-Location c:\path\to\exe
FileName.exe /switch 1 /switch 2
}
You don’t need to use Start-Process. Just call the file and it should start execution.
I found the Invoke-Command cmdlet in PowerShell that supposedly is invoking a command on another server but this doesn't quite work. Instead what I get is the print of what the bat/exe. My exe is a console app and the bat was a test I did that launches the exe with start "" "myexe.exe".
This is the command I'm trying to do:
Invoke-Command -ComputerName 10.10.10.10 -ScriptBlock {
'C:\Program Files\program.exe'
}
or
Invoke-Command -ComputerName 10.10.10.10 -ScriptBlock {
'C:\Program Files\batch.bat'
}
In both cases instead of the command getting invoked on the other server I get the print on the server I call from.
Did I miss an argument somewhere? I want to launch the exe/bat on the remote server, not on the server I'm on.
EDIT
I made it work with this:
$command = "PathtoExe.exe"
$process = [WMICLASS]"\\10.10.10.10\ROOT\CIMV2:win32_process"
$result = $process.Create($command)
But now the exe is not displayed, it's like running in the background.
Your problem is how you're trying to call the executable. In PowerShell, everything is an object. What you're doing is printing the String to the console instead of executing. To invoke the string, you need to use the call operator: &
Invoke-Command -ComputerName 10.10.10.10 -ScriptBlock {
& 'C:\Program Files\batch.bat'
}
This will cause it to use the default program for that extension.
I had the same pain trying to run "netsh.exe" on a remote host. Eventually got it working with the following code:
Invoke-Command -ComputerName 10.10.10.10 -ScriptBlock {Invoke-Expression "C:\Program Files\program.exe"}
I launch a local script on a remote computer with:
Invoke-Command -ComputerName RemoteServer -FilePath C:\myFolder\Script1.ps1
This script dot-sources another script (Script2), which also is located on my local computer in "C:\myFolder". This fails because Script1 trys to load the Script2 from the remote computer.
Is there a way to load Script2 from my local computer inside Script1 inside the remoting session?
[Workaround]
Create a session to the remote server
Use the session to load the script2
use the same session to run the script1.
eg:- $Session = New-PSSession -ComputerName $Server
Invoke-command -Session $Session -FilePath <script2> this should load functions
Invoke-command -Session $Session -FilePath <script1>
here the functions in script2 will be available for script1 to consume, so no need to refer and dot source script2 .
I don't think this can work the way you outlined it since code running on the remote machine cannot find a file that is relative to the local machine.
The only way to achieve this is to share your script and include it as with a UNC path, or an administrative share, like \\localmachine\c$\users\test\script\a.ps1.
But there's a chance you'll run into authentication issues (double hop).
The (easiest) solution: copy all your scripts to the remote machine first and make sure that the paths used in the scripts will work.