This was a good question that came up in my Windows Server 2008 Fundamentals course. The student needed to list all of the server roles on the local server and the services that each role utilizes for a collage class she was taking. This was actually an easy one to resolve.
Import-Module ServerManager
Get-WindowsFeature -ErrorAction Stop |
Where-Object {($_.installed -eq $true) -and ($_.SystemService -ne $Null)} |
Select-Object -Property Name, SystemService
This code requires the ServerManager module. Since it was being executed on the local Windows 2008 R2 server, there was not an issue. What about executing this code against remote clients? At this point, the code is only somewhat reusable. One of my students worked in an environment of over 3000 servers. How could it be usable for him? The help file for Get-WindowsFeature does not show any built in remoting technology. For this reason, we need to enable PowerShell Remoting.
PowerShell remoting is turned on by default on Server 2012 and Windows 8. From Server 20008 R2 and Windows 7, follow these instructions to turn on PowerShell remoting in your domain using Group Policy. Below is the code to all this information to be recovered for remote clients.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | Function Get-RoleServiceUsage { [cmdletbinding()] Param( [Parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)] $Name = "LocalHost" ) Begin {}
Process { ForEach ($Item in (Invoke-Command -ComputerName $Name -ErrorAction Continue ` -ScriptBlock { Param ($Name) Try { Import-Module ServerManager -ErrorAction Stop; Get-WindowsFeature -ErrorAction Stop | Where-Object {($_.installed -eq $true) -and ($_.SystemService -ne $Null)} | Select-Object -Property Name, SystemService } Catch { Write-Host "Error: No ServerManager on Server: " ` -NoNewline -ForegroundColor Red -BackgroundColor DarkRed Write-HOst "$Name"
} } -args $Name ))
{ Write-Output $Item } }
End {}
<# .SYNOPSIS Returns the services being used by server roles.
.DESCRIPTION Returns an object representing each role installed on the server and the services that are being used being used by each role.
.PARAMETER Name The Name of the server to recover role and service information from.
.EXAMPLE "PHX-DC1" | Get-RoleServiceUsage
Name : ADDS-Domain-Controller SystemService : {ntds*, netlogon*, kdc*, ntfrs...} PSComputerName : PHX-dc1 RunspaceId : cd61ea87-1899-484b-887f-29180f7134de PSShowComputerName : True
Name : DNS SystemService : {dns*} PSComputerName : PHX-dc1 RunspaceId : cd61ea87-1899-484b-887f-29180f7134de PSShowComputerName : True
Returns the roles and their respective services from a single client.
.EXAMPLE PHX-DC1" | Get-RoleServiceUsage | ForEach -process {Write-Host $_.Name -BackgroundColor Gray; $_ |Select-Object -ExpandProperty SystemService}
Returns a list of both the roles and ther services, with the roles highlighted.
.NOTES Requires the ServerManager module on each client this cmdlet is executed against.
#> } # End Function: Get-RoleServiceUsage |
Line 1 is the declaration of our function, and the name of the cmdlet that we are creating: Get-RoleServiceUsage.
Lines 2 and 82 encapsulate the code of the function.
Line 3 enables this function to become a cmdlet by allowing the usage of the PowerShell Default Parameters. To read more about the CmdletBinding attribute, take a look at the PowerShell help file About_Functions_Advanced_Parameters.
Line 4 starts our parameter block that ends at line 9
Lines 5 – 8 declares our only parameter, $Name. This will be the name of a server that we want to retrieve information from. Notice that the parameter has a default value of “LocalHost” and can accept input via the PowerShell pipeline. This means we can pipe a comma seperated list of server names into this cmdlet so we can reach out to many servers easily.
Line 10 holds an empty BEGIN block. This block is not used in this code.
Lines 12 – 37 holds our PROCESS block. The Process block will execute once for each name piped to our cmdlet.
Line 14 starts a very complex ForEach statement. Essentially the collection of objects that we are recovering from the servers are gathered starting with (Invoke-Command in line 14 and ends on line 31. The results are stored in $Item for later processing. The Invoke-Command cmdlet is used because we can send code to other clients using the –ComputerName parameter.
Line 15 starts the –ScriptBlock portion of the Invoke-Command cmdlet. Everything inside of the curly braces from line 15 to line 31 is sent to the remote client.
Line 16 allows for a parameter to be sent the the remote client. This parameter is called $Name and the actual value is sent from the –Args parameter on line 31.
Line 17 sets up some error handling. We are looking for a potential error on Lines 19 or 20.
Line 19 will load the ServerManager module on the remote client. If this fails, the Catch block on line 24 will execute.
Lines 20-22 is one continuous PowerShell command. The first cmdlet is Get-WindowsFeature. This cmdlet came from the ServerManager module and it will return a list of objects representing all the roles and features that are available to the remote server.
Line 21 filters the list of objects se we only will be working with objects that are both installed, and use a service as part of their functionality.
Line 22 filters out extra properties and returns to us an object containing the role’s name and the list of services that particular role uses. This is the information that is stored in the variable $Item.
Lines 24 – 30 will handle any errors that occur on lines 19 and 20. This block will execute should you accidental include clients in the search which do not have access to the ServerManage module. Should RSAT be installed, you will get results. This is another avenue for you to look into for additional error handling.
Lines 34-36 execute for each object recovered in the variable $Item from line 14. In this case, the object is simply placed in the PowerShell pipeline.
Line 39 is the END block of our function. It is not used.
Lines 42 – 82 is the help file for this function.
Line 83 ends the function.
Once you load this function into memory, you can access the help file by executing:
Get-Help Get-RoleServiceUsage –Detailed
Take a look at the examples to learn how to use it.
Comments