当前位置: 移动技术网 > IT编程>脚本编程>Shell > Powershell小技巧之使用WS-Man来调用PowerShell命令

Powershell小技巧之使用WS-Man来调用PowerShell命令

2017年12月08日  | 移动技术网IT编程  | 我要评论

虽然powershell远程管理被构建在 ws-management的之上,但它是协议中的协议。如果尝试使用 psrp (powershell远程处理协议)直接进行交互,本质上需要在客户端机器上运行一个powershell副本。另一种方法是使用一个鲜为人知的远程命令行工具,称为winrs。winrs是一个简单的工具,允许远程cmd.exe,它也是构建在ws-management之上的。所不同的是winrs重用了 ws-transfer中的create和delete,并引入了一些新的自定义的soap web-methods。本文中,我将重点放在winrs“协议”,不会讨论 ws-transfer,soap,http等细节。关于winrs,ws-management的一些详细文档可以参考:[ms-wsmv]: web services management protocol extensions for windows vista。

winrs具有相对简单的协议,工作流程为:

ws-transfer创建一个shell,一个epr(端点引用)。创建的shell会被返回,用于接下来的一系列操作。
调用命令的自定义soap动作,开始一个新的命令
调用自定义的soap接受动作,来接收命令输出(发送输入时有相应的send命令,但不是该场景必须的)
重复步骤3,直到commandstate完成
ws-transfer来删除shell上的端点引用。
让我们较为详细地浏览每个步骤吧:
对于ws-transfer create soap消息,body中应当包含你要发送或者接受的流,资源的uri应当为:.
所以本质上我们创建了一个cmd.exe shell用来运行powershell。

复制代码 代码如下:

<shell xmlns='http://schemas.microsoft.com/wbem/wsman/1/windows/shell'>
  <inputstreams>stdin</inputstreams>
  <outputstreams>stdout stderr</outputstreams>
</shell>

如果请求成功,你会接受到一个标准的ws-transfer create soap响应,它包含了一个刚才创建的类似的shell epr:

复制代码 代码如下:

<w:selectorset>
  <w:selector name="shellid">afcfb065-f551-4604-bfdfd9b706798b5d</w:selector>
</w:selectorset>

这个epr应该缓存的所有后续操作。第一个自定义soap动作命令使用动作uri:。 winrs支持两种控制台模式:交互式和批处理。对于一个交互式会话,winrs将等待输入(即使命令已经完成),直到客户端指示没有更多。对于一个批处理会话,winrs期望只在运行命令的生命周期有输入被发送。对于此场景,指定的ws-management选项winrs_consolemode_stdin为true来意味正在使用批处理模式非常重要。命令行被分成单独的命令和参数。soap片段像这样:

复制代码 代码如下:


  <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>

如果这个请求是成功的,该响应将包含一个 commandid元素,应当会被缓存在body中,用于后续操作来接收输出。虽然该协议被定义为允许一个shell来托管多个命令,但是winrs被限制了每个shell只能处理单个命令。类似的响应例子如下:

复制代码 代码如下:

<rsp:commandresponse>
  <rsp:commandid>772b44df-2ea2-4aa5-87d1-a07e1fae7a4e</rsp:commandid>
</rsp:commandresponse>

一旦接收到命令的响应,该命令在服务器上运行。 一旦数据量达到了最大值,winrs将阻止输出(当然也包括命令)。自定义soap动作,接收使用操作uri。自定义soap使用动作uri:。因为所产生的输出可能会超过soap请求大小,客户端需要指定一个递增sequenceid防止数据包丢失。 winrs只会缓存最后发送的数据包。请求应当包含你想读取的数据流,commandid也会关联body中的数据流。

复制代码 代码如下:

<receive sequenceid='0'
   xmlns='http://schemas.microsoft.com/wbem/wsman/1/windows/shell'>
  <desiredstream commandid='772b44df-2ea2-4aa5-87d1-a07e1fae7a4e'>
    stdout stderr
  </desiredstream>
</receive>

响应将包含base64流编码的文本输出(保持soap xml格式良好和有效)。客户端应检查命令的状态,以了解是否继续以调用接收更多的输出。

复制代码 代码如下:

<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="">
  <rsp:exitcode>0</rsp:exitcode>
  </rsp:commandstate>
</rsp:receiveresponse>

一旦commandstate为“done”,会没有更多的输出,并且ws-transfer delete 会在shelll epr上被调用。这将会清理服务器上正在使用的资源。

该示例代码展示如何调用一个powershell 命令。它不使用任何winrm的api,而是从模板创建必要的soap消息,并使用system.net.httpwebrequest将其通过网络发送。为了使用windows中的示例代码,您需要启用winrm服务配置基本身份验证(只适用于本地账号),您可以以管理员权限运行此powershell命令:

复制代码 代码如下:

winrspsh user password "get-service"

如果你想让输出更加规范一点可以转换为为xml((.net serialization):

复制代码 代码如下:

winrspsh user password "(get-service ^| convertto-xml).outerxml"

注意上面的例子中,你必须把管道字符转义,这样cmd.exe就不会去解释它了。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网