2

I need to call a powershell script from another powershell script. The powershell script in question, myrobocopy.ps1, is a generalised module, just tuned to our specific needs. I need to call this from another script and get the error code it returns.

Attempts:

I tried it with Invoke-Expression, like this:

$source = "C:/sourcefolder"
$destination = "C:/destinationfolder"
$filename = "filename /LOG+:log.txt"
$arguments = "-source $source -destination $destination -file $filename"
$robocopyscript = "myrobocopy.ps1"
Invoke-Expression "$robocopyscript $arguments"
    if ($LASTEXITCODE -ne 1){
        $problems = 1
    }

I think the issue with this is that we can't force the process to wait until myrobocopy.ps1 is finished. Additionally, if I'm honest with you, I don't even think $LASTEXITCODE works here, since Invoke-Expression isn't some global error handling tool. I'm new to Powershell, so yeah, its dumb, just showing my work here.

Next attempt looked like this:

$robocopy = "C:\testfolder\myrobocopy.ps1"
$source = "C:\testfolder"
$destination = "C:\testdestination"
$filename = "test.bat"
$arguments = "-source $source -destination $destination -file $filename"
$p = Start-Process $robocopy $arguments -Passthru -Wait
$code = $p.ExitCode

For all I know, this should work, yet when this script runs, it just opens myrobocopy.ps1 in notepad. I've seen some other answers regarding how to associate ps1 files with powershell itself, but I don't believe (could be mistaken here) that is the issue here.

Finally, I read that I need to actually start powershell itself, and then call the ps script. I'm not really sure how to do that, so I tried the following:

$robocopy = "C:\testfolder\myrobocopy.ps1"
$source = "C:\testfolder"
$destination = "C:\testdestination"
$filename = "test.bat"
$arguments = "-source $source -destination $destination -file $filename"
$p = Start-Process "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File $robocopy -ArgumentList $arguments -PassThru -Wait
$code = $p.ExitCode

This returns the following error: Start-Process : A positional parameter cannot be found that accepts argument 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'

So yeah I'm slightly lost. I'm sure I just don't know the syntax on how to do it. Help would be greatly appreciated, thank you!

EDIT: Just to add more info, myrobocopy.ps1 accepts 3 string parameters and explicitly returns the $LASTEXITCODE after running robocopy.

ANSWER:

Using the call operator made this work, and you use $LASTEXITCODE to retrieve the exit code.

$robocopy = "C:\testfolder\myrobocopy.ps1"
$source = "C:\testfolder"
$destination = "C:\testdestination"
$filename = "test.bat"
& $robocopy $source $destination $filename
Write-Output $LASTEXITCODE
2
  • scripts don't usually have exit codes - binaries do. Does myrobocopy.ps1 return the $LASTEXITCODE after running robocopy? Commented Aug 17, 2021 at 12:15
  • @MathiasR.Jessen Yes it does. I'm going to update my original post to reflect this. Thank you for helping make my question clearer. Commented Aug 17, 2021 at 12:18

2 Answers 2

4

If your "C:\testfolder\myrobocopy.ps1" put the result code on the pipeline, the call operator should do the trick:

$result = & "C:\testfolder\myrobocopy.ps1"
Sign up to request clarification or add additional context in comments.

1 Comment

This is what I did. Adding the full answer to the question now.
2

Another way to run robocopy and get the correct exit code would be to use Invoke-Expression with $global:LASTEXITCODE:

Function Start-Robocopy {
    Param (
        [Parameter(Mandatory)]
        [String]$Source,
        [Parameter(Mandatory)]
        [String]$Destination,
        [Parameter(Mandatory)]
        [String]$Switches,
        [String]$File
    )

    Try {
        $result = [PSCustomObject]@{
            Source         = $Source
            Destination    = $Destination
            File           = $File
            Switches       = $Switches
            RobocopyOutput = $null
            ExitCode       = $null
            Error          = $null
        }
        
        $global:LASTEXITCODE = 0 # required to get the correct exit code
        
        $expression = [String]::Format(
            'ROBOCOPY "{0}" "{1}" {2} {3}', 
            $Source, $Destination, $File, $Switches
        )
        $result.RobocopyOutput = Invoke-Expression $expression
        $result.ExitCode = $LASTEXITCODE
    }
    Catch {
        $result.Error = $_
    }
    Finally {
        $result
    }
}

$startParams = @{
    Source      = '\\contoso\FolderA'
    Destination = '\\contoso\FolderB' 
    Switches    = '/MIR /Z /R:3 /W:10 /NP /MT:16'
}
Start-Robocopy @startParams

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.