Build reports and analyze group policies using PowerShell

    The topic of using PowerShell for administration is extremely relevant, and more and more articles on this topic appear on Habré. Jeffrey Hicks’s previous translation of the article , which we published last Friday, sparked a wave of interest. And how can one not recall the remarkable performance of the same author at TechEd North America 2012. The report that Jeffrey Hicks conducted with Jeremy Moskowitz was devoted to the analysis of group policy objects and the generation of reports. The original material (video) is here , but we give briefly the content + scripts. In any case, we recommend watching the video itself.

    The report focused on two issues:
    1. Builds Group Policy Reports
    2. Group Policy Analysis

    Details - under the cut.


    We use PowerShell in conjunction with group policies: what is needed for this?


    To use PowerShell when working with group policies, we need:


    The sequence of our actions:

    • Import Group Policy Module (Import-module GroupPolicy)
    • Get a GPO using PowerShell (Get a GPO PowerShell Object)
    • Build a report based on this object
    • Building HTML / XML Reports on Group Policy Objects
    • Parsim and search in XML for analysis purposes
    • Search using Select-XML and Xpath


    Build Group Policy Reports


    Problem number 1. You need to get information about what is currently happening in group policies


    PS C:\> Import-Module GroupPolicy
    PS C:\> Get-GPO JeremyGPO
    

    In this case, instead of JeremyGPO stands the display name (DisplayName) of the GPO. This plate is displayed

    DisplayName      : JeremyGPO
    DomainName       : GLOBOMANTICS.local
    Owner            : GLOBOMANTICS\Domain Admins
    Id               : cd73c562-5bfe-40e2-b81e-28da10da425c
    GpoStatus        : ComputerSettingsDisabled
    Description      :
    CreationTime     : 12/28/2011 2:52:37 PM
    ModificationTime : 5/21/2012 11:08:26 AM
    UserVersion      : AD Version: 4, SysVol Version: 4
    ComputerVersion  : AD Version: 1, SysVol Version: 1
    WmiFilter        :
    


    Solution: create reports.

    For example, we are faced with the task of obtaining a list of all group objects that have been changed in the last 30 days, sorted in descending order (last at the top) with three values ​​(display name, time of change, description). The received information must be exported to a .csv file (GPOModReport.csv in this example). How it looks in PowerShell:

    PS C:\> get-gpo -all | Where {$_.ModificationTime -gt (Get-Date).AddDays(-30)}
    ... | Sort ModificationTime -Descending | Where {$_.ModificationTime -ge (Get-Date).AddDays(-30)} | Select Displayname,ModificationTime,Description
    ... | Export-CSV R:\GPOModReport.csv
    


    Examples of additional commands
    #Созданные и измененные объекты групповых политик
    PS C:\>get-gpo -all | Sort CreationTime,Modificationtime | Select Displayname,*Time
    


    #Находим все объекты групповых политик, измененные за последние 30 дней 
    PS C:\>get-gpo -all | Where {$_.ModificationTime -ge (Get-Date).AddDays(-30)}
    


    #Создаем отчет по отдельному объекту групповых политик (Defaul Domain Policy)
    PS C:\>Get-GPOReport -name "Default Domain Policy" -ReportType HTML -Path "c:\work\ddp.htm"
    invoke-item "c:\work\ddp.htm"
    


    #Создаем отчеты по всем объектам групповых политик
    PS C:\>Get-GPOReport -All -ReportType HTML -Path "c:\work\allgpo.htm"
    invoke-item "c:\work\allgpo.htm"
    


    #Создаем для каждого объекта групповых политик свой отчет
    #заменяем пробелы на _ в имени GPO
    PS C:\>Get-GPO -all | foreach { 
     $f="{0}.htm" -f ($_.Displayname).Replace(" ","_")
     $htmfile=Join-Path -Path "C:\work" -ChildPath $f
     Get-GPOReport -Name $_.Displayname -ReportType HTML -Path $htmfile
     Get-Item $htmfile 
    }
    



    Problem number 2. Too many GPOs that are not used.


    Task: find empty GPOs


    • Define Group Policy Objects Without Settings
    • Looking for XML ExtensionData


    PS C:\> Import-Module GroupPolicy
    PS C:\> [xml]$r = Get-GPOReport -Name MyGPO 
    -ReportType XML
    PS C:\> if ((-Not $r.gpo.user.extensiondata) -AND (-not $r.gpo.computer.extensiondata)) {
     "GPO is empty"
     }
    


    Additional teams
    #requires -version 2.0
    #find empty gpos in the domain
    Function Get-EmptyGPO {
    Param (
    [Parameter(Position=0,ValueFromPipeline=$True,
    ValueFromPipelinebyPropertyName=$True)]
    [string]$DisplayName
    )
    Begin {
    #import the GroupPolicy Module
    Import-Module GroupPolicy
    }
    Process {
    #create an XML report
    [xml]$report=Get-GPOReport -Name $displayname -ReportType XML
     #totally empty
     if ((-Not $report.gpo.user.extensiondata) -AND (-not $report.gpo.computer.extensiondata)) {
        #no extension data so write
        Get-GPO -Name $Displayname
    }
    } #process
    End {}
    } #function
    Function Test-EmptyGPO {
    Param (
    [Parameter(Position=0,ValueFromPipeline=$True,
    ValueFromPipelinebyPropertyName=$True)]
    [string]$DisplayName
    )
    Begin {
    #import the GroupPolicy Module
    Import-Module GroupPolicy
    }
    Process {
        #set default values
        $User=$False
        $Computer=$False
        #create an XML report
        [xml]$report=Get-GPOReport -Name $displayname -ReportType XML
        if ($report.gpo.user.extensiondata) {
         $User=$True
        }
        If ( $report.gpo.computer.extensiondata) {
         $Computer=$True
        }
        #write a custom object to the pipeline
        New-Object -TypeName PSObject -Property @{
        Displayname=$report.gpo.name
        UserData=$User
        ComputerData=$Computer
        }
    } #Process
    End {}
    } #function
    #Get-GPO -All | Get-EmptyGPO
    #Get-GPO -All | Test-EmptyGPO
    



    Problem number 3.
    Who accessed the GPO?
    Are there GPOs in which half of the policies are deactivated (“Are there any GPOs with 'half' the policy disabled?”)
    Are there GPOs in which all policies are deactivated (“Are there any GPOs with 'all' the policy disabled?”)

    We apply the filter according to the status of GPO (GPOStatus). Each of the three questions above corresponds to three teams:

    PS C:\> get-gpo -all | Sort GPOStatus | format-table -GroupBy GPOStatus Displayname,*Time
    PS C:\> get-gpo -all | where {$_.GPOStatus -match "disabled"} | Select GPOStatus,Displayname
    PS C:\> get-gpo -all | where {$_.GPOStatus -match "AllSettingsDisabled"}
    


    Analyzing Group Policy Objects


    Problem number 4. Discovering GPOs Without Links


    PS C:\> Import-Module ActiveDirectory
    Get-ADOrganizationalUnit -filter * | select-object
    -ExpandProperty DistinguishedName | get-adobject 
    -prop gplink | where {$_.gplink} | Select-object 
    -expand gplink | foreach-object { 
    foreach ($item in ($_.Split("]["))) {
    $links+=$regex.match($item).Value
       } 
    } 
    Get-GPO -All | Where {$links -notcontains $_.id}
    


    Additional teams
    #requires -version 2.0
    <#
     Find unlinked GPOs. This requires the Active Directory Module
     This version does not query for site links
     #>
    Import-Module ActiveDirectory,GroupPolicy
    #GUID regular expression pattern
    [Regex]$RegEx = "(([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12})"
    #create an array of distinguishednames
    $dn=@()
    $dn+=Get-ADDomain | select -ExpandProperty DistinguishedName
    $dn+=Get-ADOrganizationalUnit -filter * | select -ExpandProperty DistinguishedName
    $links=@()
    #get domain and OU links
    foreach ($container in $dn) {
        #pull the GUID and add it to the array of links
        get-adobject -identity $container -prop gplink | 
        where {$_.gplink} | Select -expand gplink | foreach {
          #there might be multiple GPO links so split 
          foreach ($item in ($_.Split("]["))) {
            $links+=$regex.match($item).Value
          } #foreach item
        } #foreach
    } #foreach container
    #$links
    <#
     get all gpos where the ID doesn't belong to the array
     write the GPO to the pipeline
    #>
    Get-GPO -All | Where {$links -notcontains $_.id} 
    



    Problem 5. Group Policy objects with excessive settings in the registry (“Extra Registry Settings”)

    Find excessive settings in the registry
    #Use Xpath with the XML report data
    PS C:\> [xml]$report = Get-GPOReport -Name MyGPO 
    -ReportType XML
    PS C:\> $ns = @{q3 = "http://www.microsoft.com/GroupPolicy/Settings/Registry"}
    PS C:\> $nodes = Select-Xml -Xml $report -Namespace $ns -XPath "//q3:RegistrySetting" | select -expand Node | Where {$_.AdmSetting -eq 'false'}
    


    Additional teams
    #requires -version 2.0
    #find GPOs with extra registry, ie non-ADM settings
    Function Test-GPOExtraRegistry {
    Param (
    [Parameter(Position=0,ValueFromPipeline=$True,
    ValueFromPipelinebyPropertyName=$True)]
    [string]$DisplayName
    )
    Begin {
        #import the GroupPolicy Module
        Import-Module GroupPolicy
    }
    Process {
    #create an XML report
    [xml]$report=Get-GPOReport -Name $displayname -ReportType XML
    #define the XML namespace
    $ns=@{q3="http://www.microsoft.com/GroupPolicy/Settings/Registry"}
    $nodes=Select-Xml -Xml $report -Namespace $ns -XPath "//q3:RegistrySetting" | 
    select -expand Node | Where {$_.AdmSetting -eq 'false'}
    if ($nodes) {
      #extra settings were found so get the GPO and write it to the pipeline
      Get-GPO -Name $Displayname
    }
    }
    End {}
    } #function
    #Import-Module GroupPolicy
    #Get-GPO -all | Test-GPOExtraRegistry 
    



    Once again, we indicate that in the post we presented only the dry residue of what was demonstrated in the report. The report itself can be viewed here .

    Bonuses:


    You can also use our NetWrix Group Policy Change Reporter program to generate group policy reports .

    Also popular now: