Baseline Hardening – Before and After
Telnet enabledSSH onlyRemote access protocol
SMBv1 onSMBv1 offFile sharing protocol
Admin sharedLAPS uniqueLocal administrator password
Balanced powerHigh PerformancePower plan (+ performance)
FW defaultFW explicit rulesWindows Firewall
No NTPDomain NTPTime synchronization

These are table-stakes changes. Not optional. Apply before the system goes into production.

Not every environment is running Windows Server 2025. Many organizations are still operating on Server 2016, 2019, or 2022, and plenty will be for years. These are supported, viable platforms that can be secured effectively. The steps to do that are well-established, and most of them are not complicated.

This post covers the baseline hardening approach for Windows Server 2016 through 2022. The focus is on what to do in the first pass – the changes that should be applied to every server before it handles production workloads. The Advanced Audit Policy configuration and Group Policy hardening are covered in separate posts in this series.


Why This Needs to Be Done Deliberately

A freshly installed Windows Server is not hardened. The default configuration is designed for maximum compatibility. Services that may be needed are enabled. Protocols that have been deprecated are still active. Default accounts exist with default settings. The assumption is that the administrator will configure the server appropriately for its purpose. In practice, that configuration step gets skipped more often than it gets done.

Physical security environments compound this problem. Genetec servers, C-CURE servers, Milestone servers – these systems often run on Windows Server. The integrators who deploy them are usually excellent at the security application but frequently less comfortable with the OS hardening. The result is a well-configured VMS running on a poorly hardened Windows installation.

This is the starting point. Get these right before anything else.


Windows Update Configuration

Security updates should be applied. On servers supporting physical security applications, test updates before applying them to production. Most Genetec, Milestone, and C-CURE deployments have documented compatibility with specific Windows patch levels – check the vendor’s release notes before applying a major cumulative update to a production system.

For servers where automatic updates are acceptable, configure Windows Update through Group Policy to defer feature updates (which can break application compatibility) while applying security updates on a defined schedule.

For isolated or mission-critical systems where automatic updates are not acceptable, use WSUS to control update distribution. Document the update approval and testing process. A server that has not received security updates in 12 months is not a stable system – it is a system where stability is being traded for exposure.

Consider Windows LTSC (Long-Term Servicing Channel) for servers running physical security applications. LTSC receives security updates without the feature releases that can cause application compatibility problems. Several major VMS vendors explicitly support LTSC versions. This is particularly relevant for servers that cannot be updated frequently due to application compatibility constraints.


Roles and Features Audit

Windows Server installs with a set of roles and features that may not be needed for the server’s specific function. Every enabled feature is part of the attack surface. Disable what you do not need.

## Audit installed roles and features:
Get-WindowsFeature | Where-Object {$_.Installed -eq $true} | Select DisplayName, Name
## Remove features that are not needed:
## Example: Remove Windows Media Player (often installed by default)
Remove-WindowsFeature Windows-Media-Player
## Remove Internet Explorer (use Edge or Chrome, not IE):
Remove-WindowsFeature Internet-Explorer-Optional-amd64
## Remove SMBv1:
Remove-WindowsFeature FS-SMB1

SMBv1 must be removed. It is not simply a matter of disabling the protocol – the feature should be removed entirely. Windows Server 2022 does not install SMBv1 by default, but Server 2016 and 2019 do. Remove it.


Local Account Hardening

The built-in Administrator account is a known attack target. Its existence is documented, its SID is predictable, and it cannot be locked out by standard lockout policies. Rename it. Create a named local administrator account with a different name for actual administrative use, and disable or rename the built-in Administrator.

## Rename the built-in Administrator account:
## Computer Management > Local Users and Groups > Users > Administrator > Rename
## Or via command line:
wmic useraccount where name='Administrator' rename 'LOCALADM'
## Disable the renamed built-in account:
## (After creating a different named account for admin access)
Disable-LocalUser -Name "LOCALADM"

Deploy LAPS (Local Administrator Password Solution) for all servers. LAPS ensures each server has a unique, randomly generated local administrator password stored in Active Directory. Without LAPS, the shared local administrator password across all servers means one compromised server exposes the local admin credentials for every server that shares that password.

Disable the Guest account. It should already be disabled by default, but verify:

Get-LocalUser "Guest" | Select Name, Enabled
## Should return Enabled: False

Windows Firewall Configuration

The Windows Firewall should be enabled on all server profiles (Domain, Private, Public). Do not disable the Windows Firewall to resolve application connectivity problems. Identify the specific ports the application needs and add explicit rules for those ports.

## Verify firewall is enabled on all profiles:
Get-NetFirewallProfile | Select Name, Enabled
## Enable if disabled:
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
## Example: Allow Genetec Directory port inbound:
New-NetFirewallRule -DisplayName "Genetec Directory TCP 5500" -Direction Inbound -Protocol TCP -LocalPort 5500 -Action Allow -Profile Domain
## Block unnecessary inbound rules from the default ruleset:
## Review Get-NetFirewallRule | Where-Object {$_.Enabled -eq "True" -and $_.Direction -eq "Inbound"}
## Disable rules that are not needed for this server's function

The Windows Firewall default profile is permissive for many inbound connections because Windows assumes the administrator will configure it for the server’s role. Review the enabled inbound rules and disable those that are not required. The goal is an explicit allow list, not a default-permit list with a few blocked exceptions.


Services Audit

Disable services that are not needed for the server’s function. Unnecessary services are attack surface and resource consumption. The specific services to disable depend on the server’s role, but common candidates on dedicated security application servers:

## Services to evaluate for disabling on dedicated security application servers:
## (Verify compatibility with the specific application before disabling)
$services_to_disable = @(
    "Fax",                    # Fax service
    "XblGameSave",           # Xbox Game Save
    "XboxNetApiSvc",         # Xbox Live Networking
    "WinRM",                  # Windows Remote Management (if not using WinRM)
    "RemoteRegistry",        # Remote Registry (high-value target – disable if not needed)
    "Spooler"                # Print Spooler (if no printing needed – EternalBlue target)
)
foreach ($svc in $services_to_disable) {
    try {
        Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
        Set-Service -Name $svc -StartupType Disabled -ErrorAction SilentlyContinue
        Write-Host "Disabled: $svc"
    } catch { Write-Host "Not found or error: $svc" }
}

The Print Spooler service deserves specific attention. The PrintNightmare vulnerabilities (CVE-2021-1675, CVE-2021-34527) are critical vulnerabilities in the Print Spooler service that allow privilege escalation and remote code execution. On servers that do not need printing functionality – which includes most VMS and access control servers – disable the Print Spooler entirely.


Time Synchronization

Configure all servers to synchronize time from the domain hierarchy. On domain-joined servers, the Windows Time Service (W32tm) handles this automatically by default. Verify it is configured correctly and monitor for drift. A 5-minute clock difference causes Kerberos authentication failures. A significant clock difference causes event log timestamps to be incorrect, which degrades the value of audit logs for incident response.

## Check current NTP configuration:
w32tm /query /configuration
## Check current time accuracy:
w32tm /query /status
## Force sync:
w32tm /resync /force

On servers that are not domain-joined, configure NTP explicitly:

w32tm /config /manualpeerlist:"pool.ntp.org" /syncfromflags:manual /reliable:yes /update
net stop w32tm && net start w32tm

PowerShell Hardening

PowerShell is the primary administrative scripting environment on Windows and is heavily used by attackers for post-exploitation. Hardening PowerShell does not mean disabling it – it means logging its use and restricting what it can do.

## Enable PowerShell script block logging (logs all script execution):
Set-ItemProperty "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name EnableScriptBlockLogging -Value 1
## Enable PowerShell module logging:
Set-ItemProperty "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name EnableModuleLogging -Value 1
Set-ItemProperty "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name ModuleNames -Value @("*")
## Set execution policy to RemoteSigned (allows local scripts, requires signing for remote):
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force

PowerShell Constrained Language Mode restricts what scripts can do and is worth considering for servers where interactive PowerShell use is not needed. It prevents PowerShell from being used as a post-exploitation framework while allowing automated management scripts to continue functioning:

## Enable Constrained Language Mode for all users except administrators:
## (Configure via AppLocker or WDAC policy – see Microsoft documentation)

TLS Baseline Settings

Enable TLS 1.2 and TLS 1.3 (where supported). Disable TLS 1.0, TLS 1.1, SSL 2.0, and SSL 3.0. Use IISCrypto (free tool) to apply these settings safely with built-in rollback capability. The detailed TLS configuration is covered in the other considerations post in this series, but the core setting applies here as part of the baseline.