diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs index 29c407c50d0..24d574b0edd 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs @@ -571,7 +571,7 @@ protected override void ProcessRecord() { if (!DependentServices.IsPresent && !RequiredServices.IsPresent) { - WriteObject(service); + WriteObject(AddProperties(service)); } else { @@ -594,6 +594,107 @@ protected override void ProcessRecord() } #endregion Overrides + + /// + /// Adds UserName, Description, BinaryPathName, DelayedAutoStart and StartupType to a ServiceController object. + /// + /// + /// ServiceController as PSObject with UserName, Description and StartupType added + private PSObject AddProperties(ServiceController service) { + NakedWin32Handle hScManager = IntPtr.Zero; + NakedWin32Handle hService = IntPtr.Zero; + int lastError = 0; + PSObject serviceAsPSObj = PSObject.AsPSObject(service); + try + { + hScManager = NativeMethods.OpenSCManagerW( + lpMachineName: service.MachineName, + lpDatabaseName: null, + dwDesiredAccess: NativeMethods.SC_MANAGER_CONNECT + ); + if (IntPtr.Zero == hScManager) { + lastError = Marshal.GetLastWin32Error(); + Win32Exception exception = new Win32Exception(lastError); + WriteNonTerminatingError( + service, + exception, + "FailToOpenServiceControlManager", + ServiceResources.FailToOpenServiceControlManager, + ErrorCategory.PermissionDenied); + } + hService = NativeMethods.OpenServiceW( + hScManager, + service.ServiceName, + NativeMethods.SERVICE_QUERY_CONFIG + ); + if (IntPtr.Zero == hService) { + lastError = Marshal.GetLastWin32Error(); + Win32Exception exception = new Win32Exception(lastError); + WriteNonTerminatingError( + service, + exception, + "CouldNotGetServiceInfo", + ServiceResources.CouldNotGetServiceInfo, + ErrorCategory.PermissionDenied); + } + + NativeMethods.SERVICE_DESCRIPTIONW description = new NativeMethods.SERVICE_DESCRIPTIONW(); + bool querySuccessful = NativeMethods.QueryServiceConfig2(hService, NativeMethods.SERVICE_CONFIG_DESCRIPTION, out description); + + NativeMethods.SERVICE_DELAYED_AUTO_START_INFO autostartInfo = new NativeMethods.SERVICE_DELAYED_AUTO_START_INFO(); + querySuccessful = querySuccessful && NativeMethods.QueryServiceConfig2(hService, NativeMethods.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, out autostartInfo); + + NativeMethods.QUERY_SERVICE_CONFIG serviceInfo = new NativeMethods.QUERY_SERVICE_CONFIG(); + querySuccessful = querySuccessful && NativeMethods.QueryServiceConfig(hService, out serviceInfo); + + if(!querySuccessful) { + WriteNonTerminatingError( + service: service, + innerException: null, + errorId: "CouldNotGetServiceInfo", + errorMessage: ServiceResources.CouldNotGetServiceInfo, + category: ErrorCategory.PermissionDenied + ); + } + + PSProperty noteProperty = new PSProperty("UserName", serviceInfo.lpServiceStartName); + serviceAsPSObj.Properties.Add(noteProperty, true); + serviceAsPSObj.TypeNames.Insert(0, "System.Service.ServiceController#UserName"); + + noteProperty = new PSProperty("Description", description.lpDescription); + serviceAsPSObj.Properties.Add(noteProperty, true); + serviceAsPSObj.TypeNames.Insert(0, "System.Service.ServiceController#Description"); + + noteProperty = new PSProperty("DelayedAutoStart", autostartInfo.fDelayedAutostart); + serviceAsPSObj.Properties.Add(noteProperty, true); + serviceAsPSObj.TypeNames.Insert(0, "System.Service.ServiceController#DelayedAutoStart"); + + noteProperty = new PSProperty("BinaryPathName", serviceInfo.lpBinaryPathName); + serviceAsPSObj.Properties.Add(noteProperty, true); + serviceAsPSObj.TypeNames.Insert(0, "System.Service.ServiceController#BinaryPathName"); + + noteProperty = new PSProperty("StartupType", NativeMethods.GetServiceStartupType(service.StartType, autostartInfo.fDelayedAutostart)); + serviceAsPSObj.Properties.Add(noteProperty, true); + serviceAsPSObj.TypeNames.Insert(0, "System.Service.ServiceController#StartupType"); + } + finally + { + if (IntPtr.Zero != hService) { + bool succeeded = NativeMethods.CloseServiceHandle(hService); + if (!succeeded) { + Diagnostics.Assert(lastError != 0, "ErrorCode not success"); + } + } + + if (IntPtr.Zero != hScManager) { + bool succeeded = NativeMethods.CloseServiceHandle(hScManager); + if (!succeeded) { + Diagnostics.Assert(lastError != 0, "ErrorCode not success"); + } + } + } // finally + return serviceAsPSObj; + } } #endregion GetServiceCommand @@ -1403,7 +1504,7 @@ public string Description [Parameter] [Alias("StartMode", "SM", "ST")] [ValidateNotNullOrEmpty] - public ServiceStartMode StartupType + public ServiceStartupType StartupType { get { return startupType; } set @@ -1413,7 +1514,7 @@ public ServiceStartMode StartupType } // We set the initial value to an invalid value so that we can // distinguish when this is and is not set. - internal ServiceStartMode startupType = (ServiceStartMode)(-1); + internal ServiceStartupType startupType = ServiceStartupType.InvalidValue; /// @@ -1530,6 +1631,7 @@ protected override void ProcessRecord() NakedWin32Handle hScManager = IntPtr.Zero; NakedWin32Handle hService = IntPtr.Zero; + IntPtr delayedAutoStartInfoBuffer = IntPtr.Zero; try { hScManager = NativeMethods.OpenSCManagerW( @@ -1567,10 +1669,9 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); return; } - // Modify startup type or display name or credential if (!String.IsNullOrEmpty(DisplayName) - || (ServiceStartMode)(-1) != StartupType || null != Credential) + || ServiceStartupType.InvalidValue != StartupType || null != Credential) { DWORD dwStartType = NativeMethods.SERVICE_NO_CHANGE; if (!NativeMethods.TryGetNativeStartupType(StartupType, out dwStartType)) @@ -1638,6 +1739,32 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); } + // Set the delayed auto start + NativeMethods.SERVICE_DELAYED_AUTO_START_INFO ds = new NativeMethods.SERVICE_DELAYED_AUTO_START_INFO(); + ds.fDelayedAutostart = StartupType == ServiceStartupType.AutomaticDelayedStart; + size = Marshal.SizeOf(ds); + delayedAutoStartInfoBuffer = Marshal.AllocCoTaskMem(size); + Marshal.StructureToPtr(ds, delayedAutoStartInfoBuffer, false); + + status = NativeMethods.ChangeServiceConfig2W( + hService, + NativeMethods.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + delayedAutoStartInfoBuffer); + + if (!status) + { + int lastError = Marshal.GetLastWin32Error(); + Win32Exception exception = new Win32Exception(lastError); + WriteNonTerminatingError( + Name, + DisplayName, + Name, + exception, + "CouldNotSetServiceDelayedAutoStart", + ServiceResources.CouldNotSetServiceDelayedAutoStart, + ErrorCategory.PermissionDenied); + } + // Handle the '-Status' parameter if (!string.IsNullOrEmpty(Status)) { @@ -1694,6 +1821,10 @@ protected override void ProcessRecord() } finally { + if (IntPtr.Zero != delayedAutoStartInfoBuffer) + { + Marshal.FreeCoTaskMem(delayedAutoStartInfoBuffer); + } if (IntPtr.Zero != hService) { bool succeeded = NativeMethods.CloseServiceHandle(hService); @@ -1809,12 +1940,12 @@ public string Description /// /// [Parameter] - public ServiceStartMode StartupType + public ServiceStartupType StartupType { get { return startupType; } set { startupType = value; } } - internal ServiceStartMode startupType = ServiceStartMode.Automatic; + internal ServiceStartupType startupType = ServiceStartupType.Automatic; /// /// Account under which the service should run @@ -1865,6 +1996,7 @@ protected override void BeginProcessing() NakedWin32Handle hScManager = IntPtr.Zero; NakedWin32Handle hService = IntPtr.Zero; IntPtr password = IntPtr.Zero; + IntPtr delayedAutoStartInfoBuffer = IntPtr.Zero; try { hScManager = NativeMethods.OpenSCManagerW( @@ -1987,6 +2119,34 @@ protected override void BeginProcessing() ErrorCategory.PermissionDenied); } + // Set the delayed auto start + if(StartupType == ServiceStartupType.AutomaticDelayedStart) { + NativeMethods.SERVICE_DELAYED_AUTO_START_INFO ds = new NativeMethods.SERVICE_DELAYED_AUTO_START_INFO(); + ds.fDelayedAutostart = true; + size = Marshal.SizeOf(ds); + delayedAutoStartInfoBuffer = Marshal.AllocCoTaskMem(size); + Marshal.StructureToPtr(ds, delayedAutoStartInfoBuffer, false); + + succeeded = NativeMethods.ChangeServiceConfig2W( + hService, + NativeMethods.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + delayedAutoStartInfoBuffer); + + if (!succeeded) + { + int lastError = Marshal.GetLastWin32Error(); + Win32Exception exception = new Win32Exception(lastError); + WriteNonTerminatingError( + Name, + DisplayName, + Name, + exception, + "CouldNotNewServiceDelayedAutoStart", + ServiceResources.CouldNotNewServiceDelayedAutoStart, + ErrorCategory.PermissionDenied); + } + } + // write the ServiceController for the new service using (ServiceController service = new ServiceController(Name)) // ensure dispose @@ -1996,6 +2156,11 @@ protected override void BeginProcessing() } finally { + if (IntPtr.Zero != delayedAutoStartInfoBuffer) + { + Marshal.FreeCoTaskMem(delayedAutoStartInfoBuffer); + } + if (IntPtr.Zero != password) { Marshal.ZeroFreeCoTaskMemUnicode(password); @@ -2305,6 +2470,7 @@ internal static class NativeMethods // from winuser.h internal const int ERROR_SERVICE_ALREADY_RUNNING = 1056; internal const int ERROR_SERVICE_NOT_ACTIVE = 1062; + internal const int ERROR_INSUFFICIENT_BUFFER = 122; internal const DWORD SC_MANAGER_CONNECT = 1; internal const DWORD SC_MANAGER_CREATE_SERVICE = 2; internal const DWORD SC_MANAGER_ALL_ACCESS = 0xf003f; @@ -2316,6 +2482,9 @@ internal static class NativeMethods internal const DWORD SERVICE_DEMAND_START = 0x3; internal const DWORD SERVICE_DISABLED = 0x4; internal const DWORD SERVICE_CONFIG_DESCRIPTION = 1; + internal const DWORD SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; + internal const DWORD SERVICE_CONFIG_SERVICE_SID_INFO = 5; + internal const DWORD SERVICE_WIN32_OWN_PROCESS = 0x10; internal const DWORD SERVICE_ERROR_NORMAL = 1; @@ -2336,6 +2505,25 @@ NakedWin32Handle OpenServiceW( DWORD dwDesiredAccess ); + [DllImport(PinvokeDllNames.QueryServiceConfigDllName, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern + bool QueryServiceConfigW( + NakedWin32Handle hSCManager, + IntPtr lpServiceConfig, + DWORD cbBufSize, + out DWORD pcbBytesNeeded + ); + + [DllImport(PinvokeDllNames.QueryServiceConfig2DllName, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern + bool QueryServiceConfig2W( + NakedWin32Handle hService, + DWORD dwInfoLevel, + IntPtr lpBuffer, + DWORD cbBufSize, + out DWORD pcbBytesNeeded + ); + [DllImport(PinvokeDllNames.CloseServiceHandleDllName, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern bool CloseServiceHandle( @@ -2379,6 +2567,26 @@ internal struct SERVICE_DESCRIPTIONW internal string lpDescription; }; + [StructLayout(LayoutKind.Sequential)] + internal struct QUERY_SERVICE_CONFIG + { + internal uint dwServiceType; + internal uint dwStartType; + internal uint dwErrorControl; + [MarshalAs(UnmanagedType.LPWStr)] internal string lpBinaryPathName; + [MarshalAs(UnmanagedType.LPWStr)] internal string lpLoadOrderGroup; + internal uint dwTagId; + [MarshalAs(UnmanagedType.LPWStr)] internal string lpDependencies; + [MarshalAs(UnmanagedType.LPWStr)] internal string lpServiceStartName; + [MarshalAs(UnmanagedType.LPWStr)] internal string lpDisplayName; + }; + + [StructLayout(LayoutKind.Sequential)] + internal struct SERVICE_DELAYED_AUTO_START_INFO + { + internal bool fDelayedAutostart; + }; + [DllImport(PinvokeDllNames.CreateServiceWDllName, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern NakedWin32Handle CreateServiceW( @@ -2460,6 +2668,77 @@ public static extern bool QueryInformationJobObject(SafeHandle hJob, int JobObje ref JOBOBJECT_BASIC_PROCESS_ID_LIST lpJobObjectInfo, int cbJobObjectLength, IntPtr lpReturnLength); + internal static bool QueryServiceConfig(NakedWin32Handle hService, out NativeMethods.QUERY_SERVICE_CONFIG configStructure) + { + IntPtr lpBuffer = IntPtr.Zero; + configStructure = default(NativeMethods.QUERY_SERVICE_CONFIG); + DWORD bufferSize, bufferSizeNeeded = 0; + bool status = NativeMethods.QueryServiceConfigW( + hSCManager: hService, + lpServiceConfig: lpBuffer, + cbBufSize: 0, + pcbBytesNeeded: out bufferSizeNeeded); + + if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) { + return status; + } + + try + { + lpBuffer = Marshal.AllocCoTaskMem((int)bufferSizeNeeded); + bufferSize = bufferSizeNeeded; + + status = NativeMethods.QueryServiceConfigW( + hService, + lpBuffer, + bufferSize, + out bufferSizeNeeded); + configStructure = (NativeMethods.QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(lpBuffer, typeof(NativeMethods.QUERY_SERVICE_CONFIG)); + } + finally + { + Marshal.FreeCoTaskMem(lpBuffer); + } + return status; + } + + internal static bool QueryServiceConfig2(NakedWin32Handle hService, DWORD infolevel, out T configStructure) + { + IntPtr lpBuffer = IntPtr.Zero; + configStructure = default(T); + DWORD bufferSize, bufferSizeNeeded = 0; + + bool status = NativeMethods.QueryServiceConfig2W( + hService: hService, + dwInfoLevel: infolevel, + lpBuffer: lpBuffer, + cbBufSize: 0, + pcbBytesNeeded: out bufferSizeNeeded); + + if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) { + return status; + } + + try + { + lpBuffer = Marshal.AllocCoTaskMem((int)bufferSizeNeeded); + bufferSize = bufferSizeNeeded; + + status = NativeMethods.QueryServiceConfig2W( + hService, + infolevel, + lpBuffer, + bufferSize, + out bufferSizeNeeded); + configStructure = (T)Marshal.PtrToStructure(lpBuffer, typeof(T)); + } + finally + { + Marshal.FreeCoTaskMem(lpBuffer); + } + return status; + } + /// /// Get appropriate win32 StartupType /// @@ -2472,22 +2751,23 @@ public static extern bool QueryInformationJobObject(SafeHandle hJob, int JobObje /// /// If a supported StartupType is provided, funciton returns true, otherwise false. /// - internal static bool TryGetNativeStartupType(ServiceStartMode StartupType, out DWORD dwStartType) + internal static bool TryGetNativeStartupType(ServiceStartupType StartupType, out DWORD dwStartType) { bool success = true; dwStartType = NativeMethods.SERVICE_NO_CHANGE; switch (StartupType) { - case ServiceStartMode.Automatic: + case ServiceStartupType.Automatic: + case ServiceStartupType.AutomaticDelayedStart: dwStartType = NativeMethods.SERVICE_AUTO_START; break; - case ServiceStartMode.Manual: + case ServiceStartupType.Manual: dwStartType = NativeMethods.SERVICE_DEMAND_START; break; - case ServiceStartMode.Disabled: + case ServiceStartupType.Disabled: dwStartType = NativeMethods.SERVICE_DISABLED; break; - case (ServiceStartMode)(-1): + case ServiceStartupType.InvalidValue: dwStartType = NativeMethods.SERVICE_NO_CHANGE; break; default: @@ -2496,8 +2776,44 @@ internal static bool TryGetNativeStartupType(ServiceStartMode StartupType, out D } return success; } + + internal static ServiceStartupType GetServiceStartupType(ServiceStartMode startMode, bool delayedAutoStart) + { + ServiceStartupType result = ServiceStartupType.Disabled; + switch(startMode) + { + case ServiceStartMode.Automatic: + result = delayedAutoStart ? ServiceStartupType.AutomaticDelayedStart : ServiceStartupType.Automatic; + break; + case ServiceStartMode.Manual: + result = ServiceStartupType.Manual; + break; + case ServiceStartMode.Disabled: + result = ServiceStartupType.Disabled; + break; + } + return result; + } } #endregion NativeMethods + + #region ServiceStartupType + /// + ///Enum for usage with StartupType. Automatic, Manual and Disabled index matched from System.ServiceProcess.ServiceStartMode + /// + public enum ServiceStartupType { + ///Invalid service + InvalidValue = -1, + ///Automatic service + Automatic = 2, + ///Manual service + Manual = 3, + ///Disabled service + Disabled = 4, + ///Automatic (Delayed Start) service + AutomaticDelayedStart = 10 + } + #endregion ServiceStartupType } #endif // Not built on Unix diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx index 4a1aa45ee7d..6218714a18c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx @@ -162,15 +162,24 @@ Service '{1} ({0})' cannot be configured due to the following error: {2} + + Service '{1} ({0})' cannot be queried due to the following error: {2} + Service '{1} ({0})' description cannot be configured due to the following error: {2} + + Service '{1} ({0})' automatic (delayed start) cannot be configured due to the following error: {2} + Service '{1} ({0})' cannot be created due to the following error: {2} Service '{1} ({0})' was created, but its description cannot be configured due to the following error: {2} + + Service '{1} ({0})' was created, but its StartupType 'Automatic (Delayed Start)' could not be configured due to the following error: {2} + Service '{1} ({0})' cannot be removed due to the following error: {2} diff --git a/src/System.Management.Automation/utils/PInvokeDllNames.cs b/src/System.Management.Automation/utils/PInvokeDllNames.cs index 619349b888f..1841115f560 100644 --- a/src/System.Management.Automation/utils/PInvokeDllNames.cs +++ b/src/System.Management.Automation/utils/PInvokeDllNames.cs @@ -136,5 +136,7 @@ internal static class PinvokeDllNames internal const string Process32NextDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*122*/ internal const string GetACPDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*123*/ internal const string DeleteServiceDllName = "api-ms-win-service-management-l1-1-0.dll"; /*124*/ + internal const string QueryServiceConfigDllName = "api-ms-win-service-management-l2-1-0.dll"; /*125*/ + internal const string QueryServiceConfig2DllName = "api-ms-win-service-management-l2-1-0.dll"; /*126*/ } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 index 77f3fc62667..e3f189a65d3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 @@ -4,9 +4,19 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW if ( -not $IsWindows ) { $PSDefaultParameterValues["it:skip"] = $true } + if ($IsWindows) { + $userName = "testuserservices" + $testPass = "Secret123!" + net user $userName $testPass /add > $null + $password = ConvertTo-SecureString $testPass -AsPlainText -Force + $creds = [pscredential]::new(".\$userName", $password) + } } AfterAll { $global:PSDefaultParameterValues = $originalDefaultParameterValues + if ($IsWindows) { + net user $userName /delete > $null + } } It "SetServiceCommand can be used as API for '' with ''" -TestCases @( @@ -14,10 +24,8 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW @{parameter = "DisplayName" ; value = "hello"}, @{parameter = "Description" ; value = "hello world"}, @{parameter = "StartupType" ; value = "Automatic"}, - @{parameter = "StartupType" ; value = "Boot"}, @{parameter = "StartupType" ; value = "Disabled"}, @{parameter = "StartupType" ; value = "Manual"}, - @{parameter = "StartupType" ; value = "System"}, @{parameter = "Status" ; value = "Running"}, @{parameter = "Status" ; value = "Stopped"}, @{parameter = "Status" ; value = "Paused"}, @@ -96,10 +104,8 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW @{parameter = "DisplayName" ; value = "hello world"}, @{parameter = "Description" ; value = "this is a test"}, @{parameter = "StartupType" ; value = "Automatic"}, - @{parameter = "StartupType" ; value = "Boot"}, @{parameter = "StartupType" ; value = "Disabled"}, @{parameter = "StartupType" ; value = "Manual"}, - @{parameter = "StartupType" ; value = "System"}, @{parameter = "Credential" ; value = ( [System.Management.Automation.PSCredential]::new("username", #[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Demo/doc/test secret.")] @@ -235,6 +241,33 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW { Remove-Service -Name "testremoveservice" -ErrorAction 'Stop' } | ShouldBeErrorId "InvalidOperationException,Microsoft.PowerShell.Commands.RemoveServiceCommand" } + It "Get-Service can get the '' of a service" -TestCases @( + @{property = "Description"; value = "This is a test description"} + @{property = "BinaryPathName"; value = "$PSHOME\powershell.exe";}, + @{property = "UserName"; value = $creds.UserName; parameters = @{ Credential = $creds }}, + @{property = "StartupType"; value = "AutomaticDelayedStart";} + ) { + param($property, $value, $parameters) + try { + $servicename = "testgetservice" + $startparameters = @{Name = $servicename; BinaryPathName = "$PSHOME\powershell.exe"} + if($parameters -ne $null) { + foreach($key in $parameters.Keys) { + $startparameters.$key = $parameters.$key + } + } else { + $startparameters.$property = $value + } + $service = New-Service @startparameters + $service | Should Not BeNullOrEmpty + $service = Get-Service -Name $servicename + $service.$property | Should BeExactly $value + } + finally { + Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue + } + } + It "Set-Service can accept a ServiceController as pipeline input" { try { $servicename = "testsetservice" @@ -281,11 +314,11 @@ Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnW (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"}, + errorid = "CannotConvertArgumentNoMessage,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"} + errorid = "CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetServiceCommand"} ) { param($cmdlet, $name, $parameter, $value, $errorid) $parameters = @{$parameter = $value; Name = $name; ErrorAction = "Stop"}