Fix Set-Service -Status Stopped
to stop services with dependencies (#5525)
This commit is contained in:
parent
2b61159ca7
commit
358e8abefe
|
@ -1000,6 +1000,7 @@ function Publish-PSTestTools {
|
|||
$tools = @(
|
||||
@{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"}
|
||||
@{Path="${PSScriptRoot}/test/tools/WebListener";Output="WebListener"}
|
||||
@{Path="${PSScriptRoot}/test/tools/TestService";Output="TestService"}
|
||||
)
|
||||
|
||||
$Options = Get-PSOptions -DefaultToNew
|
||||
|
|
|
@ -1540,6 +1540,15 @@ namespace Microsoft.PowerShell.Commands
|
|||
}
|
||||
internal string serviceStatus = null;
|
||||
|
||||
/// <summary>
|
||||
/// The following is the definition of the input parameter "Force".
|
||||
/// This parameter is useful only when parameter "Stop" is enabled.
|
||||
/// If "Force" is enabled, it will also stop the dependent services.
|
||||
/// If not, it will send an error when this service has dependent ones.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is not a parameter for this cmdlet.
|
||||
/// </summary>
|
||||
|
@ -1786,24 +1795,17 @@ namespace Microsoft.PowerShell.Commands
|
|||
{
|
||||
if (!service.Status.Equals(ServiceControllerStatus.Stopped))
|
||||
{
|
||||
//check for the dependent services as set-service dont have force parameter
|
||||
// Check for the dependent services as set-service dont have force parameter
|
||||
ServiceController[] dependentServices = service.DependentServices;
|
||||
|
||||
if ((dependentServices != null) && (dependentServices.Length > 0))
|
||||
if ((!Force) && (dependentServices != null) && (dependentServices.Length > 0))
|
||||
{
|
||||
WriteNonTerminatingError(service, null, "ServiceHasDependentServicesNoForce", ServiceResources.ServiceHasDependentServicesNoForce, ErrorCategory.InvalidOperation);
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceController[] servicedependedon = service.ServicesDependedOn;
|
||||
|
||||
if ((servicedependedon != null) && (servicedependedon.Length > 0))
|
||||
{
|
||||
WriteNonTerminatingError(service, null, "ServiceIsDependentOnNoForce", ServiceResources.ServiceIsDependentOnNoForce, ErrorCategory.InvalidOperation);
|
||||
return;
|
||||
}
|
||||
// Stop service, pass 'true' to the force parameter as we have already checked for the dependent services.
|
||||
DoStopService(service, force: true, waitForServiceToStop: true);
|
||||
DoStopService(service, Force, waitForServiceToStop: true);
|
||||
}
|
||||
}
|
||||
else if (Status.Equals("Paused", StringComparison.CurrentCultureIgnoreCase))
|
||||
|
|
|
@ -132,9 +132,6 @@
|
|||
<data name="ServiceHasDependentServicesNoForce" xml:space="preserve">
|
||||
<value>Cannot stop service '{1} ({0})' because it has dependent services.</value>
|
||||
</data>
|
||||
<data name="ServiceIsDependentOnNoForce" xml:space="preserve">
|
||||
<value>Cannot stop service '{1} ({0})' because it is dependent on other services.</value>
|
||||
</data>
|
||||
<data name="CouldNotStopService" xml:space="preserve">
|
||||
<value>Service '{1} ({0})' cannot be stopped due to the following error: {2}</value>
|
||||
</data>
|
||||
|
|
|
@ -12,12 +12,28 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW
|
|||
net user $userName $testPass /add > $null
|
||||
$password = ConvertTo-SecureString $testPass -AsPlainText -Force
|
||||
$creds = [pscredential]::new(".\$userName", $password)
|
||||
|
||||
$testservicename1 = "testservice1"
|
||||
$testservicename2 = "testservice2"
|
||||
$svcbinaryname = "TestService"
|
||||
$svccmd = Get-Command $svcbinaryname
|
||||
$svccmd | Should -Not -BeNullOrEmpty
|
||||
$svcfullpath = $svccmd.Path
|
||||
$testservice1 = New-Service -BinaryPathName $svcfullpath -Name $testservicename1
|
||||
$testservice1 | Should -Not -BeNullOrEmpty
|
||||
$testservice2 = New-Service -BinaryPathName $svcfullpath -Name $testservicename2 -DependsOn $testservicename1
|
||||
$testservice2 | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
AfterAll {
|
||||
$global:PSDefaultParameterValues = $originalDefaultParameterValues
|
||||
if ($IsWindows) {
|
||||
net user $userName /delete > $null
|
||||
|
||||
Stop-Service $testservicename2
|
||||
Stop-Service $testservicename1
|
||||
Remove-Service $testservicename2
|
||||
Remove-Service $testservicename1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,4 +345,32 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW
|
|||
}
|
||||
{ & $cmdlet @parameters } | Should -Throw -ErrorId $errorid
|
||||
}
|
||||
|
||||
Context "Set-Service test cases on the services with dependent relationship" {
|
||||
BeforeEach {
|
||||
{ Set-Service -Status Running $testservicename2 } | Should -Not -Throw
|
||||
(Get-Service $testservicename1).Status | Should -BeExactly "Running"
|
||||
(Get-Service $testservicename2).Status | Should -BeExactly "Running"
|
||||
}
|
||||
|
||||
It "Set-Service can stop a service with dependency" {
|
||||
$script = { Set-Service -Status Stopped $testservicename2 -ErrorAction Stop }
|
||||
{ & $script } | Should -Not -Throw
|
||||
(Get-Service $testservicename2).Status | Should -BeExactly "Stopped"
|
||||
}
|
||||
|
||||
It "Set-Service cannot stop a service with running dependent service" {
|
||||
$script = { Set-Service -Status Stopped $testservicename1 -ErrorAction Stop }
|
||||
{ & $script } | Should -Throw
|
||||
(Get-Service $testservicename1).Status | Should -BeExactly "Running"
|
||||
(Get-Service $testservicename2).Status | Should -BeExactly "Running"
|
||||
}
|
||||
|
||||
It "Set-Service can stop a service with running dependent service by parameter -Force" {
|
||||
$script = { Set-Service -Status Stopped -Force $testservicename1 -ErrorAction Stop }
|
||||
{ & $script } | Should -Not -Throw
|
||||
(Get-Service $testservicename1).Status | Should -BeExactly "Stopped"
|
||||
(Get-Service $testservicename2).Status | Should -BeExactly "Stopped"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -667,7 +667,8 @@ function Invoke-OpenCover
|
|||
|
||||
$updatedEnvPath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath"
|
||||
$testToolsExePath = (Resolve-Path(Join-Path $TestPath -ChildPath "..\tools\TestExe\bin")).Path
|
||||
$updatedProcessEnvPath = "${testToolsExePath};${env:PATH}"
|
||||
$testServiceExePath = (Resolve-Path(Join-Path $TestPath -ChildPath "..\tools\TestService\bin")).Path
|
||||
$updatedProcessEnvPath = "${testServiceExePath};${testToolsExePath};${env:PATH}"
|
||||
|
||||
$startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}'; `$env:Path = '${updatedProcessEnvPath}';"
|
||||
$targetArgs = "${startupArgs}", "Invoke-Pester","${TestPath}","-OutputFormat $PesterLogFormat"
|
||||
|
|
19
test/tools/TestService/Program.cs
Normal file
19
test/tools/TestService/Program.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
using System.ServiceProcess;
|
||||
|
||||
namespace TestService
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
ServiceBase[] ServicesToRun;
|
||||
ServicesToRun = new ServiceBase[]
|
||||
{
|
||||
new Service1()
|
||||
};
|
||||
ServiceBase.Run(ServicesToRun);
|
||||
}
|
||||
}
|
||||
}
|
24
test/tools/TestService/Service1.Designer.cs
generated
Normal file
24
test/tools/TestService/Service1.Designer.cs
generated
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
namespace TestService
|
||||
{
|
||||
partial class Service1
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
this.ServiceName = "Service1";
|
||||
}
|
||||
}
|
||||
}
|
22
test/tools/TestService/Service1.cs
Normal file
22
test/tools/TestService/Service1.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
using System.ServiceProcess;
|
||||
|
||||
namespace TestService
|
||||
{
|
||||
public partial class Service1 : ServiceBase
|
||||
{
|
||||
public Service1()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnStart(string[] args)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
16
test/tools/TestService/TestService.csproj
Normal file
16
test/tools/TestService/TestService.csproj
Normal file
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\Test.Common.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>Very tiny windows service to do service testing</Description>
|
||||
<AssemblyName>TestService</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in a new issue