Fix Remote Group Policy Modelling Delegation

Recently I was trying to delegate Group Policy Modelling in an AD Domain so that we could remotely query RSoP data from a management server with RSAT installed. I had assumed this was as simple as granting a user or group the ‘Generate Resultant Set of Policy (Planning)’ permission from the AD Delegation Wizard.

When I tested granting this to my group, I was not able to model RSoP data using the Group Policy Management Console. So went digging and worked through this in my lab to come to an understanding of the issue.

After some trial and error, I realised the Windows Component Object model (COM) governs remote access to domain controllers which is required for remotely accessing Group Policy Modelling.

By default, the following groups have security limits set to allow:
Everyone: Local Launch, Local Activation
Administrators: Local Launch, Local Activation, Remote Launch, Remote Activation
Performance Log Users: Local Launch, Local Activation, Remote Launch, Remote Activation
Distributed COM Users: Local Launch, Local Activation, Remote Launch, Remote Activation

I tried adding my test user to the builtin ‘Distributed COM Users‘ group and wallah! I was able to use Group Policy Modelling remotely.

Group Description: Members are allowed to launch, activate and use Distributed COM objects on this machine.

Unless a user is a member of one of the above groups with Remote Activation set to ‘allow’, then they will be instantly denied when they try to do Group Policy Modelling remotely.

I have confirmed this by logging into a member server with RSAT installed, as a Domain Admin user, then on a domain controller, unticking ‘allow’ for the Administrators group for Remote Activation on properties of the ‘Component Services\Computers\My Computer’ object on the ‘COM Security’ tab in ‘edit limits’:

In this state, a Domain Admin is unable to invoke Group Policy Modelling remotely. If I re-tick remote activation (default state) then the Domain Admin can perform Group Policy Modelling remotely.

But what happens if you have multiple domain controllers? You don’t want to have to set this individually on every domain controller, and also set it on any new domain controllers that may be added later. A colleague and I were discussing this, and he managed to find a Windows Server 2003 article that is still relevant, and available on the Wayback machine, albeit long gone from the public internet.

https://web.archive.org/web/20140501014941/http:/support.microsoft.com/kb/914047

As you can see, Microsoft call out this exact issue, and also provide a solution for deploying the access to multiple domain controllers. Even better, it makes it straight forward to create your own delegation group and apply it to all domain controllers:

Once the GPO has been set, the setting cannot be controlled from Component Services, so ensure you capture current settings and ensure anything non-default is also added to your policy.

Hopefully this helps someone! Thanks for reading.

Get Windows 10 Version Information

This morning I needed to quickly get Windows 10 version information for all workstations in a domain, so I wrote the below PowerShell script. This basic script only needed a few things to get the job done; a way to get all workstations in the domain, a way to only check computers that are online at the time, so the script doesn’t take too long with all the failures generated by offline systems, and the registry keys to determine the current OS build and minor version.

Import-Module -Name ActiveDirectory

$all_computers = Get-ADComputer -Filter * -SearchBase 'OU=computers,DC=somedomain,DC=com' | Select-Object -Property Name

$ExportPath = "$env:TEMP\$(Get-date -Format 'yyyyMMddhhmmss')_workstation_os_build_report.csv"

foreach ($c in $all_computers.name)

{

    if (Test-Connection -ComputerName $c -count 1 -Quiet ) {

    Write-Host "Processing $c" -ForegroundColor Cyan

    $CurrentBuild = ""
    $UBR = ""
    $OSVersion = ""
    $ComputerSystem = ""
    $props = ""
    $obj = ""

        $CurrentBuild = Invoke-Command -ComputerName $c -ScriptBlock { (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' –Name CurrentBuild).CurrentBuild } -ErrorAction SilentlyContinue
        $UBR = Invoke-Command -ComputerName $c -ScriptBlock { (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' –Name UBR).UBR } -ErrorAction SilentlyContinue
        $OSVersion = $CurrentBuild + "." + $UBR
        $ComputerSystem = Get-WmiObject -ComputerName $c -Class Win32_ComputerSystem -ErrorAction SilentlyContinue

       $props = [ordered]@{ 
        'HostName' = $ComputerSystem.Name;
        'OSVerion' = $OSVersion
        }
        $obj = New-Object -TypeName PSObject -Property $props

    Write-Output $obj | Export-Csv -Path $ExportPath -NoTypeInformation -Append -NoClobber -Force
    }
    else {
        Write-Host "$c is offline..." -ForegroundColor Green
    }

}
Write-Host "Output csv file is located here: `n `n $ExportPath `n" -ForegroundColor Yellow

Obviously there are a few issues with this script. It won’t get systems that are turned off, PowerShell remoting needs to be enabled/working, and in a large domain, it’s probably going to take a long time without some sort of parallelisation or a more efficient way of querying each host…. regardless, this was just a quick indicator for me of the general patch levels of systems in the domain.

Code also on my github here.

Thanks for reading.

Get all AD group members with PowerShell

I was recently doing an audit of AD group memberships and since I find it easier to do this by filtering a spreadsheet, I needed to get all groups and their members out to a CSV. This basic script does the job and captures key properties like the name, DN and SID for the group as well as the name, DN, SID and object class for the member. This information would be enough to re-create a group structure and re-populate members if you needed to.

# Get All AD Group members for all groups

$groups = Get-ADGroup -Filter *

foreach ($group in $groups) {

$members = Get-ADGroupMember -Identity $group

    foreach ($member in $members) {

            [PSCustomObject]@{
            GroupName = $group.Name
            GroupDN = $group.DistinguishedName
            GroupSID = $group.SID
            MemberName = $member.name
            MemberDN = $member.DistinguishedName
            MemberSID = $member.SID
            MemberObjectClass = $member.ObjectClass
            } | Export-Csv -Path C:\temp\all_adgroupmembers_20220323_1.csv -NoClobber -NoTypeInformation -Append 
        }

}

Code also on my github here.

Thanks for reading.