在Powershell 2.0中将命令结果捕获到变量并写入控制台时未看到预期输出

时间:2016-05-13 17:24:31

标签: powershell

我试图了解Powershell中的内容(v2.0,如果重要的话)。我正在将一个命令的结果捕获到变量中,当我将它写入控制台时,我没有得到我期望的结果。除输出外的所有内容都按预期运行。

这是一个MCVE,其行为方式与我编写的脚本相同。我只是将其分解,以便我可以提供有关正在发生的事情的评论,它不按照我认为应该工作的方式进行评论,以及我认为可能发生的事情。

在第一个代码段中,我正在验证服务MyService的状态 在计算机上svr0123。这给出了我期待的输出。

PS C:\Temp> Get-Service -Name MyService -CN svr0123

Status   Name               DisplayName
------   ----               -----------
Stopped  MyService          My_Service_Display_Name

PS C:\Temp>

在第二个片段中,我正在做同样的事情,只是将输出分配给 $results旨在重新启动任何已停止的服务。再次,这 给出了我期待的输出。

PS C:\Temp> $results = Get-Service -Name MyService -CN svr0123
PS C:\Temp> Write-Output $results

Status   Name               DisplayName
------   ----               -----------
Stopped  MyService          My_Service_Display_Name

PS C:\Temp>

最后,我正在重新启动服务,然后编写$results的内容 到控制台。这会按预期执行功能。我期待 $results的内容与前两个输出相同, 但我得到了:

PS C:\Temp> $results | Where { $_.Status -eq "Stopped" } | Set-Service -Status Running
PS C:\Temp> Write-Output $results

Status   Name               DisplayName
------   ----               -----------
Running  MyService          My_Service_Display_Name

PS C:\Temp>

这是不正确的,除非每次我引用的内容 $results它再次调用Get-Service命令,这是违反直觉的。如果是这样的话,那就是 似乎我没有存储命令的输出,而是我 将别名存储到命令中。如果我在重新启动之前将$results的内容写入控制台,则所有内容都会按预期输出。

这是一个微不足道的修复,但我试图理解我观察的背后的“为什么”。我的问题是:

  • 事实上,这是发生了什么?在Powershell文档中的位置 我能详细了解这个吗?
  • 如果这是正在发生的事情,有没有办法可以存储 输出以便我不会招致多次通话?在这方面它是微不足道的 case,但我的脚本将在繁忙的网络上使用,有时可能会使用 查询给定运行中的数百台服务器。

2 个答案:

答案 0 :(得分:1)

我认为在显示服务对象时它不会重新调用Get-Service。我认为$service对象有一个内部状态,它是一个文本值,当你将它传递给Set-Service时,状态值会被改变,服务也会被启动/停止。

由于尝试使用$service.Status = "Running"直接更改它会生成错误,因为该属性是只读的,因此可以通过服务对象自己的$service.Start()$service.Stop()方法进行此更改$service | get-member

支持一些快速测试的证据:

  • $service = get-service testsvc; $service看到状态正在运行,然后我转到控制面板并停止那里的服务,$service状态不会改变。

  • 我直接调用$service.Start()来重启服务,我得到一个异常(可能是因为我的PowerShell没有作为管理员运行)所以服务实际上并没有开始运行,但是{{1}确实改变(错误地)说服务正在运行。

通过这种方式,我在报告状态和实际状态之间断开连接令我信服,以及每个对象“知道”它是如何生成并且任意重新运行该代码的方式似乎难以置信/不切实际(如果这是一个30分钟的查询来生成它吗?)但我不知道确定交互是什么。

答案 1 :(得分:1)

当你致电Get-Service -Name MyService -CN svr0123时,它会返回一个ServiceController对象,而不仅仅是输出文本。

所以,当你拨打这一行时:

$results = Get-Service -Name MyService -CN svr0123

$results不仅仅是一个包含命令输出的字符串变量。它实际上是ServiceContoller类型的变量。

运行此以查看:

$results.GetType()

你会得到这个:

IsPublic IsSerial Name                      BaseType
-------- -------- ----                      --------
True     False    ServiceController         System.ComponentModel.Component

因此,第二次执行Write-Output $results时,服务已启动,$results变量显示服务的当前状态。