What is Just Enough Administration (JEA)?

Just Enough Administration (JEA) is a PowerShell security technology built into Windows Server 2022 that enables role-based access control for administrative tasks. Rather than granting users full administrator rights to perform specific jobs, JEA creates constrained PowerShell remoting endpoints where users can only run a pre-approved set of cmdlets and scripts. A helpdesk technician, for example, can be given the ability to reset AD passwords but nothing else — they cannot browse the filesystem, install software, or run arbitrary code. JEA sessions run as a privileged virtual account or Group Managed Service Account (gMSA) on the target server, so the connecting user never needs local admin rights. All activity is logged to a transcript file for auditing.

JEA is built on top of PowerShell Remoting (WinRM) and uses two configuration file types: Role Capability Files (.psrc) that define what a role can do, and Session Configuration Files (.pssc) that define the endpoint and map users to roles.

Creating Role Capability Files (.psrc)

A Role Capability File defines the set of PowerShell cmdlets, functions, providers, scripts, and external executables available within a JEA role. Create a role capability file using New-PSRoleCapabilityFile:

# Create the directory structure for role capabilities
# Role capability files must live in a RoleCapabilities subfolder of a PowerShell module
$modulePath = "$env:ProgramFilesWindowsPowerShellModulesJEARoles"
New-Item -Path "$modulePathRoleCapabilities" -ItemType Directory -Force

# Create a helpdesk role capability file
New-PSRoleCapabilityFile -Path "$modulePathRoleCapabilitiesHelpDesk.psrc" `
    -Description "Helpdesk role: AD password reset and account unlock only" `
    -VisibleCmdlets @(
        'Restart-Computer',
        @{ Name = 'Set-ADAccountPassword'; Parameters = @{ Name = 'Identity' }, @{ Name = 'NewPassword' }, @{ Name = 'Reset' } },
        @{ Name = 'Unlock-ADAccount'; Parameters = @{ Name = 'Identity' } },
        @{ Name = 'Get-ADUser'; Parameters = @{ Name = 'Identity' }, @{ Name = 'Filter' }, @{ Name = 'Properties' } },
        'Get-Help'
    ) `
    -VisibleFunctions @('TabExpansion2','Get-HelpMessage') `
    -VisibleAliases @('help') `
    -VisibleProviders @() `
    -VisibleExternalCommands @()

# Create a network admin role capability file
New-PSRoleCapabilityFile -Path "$modulePathRoleCapabilitiesNetworkAdmin.psrc" `
    -Description "Network admin role: manage network adapters and firewall rules" `
    -VisibleCmdlets @(
        'Get-NetAdapter',
        'Get-NetIPAddress',
        'Get-NetIPConfiguration',
        'Get-NetRoute',
        'Get-NetFirewallRule',
        @{ Name = 'Set-NetIPAddress'; Parameters = @{ Name = 'InterfaceAlias' }, @{ Name = 'IPAddress' }, @{ Name = 'PrefixLength' } },
        @{ Name = 'New-NetFirewallRule'; Parameters = @{ Name = 'DisplayName' }, @{ Name = 'Direction' }, @{ Name = 'Action' }, @{ Name = 'Protocol' }, @{ Name = 'LocalPort' } },
        @{ Name = 'Remove-NetFirewallRule'; Parameters = @{ Name = 'DisplayName' } },
        'Test-NetConnection',
        'Resolve-DnsName',
        'Get-DnsClientServerAddress',
        'Clear-DnsClientCache'
    ) `
    -VisibleExternalCommands @('C:WindowsSystem32ipconfig.exe','C:WindowsSystem32ping.exe','C:WindowsSystem32tracert.exe')

Notice the syntax for restricting individual parameters on cmdlets. The @{ Name = 'Set-ADAccountPassword'; Parameters = ... } hashtable form lets you further constrain which parameters a user can pass, preventing privilege escalation through parameter abuse. An attacker who can only pass -Identity and -NewPassword to Set-ADAccountPassword cannot pivot to other operations.

Creating Session Configuration Files (.pssc)

The Session Configuration File defines the JEA endpoint — who can connect, what roles they receive, how the virtual account is configured, and where transcripts are saved:

New-PSSessionConfigurationFile -Path "C:JEAHelpdeskEndpoint.pssc" `
    -SessionType RestrictedRemoteServer `
    -Description "JEA endpoint for helpdesk staff" `
    -RunAsVirtualAccount $true `
    -TranscriptDirectory "C:JEATranscriptsHelpdesk" `
    -RoleDefinitions @{
        'CORPHelpDeskTier1' = @{ RoleCapabilities = 'HelpDesk' }
        'CORPHelpDeskTier2' = @{ RoleCapabilities = 'HelpDesk','NetworkAdmin' }
    } `
    -LanguageMode NoLanguage `
    -ExecutionPolicy RemoteSigned

# Create transcript directory
New-Item -Path "C:JEATranscriptsHelpdesk" -ItemType Directory -Force

# Validate the configuration file syntax before registering
Test-PSSessionConfigurationFile -Path "C:JEAHelpdeskEndpoint.pssc"

The SessionType RestrictedRemoteServer setting is critical — it restricts the language mode and disables direct .NET object creation. The LanguageMode NoLanguage setting prevents users from running arbitrary PowerShell expressions; they can only call the explicitly approved cmdlets. Always run Test-PSSessionConfigurationFile before registering to catch syntax errors.

Registering the JEA Endpoint

Register the endpoint using Register-PSSessionConfiguration. This creates a WinRM listener that users connect to by name:

# Register the helpdesk JEA endpoint
Register-PSSessionConfiguration `
    -Name "JEA_HelpDesk" `
    -Path "C:JEAHelpdeskEndpoint.pssc" `
    -Force

# Verify the endpoint is registered
Get-PSSessionConfiguration | Where-Object Name -like 'JEA*' |
    Select-Object Name, PSVersion, RunAsVirtualAccountGroups

# The endpoint will be visible in WinRM listener list
winrm enumerate winrm/config/listener

After registration, restart WinRM or the endpoint will not be reachable until the next service restart. The -Force flag re-registers if an endpoint with the same name already exists, which is useful during updates.

Run-As Virtual Accounts vs Group Managed Service Accounts

JEA session commands run in the context of a privileged account on the target server — either a local Virtual Account or a Group Managed Service Account (gMSA).

Virtual Accounts are automatically created local accounts that are members of the local Administrators group (or a specified group) and are tied to the WinRM service. They are easy to set up and require no additional infrastructure:

# Virtual account (default - local admin on the target server)
# In .pssc:
RunAsVirtualAccount = $true

# Virtual account with restricted group membership (best practice)
RunAsVirtualAccount = $true
RunAsVirtualAccountGroups = @('Backup Operators')  # only add to groups needed

Group Managed Service Accounts (gMSA) are preferred in domain environments because the account is domain-trusted. This is required when the JEA commands need to access network resources like other domain controllers or file servers:

# First create the gMSA in Active Directory (run on a DC)
New-ADServiceAccount `
    -Name "jea-helpdesk" `
    -DNSHostName "jea-helpdesk.corp.example.com" `
    -PrincipalsAllowedToRetrieveManagedPassword "Domain Computers"

# Install the gMSA on the target server
Install-ADServiceAccount -Identity "jea-helpdesk"
Test-ADServiceAccount -Identity "jea-helpdesk"

# Reference in the .pssc file instead of RunAsVirtualAccount:
GroupManagedServiceAccount = 'CORPjea-helpdesk$'

Testing JEA Endpoints

After registering an endpoint, test it by connecting as a non-privileged user and verifying the restricted environment:

# Connect to the JEA endpoint as a helpdesk user
$credential = Get-Credential -UserName "CORPhduser01" -Message "Helpdesk credentials"

Enter-PSSession -ComputerName SRV01 `
    -ConfigurationName "JEA_HelpDesk" `
    -Credential $credential

# Inside the session, verify what is available
Get-Command   # Should only show approved cmdlets
Get-PSProvider  # Should show no providers if VisibleProviders = @()

# Try to run a forbidden command — should fail
Get-ChildItem C:  # AccessDenied in NoLanguage mode

# Try an approved command
Get-ADUser -Identity "targetuser" -Properties Enabled,LockedOut

# Exit the session
Exit-PSSession

The Get-PSSessionCapability cmdlet lets administrators inspect what capabilities a specific user will have in an endpoint without connecting as that user — useful for auditing and troubleshooting:

# Run on the server where the endpoint is registered
Get-PSSessionCapability -ConfigurationName "JEA_HelpDesk" -Username "CORPhduser01" |
    Select-Object Name, CommandType | Sort-Object CommandType, Name | Format-Table -AutoSize

Auditing JEA Sessions via Transcript Directory

Every JEA session automatically generates a transcript file in the directory specified in the .pssc file. These transcripts capture all input and output, providing a complete audit trail. Set up log rotation to manage transcript storage:

# Review transcript directory
Get-ChildItem "C:JEATranscriptsHelpdesk" | Sort-Object LastWriteTime -Descending | Select-Object -First 10

# Read the latest transcript
$latest = Get-ChildItem "C:JEATranscriptsHelpdesk" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Get-Content $latest.FullName

# Find all sessions where Set-ADAccountPassword was called (security audit)
Select-String -Path "C:JEATranscriptsHelpdesk*.txt" -Pattern "Set-ADAccountPassword" |
    Select-Object Filename, LineNumber, Line | Format-Table -AutoSize

# Clean up transcripts older than 90 days
Get-ChildItem "C:JEATranscripts" -Recurse -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-90) } |
    Remove-Item -Force

Forward transcripts to a centralized log management system (SIEM) for long-term retention and correlation. PowerShell also supports Enhanced Script Block Logging via Group Policy which captures more detail than transcripts alone.

JEA for Helpdesk: AD Password Reset Only

A minimal helpdesk JEA configuration that only permits AD password resets and account unlocks, useful as a starting point for a Tier 1 support team:

# HelpDeskMinimal.psrc
New-PSRoleCapabilityFile -Path "$modulePathRoleCapabilitiesHelpDeskMinimal.psrc" `
    -VisibleCmdlets @(
        @{
            Name = 'Set-ADAccountPassword'
            Parameters = @(
                @{ Name = 'Identity'; ValidateSet = $null },
                @{ Name = 'NewPassword'; ValidateSet = $null },
                @{ Name = 'Reset'; ValidateSet = $null }
            )
        },
        @{ Name = 'Unlock-ADAccount'; Parameters = @( @{ Name = 'Identity' } ) },
        @{ Name = 'Get-ADUser'; Parameters = @( @{ Name = 'Identity' }, @{ Name = 'Properties'; ValidateSet = 'LockedOut','Enabled','PasswordExpired','PasswordLastSet' } ) }
    ) `
    -VisibleCmdlets @('Get-Help') `
    -LanguageMode NoLanguage

Deploying JEA with DSC

For large-scale deployment, use Desired State Configuration to ensure JEA endpoints are consistently configured across all servers. The JeaDsc module on the PowerShell Gallery provides DSC resources for JEA:

Install-Module JeaDsc -Scope AllUsers -Force

# DSC Configuration to deploy JEA endpoint
Configuration HelpdeskJEA {
    param([string[]]$ComputerName)

    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -ModuleName JeaDsc

    Node $ComputerName {
        File TranscriptDir {
            Ensure          = 'Present'
            Type            = 'Directory'
            DestinationPath = 'C:JEATranscriptsHelpdesk'
        }

        JeaRoleCapabilities HelpDeskRole {
            Ensure             = 'Present'
            Name               = 'HelpDesk'
            ModuleName         = 'JEARoles'
            VisibleCmdlets     = @('Get-ADUser','Unlock-ADAccount','Set-ADAccountPassword')
            Description        = 'Helpdesk password reset role'
        }

        JeaSessionConfiguration HelpdeskEndpoint {
            Ensure                = 'Present'
            Name                  = 'JEA_HelpDesk'
            RoleDefinitions       = "@{ 'CORPHelpDeskTier1' = @{ RoleCapabilities = 'HelpDesk' } }"
            RunAsVirtualAccount   = $true
            TranscriptDirectory   = 'C:JEATranscriptsHelpdesk'
            DependsOn             = '[JeaRoleCapabilities]HelpDeskRole','[File]TranscriptDir'
        }
    }
}

# Compile and apply
HelpdeskJEA -ComputerName 'SRV01','SRV02','SRV03' -OutputPath "C:DSCJEA"
Start-DscConfiguration -Path "C:DSCJEA" -Wait -Verbose -Force

JEA dramatically reduces the attack surface of your Windows Server 2022 infrastructure by enforcing least-privilege principles at the PowerShell layer. Even if a helpdesk account is compromised, the attacker is limited to resetting passwords — they cannot install malware, access the filesystem, or pivot to other systems. Combined with transcript logging forwarded to a SIEM, JEA provides both security enforcement and a complete audit trail that satisfies compliance requirements in regulated industries.