fix set-service failing test (#4802)

* Add '-ErrorAction Stop' in Set-Service.Tests.ps1 to correctly test exceptions.
* Refactor StartupType service code and add a throw for disabled startup types (System, Boot).
* Made StartupType(-1) equivalent to Win32 SERVICE_NO_CHANGE.
This commit is contained in:
Steve Lee 2017-09-15 01:24:40 -07:00 committed by Ilya
parent da49841f16
commit b723d6b7f2
3 changed files with 76 additions and 48 deletions

View file

@ -1511,8 +1511,6 @@ namespace Microsoft.PowerShell.Commands
internal ServiceStartMode startupType = (ServiceStartMode)(-1);
/// <summary>
/// The following is the definition of the input parameter "Status".
/// This specifies what state the service should be in (e.g. Running, Stopped,
@ -1684,22 +1682,13 @@ namespace Microsoft.PowerShell.Commands
|| (ServiceStartMode)(-1) != StartupType)
{
DWORD dwStartType = NativeMethods.SERVICE_NO_CHANGE;
switch (StartupType)
if (!NativeMethods.TryGetNativeStartupType(StartupType, out dwStartType))
{
case ServiceStartMode.Automatic:
dwStartType = NativeMethods.SERVICE_AUTO_START;
break;
case ServiceStartMode.Manual:
dwStartType = NativeMethods.SERVICE_DEMAND_START;
break;
case ServiceStartMode.Disabled:
dwStartType = NativeMethods.SERVICE_DISABLED;
break;
default:
Diagnostics.Assert(
((ServiceStartMode)(-1)) == StartupType,
"bad StartupType");
break;
WriteNonTerminatingError(StartupType.ToString(), "Set-Service", Name,
new ArgumentException(), "CouldNotSetService",
ServiceResources.UnsupportedStartupType,
ErrorCategory.InvalidArgument);
return;
}
bool succeeded = NativeMethods.ChangeServiceConfigW(
hService,
@ -2002,25 +1991,14 @@ namespace Microsoft.PowerShell.Commands
ErrorCategory.PermissionDenied);
return;
}
DWORD dwStartType = NativeMethods.SERVICE_AUTO_START;
switch (StartupType)
if (!NativeMethods.TryGetNativeStartupType(StartupType, out DWORD dwStartType))
{
case ServiceStartMode.Automatic:
dwStartType = NativeMethods.SERVICE_AUTO_START;
break;
case ServiceStartMode.Manual:
dwStartType = NativeMethods.SERVICE_DEMAND_START;
break;
case ServiceStartMode.Disabled:
dwStartType = NativeMethods.SERVICE_DISABLED;
break;
default:
Diagnostics.Assert(
((ServiceStartMode)(-1)) == StartupType,
"bad StartupType");
break;
WriteNonTerminatingError(StartupType.ToString(), "New-Service", Name,
new ArgumentException(), "CouldNotNewService",
ServiceResources.UnsupportedStartupType,
ErrorCategory.InvalidArgument);
return;
}
// set up the double-null-terminated lpDependencies parameter
IntPtr lpDependencies = IntPtr.Zero;
if (null != DependsOn)
@ -2410,6 +2388,43 @@ namespace Microsoft.PowerShell.Commands
public static extern bool QueryInformationJobObject(SafeHandle hJob, int JobObjectInfoClass,
ref JOBOBJECT_BASIC_PROCESS_ID_LIST lpJobObjectInfo,
int cbJobObjectLength, IntPtr lpReturnLength);
/// <summary>
/// Get appropriate win32 StartupType
/// </summary>
/// <param name="StartupType">
/// StartupType provided by the user.
/// </param>
/// <param name="dwStartType">
/// Out parameter of the native win32 StartupType
/// </param>
/// <returns>
/// If a supported StartupType is provided, funciton returns true, otherwise false.
/// </returns>
internal static bool TryGetNativeStartupType(ServiceStartMode StartupType, out DWORD dwStartType)
{
bool success = true;
dwStartType = NativeMethods.SERVICE_NO_CHANGE;
switch (StartupType)
{
case ServiceStartMode.Automatic:
dwStartType = NativeMethods.SERVICE_AUTO_START;
break;
case ServiceStartMode.Manual:
dwStartType = NativeMethods.SERVICE_DEMAND_START;
break;
case ServiceStartMode.Disabled:
dwStartType = NativeMethods.SERVICE_DISABLED;
break;
case (ServiceStartMode)(-1):
dwStartType = NativeMethods.SERVICE_NO_CHANGE;
break;
default:
success = false;
break;
}
return success;
}
}
#endregion NativeMethods
}

View file

@ -201,4 +201,7 @@
<data name="ComputerAccessDenied" xml:space="preserve">
<value>The command cannot be used to configure the service '{0}' because access to computer '{1}' is denied. Run PowerShell as admin and run your command again.</value>
</data>
<data name="UnsupportedStartupType" xml:space="preserve">
<value>The startup type '{0}' is not supported by {1}.</value>
</data>
</root>

View file

@ -22,15 +22,18 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
@{parameter = "Status" ; value = "Running"},
@{parameter = "Status" ; value = "Stopped"},
@{parameter = "Status" ; value = "Paused"},
@{parameter = "InputObject" ; value = (Get-Service | Select-Object -First 1)},
@{parameter = "InputObject" ; script = {Get-Service | Select-Object -First 1}},
# cmdlet inherits this property, but it's not exposed as parameter so it should be $null
@{parameter = "Include" ; value = "foo", "bar" ; expectedNull = $true},
# cmdlet inherits this property, but it's not exposed as parameter so it should be $null
@{parameter = "Exclude" ; value = "foo", "bar" ; expectedNull = $true}
) {
param($parameter, $value, $expectedNull)
param($parameter, $value, $script, $expectedNull)
$setServiceCommand = [Microsoft.PowerShell.Commands.SetServiceCommand]::new()
if ($script -ne $Null) {
$value = & $script
}
$setServiceCommand.$parameter = $value
if ($expectedNull -eq $true) {
$setServiceCommand.$parameter | Should BeNullOrEmpty
@ -42,7 +45,7 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
It "Set-Service parameter validation for invalid values: <script>" -TestCases @(
@{
script = {Set-Service foo -StartupType bar};
script = {Set-Service foo -StartupType bar -ErrorAction Stop};
errorid = "CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetServiceCommand"
}
) {
@ -58,6 +61,7 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
) {
param($parameter, $value, $expected)
$currentService = Get-CimInstance -ClassName Win32_Service -Filter "Name='spooler'"
$originalStartupType = (Get-Service -Name spooler).StartType
try {
$setServiceCommand = [Microsoft.PowerShell.Commands.SetServiceCommand]::new()
$setServiceCommand.Name = "Spooler"
@ -76,7 +80,7 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
}
finally {
if ($parameter -eq "StartupType") {
$setServiceCommand.StartupType = $currentService.StartMode
$setServiceCommand.StartupType = $originalStartupType
}
else {
$setServiceCommand.$parameter = $currentService.$parameter
@ -158,17 +162,23 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
}
}
It "New-Service with bad parameters will fail for '<name>' where '<parameter>' = '<value>'" -TestCases @(
@{name = 'credtest' ; parameter = "Credential" ; value = (
It "Using bad parameters will fail for '<name>' where '<parameter>' = '<value>'" -TestCases @(
@{cmdlet="New-Service"; name = 'credtest' ; parameter = "Credential" ; value = (
[System.Management.Automation.PSCredential]::new("username",
(ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force)))
},
# This test case fails due to #4803. Disabled for now.
# @{name = 'badstarttype'; parameter = "StartupType"; value = "System"},
@{name = 'winmgmt' ; parameter = "DisplayName"; value = "foo"}
(ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force)));
errorid = "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"},
@{cmdlet="New-Service"; name = 'badstarttype'; parameter = "StartupType"; value = "System";
errorid = "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"},
@{cmdlet="New-Service"; name = 'winmgmt' ; parameter = "DisplayName"; value = "foo";
errorid = "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"},
@{cmdlet="Set-Service"; name = 'winmgmt' ; parameter = "StartupType"; value = "Boot";
errorid = "CouldNotSetService,Microsoft.PowerShell.Commands.SetServiceCommand"}
) {
param($name, $parameter, $value)
$parameters = @{$parameter = $value; Name = $name; Binary = "$PSHOME\powershell.exe"; ErrorAction = "Stop"}
{ New-Service @parameters } | ShouldBeErrorId "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"
param($cmdlet, $name, $parameter, $value, $errorid)
$parameters = @{$parameter = $value; Name = $name; ErrorAction = "Stop"}
if ($cmdlet -eq "New-Service") {
$parameters += @{Binary = "$PSHOME\powershell.exe"};
}
{ & $cmdlet @parameters } | ShouldBeErrorId $errorid
}
}