Powershell : Dynamic group based on criteria

If you’re familiar with Active Directory, then dynamic groups nothing special but they require very loose filters to be able to make that group dynamic.

If you are looking to filter based on a OU or User account prefix, mailbox status or type of contact then dynamic groups are very good for that.

Custom "dynamic"

If you wish to have a group that is dynamically refreshed with custom attributes more specifically custom scripting then this cannot be accomplished, unless that is you write your own script.

Find you target

In this particular example, I have chosen to look for Java installations based on the uninstalled Registry keys, if these keys are detected, it will be added to a dynamic list of computer computers that will then be added to an active directory group.

Do you need excluded computers?

I’ve also built the option to exclude computers you do not want to include in this group, which may be required if you have exceptions.

Script will automatically refresh members of that group

The group, however, will be automatically refreshed so only computers added by the script will remain in that group, which means if someone secret squirrels a computer account into that group the next time the script is run it will not be in that group.

Script : AppScanner.ps1

# Script to detect Java installations across domain computers and manage AD group membership
# Requires Active Directory PowerShell module and appropriate permissions

# Parameters
$targetADGroup = "Active-JavaComputers"
$searchOUs = @(
    "OU=Servers,DC=bears,DC=local",
    "OU=LegacyServers,DC=bears,DC=local"
)

$excludedComputers = @(
    "COMPUTER1",
    "COMPUTER2",
)

# Import required module
Import-Module ActiveDirectory

# Get computers from specified OUs
$computers = @()
foreach ($ouPath in $searchOUs) {
    try {
        $ouComputers = Get-ADComputer -Filter * -SearchBase $ouPath -Properties Name | 
                      Select-Object -ExpandProperty Name
        $computers += $ouComputers
        Write-Host "Successfully retrieved computers from OU: $ouPath" -ForegroundColor Green
    }
    catch {
        Write-Warning "Error accessing OU $ouPath : $_"
        $errors += "OU Access : Error accessing $ouPath : $_"
    }
}

# Initialize arrays for results
$computersWithJava = @()
$errors = @()

# Function to check for Java installation
function Test-JavaInstallation {
    param (
        [string]$computerName
    )
       try {
        $java32 = Invoke-Command -ComputerName $computerName -ScriptBlock {
            Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
            Where-Object { $_.DisplayName -like "*Java*" }
        } -ErrorAction Stop
        $java64 = Invoke-Command -ComputerName $computerName -ScriptBlock {
            Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
            Where-Object { $_.DisplayName -like "*Java*" }
        } -ErrorAction Stop
        if ($java32 -or $java64) {
            return $true
        }
        return $false
    }
    catch {
        Write-Warning "Error checking Java on $computerName : $_"
        $script:errors += "$computerName : $_"
        return $false
    }
}

# Process each computer
foreach ($computer in $computers) {
    # Skip if computer is in excluded list
    if ($excludedComputers -contains $computer) {
        Write-Host "Skipping excluded computer: $computer" -ForegroundColor Yellow
        continue
    }
    Write-Host "Checking $computer..." -NoNewline
    if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {
        if (Test-JavaInstallation -computerName $computer) {
            $computersWithJava += $computer
            Write-Host " Java found!" -ForegroundColor Green
        }
        else {
            Write-Host " No Java installation found." -ForegroundColor Gray
        }
    }
    else {
        Write-Host " Offline" -ForegroundColor Red
        $errors += "$computer : Offline"
    }
}

# Create or get the AD group
try {
    $group = Get-ADGroup -Identity $targetADGroup
}
catch {
    Write-Host "Creating AD group: $targetADGroup"
    $group = New-ADGroup -Name $targetADGroup -GroupScope Global -GroupCategory Security
}

# Backup current group membership before making changes
$currentMembers = Get-ADGroupMember -Identity $targetADGroup -ErrorAction SilentlyContinue
if ($currentMembers) {
    $backupDate = Get-Date -Format "yyyyMMdd_HHmmss"
    $currentMembers | Select-Object Name | Export-Csv
"GroupMembership_Backup_$backupDate.csv"
    Write-Host "Current group membership backed up to GroupMembership_Backup_$backupDate.csv" -ForegroundColor Cyan
}

# Remove all existing members from the group
try {
    if ($currentMembers) {
        Remove-ADGroupMember -Identity $targetADGroup -Members $currentMembers -Confirm:$false -ErrorAction Stop
        Write-Host "Cleared existing group membership" -ForegroundColor Yellow
    }
}
catch {
    Write-Warning "Error clearing group membership: $_"
    $errors += "Group Cleanup : Error clearing membership: $_"
}

# Add new members based on scan results
foreach ($computer in $computersWithJava) {
    try {

        $computerObject = Get-ADComputer -Identity $computer
        Add-ADGroupMember -Identity $targetADGroup -Members $computerObject -ErrorAction Stop
        Write-Host "Added $computer to $targetADGroup" -ForegroundColor Green
    }
    catch {
        Write-Warning "Error adding $computer to group: $_"
        $errors += "$computer : Error adding to group: $_"
    }
}

# Output results
Write-Host "`nSummary:" -ForegroundColor Cyan
Write-Host "Total computers checked: $($computers.Count)"
Write-Host "Computers with Java: $($computersWithJava.Count)"
Write-Host "Computers in exclusion list: $($excludedComputers.Count)"
Write-Host "Previous group members: $($currentMembers.Count)"
Write-Host "Number of OUs searched: $($searchOUs.Count)"

# Export results to files
$computersWithJava | Out-File "JavaComputers.txt"
$errors | Out-File "JavaDetection_Errors.txt"
Write-Host "`nDetailed results have been exported to JavaComputers.txt and JavaDetection_Errors.txt"

When the script completes it will tell you how many computers are now in the group defined in the script as the variable:


Now if you search your domain for this group with the command:

Get-ADGroup Active-JavaComputers

This will confirm the group has been created as below:


Then if you wish to see the members or more importantly ensure all the computers are in that group you can run this command to get a count:

(Get-ADGroupMember Active-JavaComputers).count

This should confirm the correct number of computers are indeed in that directory group which in this case is 90 and that will be returned in the prompt, if you wish to see a list of all the members run this command:

Get-ADGroupMember Active-JavaComputers | Select name

Previous Post Next Post

نموذج الاتصال