February 9th, 2009

Hey, Scripting Guy! How Can I List All Group Policy Objects in a Domain?

Hey, Scripting Guy! Question

Hey, Scripting Guy! Do you ever wonder how some people ever get their jobs? We had a guy who was hired to organize our Group Policy implementation. The person was a loser. I mean, I do not think he could even spell Group Policy. Needless to say, the whole thing has morphed into some kind of Salvador Dali Space Elephant that bears little resemblance to the original plan. I know you wrote a book on Active Directory design a few years ago, and I would love to hire you to come straighten this mess out, but I guess that is out of the question. Can I at least get you to write me a script that will tell me what Group Policy objects we have?

– LW

SpacerHey, Scripting Guy! Answer

Hi LW,

So you are the one that bought a copy of that book. Thanks. I wrote a series of Windows PowerShell scripts for the Windows Server 2008 Resource Kit; 10 of the scripts were for Group Policy. In Windows Server 2008 R2, there is a series of Group Policy cmdlets that provide for native Windows PowerShell support. We can also use the COM object that ships with the Group Policy Management Console. The cool thing about this is that the Group Policy Management Console is included in the Microsoft Remote Server Administration Tools (RSAT Tools) for Windows Vista. You can also download it for other versions of the Windows operating system. On Windows Server 2008, you gain access to the Group Policy Management Console when you install the Group Policy Management feature from within Server Manager.

This week is Group Policy week. We will spend the week looking at some of the things you can do using Windows PowerShell when you have access to the COM object that ships with the Group Policy Management Console. There are some good VBScripts that illustrate working with Group Policy in the Script Center Script Repository, and in theCommunity-Submitted Scripts Center. You can also download a collection of sample Group Policy management scripts.

The ListAllGPOs.ps1 script will list all Group Policy Objects (GPOs) in your current domain. You can query for a list of all GPOs in your current domain by running the script with the -q switch. If you use -q and -v, you will get a GPO verbose listing, which includes detailed information about the Group Policy objects. Help with the syntax can be obtained by using -h, -e, and -f. You can type the full switch names if you wish, but there is no real reason to do so unless you just feel the need to practice your typing skills. Here are a few examples of the syntax for launching thescript:

ListAllGPOs.ps1 -q
ListAllGPOs.ps1 -q -v
ListAllGPOs.ps1 -h
ListAllGPOs.ps1 -e
ListAllGPOs.ps1 -f

The complete ListALlGPOs.ps1 script is seen here:

ListAllGPOs.ps1

param(
      $domain = $env:userDNSdomain,
      [switch]$query,
      [switch]$verbose,
      [switch]$help,
      [switch]$examples,
      [switch]$min,
      [switch]$full
      ) #end param
# Begin Functions
function Get-HelpTopic()
{
 $descriptionText= `
@"
 NAME: ListAllGPOs.ps1
 DESCRIPTION:
 Returns detailed information about all GPOs in
 the selected domain
 PARAMETERS:
 -domain domain to return GPO information
 -query perform the query. By default returns name
  and guid of GPO
 -verbose returns extended GPO information
 -help prints help description and parameters file
 -examples prints only help examples of syntax
 -full prints complete help information
 -min prints minimal help. Modifies -help
"@ #end descriptionText
$examplesText= `
@"
 SYNTAX:
 ListAllGPOs.ps1
 Displays an error missing query, and calls help
 ListAllGPOs.ps1  -query
 Lists name and guid of the GPOs in current domain
 ListAllGPOs.ps1 -query -domain "nwtraders.com" -verbose
 Lists detailed GPO information about the GPOs in
 nwtraders.com domain
 ListAllGPOs.ps1 -help
 Prints the help topic for the script
 ListAllGPOs.ps1 -help -full
 Prints full help topic for the script
 ListAllGPOs.ps1 -help -examples
 Prints only the examples for the script
 ListAllGPOs.ps1 -examples
 Prints only the examples for the script
"@ #end examplesText
$remarks = `
"
REMARKS
     For more information, type: $($MyInvocation.ScriptName) -help -full
" #end remarks
  if($examples) { $examplesText ; $remarks ; exit }
  if($full)     { $descriptionText; $examplesText ; exit }
  if($min)      { $descriptionText ; exit }
  $descriptionText; $remarks
  exit
} #end Get-HelpTopic function
function New-Line (
                  $strIN,
                  $char = "=",
                  $sColor = "Yellow",
                  $uColor = "darkYellow",
                  [switch]$help
                 )
{
 if($help)
  {
    $local:helpText = `
@"
     New-Line accepts inputs: -strIN for input string and -char for seperator
     -sColor for the string color, and -uColor for the underline color. Only
     the -strIn is required. The others have the following default values:
     -char: =, -sColor: Yellow, -uColor: darkYellow
     Example:
     New-Line -strIN "Hello world"
     New-Line -strIn "Morgen welt" -char "-" -sColor "blue" -uColor "yellow"
     New-Line -help
"@
   $local:helpText
   break
  } #end New-Line help
 $strLine= $char * $strIn.length
 Write-Host -ForegroundColor $sColor $strIN
 Write-Host -ForegroundColor $uColor $strLine
} #end New-Line function
Function Get-GPO()
{
 New-Line("Listing GPOs from $domain")
 $gpm=New-Object -ComObject gpmgmt.gpm
 $constants = $gpm.GetConstants()
 $gpmDomain = $gpm.GetDomain($domain,$null,$constants.useanydc)
 $gpmSearchCriteria = $gpm.CreateSearchCriteria()
 $gpo=$gpmdomain.SearchGPOs($gpmSearchCriteria)
 if($verbose)
  {
   $gpo
  }
 ELSE
  {
   foreach($ogpo in $gpo)
    {
     $hash += @{ $ogpo.ID = $ogpo.DisplayName }
    }
     format-table -inputobject $hash -autosize
  } #end else
 exit
} #end Get-GPO
# Entry Point
if($help)      { Get-HelpTopic }
if($examples)  { Get-HelpTopic }
if($full)      { Get-HelpTopic }
if($query)     { Get-GPO }
if(!$query)    { "Missing query" ; Get-HelpTopic }

The first thing we do in the ListAllGPOs.ps1 script is define some command-line parameters. The command-line parameters are used to control the way the script behaves at run time. They are very similar to the VBScript command-line arguments. If you want to supply a default value for a command-line parameter, you make a value assignment when you specify the variable that will be used to hold the parameter. If you want to make a switched parameter, you use the [switch] type alias to convert the parameter from a normal parameter to a switched parameter. A switched parameter is one that is a Boolean value (yes/no, true/false), and it only does something when it is present. If the switched parameter is not present on the command line, it is ignored. You do not supply a value when you use a switched parameter, because its very presence changes the behavior of the script:

param(
      $domain = $env:userDNSdomain,
      [switch]$query,
      [switch]$verbose,
      [switch]$help,
      [switch]$examples,
      [switch]$min,
      [switch]$full
      ) #end param

The first function we come to in the script is the Get-HelpTopic function. The Get-HelpTopic function consumes most of the lines in the script. It is made up of a series of Here-Strings. Here-Strings allow you to type information without worrying about things such as escaping special characters. It is a what-you-see-is-what-you-get (WYSIWYG) sort of thing that makes it perfect for developing command-line Help for your script. The Get-HelpTopic function is essentially three large Here-Strings, each of which is assigned to a separate variable. The contents of a particular variable are displayed based upon which switched parameter is supplied from the command line. For more information about this technique, you can refer to the Microsoft Press book, Windows PowerShell Scripting Guide. The Get-HelpTopic function is seen here, with most of the Here-Strings edited out (this will allow you to study the way the function works, without the distraction of dozens of lines of text; the complete function is, of course, shown in the program listing at the beginning of this article):

function Get-HelpTopic()
{
 $descriptionText= `
@"
 NAME: ListAllGPOs.ps1
 DESCRIPTION:
"@
$examplesText= `
@"
 SYNTAX:
 ListAllGPOs.ps1
"@
$remarks = `
"
REMARKS
"@
if($examples) { $examplesText ; $remarks ; exit }
  if($full)     { $descriptionText; $examplesText ; exit }
  if($min)      { $descriptionText ; exit }
  $descriptionText; $remarks
  exit
} #end Get-HelpTopic function

The New-Line function is based upon a function I wrote years ago in VBScript. I have since modified it nearly a dozen times, but the essential capabilities remain the same. It takes the length of a line of text, and creates a line of text that is exactly the same length as the data that is being highlighted via the underline. It is a wonderful function (if I do say so myself), and I used it so much, it is included in my Windows PowerShell profile. The working code for the function (without the associated Help text) is seen here:

$strLine= $char * $strIn.length
 Write-Host -ForegroundColor $sColor $strIN
 Write-Host -ForegroundColor $uColor $strLine

The essential functionality of the script is contained in the Get-GPO function. To work with Group Policy, we need to create an instance of the gpmgmt.gpm COM object. To do this, we use the New-Object cmdlet with the -ComObject parameter as seen here:

$gpm=New-Object -ComObject gpmgmt.gpm

Next we need to retrieve the constants we will use when we connect to the domain. To obtain the constants, all we need to do is use the GetConstants method as seen here:

$constants = $gpm.GetConstants()

Now we need to connect to the domain. To do this, we use the GetDomain method and pass it the domain name, which we have stored in the $domain variable, and we use the constant, which allows us to connect to any domain controller:

$gpmDomain = $gpm.GetDomain($domain,$null,$constants.useanydc)

Now we need to create the search criteria. To do this, we use the CreateSearchCriteria method. The returned SearchCriteria object is stored in the $gpmSearchCriteria variable and passed to the SearchGPO method as seen here:

$gpmSearchCriteria = $gpm.CreateSearchCriteria()
$gpo=$gpmdomain.SearchGPOs($gpmSearchCriteria)

When we have the collection of Group Policy objects, we now look to see if the script was run with the -verbose parameter. If it was, we display all the information about the Group Policy object. If the script was not run with the -verbose parameter, we display only the name of the GPO. The code that makes this determination is seen here:

if($verbose)
  {
   $gpo
  }
 ELSE
  {
   foreach($ogpo in $gpo)
    {
     $hash += @{ $ogpo.ID = $ogpo.DisplayName }
    }
     format-table -inputobject $hash -autosize
  } #end else

The complete Get-GPO function is seen here:

Function Get-GPO()
{
 New-Line("Listing GPOs from $domain")
 $gpm=New-Object -ComObject gpmgmt.gpm
 $constants = $gpm.GetConstants()
 $gpmDomain = $gpm.GetDomain($domain,$null,$constants.useanydc)
 $gpmSearchCriteria = $gpm.CreateSearchCriteria()
 $gpo=$gpmdomain.SearchGPOs($gpmSearchCriteria)
 if($verbose)
  {
   $gpo
  }
 ELSE
  {
   foreach($ogpo in $gpo)
    {
     $hash += @{ $ogpo.ID = $ogpo.DisplayName }
    }
     format-table -inputobject $hash -autosize
  } #end else
 exit
} #end Get-GPO

When the script is run, it produces an output similar to what you see here:

Image of the output produced by the script

 

Well, LW, that is it for gathering a listing of all the GPOs that are defined in the domain. Join us tomorrow as Group Policy Week continues, when we will look at finding unlinked GPOs. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Author

0 comments

Discussion are closed.