Thursday, March 5, 2015

PowerShell : A deep dive into remoting - part 4

There are two common options for approaching remoting with PowerShell. The first is known as one-to-one remoting, in which you
essentially bring up an interactive PowerShell prompt on a remote computer, where you can enter the commands that are executed on the remote computer. The second option is called one-to-many remoting and it is especially suited for situations when you may want to run the same commands or scripts in parallel to several remote computers.

To start a one-to-one remoting session, you can use the Enter-PSSession cmdlet by specifying the computer name as
Enter-PSSession -ComputerName "COMP1"

The cmdlet also supports the -Credential parameter to enter the remote session with the credentials supplied.

After entering the session, you can see that the powershell prompt now contains the computer name and you can execute cmdlets on the remote computer

Once you are in a remote session, the commands executed are transported to the remote computer and the result of execution is returned back as serialized XML format back to the machine which is deserialized into objects back and passed to the pipeline.

Mind that any Snapins added to the local session will not be available on the remote session, you need to add the snapins on the remote session after entering the session, the same applies to the imported modules.
When you’ve finished with the remote machine, run Exit-PSSession. This will return you to your local prompt, close the connection to the remote machine, and free up resources on the remote machine. This will also happen automatically if you just close the PowerShell window.

The Get-PSSession cmdlet will show any active sessions currently available.
If you want to execute cmdlets on multiple computers,then you have to use the One-to-many remoting technique using the Invoke-Command cmdlet. This will transmit the commands to multiple remote computers and executed there. The results are again serialized into XML and send back to the executing machine which is deserialized into objects to be put back to the pipeline.

The Invoke-Command has a -ScriptBlock parameter that is used to specify a scriptblock to be executed on the remote computer as

Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName COMP1

This will invoke the Get-EventLog cmdlet and then serialize the results to XML and return back to the executing machine, where the data is deserialized back to the System.Diagnostics.EventLogEntryType. The computername parameter ensures that the script is executed on COMP1 with the credentials of the current user.
The Invoke-Command also accepts multiple computer names like 
Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName "COMP1, COMP2, COMP3"

You can also pass a credential object to the Invoke-Command to execute the command as a different user
Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName "COMP1, COMP2, COMP3" -Credential (Get-Credential -Username "domain\username" -Message "Enter password")

If you want to pass arguments to the Invoke-Command then you have to use the ArgumentList parameter as in the e.g. below
Invoke-Command -ScriptBlock { param($name} Get-EventLog -Application $name -Newest 5} -ComputerName COMP1 -ArgumentList "Application"

The ArgumentList accepts an array of objects, so if you have multiple arguments you need to pass it as an array as given below
$arguments = @"arg1", "arg2", arg3)
Invoke-Command -ScriptBlock ${function:Do-Something} -ArgumentList $arguments -ComputerName COMP1

If you want to run scripts on the remote machine, you need to use the -FilePath parameter

Invoke-Command -FilePath C:\Temp\Script1.ps1 -ComputerName COMP1
This will execute the script file in the local machines C:\Temp\Script1.ps1 location on the remote computer (COMP1). If you need to execute a script file that is present on the remote machine, then you have to use the filepath in the -ScriptBlock parameter as
Invoke-Command -ComputerName COMP1 -ScriptBlock {C:\Temp\Script1.ps1}