PowerShell Remoting in Multi-Platform Environments – Use Cases
In our previous post we discussed how to implement OpenSSH (the plumbing) as the transport layer for PowerShell remoting. In this post, we’re going to leverage that configuration and look at some common remoting use cases. This is one of the core things I use everyday when I work with PowerShell. Remoting gives me the ability to administer scale up and administer large collections of systems. So like I said in my very first post about my PowerShell journey, it’s become a part of my every day life and techniques like this are at the core of how I use PowerShell. So let’s get started…
We’re going to look at the following
- Entering a remote command line interface on a server
- Using sessions
- Executing commands against one remote system
- Executing commands on a collection of remote systems
This is going to be awesomeness…Yep, I said awesomeness, when I’m finished you’ll agree that’s about the only way to describe this.
I do want to point out that we’re using Beta software here, things change. The version of PowerShell I’m using here is Version 6 Beta 2.
Remote Command Line Interface
Up first, let’s cover the simplest remoting case, where we use remoting to get a command line interface to a remote system.
Enter-PSSession -HostName server1.demo.local
Nothing special here, simple syntax, but the seasoned PowerShell remoting pro will notice that we’re using a new parameter here -HostName. Normally on Windows PowerShell you have the -ComputerName parameter. Now, I don’t know exactly why this is different, but perhaps the PowerShell team needed a way to differentiate between OpenSSH and WinRM based remoting. Further, Enter-PSSession now has a new parameter -SSHTransport which at the moment doesn’t seem to do much since remoting cmdlets currently use OpenSSH by default. But if you read the code comments here, it looks like WinRM will be the default and we can use this switch parameter to specify SSH as the transport.
Once we execute this command, you’ll have a command prompt to the system that passed as a parameter to -HostName. The prompt below indicates you’re on a remote system by putting the server name you’re connected to in square brackets then your normal PowerShell prompt. That’s it, you now have a remote shell. Time to get some work done on that server, eh? Want to get out of the session, just type exit.
[server1.demo.local]: PS /home/aen>
Using Sessions
So, in PowerShell, when you exit from a remoting session your session goes away. So any work, variables or program state you had will disappear. But what if we wanted to keep our session’s state, log out and log back into that session again? We can leverage sessions to help us persist our remote sessions. We can create a session connect and disconnect from it at will. So let’s check that out.
We create a new session by calling New-PSSession. This will start up the remoting session just like we did with Enter-PSSession, via SSH, but we won’t attach to the remote terminal. The output we do get from New-PSSession shows us the details of the session created. We use Get-PSSession to get a list of all current sessions.
PS /Users/aen> New-PSSession -HostName server1.demo.local -UserName aen Id Name ComputerName ComputerType State ConfigurationName Availability -- ---- ------------ ------------ ----- ----------------- ------------ 2 SSH2 server1.demo... RemoteMachine Opened DefaultShell Available
PS /Users/aen> Enter-PSSession -Id 2
PS /Users/aen> Get-PSSessionId Name ComputerName ComputerType State ConfigurationName Availability
2 SSH2 server1.demo… RemoteMachine Opened DefaultShell Available
PS /Users/aen> $s = Get-PSSession -Id 2
Executing Commands Against One Remote System
PS /Users/aen> Invoke-Command -Session $s { Get-Process | Sort-Object -Descending CPU -Top 5 } NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName PSComputerName ------ ----- ----- ------ -- -- ----------- -------------- 0 0.00 761.55 2,805.86 14770 704 sqlservr server1.demo.local 0 0.00 8.37 183.29 13480 479 vmtoolsd server1.demo.local 0 0.00 7.24 65.31 13553 550 ManagementAgent server1.demo.local 0 0.00 0.00 61.74 401 0 xfsaild/dm-0 server1.demo.local
Executing Commands Against a Collection of Remote Systems
PS /Users/aen> New-PSSession -HostName server2.demo.local -UserName aenId Name ComputerName ComputerType State ConfigurationName Availability
3 SSH3 server2.demo… RemoteMachine Opened DefaultShell Available
PS /Users/aen> Get-PSSessionId Name ComputerName ComputerType State ConfigurationName Availability
2 SSH2 server1.demo… RemoteMachine Opened DefaultShell Available 3 SSH3 server2.demo… RemoteMachine Opened DefaultShell Available
PS /Users/aen> $s = Get-PSSession
PS /Users/aen> Invoke-Command -Session $s { Get-Process | Sort-Object -Descending CPU -Top 5 }NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName PSComputerName
0 0.00 0.57 5.09 666 666 rngd server2.demo.local 0 0.00 93.82 2.03 24218 218 powershell server2.demo.local 0 0.00 6.57 1.78 1 1 systemd server2.demo.local 0 0.00 8.37 0.91 13475 474 vmtoolsd server2.demo.local 0 0.00 0.00 0.89 94 0 kworker/0:2 server2.demo.local 0 0.00 761.41 2,810.99 14770 704 sqlservr server1.demo.local 0 0.00 8.37 183.69 13480 479 vmtoolsd server1.demo.local 0 0.00 7.24 65.48 13553 550 ManagementAgent server1.demo.local 0 0.00 0.00 61.88 401 0 xfsaild/dm-0 server1.demo.local 0 0.00 1.69 58.19 13749 749 crond server1.demo.local</pre>
PS /Users/aen> Invoke-Command -Session $s { Get-Process } | Sort-Object -Descending CPU -Top 5NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName PSComputerName
0 0.00 761.41 2,814.59 14770 704 sqlservr server1.demo.local 0 0.00 8.37 183.95 13480 479 vmtoolsd server1.demo.local 0 0.00 7.25 65.59 13553 550 ManagementAgent server1.demo.local 0 0.00 0.00 61.96 401 0 xfsaild/dm-0 server1.demo.local 0 0.00 94.83 61.93 24464 393 powershell server2.demo.local</pre>
We move the sorting to the pipeline on our local system, notice the Invoke-Command call is going to return the entire process list from all machines, then it will sort the data locally and output to the local console. So you can see in this list here we have the top 5 processes across our two systems. Imagine you had a web farm of servers and you needed to chase down a bad process fast, this would be useful, right?
When we’re all finished, you’ll want to clean up your sessions. We can do that a by passing the $s variable into Remove-PSSession
PS /Users/aen> $s | Remove-PSSession
And that’s it, so like I said in my very first post about my PowerShell journey, it’s become a part of my every day life and techniques like this are at the core of how I use PowerShell.