Author Posts

August 13, 2013 at 5:26 am

Hi guys, does anyone know of a good working script that will pull all the GP's on a specific AD container and sub-containers and generate an html report?

August 13, 2013 at 7:37 am

Are you using Server 2012? Because it's pretty easy there:

Get-GPO -All |
   Where-Object {$_.Path.EndsWith('cn=system,DC=corp,DC=poshoholicstudios,DC=com')} |
   ConvertTo-Html -Property DisplayName,Id,Owner,CreationTime,ModificationTime

There is also a good free ebook about generating HTML reports on this site.

August 13, 2013 at 8:57 am

Thanks, which part of the code tells it to pull the gpo's from the sub containers? Or do you specify each container manually?

August 13, 2013 at 10:22 am

In the Where-Object clause (the filter), PowerShell is checking to see what the path (the distinguished name) ends with. If you put the top-level DN for one container in there, all child containers will end with that DN as well, so they will automatically pass the filter. Anything else will be excluded.

Also note that this is client-side filtering, not server-side filtering. Unfortunately I didn't see a filter for the Get-GPO command that would allow for more efficient filtering, so you'd have to use some other method if you want server-side filtering involved.

August 13, 2013 at 10:34 am

I've tried to run this code, sub'd the cn=users,DC=corp,DC=mydomainname,DC=com, but it returns blank results, i've tried to | out-file it to an html document, but it's also blank, why is it not working? I clearly have GPO's set on the "Users" container. When I run the get-gpo -all I see all the gpos in general, so i think there is a problem with the 2nd line.

August 13, 2013 at 11:06 am

You'll need to look at the Path property of the GPO's you get back. If the command returns nothing with the Where-Object clause in the pipeline, make sure the Where-Object clause isn't filtering too much (i.e. Double-check your filter string. Should it start with cn=? Or should it start with ou=?).

August 13, 2013 at 11:20 am

I think there's some confusion between the path to the GPO and the path to the OU(s) where the GPO is linked. The actual GPOs are always located in the System\Policies container of the domain.

To find GPOs based on whether they're linked to an OU, you'd do something like this:

Get-ADOrganizationalUnit -Filter * -SearchBase 'cn=users,DC=corp,DC=mydomainname,DC=com' -SearchScope 'Subtree' |
ForEach-Object {
    foreach ($gpoDN in $_.LinkedGroupPolicyObjects)
    {
        # Here, do something with $gpoDN (such as make a call to Get-GPO, Get-GPOReport, etc)
        Write-Host "Linked to OU '$($_.distinguishedName)': '$gpoDN'"
    }
}

August 13, 2013 at 11:23 am

I've changed it to the OU=Users, same results, I took out the OU=Users completely (leaving only the DC=corp,DC=mydomainname,DC=com) and it displays all the GPO's. I checked the path property of one of the GPO's by piping it to the get-member, and it says "Path Property string Path {get;}" not sure what it means though.

August 13, 2013 at 11:50 am

@dave – Thanks, I have tried it, but it also returns nothing in the results, I have tried different OU's with similar results.

August 13, 2013 at 11:56 am

As a starting point, you could try getting rid of the SearchBase and SearchScope options, and just use it this way:

Get-ADOrganizationalUnit -Filter * |
ForEach-Object {
    foreach ($gpoDN in $_.LinkedGroupPolicyObjects)
    {
        # Here, do something with $gpoDN (such as make a call to Get-GPO, Get-GPOReport, etc)
        Write-Host "Linked to OU '$($_.distinguishedName)': '$gpoDN'"
    }
}

If you're not getting output here, I'm not sure what's going on. Maybe that LinkedGroupPolicyObjects property is only added in PowerShell v3 (which is what I used to test this code, on a Windows Server 2012 box). If that's the case, you can work with the gpLink LDAP attribute directly, though you'll have to do a little bit of string parsing.

August 13, 2013 at 12:30 pm

Eghhh still no luck, I am using powershell 3.0...

Getting this message –

"cmdlet Get-GPO at command pipeline position 1
Supply values for the following parameters:
Guid: "

August 13, 2013 at 12:54 pm

There's no call to Get-GPO in the code I posted, so you must have changed it. Looks like you'll need to obtain the GUID for the calls to Get-GPO, though (unless you're using the -All switch). The distinguished name of a GPO should contain the GUID (CN={GUID}, etc), if you want to just parse the string, like this:

Get-ADOrganizationalUnit -Filter * |
ForEach-Object {
    foreach ($gpoDN in $_.LinkedGroupPolicyObjects)
    {
        # Here, do something with $gpoDN (such as make a call to Get-GPO, Get-GPOReport, etc)
        Write-Host "Linked to OU '$($_.distinguishedName)': '$gpoDN'"

        # Example obtaining the GUID with string parsing of the DN, and calling Get-GPO
        if ($gpoDN -match '^CN=({[0-9A-F-]+}),')
        {
            $guid = $matches[1]
            Get-GPO -Guid $guid
        }
    }
}