Server 2025 Domain Controller Not on Domain

As reported here and here, a Server 2025 domain controller does not properly detect that it is on the domain. The Server 2022 workaround, with registry entries like AlwaysExpectDomainController that I blogged here, no longer works. The workaround is to restart the Public network adapter(s) after each server boot.

I used Gemini to write a PowerShell script that would restart Public network adapters. It took quite a bit of debugging, and I tweaked some of the logging. Here’s the script. As always, use at your own risk!

<#
.Synopsis
  Find network adapters with NetworkCategory = Public and restart them.
  Run this a minute after each Server 2025 Domain Controller restart to get the DC back on the domain.
  This writes to the Application event log with Source "IT Script" and Event IDs 1100 - 1104.

  Copyright (c) 2025 by MCB Systems. All rights reserved.
  Free for personal or commercial use.  May not be sold.
  No warranties.  Use at your own risk.

.Notes 
    Name:       MCB.RestartPublicNetAdapters.ps1
    Author:     Mark Berry, MCB Systems
    Created:    03/19/2025
    Last Edit:  03/19/2025
    
    Changes:
#>

################################################################################
# Functions
################################################################################

# Function to write messages to both console and event log. 
function Write-Log {
    param (
        [string]$Message,
        [string]$Type = "Information", # Information, Warning, Error
        [int]$EventId = 0 # Default Event ID
    )

    # Prepend the name (not the full path) of the running script
    $Message = (Split-Path $PSCommandPath -Leaf) + ": " + $Message

    switch ($Type) {
        "Information" {
            Write-Host $Message
            Write-EventLog -LogName $EventLogName -Source $EventLogSource -EntryType Information -Message $Message -EventId $EventId
        }
        "Warning" {
            Write-Warning $Message
            Write-EventLog -LogName $EventLogName -Source $EventLogSource -EntryType Warning -Message $Message -EventId $EventId
        }
        "Error" {
            Write-Error $Message
            Write-EventLog -LogName $EventLogName -Source $EventLogSource -EntryType Error -Message $Message -EventId $EventId
        }
    }
}

################################################################################
# Setup
################################################################################

$EventLogName = "Application"
$EventLogSource = "IT Script"
$WaitSeconds = 30

# Check if the event source exists, create it if not
if (-not ([System.Diagnostics.EventLog]::SourceExists($EventLogSource))) {
    New-EventLog -LogName $EventLogName -Source $EventLogSource
}

#################################################################################
# Check for Public adapters and restart
################################################################################

# Get all network adapters with NetworkCategory "Public"
# The (@(...)) operator ensures that the result of the pipeline is always treated as an array, even if it contains only one element.
$PublicAdapters = @(Get-NetConnectionProfile | `
                    Where-Object {$_.NetworkCategory -eq "Public"} | `
                    ForEach-Object { Get-NetAdapter -InterfaceAlias $_.InterfaceAlias })

# Check if any public adapters were found
if ($PublicAdapters.Count -gt 0) {
    Write-Log "Found $($PublicAdapters.Count) Public network adapter(s). Will attempt restart to re-detect domain." -EventId 1100

    # Loop through each public adapter and restart it
    foreach ($Adapter in $PublicAdapters) {
        try {
            $NetworkCategory = (Get-NetConnectionProfile -InterfaceAlias $Adapter.Name).NetworkCategory # shoudl be Public, but re-confirm
            Write-Log "Restarting adapter: $($Adapter.Name), which is currently $NetworkCategory." -EventId 1101
            Restart-NetAdapter -Name $Adapter.Name -Confirm:$false
            Write-Log "Waiting $WaitSeconds seconds for Windows to identify the domain."
            Start-Sleep -Seconds $WaitSeconds
            $NetProfile = Get-NetConnectionProfile -InterfaceAlias $Adapter.Name
            $NetProfileName = $NetProfile.Name
            $NetworkCategory = $NetProfile.NetworkCategory
            if ($NetProfileName -eq "Identifying...") {
                Write-Log "Adapter $($Adapter.Name) restarted successfully. After waiting $WaitSeconds seconds, its Name still shows as $NetProfileName, so the NetworkCategory $NetworkCategory is not final." -EventId 1102
            } else {
                Write-Log "Adapter $($Adapter.Name) restarted successfully. Its Name is now $NetProfileName and its NetworkCategory is $NetworkCategory." -EventId 1103
            }
        }
        catch {
            Write-Log "Failed to restart adapter $($Adapter.Name): $($_.Exception.Message)" -Type Error -EventId 1104
        }
    }
} else {
    Write-Log "No Public network adapters found, so no adapters restarted." -EventId 1105
}

I’ve deployed that as follows:

1. Put the script on the server.

2. Create a RestartPublicNetAdapters.cmd file to run the script, for example:

cd /d C:\Scripts\PowerShell
powershell.exe -NoLogo -NoProfile -NonInteractive ".\MCB.RestartPublicNetAdapters.ps1" ; exit $LASTEXITCODE

3. In Task Scheduler, create a task to call RestartPublicNetAdapters.cmd one minute after each system start. Run the task as SYSTEM with highest privileges.

1 thought on “Server 2025 Domain Controller Not on Domain

Leave a Reply

Your email address will not be published. Required fields are marked *

Notify me of followup comments via e-mail. You can also subscribe without commenting.