Windows Server 2003 Release 2 (WS2003R2) and Windows Vista introduce a new variety of firewall-friendly remote server management, Windows Remote Management (WinRM), an implementation of the Web Services for Management specification. Instead of marshalling objects across RPC using DCOM, WinRM uses SOAP Web Services via HTTP and HTTPS for remote connections. The web server doesn't have to be installed (but it can be) as HTTP is now a system component.

It's possible to connect to the WMI service on the remote server for diagnostics and management, or to any hardware baseboard management controllers installed in case of server or component failure. WinRM is installed bud disabled by default in Vista [build 5536] but needs to be installed on WS2003R2. It is not available for Windows XP or earlier versions of Windows.

Accessing resources

WinRM operations are marshalled by the session object which is returned as the result of a successful connection to a local or remote computer from the WSMan object.

The session object has a Get method which is used to access a specific class instance - in this case the HTTP system driver.

local oWsman, oSession, cSchema, cNamespace, ;
	cClass, cResource, cResult

oWsman = createobject("WSMAN.Automation")
oSession = oWsman.CreateSession()

cSchema =  "http://schemas.microsoft.com/wsman/2005/06/"
cNamespace = "wmi/root/cimv2/"

* Only Key properties can be used to identify the target instance
cClass = "Win32_SystemDriver?Name=HTTP"

cResource = cSchema + cNamespace + cClass
cResult = oSession.Get(cResource)

messagebox(DisplayOutput(cResult))

procedure DisplayOutput(cXML)
	local oXMLFile, oXSLFile
	oXMLFile = createobject("MSXml2.DOMDocument.3.0")
	oXSLFile = createobject("MSXml2.DOMDocument.3.0")
	oXMLFile.loadxml(cXML)
	* XSL file is in system32 directory
	oXSLFile.load("wsmtxt.xsl")
	return oXMLFile.TransformNode(oXSLFile)
endproc

Configuration GETs

There are some specific GET queries which can be executed:

* Get the WinRM version
oSession.Get("wsman:system/2005/06/this")

* Get the WinRM configuration (WS2003R2)
oSession.Get("wsman:microsoft.com/wsman/2005/06/config")

* Get the WinRM configuration (Vista)
oSession.Get("wsman:microsoft.com/wsman/2005/12/config")

Note the Vista configuration URL uses a different schema and requires full Vista administrative rights: to access it you must therefore either be logged on as Administrator or if your account is in the Administrators group you must start VFP via right-clicking on the shortcut or executable file and choosing "Run as administrator" - this attribute can be also set as the default on a given shortcut in the "Compatibility" tab.

Simple enumerations

The session object's Enumerate method returns a collection of objects of a certain class and allows iteration through them.

local oWsman, oSession, cSchema, cNamespace, ;
	cClass, cResource, cXML, oItems

oWsman = createobject("WSMAN.Automation")
oSession = oWsman.CreateSession()

cSchema =  "http://schemas.microsoft.com/wsman/2005/06/"
cNamespace = "wmi/root/cimv2/"
cClass = "Win32_DiskDrivePhysicalMedia"
cResource = cSchema + cNamespace + cClass

oItems = oSession.Enumerate(cResource)

do while oItems.AtEndOfStream = .f.
	cXML = oItems.ReadItem()
	* View output as formatted XML this time.
	messagebox(DisplayOutputXML(cXML))
enddo

procedure DisplayOutputXML(cXML)
	local oXMLFile, oXSLFile
	oXMLFile = createobject("MSXml2.DOMDocument.3.0")
	oXSLFile = createobject("MSXml2.DOMDocument.3.0")
	oXMLFile.loadxml(cXML)
	* wsmpty.xsl outputs formatted XML
	oXSLFile.load("wsmpty.xsl")
	return oXMLFile.TransformNode(oXSLFile)
endproc

WQL queries in WinRM

In WS2003R2, this is as far as enumerate goes - you get all the properties of all the objects. Vista, though, has the capacity to process WQL queries:

local oWsman, oSession, cDialect, cFilter, ;
	oResultSet, cResource, cXML

oWsman = createobject("Wsman.Automation")
oSession = oWsman.CreateSession()

* Wildcard terminates the resource string
cResource = "http://schemas.microsoft.com/wsman/2005/06/wmi/root/cimv2/*"
cDialect = "http://schemas.microsoft.com/wsman/2005/06/WQL"

* Example queries:
* cFilter = [select EventCode from Win32_NTLogEvent where SourceName="WINRM"]
* cFilter = [select Name from Win32_Service where StartType="Disabled"]
cFilter = "select AdapterType,MACAddress from Win32_NetworkAdapter where PhysicalAdapter=True"

oResultSet = oSession.Enumerate(cResource, cFilter, cDialect)

do while not oResultSet.AtEndOfStream
	cXML = oResultSet.ReadItem
	DisplayProperties(cXML)
enddo

* Parse the XML manually this time
procedure DisplayProperties

	lparameters cXML
	local oParser, oNodes, cProperty, cValue, oItem

	oParser = createobject("MSXml2.DOMDocument.3.0")
	oParser.loadxml(cXML)
	oNodes = oParser.firstChild.firstChild.ChildNodes

	for each oItem in oNodes
		cProperty = oItem.basename
		cValue = oItem.nodetypedvalue
		? cProperty + ": " + cValue
	next

endproc

Calling methods

Methods - static and non-static - are called using the session object's Invoke method: input parameters and output parameters must be serialized as XML. This particular method - Win32_Process.Create - doesn't work in WinRM/Vista build 5308.

local oWSMan, oSession, cClass, cSchema, cNamespace, cResource, ;
	cMethod, cInputParameters, cOutputParameters

oWSMan = createobject("WSMAN.Automation")
oSession = oWSMan.CreateSession()

cSchema =  "http://schemas.microsoft.com/wsman/2005/06/"
cNamespace = "wmi/root/cimv2/"

* Create is a static method so obtain a generic class instance
* rather than a specific instance.

cClass = "WIN32_Process"
cMethod = "Create"

cResource = cSchema + cNamespace + cClass

* Create Input Parameter XML. 
cInputParameters = "<p:" + cMethod + "_INPUT "
cInputParameters = cInputParameters + 	[xmlns:p="] + cSchema + cNamespace + ["] + ">"

* Multiple parameters can be sent, but not embedded objects 
* (so the WIN32_ProcessStartup object cannot be sent)
cInputParameters = cInputParameters + GetParameterXML("CommandLine", "calc.exe")
cInputParameters = cInputParameters + GetParameterXML("CurrentDirectory", "c:\")

cInputParameters = cInputParameters + "<" + "/p:" + cMethod + "_INPUT" + ">"

cOutputParameters = oSession.Invoke(cMethod, cResource, cInputParameters)

* Extract the values directly from the XML using STREXTRACT (VFP7 or later)
cReturnValue = strextract(cOutputParameters, "<p:ReturnValue>", "</p:ReturnValue>")
cProcessID = strextract(cOutputParameters, "<p:ProcessID>", "</p:ProcessID>")

if cReturnValue = "0"
	cMessage = "Process created with an ID of " + cProcessID
else
	cMessage = "Process creation failed: return value was " + cReturnValue
endif

messagebox(cMessage)

procedure GetParameterXML
	lparameters cParameterName, cParameterValue
	cXML = "<p:" + cParameterName + ">" + cParameterValue + ;
		"</p:" + cParameterName + ">"
	return cXML
endproc

In part2 I will show how to make remote connections and to configure WinRM to allow connections over HTTP.


	                    
	                

Leave a Reply

Your email address will not be published. Required fields are marked *