diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs index a11fb0270c9..eb286f7c190 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs @@ -5,10 +5,13 @@ using System; using System.Diagnostics; +using System.IO; using System.Management.Automation; using System.Management.Automation.Internal; using System.Runtime.InteropServices; +#nullable enable + namespace Microsoft.PowerShell.Commands { #region Restart-Computer @@ -36,13 +39,13 @@ protected override void BeginProcessing() { string errMsg = StringUtil.Format("Command returned 0x{0:X}", retVal); ErrorRecord error = new ErrorRecord( - new InvalidOperationException(errMsg), "Command Failed", ErrorCategory.OperationStopped, "localhost"); + new InvalidOperationException(errMsg), "CommandFailed", ErrorCategory.OperationStopped, "localhost"); WriteError(error); } return; } - RunCommand("/sbin/shutdown", "-r now"); + RunShutdown("-r now"); } #endregion "Overrides" } @@ -78,13 +81,13 @@ protected override void BeginProcessing() { string errMsg = StringUtil.Format("Command returned 0x{0:X}", retVal); ErrorRecord error = new ErrorRecord( - new InvalidOperationException(errMsg), "Command Failed", ErrorCategory.OperationStopped, "localhost"); + new InvalidOperationException(errMsg), "CommandFailed", ErrorCategory.OperationStopped, "localhost"); WriteError(error); } return; } - RunCommand("/sbin/shutdown", args); + RunShutdown(args); } #endregion "Overrides" } @@ -95,7 +98,7 @@ protected override void BeginProcessing() public class CommandLineCmdletBase : PSCmdlet, IDisposable { #region Private Members - private Process _process = null; + private Process? _process = null; #endregion #region "IDisposable Members" @@ -150,22 +153,52 @@ protected override void StopProcessing() #region "Internals" + private static string? shutdownPath; + /// - /// Run a command. + /// Run shutdown command. /// - protected void RunCommand(String command, String args) { + protected void RunShutdown(String args) + { + if (shutdownPath is null) + { + CommandInfo cmdinfo = CommandDiscovery.LookupCommandInfo( + "shutdown", CommandTypes.Application, + SearchResolutionOptions.None, CommandOrigin.Internal, this.Context); + + if (cmdinfo is not null) + { + shutdownPath = cmdinfo.Definition; + } + else + { + ErrorRecord error = new ErrorRecord( + new InvalidOperationException(ComputerResources.ShutdownCommandNotFound), "CommandNotFound", ErrorCategory.ObjectNotFound, targetObject: null); + ThrowTerminatingError(error); + } + } + _process = new Process() { StartInfo = new ProcessStartInfo { - FileName = "/sbin/shutdown", + FileName = shutdownPath, Arguments = string.Empty, RedirectStandardOutput = false, + RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, } }; _process.Start(); + _process.WaitForExit(); + if (_process.ExitCode != 0) + { + string stderr = _process.StandardError.ReadToEnd(); + ErrorRecord error = new ErrorRecord( + new InvalidOperationException(stderr), "CommandFailed", ErrorCategory.OperationStopped, null); + ThrowTerminatingError(error); + } } #endregion } diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx index 63a671c0248..95685239fd7 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx @@ -387,4 +387,7 @@ The {0} parameter is not supported for CoreCLR. + + The required native command 'shutdown' was not found. + diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx index e8dcccb3dee..ce124ec084c 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx @@ -164,9 +164,6 @@ End time: {0:yyyyMMddHHmmss} {0}:{1,-3} {2} - - An error occurred while running '{0}': {1} - The current session does not support debugging; execution will continue. diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Restart-Computer.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Restart-Computer.Tests.ps1 index 8a2c050a90f..9f845f81af9 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Restart-Computer.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Restart-Computer.Tests.ps1 @@ -107,3 +107,16 @@ finally Disable-Testhook -testhookName $restartTesthookName Set-TesthookResult -testhookName $restartTesthookResultName -value 0 } + +Describe 'Non-admin on Unix' { + BeforeAll { + $skip = $false + if ($IsWindows -or [environment]::IsPrivilegedProcess -or ($null -eq (Get-Command shutdown -CommandType Application -ErrorAction Ignore))) { + $skip = $true + } + } + + It 'Reports error if not run under sudo' -Skip:($skip) { + { Restart-Computer -ErrorAction Stop } | Should -Throw -ErrorId "CommandFailed,Microsoft.PowerShell.Commands.RestartComputerCommand" + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Stop-Computer.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Stop-Computer.Tests.ps1 index c2a89117167..1bda1471e78 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Stop-Computer.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Stop-Computer.Tests.ps1 @@ -58,3 +58,16 @@ finally Disable-Testhook -testhookName $stopTesthook Set-TesthookResult -testhookName $stopTesthookResultName -Value $DefaultResultValue } + +Describe 'Non-admin on Unix' { + BeforeAll { + $skip = $false + if ($IsWindows -or [environment]::IsPrivilegedProcess -or ($null -eq (Get-Command shutdown -CommandType Application -ErrorAction Ignore))) { + $skip = $true + } + } + + It 'Reports error if not run under sudo' -Skip:($skip) { + { Stop-Computer -ErrorAction Stop } | Should -Throw -ErrorId "CommandFailed,Microsoft.PowerShell.Commands.StopComputerCommand" + } +}