It’s like SSH, but awkward

WinRM & WinRS

WinRM is Microsoft’s implementation of the WS-Management standard, a SOAP/XML based management protocol intended to allow interoperable management across OS platforms. WinRM allows you to do remote WMI queries as well as execute commands on remote systems. It is much like SSH, but lacks the finesse and design elegance.

Version 2 of these tools come by default on Windows 7 and 2008 R2, they must be installed for earlier versions as part of the Windows Management Framework Core package, which is available for XP, Vista, 2003 and 2008. This also includes PowerShell 2.0 (which itself makes use of WinRM for its Remoting features).

WS-Management uses SOAP, which is an XML-based, object-oriented protocol (a reasonable fit for PowerShell’s object-based model). SOAP is a horrible idea of course. Version 2 of WinRM uses ports 5985 for http and 5986 for https. Version 1.1 used port 80 and port 443.

So it’s a fairly inappropriate technology then, but it is quite useful which makes up for its shortcomings. SSH is an amazingly useful staple of any Unix admin’s toolkit (and with some cajoling can be used with Windows as well). WinRM fits in that same bracket of providing easy command-line access to remote hosts and, despite its shortcomings (more on those later) is genuinely useful.

1. Setting up WinRM for basic use

This process is necessary on all machines you with to remotely administer using either PowerShell remoting or WinRS. It’s a simple one-line command which can easily be run as part of your deployment system. The command to run is:

winrm quickconfig -q -transport:https

This configures a WinRM “listener”, this is like the SSH daemon, running in the background and listening for incoming connections. The transport mechanism can be either http or https – I’d always use https since it offers a higher grade of encryption than is offered by WinRM itself (which uses the NTLM or Kerberos keys to encrypt traffic) and as we’ll see later on it’s also possible that credentials would go in clear text when using specific authentication mechanisms.

A note here, you might be wondering what would happen if you enable WinRM 1.1 on a server running IIS (which is obviously going to be listening on port 80/443). Microsoft thought of this and it enables a workaround so that IIS can send the WS-Management traffic to the right place automatically. Bear this in mind if you’re using a non-IIS web server on a host and wish to enable WinRM (or just use WinRM 2.0).

Once your WinRM listener is set up you can try connecting to it from the local machine with:

winrs -r:your.machine.fqdn -ssl "cmd.exe"

Why do you have to use the FQDN of the machine? Try it with localhost and you’ll get an SSL certificate mismatch error. The HTTP transport option obviously doesn’t suffer from this.

This command gives you a full interactive shell on the remote machine, you can just run a single command if you want and the output will be returned back. Any command available on the remote machine can be run – this includes installer packages. However, any process which would require user-interaction in the GUI (e.g. an installer package run without the “/qn” flags) won’t work since processes started from a remote session can’t be user-interactive.

This is a really annoying limitation since it reduces the utility of this tool by quite a bit. A very similar limitation exists when trying to use SSH (as a service installed by Cygwin) under Windows. This is as far as I understand a decision taken by Microsoft that SYSTEM processes shouldn’t be able to interact with the standard GUI.

1a. PowerShell

The setup process detailed above is exactly what you have to do in order to use PowerShell remoting. You’ll have to be using WinRM 2.0/PowerShell 2.0 of course since remoting only works in that version.

2. Installing WinRM on XP/2003/Vista/2008

Download the correct package from here:

Install the .exe/.msu – this can be automated as well since these packages all support quiet installation. A fully patched copy of any of these OSes (except XP x64) should have all these tools by default.

3. Limitations of WinRM, compared to SSH

WinRM can’t do file transfers like SSH can (SCP), getting a file onto a remote machine is actually a bit of a pain since in its default state WinRM also cannot connect out to shares (see CredSSP section below).
Like PowerShell, WinRM is still limited to the CMD.exe Terminal – no xTerm-like niceness for you.
No port-forwarding/tunnelling (one of the really useful features of SSH).
Authentication model is quite clunky, you either use “one-hop” authentication that only allows you to access a remote machine but not access any remote resources once you’re there, or you have to use CredSSP (which is hard to set up and doesn’t work easily on XP/2003).

4. CredSSP

CredSSP is an authentication mechanism introduced with Vista. It’s original use was to allow for credential delegation from remote desktop sessions. It is also used for the same purpose with WinRM. Unfortunately by default CredSSP isn’t enabled for either client or server ends of a WinRM session. It can be turned on fairly easily using PowerShell:

Enable-WSManCredSSP -role client -delegatecomputer *
Enable-WSManCredSSP -role server

Or via WinRM command line tool:

winrm set winrm/config/client/auth @{CredSSP="true"}
winrm set winrm/config/service/auth @{CredSSP="true"}

However this command doesn’t work on Server 2003 or Windows XP. It isn’t easily possible to enable CredSSP as a mechanism for authentication in WinRM in either of these Operating Systems. This means that you can’t do multiple-hop remoting in PowerShell and you can’t access network shares from within remote sessions. This severely limits the kind of things you can do and it’s really frustrating that this functionality isn’t available for these legacy operating systems (especially given how Windows XP seems set to never go away).

One thing to note about CredSSP is that it requires an SSL secured channel (https transport) or it won’t work. You can explicitly specify that CredSSP should be used as the transport using the following flags to WinRS and Powershell:

WinRS -ad -ssl -u:username -p:password
New-PSSession -ComputerName -Authentication CredSSP -Credential -UseSSL

You can work around this for remote file shares by executing explicit “net use” commands with explicit credentials, thus mapping a network location to a local drive letter. This should then be usable by the remote session without the authentication issues. This is a bit of a cludge though really.

But then the whole thing is a cludge…

Powershell remoting with stored password

In a testing lab it’s sometimes nice to be able to automate things simply. I don’t recommend doing this in a live environment since there are obvious security issues with storing passwords in plaintext. Sometimes though it just doesn’t hurt.

I’ve been looking at moving some of our test automation scripting over to Powershell. One thing we need to be able to do is control HyperV based virtual machines. There’s a wonderful PowerShell library to do exactly this which can reduce our existing multi-dozen line VBScripts down to a 5 line PowerShell one.

In order to remotely execute PowerShell commands it is necessary to establish a PowerShell session with the remote host. This is very easy to do, e.g.:

$session = New-PSSession -computername SomeMachine

This will prompt for credentials and establish the session, you can then use the $session variable with many other commands, e.g. Invoke-Command, to run things remotely.

Obviously in an automated context I don’t want to be getting prompted for credentials, there’s a way to build a credentials object to pass into commands such as these which allows you to cache credentials once at the start of a script for reuse, but this command (Get-Credential) can take only a username as a command line argument, not a password.

I can see why they did this (it’s very insecure to store passwords in plaintext) but in some cases the insecurity of it doesn’t matter. A test lab where you’re blowing environments away all the time is one of those scenarios.

There’s a workaround, which involves building the credentials object manually. These lines accomplish this and give you a credentials object ($cred) which can be passed through to New-PSSession to authenticate.

$pwd = ConvertTo-SecureString -asplaintext -force -string 
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist ,$pwdM

It ought to be possible to store the password in an encrypted form and convert it to a SecureString for use with these commands too. This would give a little more security to the scenario.

gVim unattended install

I like Vim, and had need to deploy it unattended as part of our standard builds at work. Unfortunately the official installers appear to not support unattended installation natively so I ended up using the unofficial “Cream” distribution (there is a version which is just pure Vim, which I used).

Installing is easy, simply run the exe with the command line switch /S, e.g.:

gvim-7-3-98.exe /S

This works, but apparently fails to enable the right-click menu function. This is just a simple registry tweak however:

REG ADD HKEY_CLASSES_ROOT\*\shell\vim /ve /f /d "Edit with &Vim"
IF /i "%Processor_Architecture%"=="x86" REG ADD HKEY_CLASSES_ROOT\*\shell\vim\command /ve /f /d "\"C:\\Program Files\\Vim\\vim73\\gvim.exe\" \"%%1\""
IF /i "%Processor_Architecture%"=="AMD64" REG ADD HKEY_CLASSES_ROOT\*\shell\vim\command /ve /f /d "\"C:\\Program Files (x86)\\Vim\\vim73\\gvim.exe\" \"%%1\""

Finally the first time you run gVim it’ll ask you about its registered types library. You can silently do this in the background by running:

IF /i "%Processor_Architecture%"=="x86" "C:\Program Files\Vim\vim73\gvim.exe" -silent -register
IF /i "%Processor_Architecture%"=="AMD64" "C:\Program Files (x86)\Vim\vim73\gvim.exe" -silent -register

These snippets are taken from the batch file that I run to perform the unattended install, the architecture-detection is needed since Windows x64 mangles the Program Files path for WoW64 applications…