Summary: Use Windows PowerShell to display service dependencies on Windows for troubleshooting shutdown problems in Windows 7.
Hey, Scripting Guy! I have a problem on my Windows 7 PC. It hangs on shutdown from time to time. I have done some searches on the Internet, and it seems other people have reported similar problems. The cause appears to be related to either crappy video drivers or crappy audio drivers, depending on whose website I am reading. One site suggested creating a .bat file to stop the services manually before shutting down the workstation. I would like to use Windows PowerShell to write such a script, but I need to find out information about the service dependencies. I looked at using WMI to find service dependencies, but I do not see any information via the Win32_Service WMI class. Can you help me?
— VG
Hello VG,
Microsoft Scripting Guy Ed Wilson here. One of the cool things about Twitter is that it allows you to communicate with thousands of people instantaneously. One of the cool things about Windows PowerShell is that the code can be so short, it fits into the limitations of a tweet. This makes Twitter and Windows PowerShell an awesome combination. As a case in point, I posted a tweet about listing colors that are used by the Write-Host cmdlet. One of the Scripting Guy forum moderators saw the tweet and posted a line of code he uses to display both the console colors and the name of the console color. The cool thing is that I was familiar with the .NET Framework class he used, but I had never written that line of code before. I added it to the discussion in this post. Way cool! While I had Trevor on the line, I also asked him if he would like to write a guest blog article. He said yes, so we have that to look forward.
VG, none of that has anything to do with services, but it has to do with the display of service names in the Get-ServiceDependencies.ps1 script that is shown here.
Get-ServiceDependencies.ps1
Get-Service -CN . | Where-Object { $_.status -eq ‘running’} |
ForEach-Object {
write-host -ForegroundColor 9 “Service name $($_.name)”
if($_.DependentServices)
{ write-host -ForegroundColor 3 “`tServices that depend on $($_.name)”
foreach($s in $_.DependentServices)
{ “`t`t” + $s.name }
} #end if DependentServices
if($_.RequiredServices)
{ Write-host -ForegroundColor 10 “`tServices required by $($_.name)”
foreach($r in $_.RequiredServices)
{ “`t`t” + $r.name }
} #end if DependentServices
} #end foreach-object
The Get-ServiceDependencies.ps1 script uses the Get-Service cmdlet to retrieve information about services on the computer. You can use the Get-Service cmdlet to run against a local computer or a remote computer. When running against a remote computer, the Windows Firewall must be modified to permit the cmdlet through the firewall. In addition, you must have administrative permission on the remote machine. Unfortunately, there is neither a –filter parameter for Get-Service, nor a –credential parameter. This means that all services are returned by the Get-Service cmdlet. It also means that you cannot supply alternative credentials for the Get-Service cmdlet.
The period is a shortcut to specify the local host; it works for the Get-Service cmdlet and other cmdlets. Because there is no filter parameter for the Get-Service cmdlet, it is necessary to pipe the results of the Get-Service cmdlet to the Where-Object cmdlet. The property status is checked and if the status indicates the service is running, the ServiceController object is passed along the pipeline to the ForEach-Object cmdlet. Each service is an instance of the System.ServiceProcess.ServiceController .NET Framework class and as such has a large number of properties and methods available to it. Check MSDN for all the things you can do with the ServiceController class. The part of the script that retrieves all the services on the local computer and filters them out to find only the ones that are running is shown here:
Get-Service -CN . | Where-Object { $_.status -eq ‘running’} |
The ServiceContoller .NET Framework class has two properties that are extremely interesting. The first one is the dependentServices property, and the second one is the RequiredServices property. This makes it easy to find service dependencies. The ForEach-Object cmdlet takes each ServiceController object as it comes across the pipeline, and allows us to work with them individually. The Write-Host cmdlet is used to write the name of the service to the Windows PowerShell output in color.
The color combinations that can be used with the Write-Host cmdlet are limited to 16 colors. However, when selecting colors, I find it hard to visualize how yellow, or green might show up. Therefore, I use a simple line of code to display all the colors to the Windows PowerShell ISE output pane. This is seen here.
0..15 | % { Write-Host -ForegroundColor $_ “$_” }
The 0..15 line creates an array of 16 numbers. This is seen here.
PS C:\> $a = 0..15
PS C:\> $a.GetType()IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True Object[] System.ArrayPS C:\>
Each of the numbers is passed over the pipeline to the ForEach-Object cmdlet. The % symbol is an alias for the ForEach-Object cmdlt. The $_ character refers to the current number on the pipeline. It therefore changes the foreground color to the color represented by the number. As seen in the following image, some of the colors are nearly invisible, and many of the other colors are pretty well washed out. It then becomes a simple matter to select colors that you like and that show up well in the Windows PowerShell ISE output pane. Keep in mind that if you have changed the color scheme for the Windows PowerShell ISE by following the discussion in our recent Weekend Scripter posts about the ISE, you will need to choose different color values for your environment.
Trevor Sullivan (pcgeek86 on Twitter), one of the moderators on the Official Scripting Guys Forum and a consultant from Chicago, saw my tweet about the above line of code to display colors via Write-Host, and he mentioned that he likes to see the color names. To display the colors and the color names, he queries the static properties from the system.consolecolor .NET Framework class. He uses the Get-Member cmdlet to retrieve the static properties. Static properties of the consolecolor class are shown here:
PS C:\> [consolecolor] | gm -st -m property
TypeName: System.ConsoleColor
Name MemberType Definition
—- ———- ———-
Black Property static System.ConsoleColor Black {get;}
Blue Property static System.ConsoleColor Blue {get;}
Cyan Property static System.ConsoleColor Cyan {get;}
DarkBlue Property static System.ConsoleColor DarkBlue {get;}
DarkCyan Property static System.ConsoleColor DarkCyan {get;}
DarkGray Property static System.ConsoleColor DarkGray {get;}
DarkGreen Property static System.ConsoleColor DarkGreen {get;}
DarkMagenta Property static System.ConsoleColor DarkMagenta {get;}
DarkRed Property static System.ConsoleColor DarkRed {get;}
DarkYellow Property static System.ConsoleColor DarkYellow {get;}
Gray Property static System.ConsoleColor Gray {get;}
Green Property static System.ConsoleColor Green {get;}
Magenta Property static System.ConsoleColor Magenta {get;}
Red Property static System.ConsoleColor Red {get;}
White Property static System.ConsoleColor White {get;}
Yellow Property static System.ConsoleColor Yellow {get;}
He then pipelines the property names to the Write-Host cmdlet to display the color name in color. (Who’s on first?) Here is his line of code:
[consolecolor] | gm -st -m property | % { write-host -f $_.Name $_.Name }
Back to the Get-ServiceDependencies.ps1 script. When the service name has been displayed, if there are any dependent services, this fact is displayed by tabbing over one spot, displaying the service name, and stating there are dependencies. The ForEach statement is used to walk through the collection of dependent services, and the dependent service name is displayed two tab spots over. This portion of the script is shown here:
ForEach-Object {
write-host -ForegroundColor 9 “Service name $($_.name)”
if($_.DependentServices)
{ write-host -ForegroundColor 3 “`tServices that depend on $($_.name)”
foreach($s in $_.DependentServices)
{ “`t`t” + $s.name }
} #end if DependentServices
If the service requires other services, those services can be detailed from the RequiredServices property. The if statement is used to determine if there are any required services. If there are, the Write-Host cmdlet is used to display the service name and each of the required services. The required services are stored as an array in the RequiredServices property, and after tabbing over two spots, the name of the required service is printed out. This portion of the script is shown here:
if($_.RequiredServices)
{ Write-host -ForegroundColor 10 “`tServices required by $($_.name)”
foreach($r in $_.RequiredServices)
{ “`t`t” + $r.name }
} #end if DependentServices
When the Get-ServiceDependencies.ps1 script runs, the output is displayed that is shown in the following image.
VG, that is all there is to using Windows PowerShell to retrieve information about service dependencies. WMI Week will continue tomorrow when we will continue to talk about working with services.
We would love for you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments