Tuesday, 14 June 2011

WINRM - Loosely Translated as SSH for Windows

When I am developing a side project, I always make sure it is on a different operating system and a different language than what I would normally use in my day job.  I want there to be a clear distinction or else the lines can become all too blurred.  My current side project is written in ruby and rails and it is while developing this that I have fallen in love with both SSH and Capistrano.  SSH or secure shell is a protocol for remote administration of Unix computers.  Simply put, SSH allows me to stay in the same terminal instance when I am moving from my client machine to other remote servers.  

Capistrano is a DSL for deploying ruby on rails applications.  Capistrano has highlighted just what a gaping hole this is in current ugly .NET deployment practices.  I very much include my own crude powershell scripts in this dirty breed.  Capistrano uses SSH to connect to the remote server and run your deployment from your client machine.  Pretty nifty and yet another source of rails envy I now have.

Returning to my day job and windows, I missed this facility and started looking at powershell for a similar capability.  There is more than one way of executing powershell on a remote server.  Winrm looked to be the best fit for me.  With winrm, you can start and finish powershell sessions on the remote server.  In the examples I am about to give, all the machines have powershell 2.0 installed.  There are different requirements for each operating system.  The following guide should help you install winrm on the client and on any remote servers you wish to access.

Enabling Winrm on a remote Server for Client Requests

Enabling WinrRM between computers on the same domain is very easy, simply run the following command in an elevated Powershell console on the remote server.  

PS> Enable-PSRemoting                  

You should get a response like this:

If you do not get a response like above you might want to check that winrm is installed and that the windows service is running.

By default winrm runs over http on port 5985 and you might need your network guys to open a hole in the firewall for this port.   It took the network guys I work with five weeks to accomplish this task which is an absurd amount of time for such a task but I better not get into that now.  We also restricted access to this port to an I.P. range for extra security.  

If the server is on a different domain, you also need to run the following command which sets a registry entry that allows a client server to authenticate from a different domain to the local server.

PS> New-Itemproperty -name LocalAccountTokenFilterPolicy -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -propertyType DWord -value 1

Another gotcha that I fell for is to make sure that you restart the winrm windows service to pick up the changes. 

Enabling Winrm on the Client

You might not need to do this but I had to add a trust entry for every server I wanted to connect to with the following command on my workstation:

PS> winrm s winrm/config/client '@{TrustedHosts="samedomainserver,99.999.999.999"}'       

You will note that I have more than one server listed here and they are comma delimited.  I also have a computer name and an I.P. address in my list.  The IP address is for a server on a different domain.

Executing Commands on the Remote Server

There are two ways that I know of executing commands on the remote server.  The first is by invoking the Invoke-Command cmdlet which allows you to access one off commands:

PS>  Invoke-Command -ComputerName MyRemoteServer -ScriptBlock {Get-Process} -Credential Get-Credential   

The Get-Credential cmdlet opens a windows form dialog to allow you to log in against the required account:

The second allows you to start a remote powershell session using the Enter-PSsession cmdlet:

PS> Enter-Pssession -ComputerName MyRemoteServer -Credential Get-Credential            

I can also exit my remote session with the Exit-PSsession cmdlet.                                                                                                            

The Icing on the Winrm Cake

I talked about the powershell profile in this post and starting a remote powershell session is a prime candidate for adding to my powershell profile.  I have the following two functions defined in my powershell profile:

  1. function PS-Production
  2. {
  3.     Enter-PSSession -ComputerName 99.999.999.999 -Credential Get-Credential
  4. }
  6. function PS-Demo
  7. {
  8.     Enter-PSSession MyRemoteServer -Credential Get-Credential
  9. }

It can get confusing when bouncing about from server to server so I have the following function in my profile to let me know exactly which account I am running under:

  1. function whoami
  2. {
  3.     (get-content env:\userdomain) + "\" + (get-content env:\username);
  4. }

If you are on windows and still flapping about with Dos or worse, using windows explorer to do everything then I beseige you to pick up powershell.  It is worth the effort.

I think a capistrano like experience could be created with powershell and winrm.  Maybe something I will look into at some stage.

1 comment: