【问题标题】:Restart-Service on remote computer results in NoServiceFoundForGivenName, but Get-Service works远程计算机上的 Restart-Service 导致 NoServiceFoundForGivenName,但 Get-Service 有效
【发布时间】:2016-09-28 21:50:32
【问题描述】:

我正在尝试在我的所有 SQL Server 实例上远程重新启动 SQL 代理服务。我从我的一个开发服务器运行以下脚本,同时登录到一个帐户,该帐户在 CSV 文件中列出的每个服务器上都具有本地管理员权限。该文件包含我的所有 SQL 实例的主机名和实例名,包括此开发服务器和远程服务器。所有都是 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

Enable-Remoting 之前已在每台服务器上本地运行。

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

【问题讨论】:

    标签: service sql-server-2008-r2 powershell-2.0 windows-server-2008-r2 restart


    【解决方案1】:

    那是因为 Get-Service 仍在本地运行;它不知道管道中上一个命令中的 -Computer 参数,并且它不支持 -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>
    

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

    Get-Service ($serviceName) | Restart-Service
    

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

    选项 2:使用调用命令

    另一种选择(可能更适合您正在执行的自动化操作)是使用 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. 脚本块信息:https://technet.microsoft.com/en-us/library/hh847893.aspx
    2. 调用命令:https://technet.microsoft.com/en-us/library/hh849719.aspx

    选项 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 的一大优点。这些答案都不是“错误的”,因为您可以使用其中任何一个。它们都是潜在的解决方案,我相信还有更多。

    【讨论】:

      猜你喜欢
      • 2012-05-31
      • 2014-02-24
      • 1970-01-01
      • 2020-09-08
      • 2013-09-22
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多