Default Domain Policy GPOs

Every now and then I find myself wishing I had a documented copy of a clean Default Domain Policy GPO and Default Domain Controllers GPO lying around for reference.

I was setting up a Server 2016 AD lab in Azure today and thought I’d take the opportunity to save a copy of the GPO reports in HTML and PDF format while I was at it. Here they are, in case anybody’s interested:

  • Default Domain Policy [HTML] [PDF]
  • Default Domain Controllers Policy [HTML] [PDF]

 

View the creation date for AD-integrated DNS records

6 months in to my new job, and I’ve still got a big mess of old static DNS records to clean up from our Active Directory-integrated DNS.

The DNS management console doesn’t show any sort of date information, but I knew that because the data is stored in AD, there should be some sort of created/modified date on each record.

I had a look using ADSIEdit, and sure enough, there were the dates! Here’s a quick one-liner to pull out the records and their created/modified dates:

Get-ChildItem "AD:DC=contoso.com,CN=MicrosoftDNS,CN=System,DC=contoso,DC=com" | Get-ADObject -Properties Created,Modified | Select-Object Name,Created,Modified | Sort-Object -Property Created

Armed with the creation date of each record, I’m in a better position to determine which ones are no longer needed.

Office 365/Azure AD: Find all users with an email address that matches a specific string

We have a lot of shared mailboxes in Office 365. Today, I needed to find a subset of those,  change their UPN, and set the FirstName and LastName attributes.

I came across this lengthy PowerShell script that someone had created years ago to find users, but the simplest way to do this is via this one line of PowerShell, once you’ve connected to Azure AD:

Get-MsolUser -MaxResults 1000 | Where-Object {($_.ProxyAddresses -like '*texttomatch*')}

An alternative method, if you’re not connected to Azure PowerShell, but are connected to Exchange Online via PowerShell, is to use Get-Mailbox:

Get-Mailbox -ResultSize 1000 | ? {$_.EmailAddresses -like '*texttomatch*'}

Use PowerShell to remove home directories for users who no longer exist in AD

Today I had to migrate a home directory share to another server. I didn’t want to migrate folders for users who no longer existed in AD or were disabled, so I wrote a script to move those users’ folders into another location.

You could tweak this to be run as a scheduled task, thereby keeping your user home directory share clear of old users’ folders.

Note that this requires the ActiveDirectory PowerShell module in order to enumerate the list of users from AD. I started looking at a fallback method using [adsisearcher], but it wasn’t worth my time.

Note: 2 years later and at a different employer, and I built one using [adsisearcher] to remove user profile folders (not home directories) because I wanted it to run locally on a file server without the requirement to have the AD PowerShell module installed. See the bottom of the page for that update.

$homeDriveRoot = "\server1userfolders"
$leaversRoot = "\server1userfoldersoldusers"

# Get the list of folders in the home drive share
$folders = Get-ChildItem $homeDriveRoot | Select -ExpandProperty Name

# Get the list of active users from AD
$activeUsers =  Get-ADUser -Filter {Enabled -eq $true} | Select -ExpandProperty SamAccountName

# Compare the list of users to the list of folders
$differences = Compare-Object -ReferenceObject $activeUsers -DifferenceObject $folders | ? {$_.SideIndicator -eq "=>"} | Select -ExpandProperty InputObject

# For each folder that shouldn't exist, move it
$differences | ForEach-Object {Move-Item -Path "$homeDriveRoot$_" -Destination "$leaversRoot$_" -Force}

2017 update: Here’s a version using ADSI instead of Active Directory PowerShell that I wrote to remove old roaming user profiles. Note that you’ll need to remove the -WhatIf from the last line to have it actually delete folders

$profilesFolder = 'D:\path\to\profiles'
$profiles = Get-ChildItem $profilesFolder

foreach ($roamingProfile in $profiles) {
 # Split on the dot, because of .V2 and .V4 folders
 $username = $roamingProfile.Name.Split('.')[0]
 
 # Find a matching user using ADSI
 $matchingUser = ([ADSISEARCHER]"samaccountname=$($username)").Findone()
 
 # Skip this folder if we DO find a matching user
 if ($matchingUser -ne $null) { continue }
 
 # Remove the folder
 $roamingProfile | Remove-Item -Recurse -Force -Verbose -WhatIf
}

Copy Active Directory Group Membership with PowerShell

If you need to copy AD group memberships from one user or computer account to another, you can do so with the following two lines of PowerShell.

This depends on the ActiveDirectory module being loaded, or auto-loaded in PS 3.0 or newer.

# Get the memberships from the source computer account
$memberships = Get-ADComputer source -Properties memberof | Select-Object -ExpandProperty memberof

# Apply the memberships to the destination computer account
Get-ADComputer destination | Add-ADPrincipalGroupMembership -MemberOf $memberships -Verbose -WhatIf

Apply GPO based on installed Server Feature (WMI Filtering)

Today I came across a server that had been placed in a sub-OU by a colleague simply for the purposes of applying a GPO to it. The GPO in question was configured to make some changes to the BranchCache feature.

If the policy needs to apply to a subset of all servers in an OU, it would be cleaner to apply a WMI filter to the GPO itself rather than limiting the scope of the GPO by explicit security filtering.

Here’s what I did to clean it up:

  1. Created a WMI filter in GPMC:
    SELECT * FROM Win32_ServerFeature WHERE Name like ‘branchcache%’
  2. Applied the filter to the GPO in question
  3. Applied the GPO to the OU where the server originally lived
  4. Moved the server back to the original OU

This same strategy could be used to apply a policy to all IIS servers, all file servers, etc. The possibilities are practically limitless.

You could even filter on something like Win32_Product to apply a specific GPO to Exchange servers, for example.

SELECT * FROM Win32_Product WHERE name = 'microsoft exchange server'

Don’t use Win32_Product. It’s not a good idea, and even Microsoft warn against using it.