问题
I've developed a PS1 file which will be responsible to apply SQL Server Patches, based on a Server List. So, it'll read a text file with all servers I need to patch and apply Patch. I've decided using PARAM for "Source Folder" ( where I'll get Server List and record output ); "Destination Folder" ( where I'll be able to run patch ), "File" ( name of patch ), "Instance" ( SQL Server Instance which I'll be running Patch update ). When I start to run commands below, it's able to read Servers List ( so, 1st PARAM is ok ), but, it returns the error below aborting process. What is missing or what am I doing wrong on code below?
PS.: I also would like to use Try...Catch to record a message on the output file. Did I write it correctly? Thanks in advance!
[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
}
How I'm running command above: .\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 :
回答1:
You've to pass your arguments either via -ArgumentList
or via $using
convention to the Invoke-Command
cmdlet. Since you are not doing it that way $folderdest
, $file
will be null in the scope of the Invoke-Command
scriptblock -> the scriptblock defines a seperate scope!
From Microsoft:
-ArgumentList
Supplies the values of local variables in the command. The variables in the command are replaced by these values before the command is run on the remote computer. Enter the values in a comma-separated list. Values are associated with variables in the order that they are listed. The alias for ArgumentList is Args.
Also checkout the exmamples of the Invoke-Command
cmdlet via Get-Help Invoke-Command -Examples
.
If you don't like the ArgumentList
solution you can also use remote variables.
Additionally you should also define an absolute path to your Setup.exe
!
So your code should look like:
....
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
}
....
Hope that helps.
来源:https://stackoverflow.com/questions/46923735/powershell-value-of-argument-path-is-null