Report on Group Policy Objects that have Logon Scripts

Recently, I was asked to generate a report on Group Policy Objects (GPO) that are using logon scripts and also to determine the type of logon script being used. Of course the logical approach is to use PowerShell to make this happen. Prior to this I would have had to mess around with the COM object (GPMgmt.GPM) to make my connection to view GPOs. Fast forward to now and we have the GroupPolicy module which is available on Windows 2008 R2 and above OS. Using this module, I can look at all of the GPOs and generate reports on each as an XML object which allows me to traverse the object to find exactly what I want to know.

First thing is to make sure that the module is available.

Get-Module -Name GroupPolicy

image

To view all of the GPOs all we need to do is use the following command:

Get-GPO -All

image

As you can see, all GPOs are shown with the command. Because I need to scan each GPO to see which ones have a logon script, I will need to iterate through each GPO and use Get-GPOReport –XML to output an string which will then be casted out as an XML object using [xml].

$gpos = @(get-gpo -All)
$xml = [xml]($gpos[0] | Get-GPOReport -ReportType XML)

image

I then have to work through both the User configuration and Computer configuration to determine if either of these are using logon scripts.

Write-Verbose 'User Settings' -Verbose
@($xml.GPO.User.ExtensionData | Where {$_.Name -eq 'Scripts'})
Write-Verbose 'Computer Settings' -Verbose
@($xml.GPO.Computer.ExtensionData | Where {$_.Name -eq 'Scripts'})

image

It looks like the User configuration is where the logon script resides at. Time to dive deeper into the XML object to find out what the script is.

$userScripts = @($xml.GPO.User.ExtensionData | Where {$_.Name -eq 'Scripts'})
If ($userScripts.count -gt 0) {
    $userScripts.extension.Script | ForEach {
        New-Object PSObject -Property @{
            GPOName = $gpo.DisplayName
            ID = $gpo.ID
            GPOState = $gpo.GpoStatus
            GPOType = 'User'
            Type = $_.Type
            Script = $_.command
            ScriptType = $_.command -replace '.*\.(.*)','$1'
        }
    }
}

image

Here you can see that I first check to see if there are in fact any scripts by checking the count. After it has been confirmed, I simply iterate through each possibly script using the extension.script property. I then create a custom object that outputs various properties from the GPO to include the GPO, script, location as well as the script type which I do a simple replace on the name to get the extension of the file.

So with that, I am able to scan all of my GPOs and locate everything single GPO which has a logon script as well as what the script is and its location. I was able to export all of this to a CSV file and send it to the administrator that needed this.

Of course, this makes a nice little script that can be used whenever to generate a report. With that, I have a script called Get-GPOLogonScriptReport.ps1 which you can run (assuming that you have the GroupPolicy Module available and have the proper rights to read all of the GPOs) to quickly find out what GPOs are using logon scripts both for User configurations and Computer configurations. This script is PowerShell V2 and above compatible.

 .\Get-GPOLogonScriptReport.ps1 | 
Export-Csv -NoTypeInformation -Path 'GPOLogonScriptReport.csv'

image

The script uses Write-Progress to track each GPO being scanned and in this case, I am exporting the data being returned to a CSV file for review later on.

Give it a download and let me know what you think!

Download the Script

Get-GPOLogonScriptReport.ps1

This entry was posted in powershell and tagged , , , , . Bookmark the permalink.

8 Responses to Report on Group Policy Objects that have Logon Scripts

  1. Dave Morse says:

    Another Tip
    If you need to include the WmiFilter for each gpo, add the following line to each of the ForEach loop:
    WMIFilter = $gpo.WmiFilter.Description

    What tripped me up was that the WmiFilter property returns an object, which means you need to select the property you need from that embedded object. Easy enough to do once you figure out it is returning an object.

  2. Dave Morse says:

    Excellent Script – Saved me from having to write it myself – Woot!

    I did add a Where-Object clause to the $gpos variable to filter out the GPO’s that do not apply to my OU. It is a shame the Get-GPO commandlet doesn’t include a filter option.

    $gpos = @(Get-GPO -All | Where-Object {$_.DisplayName -like ‘PHD*’})

    Just a little help for anyone with a similar need.

  3. Johan says:

    Boe, this script saved me a lot of time solving my problem, making a script to find the GPO’s with some abandoned scripts in the sysvol folders. Now I can find the GPO with the GPO.ID from the \DC\sysvol\domain\Policiesfolder structure.
    Thanks!
    Johan

  4. MarcoPorco says:

    Great script! I made a small addition locally:

    Parameters = $_.Parameters

    Added in just after “Script = $_.command” in both user and computer sections. This captures those executables that don’t really tell me much like “cscript.exe” along with the parameters that make sense of the “script”.

    Also, I commented out the “start-sleep -seconds 5” line as I can’t see any reason for this. Did you mean for that to stay in there?

  5. Paul says:

    Thank you for this very nice script. Just a comment however: in my case, I ran it first under PowerShell v2.0 and the returned fields “Type”, Script” and “ScriptType” were empty. These fields were OK under PowerShell v3.0 and v4.0. Could it be that a minimal version 3.0 of PowerShell is necessary to get the desired result ?

  6. zaytsevi says:

    small type on the technet gallary
    -NotTypeInformation

    should be -NoTypeInformation

  7. Dean says:

    Very cool.

Leave a comment