New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Robocopy Broken #18944
Comments
What is in robocopy log? |
I know you're aware of at least some of this, but let me summarize: By convention, CLIs use nonzero exit codes to signal error conditions, and that is what the - experimental, at this point - Robocopy does not follow this convention and uses nonzero codes as success error codes too (which communicate additional information) - see https://ss64.com/nt/robocopy-exit.html Robocopy is a prominent example of such an "unconvential" CLI, but there's no telling how many there are, so it's impossible to anticipate all possible CLIs that require special treatment (let alone maintain tables of what nonzero codes, specifically, indicate success), so I don't think maintaining a list of exceptions is practical. Pragmatically speaking:
|
@mklement0 Thank you for the explanation. A another way to prevent the failure would be to shell out to cmd.exe and redirect stderr to stdout. I had to do that 5 to 10 years ago. When scripting in TFS. Ironically there was a tfs exe which wrote things it thought were very important to stderr. To do that with robocopy will be very complicated if we need to detect real errors. |
@RichardMeadowsTC, shelling out to However, If you shell out to # OK, but you Robocopy's exit code is lost.
cmd /c 'robocopy .\PowerShell-7.4.0-preview.1-win-x64\ .\temp\ & exit 0' Note that the |
I would need to run some prototypes. I am not so sure about the cmd.exe not returning the exit code of the process which was ran. I do know powershell.exe tends to return 0 only. Anyway it is all overly complicated and would require a special wrapper for EXEs. |
It does - that's precisely why you need A simple wrapper function that avoids the PowerShell error while preserving the exit code: function Invoke-WithExitCodeIgnored {
param([Parameter(Mandatory, Position=0)] [scriptblock] $ScriptBlock)
$PSNativeCommandUseErrorActionPreference = $false
& $ScriptBlock
}
# Sample call
Invoke-WithExitCodeIgnored { robocopy .\PowerShell-7.4.0-preview.1-win-x64\ .\temp\ }
# Now you can examine $LASTEXITCODE |
There is no need for Exit 0 in cmd script. Only ever needed that when running ps1 script from cmd scripts. Not the other way around. How well last exit code is sent from cmd.exe I need to check. |
I've explained why |
I don't think you understand. I working on my tuck today. Will get back to this in the morning. But there a thing we can fix right now. The exit code just set it to what robocopy sets. But I think that is not even necessary. As I have never seen that needed in cmd scripts. Only seen that needed in powershell scripts. All that said, I think what you do have for properly working solution is very good. |
What about a built-in variable to complement $PSNativeCommandUseErrorActionPreference, such as: $ZEROEXITCODE The variable resets to zero after a native command is executed.
This would maintain the benefit of $PSNativeCommandUseErrorActionPreference = $true |
All we have to do is set $PSNativeCommandUseErrorActionPreference = $false I made an EXE to verify all this. And sample scripts. https://github.com/RichardMeadowsTC/PowerShellCmdInvoke This is a side note. The cmd.exe will return current error level. This is different than powershell which has always tried to hide script result from app which invokes powershell.exe or pwsh.exe. I can guess they aren't changing it to prevent existing code from breaking. But here clearly lots of code is going to be broken. Much more than was broken with Pwsh.exe version 7.3.
|
Then set it back to $true after running the command. If not, why have the feature at all? |
The reason for not setting it back is that it never should have been enabled. Old scripts that we have are well tested and check $LASTEXITCODE where necessary. |
Please see the following proposal for a possible solution: |
I don't like the idea of an "ignore list" for the experimental feature, but robocopy isn't going to change and there are also other known tools that don't follow the non-zero exit is error convention. |
For tools that don't follow the non-zero exit is error convention, there is the option to set (by default or otherwise) |
@SteveL-MSFT, please confirm that Proceeding on that assumption:
|
The following assumes Assume "$PSHOME\ZeroErrorCodes.json" store the minimum magnitude non-error exit codes (with sign), for CLI executables that do not follow the non-zero exit code implies error convention. Example content:
At Powershell startup:
When user inputs a native command, Powershell does this processing:
Consider these scenarios. User runs Robocopy which copies zero files without error:
User runs Robocopy which copies files without error:
User runs Robocopy which returns error:
CLI whose json value is zero:
An exe not in json file:
Same but user sets ZeroErrorCode immediately prior to execution:
|
Discussion in the team we agree that this feature is working as expected and we don't want to special case |
To offer an alternative, let me add solutions that already work / will work with # With a conformant CLI
# In a script, use `exit` instead of `throw`
cmd /c 'echo hi && exit 5' || $(throw $LASTEXITCODE)
# With special handling for Robocopy
# Only treat exit codes > 3 as errors.
robocopy .\PowerShell-7.4.0-preview.1-win-x64\ .\temp\ || $(if ($LASTEXITCODE -gt 3) { throw $LASTEXITCODE }) Note the unfortunate need to enclose even |
Hang on... I didn't see a response to mklement's request for confirmation that we would still have existing behavior in release versions. Your statement, @SteveL-MSFT almost sounds like "no, we are turning this on, and doc'ing it better". If that is the case, please allow me to respectfully scream "bloody murder". I've already gotten bug reports from users of my modules for robocopy, and git, and I can't even remember what else. I assumed this was so clearly such a massively breaking change that it surely wouldn't stand... |
@jazzdelightsme I believe it was mentioned in a separate issue that |
Glad to hear it, @SteveL-MSFT, but it's somewhat disheartening that it took three separate pleas to get you to address this aspect. |
This issue has been marked as by-design and has not had any activity for 1 day. It has been closed for housekeeping purposes. |
@SteveL-MSFT Is there an explanation for the fact that the |
@sba923, the current behavior is a bit counter-intuitive:
|
This is indeed far from intuitive... |
Prerequisites
Steps to reproduce
PowerShell 7.4.0 Preview 1
Can no longer use robocopy.exe from powershell. As robocopy.exe returns status code other than 0 for successful copies.
Repro:
Expect: Runs without creating an error object.
Actual: Creates Error Object
NativeCommandExitException: Program "Robocopy.exe" ended with non-zero exit code: 1.
Issue: This will break all of our existing automation. We use robocopy everywhere. And our scripts all use ErrorAction = Stop
Expected behavior
Actual behavior
Error details
Environment data
Visuals
Steps.zip
The text was updated successfully, but these errors were encountered: