@@ -610,146 +610,163 @@ public string[] Name
610610 /// </summary>
611611 protected override void ProcessRecord ( )
612612 {
613- foreach ( ServiceController service in MatchingServices ( ) )
613+ nint scManagerHandle = nint . Zero ;
614+ if ( ! DependentServices && ! RequiredServices )
614615 {
615- if ( ! DependentServices . IsPresent && ! RequiredServices . IsPresent )
616- {
617- WriteObject ( AddProperties ( service ) ) ;
616+ // As Get-Service only works on local services we get this once
617+ // to retrieve extra properties added by PowerShell.
618+ scManagerHandle = NativeMethods . OpenSCManagerW (
619+ lpMachineName : null ,
620+ lpDatabaseName : null ,
621+ dwDesiredAccess : NativeMethods . SC_MANAGER_CONNECT ) ;
622+ if ( scManagerHandle == nint . Zero )
623+ {
624+ Win32Exception exception = new ( ) ;
625+ string message = StringUtil . Format ( ServiceResources . FailToOpenServiceControlManager , exception . Message ) ;
626+ ServiceCommandException serviceException = new ServiceCommandException ( message , exception ) ;
627+ ErrorRecord err = new ErrorRecord (
628+ serviceException ,
629+ "FailToOpenServiceControlManager" ,
630+ ErrorCategory . PermissionDenied ,
631+ null ) ;
632+ ThrowTerminatingError ( err ) ;
618633 }
619- else
634+ }
635+
636+ try
637+ {
638+ foreach ( ServiceController service in MatchingServices ( ) )
620639 {
621- if ( DependentServices . IsPresent )
640+ if ( ! DependentServices . IsPresent && ! RequiredServices . IsPresent )
622641 {
623- foreach ( ServiceController dependantserv in service . DependentServices )
642+ WriteObject ( AddProperties ( scManagerHandle , service ) ) ;
643+ }
644+ else
645+ {
646+ if ( DependentServices . IsPresent )
624647 {
625- WriteObject ( dependantserv ) ;
648+ foreach ( ServiceController dependantserv in service . DependentServices )
649+ {
650+ WriteObject ( dependantserv ) ;
651+ }
626652 }
627- }
628653
629- if ( RequiredServices . IsPresent )
630- {
631- foreach ( ServiceController servicedependedon in service . ServicesDependedOn )
654+ if ( RequiredServices . IsPresent )
632655 {
633- WriteObject ( servicedependedon ) ;
656+ foreach ( ServiceController servicedependedon in service . ServicesDependedOn )
657+ {
658+ WriteObject ( servicedependedon ) ;
659+ }
634660 }
635661 }
636662 }
637663 }
664+ finally
665+ {
666+ if ( scManagerHandle != nint . Zero )
667+ {
668+ bool succeeded = NativeMethods . CloseServiceHandle ( scManagerHandle ) ;
669+ Diagnostics . Assert ( succeeded , "SCManager handle close failed" ) ;
670+ }
671+ }
638672 }
639673
640674 #endregion Overrides
641675
676+ #nullable enable
642677 /// <summary>
643678 /// Adds UserName, Description, BinaryPathName, DelayedAutoStart and StartupType to a ServiceController object.
644679 /// </summary>
680+ /// <param name="scManagerHandle">Handle to the local SCManager instance.</param>
645681 /// <param name="service"></param>
646682 /// <returns>ServiceController as PSObject with UserName, Description and StartupType added.</returns>
647- private PSObject AddProperties ( ServiceController service )
683+ private static PSObject AddProperties ( nint scManagerHandle , ServiceController service )
648684 {
649- NakedWin32Handle hScManager = IntPtr . Zero ;
650- NakedWin32Handle hService = IntPtr . Zero ;
651- int lastError = 0 ;
652- PSObject serviceAsPSObj = PSObject . AsPSObject ( service ) ;
685+ NakedWin32Handle hService = nint . Zero ;
686+
687+ // As these are optional values, a failure due to permissions or
688+ // other problem is ignored and the properties are set to null.
689+ bool ? isDelayedAutoStart = null ;
690+ string ? binPath = null ;
691+ string ? description = null ;
692+ string ? startName = null ;
693+ ServiceStartupType startupType = ServiceStartupType . InvalidValue ;
653694 try
654695 {
655- hScManager = NativeMethods . OpenSCManagerW (
656- lpMachineName : service . MachineName ,
657- lpDatabaseName : null ,
658- dwDesiredAccess : NativeMethods . SC_MANAGER_CONNECT
659- ) ;
660- if ( hScManager == IntPtr . Zero )
661- {
662- lastError = Marshal . GetLastWin32Error ( ) ;
663- Win32Exception exception = new ( lastError ) ;
664- WriteNonTerminatingError (
665- service ,
666- exception ,
667- "FailToOpenServiceControlManager" ,
668- ServiceResources . FailToOpenServiceControlManager ,
669- ErrorCategory . PermissionDenied ) ;
670- }
671-
696+ // We don't use service.ServiceHandle as that requests
697+ // SERVICE_ALL_ACCESS when we only need SERVICE_QUERY_CONFIG.
672698 hService = NativeMethods . OpenServiceW (
673- hScManager ,
699+ scManagerHandle ,
674700 service . ServiceName ,
675701 NativeMethods . SERVICE_QUERY_CONFIG
676702 ) ;
677- if ( hService == IntPtr . Zero )
703+ if ( hService != nint . Zero )
678704 {
679- lastError = Marshal . GetLastWin32Error ( ) ;
680- Win32Exception exception = new ( lastError ) ;
681- WriteNonTerminatingError (
682- service ,
683- exception ,
684- "CouldNotGetServiceInfo" ,
685- ServiceResources . CouldNotGetServiceInfo ,
686- ErrorCategory . PermissionDenied ) ;
687- }
688-
689- NativeMethods . SERVICE_DESCRIPTIONW description = new ( ) ;
690- bool querySuccessful = NativeMethods . QueryServiceConfig2 < NativeMethods . SERVICE_DESCRIPTIONW > ( hService , NativeMethods . SERVICE_CONFIG_DESCRIPTION , out description ) ;
691-
692- NativeMethods . SERVICE_DELAYED_AUTO_START_INFO autostartInfo = new ( ) ;
693- querySuccessful = querySuccessful && NativeMethods . QueryServiceConfig2 < NativeMethods . SERVICE_DELAYED_AUTO_START_INFO > ( hService , NativeMethods . SERVICE_CONFIG_DELAYED_AUTO_START_INFO , out autostartInfo ) ;
705+ if ( NativeMethods . QueryServiceConfig2 (
706+ hService ,
707+ NativeMethods . SERVICE_CONFIG_DESCRIPTION ,
708+ out NativeMethods . SERVICE_DESCRIPTIONW descriptionInfo ) )
709+ {
710+ description = descriptionInfo . lpDescription ;
711+ }
694712
695- NativeMethods . QUERY_SERVICE_CONFIG serviceInfo = new ( ) ;
696- querySuccessful = querySuccessful && NativeMethods . QueryServiceConfig ( hService , out serviceInfo ) ;
713+ if ( NativeMethods . QueryServiceConfig2 (
714+ hService ,
715+ NativeMethods . SERVICE_CONFIG_DELAYED_AUTO_START_INFO ,
716+ out NativeMethods . SERVICE_DELAYED_AUTO_START_INFO autostartInfo ) )
717+ {
718+ isDelayedAutoStart = autostartInfo . fDelayedAutostart ;
719+ }
697720
698- if ( ! querySuccessful )
699- {
700- WriteNonTerminatingError (
701- service : service ,
702- innerException : null ,
703- errorId : "CouldNotGetServiceInfo" ,
704- errorMessage : ServiceResources . CouldNotGetServiceInfo ,
705- category : ErrorCategory . PermissionDenied
706- ) ;
721+ if ( NativeMethods . QueryServiceConfig (
722+ hService ,
723+ out NativeMethods . QUERY_SERVICE_CONFIG serviceInfo ) )
724+ {
725+ binPath = serviceInfo . lpBinaryPathName ;
726+ startName = serviceInfo . lpServiceStartName ;
727+ if ( isDelayedAutoStart . HasValue )
728+ {
729+ startupType = NativeMethods . GetServiceStartupType (
730+ ( ServiceStartMode ) serviceInfo . dwStartType ,
731+ isDelayedAutoStart . Value ) ;
732+ }
733+ }
707734 }
708-
709- PSProperty noteProperty = new ( "UserName" , serviceInfo . lpServiceStartName ) ;
710- serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
711- serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#UserName" ) ;
712-
713- noteProperty = new PSProperty ( "Description" , description . lpDescription ) ;
714- serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
715- serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#Description" ) ;
716-
717- noteProperty = new PSProperty ( "DelayedAutoStart" , autostartInfo . fDelayedAutostart ) ;
718- serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
719- serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#DelayedAutoStart" ) ;
720-
721- noteProperty = new PSProperty ( "BinaryPathName" , serviceInfo . lpBinaryPathName ) ;
722- serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
723- serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#BinaryPathName" ) ;
724-
725- noteProperty = new PSProperty ( "StartupType" , NativeMethods . GetServiceStartupType ( service . StartType , autostartInfo . fDelayedAutostart ) ) ;
726- serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
727- serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#StartupType" ) ;
728735 }
729736 finally
730737 {
731738 if ( hService != IntPtr . Zero )
732739 {
733740 bool succeeded = NativeMethods . CloseServiceHandle ( hService ) ;
734- if ( ! succeeded )
735- {
736- Diagnostics . Assert ( lastError != 0 , "ErrorCode not success" ) ;
737- }
738- }
739-
740- if ( hScManager != IntPtr . Zero )
741- {
742- bool succeeded = NativeMethods . CloseServiceHandle ( hScManager ) ;
743- if ( ! succeeded )
744- {
745- Diagnostics . Assert ( lastError != 0 , "ErrorCode not success" ) ;
746- }
741+ Diagnostics . Assert ( succeeded , "Failed to close service handle" ) ;
747742 }
748743 }
749744
745+ PSObject serviceAsPSObj = PSObject . AsPSObject ( service ) ;
746+ PSNoteProperty noteProperty = new ( "UserName" , startName ) ;
747+ serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
748+ serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#UserName" ) ;
749+
750+ noteProperty = new PSNoteProperty ( "Description" , description ) ;
751+ serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
752+ serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#Description" ) ;
753+
754+ noteProperty = new PSNoteProperty ( "DelayedAutoStart" , isDelayedAutoStart ) ;
755+ serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
756+ serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#DelayedAutoStart" ) ;
757+
758+ noteProperty = new PSNoteProperty ( "BinaryPathName" , binPath ) ;
759+ serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
760+ serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#BinaryPathName" ) ;
761+
762+ noteProperty = new PSNoteProperty ( "StartupType" , startupType ) ;
763+ serviceAsPSObj . Properties . Add ( noteProperty , true ) ;
764+ serviceAsPSObj . TypeNames . Insert ( 0 , "System.Service.ServiceController#StartupType" ) ;
765+
750766 return serviceAsPSObj ;
751767 }
752768 }
769+ #nullable disable
753770 #endregion GetServiceCommand
754771
755772 #region ServiceOperationBaseCommand
0 commit comments