1

我试图远程重新启动所有SQL Server实例上的SQL Agent服务。我从一台开发服务器运行以下脚本,同时登录到在CSV文件中列出的每台服务器上具有本地管理员权限的帐户。该文件包含我的所有SQL实例的HostName和InstanceName,都位于此开发服务器和远程计算机上。所有都是Windows Server 2008 R2或2012,运行SQL Server 2008 R2或2012.PowerShell正在以管理员身份运行。在远程计算机上重新启动服务会导致NoServiceFoundForGivenName,但Get-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} 
    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声称该服务不存在。感觉它一定是一个权限问题,但我不知道如何解决它。有任何想法吗?

回答

2

这是因为Get-Service仍在本地运行;它不知道管道中上一个命令的-Computer参数,它不像Get-Service那样支持计算机。使用重新启动,服务为远程服务,你有两个选择:

方法1:使用Enter-PSSession将

您可以在计算机上的问题通过进入─进入远程PowerShell会话PSSession中。当你这样做时,它实际上会在远程计算机上打开一个shell,并且你提供的任何命令都会运行。 Enter-PSSession还支持-Credential参数,因此如果您在本地运行的帐户不是具有远程计算机权限的管理帐户,则可以先创建一个Credential对象,然后使用它。该代码可能是这个样子:

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

当您运行,你的提示将会改变:它将广告方括号中的远程计算机(让你知道你正在执行针对不同的命令名称主办)。这可能也将默认为用户\文件远程主机上的文件夹,像这样:现在

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

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

Get-Service ($serviceName) | Restart-Service 

只要确保当你做,你可以使用退出-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文件获得的变量来指定-ComputerName,我希望Invoke-Command运行,并且我使用带有ArgumentList和Parameters的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()方法。虽然你不能传递到重新启动,服务对象,你可以只是调用该方法,它会重新启动该服务,甚至远程:

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

+1

谢谢德鲁!那就是诀窍。 –

相关问题