Difference between - command and ScriptBlock Powershell - powershell

ps1 is on remote machine . I am running below command from some other mahcine.
Is there any difference between using both below script ---
invoke-command -computer $MachineName -command { C:\hello.ps1 }
invoke-command -computer $MachineName -scriptblock{ C:\hello.ps1 }
Also, I am going to use for loop for multiple machine having same script name but having diff sequence of work that is located on each remote machine only . Want to understand the execution for second machine will go only if first get completed . Correct ?

Difference between -command and -scriptblock
There is no difference in execution. -commandis merely an alias for scriptblock. You can verify this by getting the parameter info for the invoke-command command
(Get-Command -Name Invoke-Command).Parameters.Values | select name, aliases
Sequential execution
Yes, the execution is sequential. The command you specify will execute on the second machine after the command has completed on the first machine.
According to the help
These commands run synchronously (one at a time). When the commands
complete, the output of the commands from all of the computers is
saved in the $version variable. The output includes the name of the
computer from which the data originated.

To answer your second question: Invoke-Command works in parallel. It runs what ever is mentioned in the script block to all the machines in parallel. By default, powershell will talk upto 32 computers at once. If you specify more than that, it will queue them up so that as one computer completes, the next one in line will begin. However, I believe, you can increase that number by specifying the -throttlelimit parameter of the Invoke-Command.

Related

PowerShell Invoke-Command with FilePath on local computer - vague parameters error?

I want to run a script in file on the local machine using Invoke-Command so I can pass in parameters with -ArgumentList. I've been getting an error I don't understand, so I simplified my command. When I do this:
Invoke-Command -FilePath 'getprocess.ps1'
The content of getprocess.ps1 is:
Get-Process
The error message I get is:
Invoke-Command : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ Invoke-Command -FilePath 'getprocess.ps1'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand
I'm baffled by this error message. What does it mean? How do I get this to work?
tl;dr:
Generally, do not use Invoke-Command for local invocations - while technically possible, there's only one specific use case where doing so is called for (see below).
Instead, invoke scripts directly:
.\getprocess.ps1
Note: Unlike cmd.exe, PowerShell by design requires .\ in order to execute an executable located in the current directory. That is, to avoid accidental execution of executables in the current directory rather than from a directory listed in $env:Path, PowerShell, as a security feature, requires you to signal the intent to execute something in the current directory (.) explicitly.
For script blocks ({ ... }), use &, the call operator (e.g., & { Get-Date }).
For syntactic reasons alone, you situationally also need & for script-file paths if they're specified either as a quoted path (e.g., & '.\getprocess.ps1') and/or if the path involves variable references (e.g.,
& $HOME\getprocess.ps1).
(Separately, . , the dot-sourcing operator is needed in both cases in order to execute a script [block] directly in the caller's scope rather in a child scope).
Note that you can technically combine passing a script block to Invoke-Command (parameter -ScriptBlock) with invoking a local script:
# The script block positionally binds to the -ScriptBlock parameter.
# This is essentially the more expensive equivalent of:
# & .\getprocess.ps1
Invoke-Command { .\getprocess.ps1 }
This is slower and offers no advantage over direct invocation.
However, there is one conceivable use case:
If the script isn't an advanced script and you wanted to take advantage of Invoke-Command's stream-output-collecting
common parameters, such as -ErrorVariable (if the script or function being invoked is advanced, it supports these common parameters itself).
# Invoke locally and collect errors in $errs
Invoke-Command { .\getprocess.ps1 } -ErrorVariable errs
Caveat: At least as of PowerShell 7.2, Invoke-Command does not apply the common -ErrorAction parameter to errors that occur in the script block, so it cannot be used to control error handling; e.g., -ErrorAction Stop has no effect on the commands in the script block.
As for what you tried:
Indeed, as you point out in your own answer, -FilePath must be combined with the
-ComputerName parameter (that the error message is so generic is unfortunate).
More generally, -FilePath must be combined with any of the parameters that request remote execution, which includes -Session, -ConnectionUri, -VmId / -VmName, and, on Unix-like platforms, -HostName, and -SSHConnection.
The purpose of parameter -FilePath is to copy the content of a local script (*.ps1 file) to a remote computer for execution there. That is, it is a convenient mechanism of executing the code of a script that is (only) available locally on a remote machine.
While you can technically target the local computer via -ComputerName localhost (or, more succinctly, via -ComputerName . / -cn .), this does not amount to a local call:
Whenever -ComputerName is specified - even with -ComputerName localhost - PowerShell's remoting infrastructure is used, which has major implications:
The target computer - even if it is the local one - must be set up for PowerShell remoting - see about_Remote_Requirements.
If you target the local machine specifically, you must be running in an elevated session (running as administrator).
Execution will be much slower than direct (local) invocation.
Type fidelity can be lost for both input and output data, given that cross-process marshaling via PowerShell's XML-based serialization infrastructure is involved - see this answer.
That said, if the intent is to locally test remote execution of your script, and your local machine is set up as a remoting target, then use of -ComputerName localhost (-ComputerName . / -cn .) makes perfect sense, given that PowerShell's remoting infrastructure is then involved in the same way it would be in a truly remote call.
Note, however, that such "loopback remoting" calls require elevation (running as admin).
Although the error message doesn't make it clear, the -FilePath parameter makes the -ComputerName parameter required. To explicitly target the local computer, use -ComputerName localhost.
Invoke-Command -FilePath 'getprocess.ps1' -ComputerName localhost
I can't really use invoke-command locally. You use that when you're trying to run a command on a remote PC.
For example, you would want to run something like:
invoke-Command -ComputerName REMOTE-PC -Credentials $credential -Scriptblock {Get-Process}
That error is basically telling you that you need to fill out more parameters that are tied to that command.
try running Get-Help Invoke-Command to see some info on the command and how to run it.
You must have a computername.
$parameters = #{
ComputerName = '255.255.255.255'
FilePath = 'getprocess.ps1'
Credential = 'Domain01\User01'
}
invoke-command #parameters
Use your IP :) To allow that you must also include -credential
If that doesn't do it... invoke-expression may be a semi-suitable replacement for testing until you are ready to invoke-command on the remote machine.
You could run it locally like this, but you'd have to be at the administrator (elevated) prompt. It's nice to be able to run it as a test.
invoke-command localhost getprocess.ps1
You can actually do a strange form of parallelism too:
invoke-command localhost,localhost,localhost getprocess.ps1

Running command (scriptblock) at remote machine with runspaces

Hello I have a template with runspaces that runs command and gives output to outputbox. My big question is how to make it run on remote machine? If you run script now it gives you systeminfo of current machine but I need it on remote machines. Thanks in advance
$rs = [runspacefactory]::CreateRunspace()
https://pastebin.com/B91Dgz0a
As far as I know and used, Runspaces are for multithreading or parallel execution within the confines of a local machine. I am not aware of a way to start and manage the lifecycle of a thread on a remote machine. That is the job of the OS of the remote machine.
Scriptblock
However, Runspaces allow you to add scriptblocks to it using the AddScript() method as you have in your code. So all you have to do is change the code inside the scriptblock to something like
SystemInfo /s $remoteComputer.
You should also be able to use Invoke-command -ComputerName $remoteComputer -ScriptBlock {SystemInfo}
Passing the Argument
Now the question is of passing the $remoteComputer argument to the scriptblock. You can use the AddArgument() method of the Runspace like: (Using the variablename in your code)
$ps.Runspace.AddArgument($remoteComputer) method.
I hope it made sense.

Run script from Host onto PsSession Computer

I am trying to run the following code to run a script from my host computer onto a Vm that I have PSRemoted into (I am successfully remoted into the PSSession). Where am I going wrong?
Invoke-Command -FilePath C:\Script.ps1 -ComputerName PSRemoteComputer
You do not need to use both a PSSession and the Invoke-Command -ComputerName command as you have above. At that point, you'd be invoking C:\Script.ps1 on your VM and from your VM (which I assume doesn't exist, since C:\Script.ps1 exists on your machine).
If you exit your PSSession and run the command as you have typed it above, it should run correctly assuming PSRemoting is correctly enabled, and permissions for the script to run are set.
Keep in mind, objects are handled differently through PSRemoting, so if you are expecting a certain output you may be getting the deserialized version.

Start a program or filepath remotely

With XP machines and eventually win7 machines. I am trying to find a way to start a program remotely from the commandline or even powershell if possible. Right now we can kill tasks using the "taskkill" command, but there doesn't seem to be an easy way to start them without extra programs. I want to be able to do it without deploying anything. I tried that Psexec but that didnt work.
Invoke-Command -ComputerName server01 -ScriptBlock { yourprogram.exe }
Check out technet:
The Invoke-Command cmdlet runs commands on a local or remote computer and returns all output from the commands, including errors. With a single Invoke-Command command, you can run commands on multiple computers.
http://technet.microsoft.com/en-us/library/hh849719.aspx

Best practices for writing PowerShell scripts for local and remote usage

What are some of the best practices for writing scripts that will execute in a remote context?
For instance, I just discovered that built-in var $Profile doesn't exist during remote execution.
Profile
You've discovered one main difference, $profile not being configured.
Buried in MSDN here are some FAQs about remote powershell, or do get-help about_Remote_FAQ.
Under the "WHERE ARE MY PROFILES?" (heh) it explains:
For example, the following command runs the CurrentUserCurrentHost profile
from the local computer in the session in $s.
invoke-command -session $s -filepath $profile
The following command runs the CurrentUserCurrentHost profile from
the remote computer in the session in $s. Because the $profile variable
is not populated, the command uses the explicit path to the profile.
invoke-command -session $s {. "$home\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"}
Serialization
Another difference that may affect you is that instead of the .NET objects returned by commands being just directly returned, when you run them remotely and return them, they get serialized and deserialized over the wire. Many objects support this fine, but some do not. Powershell automatically removes methods on objects that are no longer "hooked up", and they're basically data structures then... but it does re-hook methods on some types like DirectoryInfo.
Usually you do not have to worry about this, but if you're returning complex objects over a pipe, you might...
Script blocks don't act as closures, like they do normally:
$var = 5
$sb={ $var }
&$sb # 5
Start-Job $sb | Wait-Job | Receive-Job # nothing