2

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        : 
Moerwald
  • 10,448
  • 9
  • 43
  • 83
AdemirP
  • 113
  • 1
  • 3
  • 10

1 Answers1

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-Commandcmdlet 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.

Community
  • 1
  • 1
Moerwald
  • 10,448
  • 9
  • 43
  • 83
  • Hi @Moerwald! It's awesome! I have no idea regarding ArgumentList. Thanks for sharing it :) – AdemirP Oct 25 '17 at 05:38
  • I have updated code, but error has changed. I've tried to debug by myself, but once I even didn't know ArgumentList, I'm not being able to solve it. If you can give me a hand one more time, I really appreciate :) Follows, new code and error: Invoke-Command -ComputerName $cluster -ArgumentList $file, $folderdest -ScriptBlock{ Param( [string]$f, [string]$fDest ) cd $fDest .\$f /X:$fDest Start-Sleep -s 10 D:\Software\SETUP.exe /action=patch /instancename=$instance /quiet /IAcceptSQLServerLicenseTerms} – AdemirP Oct 25 '17 at 05:40
  • ERROR: The term '.\$f' 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. – AdemirP Oct 25 '17 at 05:40
  • One more question: Can't I use $fDest as path to SETUP.EXE? Will it only work with absolute path? Tks! – AdemirP Oct 25 '17 at 05:41
  • @AdemirP: Sorry. Of course you can use `$fDest` as path to Setup.exe -> my mistake -> I'll update the answer. Regarding the `.\$f`problem, it seems that the content of `$f` points to something that is not an executeable. You can dump the content via `Write-Host $f` in the script block. – Moerwald Oct 25 '17 at 05:53
  • ! I can only thanks to you :) No worries! Regarding .\$f it's pointing to filename I'm informing at param File: SQLServer2008R2-KB3045316-x64.exe. Also, I've tried to update Path to Setup.exe to $fDest and returns another error: Unexpected token '\SETUP.exe' in expression or statement. – AdemirP Oct 25 '17 at 06:02
  • Use the call operator `&` to invoke Setup.exe -> https://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx. You can also use the `Start-Process` cmdlet. – Moerwald Oct 25 '17 at 06:08
  • ! Thanks for the updates! I've updated code as well, but error still persists on: The term '.\$rFile' is not recognized as the name of a cmdlet. Despite the param value is correct, it looks like it's trying to run from a place where file doesn't belong ( local, instead of remote ). Am I correct and why It's happening? – AdemirP Oct 25 '17 at 06:24
  • what is the content of `$rFile` ? – Moerwald Oct 25 '17 at 06:34
  • follows contents for 03 parameters we've used write-host: SQLServer2008R2-KB3045316-x64.exe D:\Software MSSQLSERVER All of them are correct as expected. Have any idea why is it giving error yet? :( Thanks a lot! – AdemirP Oct 25 '17 at 10:21
  • Is the directory, where SQLServer2008R2-KB3045316-x64.exe is situated, in the path variable of the remote machine? – Moerwald Oct 25 '17 at 12:43
  • I've checked on servers and the directory is not. :( – AdemirP Oct 25 '17 at 14:04
  • Then you should add it to your `PATH` variable, or call the exe with an absolute path. – Moerwald Oct 26 '17 at 16:02
  • @AdemirP: Is your issue solved, or is it still open? – Moerwald Nov 01 '17 at 09:36