远程计算机上的Restart-Service导致NoServiceFoundForGivenName,但Get-Service有效

时间:2016-09-28 21:50:32

标签: service sql-server-2008-r2 powershell-v2.0 windows-server-2008-r2 restart

我正在尝试在所有SQL Server实例上远程重启SQL代理服务。我在登录到CSV文件中列出的每个服务器上具有本地管理员权限的帐户时,从我的某个开发服务器运行以下脚本。该文件包含我的所有SQL实例的HostName和InstanceName,在此开发服务器和远程服务器上。所有这些都是Windows Server 2008R2或2012,运行SQL Server 2008R2或2012. PowerShell正在以管理员身份运行。

$Servers = Import-CSV C:\Temp\InstanceList.csv
ForEach ($Line In $Servers)
{
  $sqlHostName = $Line.hostName
  $sqlInstanceName = if ($Line.instanceName -eq "") {$Line.instanceName} else {("$" + $Line.instanceName)}
  $serviceName = if ($sqlInstanceName -eq "") {"SQLSERVERAGENT"} else {"SQLAgent" + $sqlInstanceName}
  Get-Service -computer $sqlHostName ($serviceName)
  Get-Service -computer $sqlHostName ($serviceName) | Restart-Service
}

它在本地计算机的实例上成功但在远程实例上失败。这是我在远程默认实例中看到的错误。第一行显示我有正确的服务名称,下一行声称它不存在:

Running  SQLSERVERAGENT     SQL Server Agent (MSSQLSERVER)
Restart-Service : Cannot find any service with service name 'SQLSERVERAGENT'.
At line:11 char:70
+   Get-Service -computer $sqlHostName ($serviceName) | Restart-Service <<<<
    + CategoryInfo          : ObjectNotFound: (SQLSERVERAGENT:String) [Restart-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.RestartServiceCommand

先前已在每台服务器上本地运行启用 - 远程处理。

为什么Get-Service能够显示服务名称,但随后Restart-Service声称该服务不存在。感觉它必须是权限问题,但我不知道如何解决它。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

那是因为Get-Service仍在本地运行;它不知道管道中前一个命令的-Computer参数,它不支持像Get-Service那样的计算机。要将Restart-Service用于远程服务,您有几个选择:

选项1:使用Enter-PSSession

您可以使用Enter-PSSession在相关计算机上输入远程PowerShell会话。当你这样做时,它基本上在远程计算机上打开一个shell,你运行的任何命令都会运行。 Enter-PSSession还支持-Credential参数,因此,如果您在本地运行的帐户不是具有远程计算机权限的管理帐户,则可以先创建凭据对象,然后再使用该帐户。代码可能如下所示:

$Credential = Get-Credential
Enter-PSSession -ComputerName $ComputerName -Credential $Credential

当你运行它时,你的提示会改变:它会在方括号中标注远程计算机的名称(让你知道你正在针对不同的主机执行命令)。它可能也会默认为远程主机上的users \ documents文件夹,如下所示:

[ComputerName]: PS C:\Users\Username\Documents>

现在,您运行的任何命令都将在目标计算机上运行。你不再需要-Computer on Get-Service了。所以你可以运行:

Get-Service ($serviceName) | Restart-Service

只需确保完成后,使用Exit-PSSession返回本地提示符。

选项2:使用Invoke-Command

另一个选项(以及可能更适合您正在进行的自动化的选项)是使用Invoke-Command。 Invoke-Command支持-Credential和-ComputerName参数,以及-ScriptBlock参数。 ScriptBlock很简洁,因为它允许您轻松传递和修改具有自己参数的代码。因此,在上面的示例中,您可以执行以下操作:

$ScriptBlock = {Get-Service | Where-Object {$_.Name -like "SQL*"} | Restart-Service}
Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock

根据您尝试做的事情,我会像这样重写您的脚本:

$Servers = Import-CSV C:\Temp\InstanceList.csv
$ScriptBlock = {param([string] $RemoteServiceName)  Get-Service | Where-Object {$_.Name -eq $RemoteServiceName} | Restart-Service}

ForEach ($Line In $Servers)
{
  $sqlHostName = $Line.hostName
  $sqlInstanceName = if ($Line.instanceName -eq "") {$Line.instanceName} else {("$" + $Line.instanceName)}
  $serviceName = if ($sqlInstanceName -eq "") {"SQLSERVERAGENT"} else {"SQLAgent" + $sqlInstanceName}
  Invoke-Command -ComputerName $sqlHostName -ScriptBlock $ScriptBlock -ArgumentList $serviceName
}

我正在使用你的循环逻辑,但是我使用你从.CSV文件中获得的变量来指定我希望运行Invoke-Command的-ComputerName,并且我正在使用带有ArgumentList的ScriptBlock和用于提供最终运行的值的参数。

如果您想了解更多关于几个概念的内容,请点击以下链接:

  1. ScriptBlock信息:https://technet.microsoft.com/en-us/library/hh847893.aspx
  2. Invoke-Command:https://technet.microsoft.com/en-us/library/hh849719.aspx
  3. 选项3:在对象上使用方法

    当然,它并不需要那么难。您可以使用Get-Service获取变量的服务,然后对该对象使用.Restart()方法。虽然您无法将对象传递给Restart-Service,但可以只是调用该方法,它甚至可以远程重启该服务:

    $Servers = Import-CSV C:\Temp\InstanceList.csv
    ForEach ($Line In $Servers)
    {
        $sqlHostName = $Line.hostName
        $sqlInstanceName = if ($Line.instanceName -eq "") {$Line.instanceName} else {("$" + $Line.instanceName)}
        $serviceName = if ($sqlInstanceName -eq "") {"SQLSERVERAGENT"} else {"SQLAgent" + $sqlInstanceName}
        $Service = Get-Service -computer $sqlHostName ($serviceName)
        $Service.Restart()
    }
    

    对于PowerShell而言,这是一件非常棒的事情。这些答案都没有&#34;错误&#34;因为你可以使用其中任何一个;他们是所有潜在的解决方案,我相信还有更多的解决方案。