WS-Management? Already here in Vista!

WS-Management is a new web services-based management protocol. It's SOAP-based of course, and it is compatible with the rest of the specifications in the WS-* Web Service stack, like WS-Transfer, WS-Enumeration, WS-Addressing.

WS-Management is enabled in Vista (and Longhorn Server) in several ways.

  • On the client side, you have a standard library (called WinRM) which can "consume" other WS-Management enabled interfaces. You could also use Indigo, or other web service frameworks to access the same services as well. Finally, there is a command-line tool also named WINRM which can be used to communicate with WS-Management enabled servers.
  • On the server side, any WMI class can be made remotely accessible through WS-Management.

Security

WS-Management is securely enabled on Vista machines. To find out the security configuration of your machine (both for client and server) you can use WS-Management itself like in the command below:

C:\>winrm get winrm/config
Config
MaxEnvelopeSizekb = 150
MaxTimeoutms = 60000
MaxBatchItems = 20
MaxProviderRequests = 25
Client
NetworkDelayms = 5000
URLPrefix = wsman
AllowUnencrypted = false
Auth
Basic = false
Digest = true
Kerberos = true
Negotiate = true
DefaultPorts
HTTP = 80
HTTPS = 443
TrustedHosts
Service
RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;ER)S:P(AU;FA;GA;;;WD)(AU;SA;GWGX;;;WD)
MaxConcurrentOperations = 100
EnumerationTimeoutms = 60000
MaxConnections = 5
AllowUnencrypted = false
Auth
Basic = false
Kerberos = true
Negotiate = true
DefaultPorts
HTTP = 80
HTTPS = 443
IPv4Filter = *
IPv6Filter = *
Winrs
AllowRemoteShellAccess = true
IdleTimeout = 900000
MaxConcurrentUsers = 5
MaxShellRunTime = 28800000
MaxProcessesPerShell = 5
MaxMemoryPerShellMB = 80
MaxShellsPerUser = 2

By default, WS-Management is not enabled for remote access, Windows authentication is used by default on local acceess, and encryption is turned on.

You can enable remote access by typing:

C:\>winrm quickconfig
WinRM is not set up to allow remote access to this machine for management.
The following changes must be made:

Set the WinRM service type to delayed auto start.
Start the WinRM service.
Create a WinRM listener on https://* to accept WS-Man requests to any IP on this machine.
Enable the WinRM firewall exception.

Make these changes [y/n]? y

WinRM has been updated for remote management.

WinRM service type changed successfully.
WinRM service started.
Created a WinRM listener on https://* to accept WS-Man requests to any IP on this machine.
WinRM firewall exception enabled.

The output above already illustrates one main advantages of web services - their flexibility with respect to firewall access. Say that you want to enable your current machine to accept incoming WS-Management SOAP requests through the port 80 (as HTTP requests). Then, all you need to do is opening port 80 and that's it! Also, NAT is not a problem, of course.

Try this type of exercise when enabling DCOM through the firewall, and you'll have nightmares. This can get really complicated. Furthermore, DCOM doesn't really work in NAT environments.

A simple example

At this point, you have a secure web service enabled on your machine, that you can then use to perform regular management queries, in WMI style. Let's get some information about a Windows service, like the status of the Spooler service.  

Note that I am doing a remote query - basically contacting the machine AOLTEAN-D2, through an internal, WS-Management web service interface:

C:\>winrm get wmicimv2/Win32_Service?Name=spooler -r:aoltean-d2
Win32_Service
AcceptPause = false
AcceptStop = true
Caption = Print Spooler
CheckPoint = 0
CreationClassName = Win32_Service
Description = Loads files to memory for later printing
DesktopInteract = true
DisplayName = Print Spooler
ErrorControl = Normal
ExitCode = 0
InstallDate = null
Name = spooler
PathName = C:\Windows\System32\spoolsv.exe
ProcessId = 1472
ServiceSpecificExitCode = 0
ServiceType = Own Process
Started = true
StartMode = Auto
StartName = LocalSystem
State = Running
Status = OK
SystemCreationClassName = Win32_ComputerSystem
SystemName = AOLTEAN-D2
TagId = 0
WaitHint = 0

Well, it looks like the spooler service is started. We can perform even more complicated queries, such as this one, to find the list of stopped services which are supposed to be started:

C:\trace>winrm enumerate wmicimv2/* -filter:"select * from win32_service where StartMode=\"Auto\" and State = \"Stopped\" " -r:aoltean-d2

XmlFragment
Win32_Service
AcceptPause = false
AcceptStop = false
Caption = Media Center Service Launcher
CheckPoint = 0
CreationClassName = Win32_Service
Description = Starts Media Center Scheduler and Media Center Receiver services at startup if TV is enabled within Media Center.
DesktopInteract = false
DisplayName = Media Center Service Launcher
ErrorControl = Ignore
ExitCode = 0
InstallDate = null
Name = ehstart
PathName = C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork
ProcessId = 0
ServiceSpecificExitCode = 0
ServiceType = Share Process
Started = false
StartMode = Auto
StartName = NT AUTHORITY\LocalService
State = Stopped
Status = OK
SystemCreationClassName = Win32_ComputerSystem
SystemName = AOLTEAN-D2
TagId = 0
WaitHint = 0

So, where does WS-Management comes into play? At its roots, WS-Management is a simple management protocol that allows us to operate with resources. WS-Management defines a few operations on these resources:

  1. Get resource properties - this is used by the "winrm get ..." command above. We can see that we interrogate here a resoure (the "spooler" Windows service) and we obtain various properties like PathName, Started, etc.
  2. Enumerate resources - this is a more complex command that allows us to enumerate several resources at once
  3. Set properties on a resource
  4. Create or delete resources
  5. Execute methods on a resource, just like WMI methods.

In some sense, resources can be viewed as "objects" in OOP point of view, and WS-Management defines a simple protocol to manipulate these "objects".

Under the hood

So where do web services come into play? Can we peek into the actual management protocol?

With web services, it is actually easy - all we need to do is to use a network protocol analyzer to sniff the HTTP packets between client and the server. Ultimately, web service interactions are nothing more than exchanging XML packets using HTTP/HTTPS, so analyzing these interactions is no more difficult than analyzing HTTP request/response commands between a browser and a web server.

Let's take the GET command above (winrm get wmicimv2/Win32_Service?Name=spooler -r:aoltean-d2). In our case, the client program attempts to get the properties of a given resource of type "wmicimv2/Win32_Service", identified by the selector "Name=spooler".

Let's dive in. With the network sniffer we obtain the following SOAP request message:

<s:Envelope
 xmlns:s="https://www.w3.org/2003/05/soap-envelope"
 xmlns:a="https://schemas.xmlsoap.org/ws/2004/08/addressing"
 xmlns:w="https://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
  <s:Header>
    <a:To>https://aoltean-d2:80/wsman</a:To>
    <w:ResourceURI s:mustUnderstand="true">https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service</w:ResourceURI>
    <a:ReplyTo>
      <a:Address s:mustUnderstand="true">https://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
    </a:ReplyTo>
    <a:Action s:mustUnderstand="true">https://schemas.xmlsoap.org/ws/2004/09/transfer/Get</a:Action>
    <w:MaxEnvelopeSize s:mustUnderstand="true">153600</w:MaxEnvelopeSize>
    <a:MessageID>uuid:2A553640-AA45-4BE1-8CE8-C3F20BD3C74E</a:MessageID>
    <w:Locale xml:lang="en-US" s:mustUnderstand="false" />
    <w:SelectorSet>
      <w:Selector Name="Name">spooler</w:Selector>
    </w:SelectorSet>
    <w:OperationTimeout>PT60.000S</w:OperationTimeout>
  </s:Header>
  <s:Body></s:Body>
</s:Envelope>

Correspondingly, the WS-Man response packet looks like this:

<s:Envelope xml:lang="en-US" xmlns:s="https://www.w3.org/2003/05/soap-envelope" xmlns:a="https://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="https://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
  <s:Header>
    <a:Action  >https://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse</a:Action>
    <a:MessageID  >uuid:3E0BE062-2615-497E-BE6A-2FC7D5B7C9C3</a:MessageID>
    <a:To>https://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
    <a:RelatesTo  >uuid:2A553640-AA45-4BE1-8CE8-C3F20BD3C74E</a:RelatesTo>
  </s:Header>
  <s:Body>
    <p:Win32_Service xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:p="https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service" xmlns:cim="https://schemas.dmtf.org/wbem/wsman/1/base" xsi:type="Win32_Service">
      <p:AcceptPause>false</p:AcceptPause>
      <p:AcceptStop>true</p:AcceptStop>
      <p:Caption>Print Spooler</p:Caption>
      <p:CheckPoint>0</p:CheckPoint>
      <p:CreationClassName>Win32_Service</p:CreationClassName>
      <p:Description>Loads files to memory for later printing</p:Description>
      <p:DesktopInteract>true</p:DesktopInteract>
      <p:DisplayName>Print Spooler</p:DisplayName>
      <p:ErrorControl>Normal</p:ErrorControl>
      <p:ExitCode>0</p:ExitCode>
      <p:InstallDate xsi:nil="true"/>
      <p:Name>spooler</p:Name>
      <p:PathName>C:\Windows\System32\spoolsv.exe</p:PathName>
      <p:ProcessId>1596</p:ProcessId>
      <p:ServiceSpecificExitCode>0</p:ServiceSpecificExitCode>
      <p:ServiceType>Own Process</p:ServiceType>
      <p:Started>true</p:Started>
      <p:StartMode>Auto</p:StartMode>
      <p:StartName>LocalSystem</p:StartName>
      <p:State>Running</p:State>
      <p:Status>OK</p:Status>
      <p:SystemCreationClassName>Win32_ComputerSystem</p:SystemCreationClassName>
      <p:SystemName>AOLTEAN-D2</p:SystemName>
      <p:TagId>0</p:TagId>
      <p:WaitHint>0</p:WaitHint>
    </p:Win32_Service>
  </s:Body>
</s:Envelope>

That's it for now. I hope that in a future post I will cover the actual structure of WS-Management messages.