Skip to content
WindowsHow-To Published Updated 6 min readViews unavailable

Enforcing Least-Privilege Remote Administration with PowerShell JEA

Setting up Just Enough Administration so a support team runs specific, pre-approved remote commands without ever holding full admin rights.

Just Enough Administration (JEA) lets you grant someone the ability to perform a specific, defined set of administrative actions remotely via PowerShell, without granting them full administrative rights on the target machine at all — a meaningfully different security posture than the common alternative of simply adding a support account to the local Administrators group because it’s the path of least resistance.

The problem JEA specifically solves

A common, risky pattern in many environments: a support team needs to perform a small number of specific tasks (restarting a particular service, clearing a specific log, checking disk space) on production servers, and the practical shortcut is granting that team full local administrator rights so they can do whatever’s needed without friction. This grants vastly more privilege than the actual task requires, and if that support account’s credentials are ever compromised, the blast radius is full administrative control rather than the narrow set of actions actually needed.

What a JEA session actually restricts

A JEA endpoint defines a specific, constrained PowerShell session: only explicitly whitelisted cmdlets, functions, and parameters are available inside it, and the session can run using a temporary, auto-elevated virtual account (or a specific configured identity) rather than the connecting user’s own account — meaning the connecting user never needs standing administrative rights of their own at all, since the actual elevated actions happen through the tightly scoped JEA session’s own identity, not theirs.

Defining a role capability file

A role capability file (.psrc) defines exactly what’s permitted inside a JEA session:

# RestartWebService.psrc
@{
    Author = 'IT Security'
    Description = 'Allows restarting the web application service only'
    VisibleCmdlets = 'Restart-Service'
    VisibleFunctions = 'Get-WebServiceStatus'
}

This specific role capability permits exactly one cmdlet (Restart-Service) and one custom function — nothing else is available inside a session using this role, regardless of what the connecting user might otherwise want to run.

Constraining even the permitted cmdlet’s actual scope

A blanket Restart-Service permission would still let someone restart any service on the machine, which is broader than intended. Parameter constraints narrow this further:

VisibleCmdlets = @{
    Name = 'Restart-Service'
    Parameters = @{ Name = 'Name'; ValidateSet = 'WebAppService' }
}

This restricts the permitted Restart-Service calls to only the specific named service, closing off the ability to use the same broadly-useful cmdlet against anything else on the system — the actual granular restriction that makes JEA meaningfully different from just granting a broad, unrestricted cmdlet.

Defining the session configuration

The session configuration file (.pssc) ties role capabilities to specific users or groups, and specifies the account context the session actually runs under:

# WebSupport.pssc
@{
    SessionType = 'RestrictedRemoteServer'
    RunAsVirtualAccount = $true
    RoleDefinitions = @{
        'DOMAIN\WebSupportTeam' = @{ RoleCapabilities = 'RestartWebService' }
    }
}

RunAsVirtualAccount = $true is a key detail — the session runs using a temporary virtual administrative account created just for this session’s lifetime, rather than either the connecting user’s own credentials or a real, standing service account whose credentials would otherwise need to be separately protected and rotated.

Registering the JEA endpoint

Register-PSSessionConfiguration -Name 'WebSupport' -Path .\WebSupport.pssc -Force

This registers the endpoint on the target server, making it available for members of DOMAIN\WebSupportTeam to connect to specifically — not as a general-purpose remote session, but constrained to exactly the role capabilities defined.

Connecting to and using the constrained session

Enter-PSSession -ComputerName webserver01 -ConfigurationName WebSupport

A member of the authorized group connecting this way gets a PowerShell session where only Restart-Service (restricted to the one named service) and the specific custom function are available — attempting anything else results in the command simply not being recognized, since it was never exposed in this constrained session at all, not merely blocked after being attempted.

Auditing what actually happened in a JEA session

JEA sessions log which specific actions were taken, by which connecting identity, even though the actions themselves executed under the shared virtual account — this combination (broad account sharing at the execution layer, but precise per-user audit logging of what was actually requested) is what makes JEA practical for real support team scenarios without sacrificing accountability for what each individual team member actually did.

Why this is worth the setup effort over just granting admin rights

The setup and maintenance overhead of defining role capabilities and session configurations is real, and meaningfully more effort than adding an account to a local Administrators group — but the security benefit (a compromised support account can only perform the specific narrow actions defined, not arbitrary administrative actions) is exactly the kind of blast-radius reduction that matters most for exactly the accounts most likely to be targeted, since support and help-desk credentials are frequently among the first targets in a real intrusion specifically because they’re expected to have broad access under the common, less careful alternative approach.

Testing a role capability file before deploying it broadly

Test-PSSessionConfigurationFile -Path .\WebSupport.pssc

Before registering an endpoint that a whole support team will connect through, validating both the role capability file and the session configuration file’s syntax catches malformed constraints — a typo in a ValidateSet value, a reference to a cmdlet that doesn’t actually exist on the target machine — before they become a production endpoint someone discovers is broken only when they actually try to use it during a real support task. Testing on a single non-production machine first, connecting as a member of the intended role and confirming both that the intended actions work and that everything outside the intended scope is genuinely unavailable, is worth the extra validation step before rolling the same endpoint configuration out fleet-wide.

Versioning role capability changes deliberately

As a support team’s actual needs evolve, role capability files inevitably need updates — a new approved action, a parameter constraint that turns out to be too narrow for a legitimate use case. Treating these files as version-controlled configuration (checked into the same source control an organization already uses for other infrastructure-as-code) rather than ad hoc edits made directly on a production server gives a reviewable change history and a rollback path if a specific change turns out to grant broader access than intended — a genuinely important safeguard specifically because JEA’s whole value proposition depends on the granted scope staying precisely as narrow as intended over time, not gradually widening through unreviewed, undocumented edits.

Related:

Sources:

Comments