2

我开发了一个 PS1 文件,该文件将负责基于服务器列表应用 SQL Server 补丁。因此,它将读取包含我需要修补和应用补丁的所有服务器的文本文件。我决定将 PARAM 用于“源文件夹”(我将在其中获取服务器列表并记录输出);“目标文件夹”(我可以在其中运行补丁)、“文件”(补丁名称)、“实例”(我将运行补丁更新的 SQL Server 实例)。当我开始运行下面的命令时,它能够读取服务器列表(所以,第一个 PARAM 是好的),但是,它在中止过程下面返回错误。下面的代码缺少什么或我做错了什么?

PS.:我也想使用 Try...Catch 在输出文件上记录一条消息。我写对了吗?提前致谢!

[CmdletBinding()]
Param (
  [Parameter(Mandatory=$True,Position=0)]
  [string]$foldersource,

  [Parameter(Position=1)]
  [string]$folderdest,

  [Parameter(Position=2)]
  [string]$file,

  [Parameter(Position=3)]
  [string]$instance

)
foreach ($cluster in GC "$foldersource\Servers_List.txt")
{
    $output = "Server: $cluster Patch Installation on: $(Get-Date -format 'u')" 
try{
    Invoke-Command -ComputerName $cluster -ScriptBlock 
    {
        cd $folderdest
        .\$file /X:$folderdest
        Start-Sleep -s 10
        .\SETUP.exe /action=patch /instancename=$instance /quiet /IAcceptSQLServerLicenseTerms
    }
    -ErrorAction Stop; 
    $output += " SUCCESS"
   }
catch
   {
      $output += "Failed - $($_.exception.message)"
   }
$output | Out-File -Append $foldersource\Patch_Result_Non_SP.txt
} 

我如何运行上面的命令: .\SQL_Server_install_non-Service_Pack_V2.ps1 "D:\Software\Patch" "D:\Software" "SQLServer2008R2-KB3045316-x64.exe" "MSSQLSERVER"

ERROR:

Cannot process argument because the value of argument "path" is null. Change the value of argument "path" to a non-null value.
+ CategoryInfo          : InvalidArgument: (:) [Set-Location],   PSArgumentNullException
+ FullyQualifiedErrorId : ArgumentNull,Microsoft.PowerShell.Commands.SetLocationCommand
+ PSComputerName        : 

   The term '.\$file' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, 
verify that the path is correct and try again.
+ CategoryInfo          : ObjectNotFound: (.\$file:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName        : 

The term '.\SETUP.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, 
verify that the path is correct and try again.
+ CategoryInfo          : ObjectNotFound: (.\SETUP.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName        : 
4

1 回答 1

1

您必须通过-ArgumentList或通过$using约定将参数传递给Invoke-Commandcmdlet。由于您没有这样做,因此$folderdest在脚本块$file的范围内将为 null Invoke-Command-> 脚本块定义了一个单独的范围!

来自微软

-参数列表

在命令中提供局部变量的值。在远程计算机上运行命令之前,命令中的变量会被这些值替换。在逗号分隔的列表中输入值。值按它们列出的顺序与变量相关联。ArgumentList 的别名是 Args。

Invoke-Command可以通过 . 查看 cmdlet的示例Get-Help Invoke-Command -Examples

如果您不喜欢该ArgumentList解决方案,您也可以使用远程变量

此外,您还应该定义一个绝对路径到您的Setup.exe!

所以你的代码应该是这样的:

....
 Invoke-Command -ComputerName $cluster -ArgumentList $file, $folderdest, $instance -ScriptBlock 
{
    Param(
       [string] $rFile,
       [string] $rfileDest,
       [string] $rInstance
    )
    
    # Remove Write-Host after the script block works fine -> Write-Host is only a quick and dirty way to dump the variables content

    Write-Host $rFile
    Write-Host $rfileDest
    Write-Host $rInstance

    cd $rfileDest

    $someArgs = "/X:{0}" -f $rfileDest
    Start-Process -FilePath  $rFile -ArgumentList $someArgs -Wait -PassThru

    Start-Sleep -s 10

    $setupArgs = "action=patch /instancename={0} /quiet /IAcceptSQLServerLicenseTerms" -f $rInstance

    Start-Process -FilePath ".\Setup.exe" -ArgumentList $setupArgs -Wait -PassThru

}
....

希望有帮助。

于 2017-10-25T05:08:03.257 回答