Although PowerShell remote administration is built on top of ws-management, it is an agreement in the protocol. If you try to interact directly using the PSRP (PowerShell Remoting protocol), you essentially need to run a PowerShell copy on the client machine. Another approach is to use a little-known remote command-line tool called WinRS. WinRS is a simple tool that allows remote CMD.EXE and is built on ws-management. The difference is that WinRS reuses the Create and delete in Ws-transfer and introduces some new custom soap web-methods. In this article, I will focus on the WinRS "Protocol" and will not discuss details such as Ws-transfer,soap,http. Some detailed documentation about Winrs,ws-management can be consulted: [MS-WSMV]: Web Services Management Protocol Extensions for Windows Vista.
WinRS has a relatively simple protocol, the workflow is:
Ws-transfer creates a shell, an EPR (endpoint reference). The created shell is returned for the next series of actions.
Invokes the custom SOAP action of the command, starting a new command
Invokes a custom SOAP acceptance action to receive the command output (there is a corresponding send command when sending the input, but not the scene required)
Repeat step 3 until Commandstate is complete
Ws-transfer to remove the endpoint reference on the shell.
Let's go through each of these steps in more detail:
For Ws-transfer Create SOAP messages, the body should contain the stream you want to send or accept, and the URI of the resource should be: Http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd.
So essentially we created a Cmd.exe shell to run the PowerShell.
Copy Code code as follows:
<shell xmlns= ' Http://schemas.microsoft.com/wbem/wsman/1/windows/shell ' >
<InputStreams>stdin</InputStreams>
<outputstreams>stdout stderr</outputstreams>
</Shell>
If the request succeeds, you will receive a standard Ws-transfer create SOAP response that contains a similar shell EPR just created:
Copy Code code as follows:
<w:SelectorSet>
<w:selector name= "Shellid" >AFCFB065-F551-4604-BFDFD9B706798B5D</w:Selector>
</w:SelectorSet>
This EPR should be cached for all subsequent operations. The first custom SOAP Action command uses action Uri:http://schemas.microsoft.com/wbem/wsman/1/windows/shell/command. WINRS supports two console modes: interactive and batch processing. For an interactive session, WinRS waits for input (even if the command has been completed) until the client instructs no more. For a batch session, WinRS expects input to be sent only during the life cycle of the running command. For this scenario, the specified ws-management option Winrs_consolemode_stdin to true means that batch mode is being used very important. The command line is divided into separate commands and parameters. Soap fragments like this:
Copy Code code as follows:
...
<w:OptionSet>
<w:option name= ' Winrs_consolemode_stdin ' >TRUE</w:Option>
</w:OptionSet>
</s:Header>
<s:Body>
<commandline xmlns= ' Http://schemas.microsoft.com/wbem/wsman/1/windows/shell ' >
<Command>powershell</Command>
<arguments>get-service | Format-csv </Arguments>
</CommandLine>
</s:Body>
If the request is successful, the response will contain a COMMANDID element that should be cached in the body for subsequent operations to receive the output. Although the protocol is defined to allow a shell to host multiple commands, the WINRS is limited to a single command that each shell can handle. Examples of similar responses are as follows:
Copy Code code as follows:
<rsp:CommandResponse>
<rsp:CommandId>772B44DF-2EA2-4AA5-87D1-A07E1FAE7A4E</rsp:CommandId>
</rsp:CommandResponse>
Once a response to a command is received, the command runs on the server. Once the amount of data reaches the maximum, WinRS blocks the output (including, of course, the command). A custom SOAP action that receives the use of the action URI. Custom SOAP uses action URI:. Because the resulting output may exceed the size of the SOAP request, the client needs to specify an incremental sequenceid to prevent packet loss. WinRS only caches the last packets sent. The request should contain the data stream you want to read, and CommandID will also correlate the data flow in the body.
Copy Code code as follows:
<receive sequenceid= ' 0 '
xmlns= ' Http://schemas.microsoft.com/wbem/wsman/1/windows/shell ' >
<desiredstream commandid= ' 772b44df-2ea2-4aa5-87d1-a07e1fae7a4e ' >
StdOut stderr
</DesiredStream>
</Receive>
The response will contain Base64 stream-encoded text output (keeping SOAP XML well-formed and valid). The client should check the status of the command to see if it continues to receive more output from the call.
Copy Code code as follows:
<rsp:ReceiveResponse>
<rsp:stream name= "stdout" commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e" >DQo=</rsp:Stream>
<rsp:stream name= "stdout" commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e" >
U3rhdhvzicagtmftzsagicagicagicagicagierpc3bsyxloyw1licagicagicagicagicagicagicagicagicag</rsp:stream>
<rsp:stream name= "stdout" commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e" >
Dqotls0tls0gicatls0ticagicagicagicagicagls0tls0tls0tls0gicagicagicagicagicagicagicagicagicanclj1bm5pbmcgih
Dpbm1nbxqgicagicagicagicbxaw5kb3dzie1hbmfnzw1lbnqgsw5zdhj1bwvudgf0aw9uicagia0kdqoncg==</rsp:stream>
<rsp:stream name= "stdout" commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e" end= "true" ></rsp:Stream>
<rsp:stream name= "stderr" commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e" end= "true" ></rsp:Stream>
<rsp:commandstate commandid= "772b44df-2ea2-4aa5-87d1-a07e1fae7a4e"
State= "Http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done" >
<rsp:ExitCode>0</rsp:ExitCode>
</rsp:CommandState>
</rsp:ReceiveResponse>
Once commandstate is "done," there will be no more output, and Ws-transfer Delete will be invoked on the shelll EPR. This will clean up the resources that are being used on the server.
The sample code shows how to invoke a PowerShell command. Instead of using any WinRM API, it creates the necessary SOAP messages from the template and sends them over the network using System.Net.HttpWebRequest. In order to use the sample code in Windows, you need to enable the WinRM service to configure Basic authentication (local account only), and you can run this PowerShell command with Administrator privileges:
Copy Code code as follows:
WINRSPSH http://server:5985/wsman user Password "Get-service"
If you want to make the output more canonical, you can convert to XML (. Net serialization):
Copy Code code as follows:
WINRSPSH Http://server:5985/wsman User Password "(Get-service ^| Convertto-xml). OuterXml "
Note that in the above example, you have to escape the pipe character so that Cmd.exe doesn't explain it.