#This script returns a unique list of all GPO's linked to an OU. You can also run #a onelevel or subtree search to get a unique list of linked OUs at or below the selected OU. #You are prompted for the domain, and navigate to desired OU. #Alan dot Kaplan at VA dot Gov #4-20-16 #Requires -version 3 #requires -module GroupPolicy #Requires -module ActiveDirectory #Use VB for MsgBox and InputBox Add-Type -assemblyname Microsoft.visualBasic Function NavOU { param([string] $adsPath) # onelevel for speed. $server is a GC $a = Get-ADOrganizationalUnit -searchscope OneLevel -server $server -searchbase $adsPath -Filter 'Name -like "*"' | Select-Object -Property name, distinguishedname | ogv -OutputMode Single -Title "Select an OU and click OK" if ($a.name.length -eq 0) {Exit} $script:adsPath = ($a).distinguishedname $Message = 'The currently selected path is ' + ($a).distinguishedname + '. Continue Navigation?' $retval = [Microsoft.VisualBasic.Interaction]::MsgBox($Message,'YesNo,systemmodal,Question',"Continue Search") if ($retval -eq 'Yes') {NavOU ($a).distinguishedname} } Function GetAdsPath(){ $adDomain = Get-AdDomain $Script:DomName = [Microsoft.VisualBasic.Interaction]::InputBox("Choose Starting Domain:", "Domain Name", $adDomain.dnsroot ) if ($Domname.Length -eq 0) {Exit} #Get a Global Catalog Server $adDomain = Get-AdDomain $domname $gc = get-addomaincontroller -server $DomName -Filter { isGlobalCatalog -eq $true} $script:server = $gc.Item(0).HostName #Write-Host $Server $adspath = $adDomain.DistinguishedName $Message = 'Do you want to select an Organizational Unit of ' + $adspath + '?' $retval = [Microsoft.VisualBasic.Interaction]::MsgBox($Message,'YesNo,systemmodal,Question','Navigate OU Structure?') if ($retval -eq 'Yes') { #Initial Path navOU $adsPath } else { $script:adsPath = $adDomain.DistinguishedName } } function Out-TextBox { [CmdletBinding()] Param ( # StrText help description [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)] $objIn, # Title help description [Parameter(Mandatory=$False, Position=1)] [string]$Title = "Results" ) $strText = $objIn | out-string ######################################################################## # Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0 # By: Alan Kaplan ######################################################################## #region Import the Assemblies [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null #endregion #region Generated Form Objects $DisplayForm = New-Object System.Windows.Forms.Form $textBox1 = New-Object System.Windows.Forms.TextBox $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState #endregion Generated Form Objects $OnLoadForm_StateCorrection= {#Correct the initial state of the form to prevent the .Net maximized form issue $DisplayForm.WindowState = $InitialFormWindowState } #---------------------------------------------- #region Edited Generated Form Code $System_Drawing_Size = New-Object System.Drawing.Size $System_Drawing_Size.Height = 560 $System_Drawing_Size.Width = 660 $DisplayForm.ClientSize = $System_Drawing_Size $DisplayForm.DataBindings.DefaultDataSourceUpdateMode = 0 $DisplayForm.Name = "DisplayForm" $DisplayForm.StartPosition = 1 $DisplayForm.Text = $title $textBox1.DataBindings.DefaultDataSourceUpdateMode = 0 $textBox1.Dock = 5 $System_Drawing_Point = New-Object System.Drawing.Point $System_Drawing_Point.X = 0 $System_Drawing_Point.Y = 0 $textBox1.Location = $System_Drawing_Point $textBox1.Multiline = $True $textBox1.Name = "textBox1" $textBox1.ScrollBars = 3 $System_Drawing_Size = New-Object System.Drawing.Size $System_Drawing_Size.Height = 560 $System_Drawing_Size.Width = 660 $textBox1.Size = $System_Drawing_Size $textBox1.TabIndex = 0 $textBox1.Text = $strText.trim() $textBox1.Font = "Courier New" #This bit de-selects text in box if($displayForm.CanFocus){ $DisplayForm.Focus() }else{ $DisplayForm.Select() } $DisplayForm.Controls.Add($textBox1) #endregion Edited Generated Form Code #Save the initial state of the form $InitialFormWindowState = $DisplayForm.WindowState #Init the OnLoad event to correct the initial state of the form $DisplayForm.add_Load($OnLoadForm_StateCorrection) #Show the Form $DisplayForm.ShowDialog()| Out-Null } #End Function Function ExportGPOs{ $ReportPath = [Microsoft.VisualBasic.Interaction]::InputBox("Write reports to what path?", ` "Path", "$env:userprofile" +'\desktop\' + $domain + ' GPO Reports' ) if ($reportpath.Length -eq 0) {Exit} # if folder does not exist... if (!(Test-Path $ReportPath)) { # create it [void](new-item $ReportPath -itemType directory) } #loosely based on code at #http://proproit.com/group-policy/the-simplest-way-to-get-group-policy-objects-reports/ $GPList.split("`n") | foreach { $Name = $_ Write-Host "Exporting HTML GPO Report for `"$name`" to`n`t`t $reportpath\$name.html" Get-GPOReport -name $name -ReportType HTML -server $domain -Domain $domain -Path $reportpath\$name.html } ii $ReportPath } ## ============== Script Begins ======== $msg = "This script will list and export the GPOs linked to an OU. It can also collect a single unique list of all linked GPOs for sub-OUs." $retval = [Microsoft.VisualBasic.Interaction]::MsgBox($msg,'OkCancel,defaultbutton1,Question', "Linked GPOs") if ($retval -eq "Cancel"){exit} getAdsPath $adsPath = $adsPath.Trim() $arraylist = New-Object System.Collections.ArrayList(,(@{})) $domain = $domName $sb = $adsPath $msg = "Return results Linked GPOs to $sb for:` 1) this OU only (Base)` 2) this OU and the immediate level below (OneLevel)` 3) this OU and all below it (SubTree)`n` 0) Quit" [int]$iScope = [Microsoft.VisualBasic.Interaction]::InputBox($msg,"Search Depth",1) switch ($iScope) { 1{$scope = 'Base'} 2{$scope = 'OneLevel'} 3{$scope = 'Subtree'} Default {Exit} } Write "Getting all GPOs linked in $sb with searchscope of $scope`n" Get-ADOrganizationalUnit -Server $domain -SearchBase $sb -SearchScope $scope -filter * | where {($_.linkedGroupPolicyObjects).count -GT 0} | select distinguishedName | foreach { $GPInfo = get-gpinheritance -Target $_.distinguishedname -Domain $domain $GPInfo | select -ExpandProperty gpolinks | select displayName |foreach {$arraylist.add($_.displayName) | out-null} $GPInfo| select -ExpandProperty InheritedGPOLinks | select DisplayName|foreach {$arraylist.add($_.displayName) | Out-Null} } $Script:GPList = $arraylist | sort | select -Unique cls $msg = "Got the list. Do you want to:` 1) Just show me` 2) Export the list to a file` 3) Export all or part of the list to HTML reports`n` 0) Quit" [int]$iScope = [Microsoft.VisualBasic.Interaction]::InputBox($msg,"Results",1) switch ($iScope) { 1{$GPList | Out-TextBox} 2{ $logfile = "$env:USERPROFILE\desktop\GPOLinkList.txt" $GPList | Add-Content $logfile ii $logfile } 3{ExportGPOs} Default {Exit} } Write "Done"