Quick Links

Have you ever wanted to delegate a task, but found that the permissions needed can be too risky to hand out? Or, have you wanted to lock down things like group creation in AD to enforce naming conventions of groups?

JEA can help you with just that and a lot more. In this article, we're going to walk through how you can delegate your already created scripts with PowerShell 5.1.

What Is JEA?

JEA is a PowerShell solution from Microsoft that can restrict users (and administrators) to only be able to perform specified tasks in a specific PowerShell session, even if they require local admin on the said resource. In addition, you can be extremely specific. Only the commands you specify can be executed, you can enable only specific parameter values and parameter values that match a specific pattern.

For example, you can enable Servicedesk to only restart a specific service with

        Restart-Service
    

, or only add groups to AD according to a specific naming convention. You can do all of this without giving them explicit permissions on a server or in AD. It's a tool that can save you a tremendous amount of time and secure your environment. Let's get started by wrapping our script into a function.

Step 1: Creating a Function Out of Your Script

The first step if you've not already done so is to make a function out of your script. This is quite easy, assuming that you already have your

        parameters
    

set up. Below, I've wrapped my simple script "New-FolderAndShare" into a function:

        Function New-FolderAndShare {
    [cmdletbinding()]
    param(
        # Name of the share
        [parameter(Mandatory)]
        [ValidatePattern("^(Project d{5}|Team (Finance|HR|IT|Multi) [a-z ]+)$")]
        [string]$ShareName,

        # Directory of the new share folder locally
        [parameter(Mandatory)]
        [ValidatePattern("^(D|E|F):\Shares\$")]
        [string]$Path,

        # Who to have full access
        [parameter(Mandatory)]
        [ValidateSet("^CONTOSO\")]
        [string]$FullAccess

    )

        $FullPath = Join-Path $Path $ShareName
    New-Item -ItemType Directory -Path $FullPath
    New-SmbShare -Path $FullPath -Name $ShareName -FullAccess $FullAccess

}

You validate the parameters with ValidatePattern in the function, but if this were a part of a module you could to that in the RoleCapabilities file instead with VisibleFunctions.

Making the script a function gives us greater control of what parameters are allowed in JEA, and makes it easier to export.

Step 2: Creating RoleCapabilities

The RoleCapabilities file decides what a specified role (defined in the next step) is allowed to do. This includes what commands they are allowed to run, what parameters they can use, and what modules to import.

While RoleCapabilities can be created manually, it's recommended to use the New-PSRoleCapabilityFile command built into PowerShell 5.1. It's also in this file that you'll load in the function that we created in the previous step.

The follwing script creates a file called FileShareCreator.psrc and adds the New-FolderAndShare function (that needs to be loaded into the current session):

        # RUN THIS IN THE SERVER THAT WILL BE THE JEA ENDPOINT

$RoleCapabilitiesParam = @{
    # Define a function that will be available in the cmdlet
    FunctionDefinitions = @{
        Name = 'New-FolderAndShare'
                # Import the code of the function
        ScriptBlock = [ScriptBlock]::Create(
            (Get-Command New-FolderAndShare).Definition
        )
    }

    # Modules used in the function needs to be explicity imported
    ModulesToImport = @(
        "SmbShare",
        "Microsoft.PowerShell.Management"
    )
    Path = ".FileShareCreator.psrc"
}

New-PSRoleCapabilityFile @RoleCapabilitiesParam

Utilize Get-Command to fetch the function in the FunctionDefinitions-parameter. You can also add the raw script with parameters.

You also specify how you are allowed to use the function in the VisibleCmdlet parameter. You do this by specifying the name of the function and its parameters together with a regular expression.

With this, you can create an extremely granular control of what a user can and can't do. But there's one caveat to making this work---you need to add the psrc-file into a module.

Step 3: Creating a Module for the RoleCapability File

It's time to create a module that you can put your role capabilities into. JEA finds the RoleCapabilities by the psrc files name without its extension, so avoid duplicates if you're going to create more role capabilities later on.

The following script is a modified version of what you find in the Official JEA documentation. It creates a new module in the module directory, creates the necessary files and folders needed, and copies the psrc file that you created in Step 2 into it:

        # RUN THIS IN THE SERVER THAT WILL BE THE JEA ENDPOINT

# Create a folder for the module
$modulePath = Join-Path $env:ProgramFiles "WindowsPowerShellModulesFileShareJEA"
New-Item -ItemType Directory -Path $modulePath

# Create an empty script module and module manifest.
# At least one file in the module folder must have the same name as the folder itself.
New-Item -ItemType File -Path (Join-Path $modulePath "FileShareJEA.psm1")
New-ModuleManifest -Path (Join-Path $modulePath "FileShareJEA.psd1") -RootModule "FileShareJEA.psm1"

# Create the RoleCapabilities folder and copy in the PSRC file
$rcFolder = Join-Path $modulePath "RoleCapabilities"
New-Item -ItemType Directory $rcFolder
Copy-Item -Path .FileShareCreator.psrc -Destination $rcFolder

You have now created a role capability and a function so that you can use it in JEA. What's left do now is to create a PowerShell Session Configuration to map AD groups to the roles you just created.

Step 4: Defining Roles

In this step, you're going to create a PowerShell Session Configuration file that defines what roles are going to be assigned what Capabilities (from the .psrc file we created in Step 2).

You're going to create the AD group and transcript directory here as well.

        # Create directory to store logs
New-Item -ItemType Directory -Path 'C:ProgramDataJEAConfigurationTranscripts' -Force

# Create AD group (you might need to do it on another server)
New-ADGroup -Path "OU=Groups,DC=contoso,DC=com" -Name 'JEA_FILESHARE_CREATOR' -GroupScope DomainLocal

# RUN THIS IN THE SERVER THAT WILL BE THE JEA ENDPOINT

# Define parameters for New-PSSessionConfigurationFile
$PSSessionConfigurationParams = @{
    # Run as a temporary account
    RunAsVirtualAccount = $True

    # That is a local administrator
    RunAsVirtualAccountGroups = @(
        "administrators"
    )

    # Path where to save log files of what connected users are doing
    TranscriptDirectory = 'C:ProgramDataJEAConfigurationTranscripts'

    # Map an active directory group to the capability we created
    RoleDefinitions = @{
        'CONTOSOJEA_FILESHARE_CREATOR' = @{
            RoleCapabilities = 'FileShareCreator'
        }
    }
        
        # Path of the PSSC file
    Path = ".SessionConfiguration.pssc"

}
# Create the PSSC file
New-PSSessionConfigurationFile @PSSessionConfigurationParams

Step 5: Creating a PowerShell Session

In this step, you will read in the SessionConfiguration.pssc file that you created in the previous step. This enables the members of JEA_FILESHARE_CREATOR to connect via PowerShell to the server:

        PS51> Register-PSSessionConfiguration -Path .SessionConfiguration.pssc -Name 'JEAFileShare' -Force

PSPath : Microsoft.WSMan.ManagementWSMan::localhostPluginJEAFileShare
PSParentPath : Microsoft.WSMan.ManagementWSMan::localhostPlugin
PSChildName : JEAFileShare
PSDrive : WSMan
PSProvider : Microsoft.WSMan.ManagementWSMan
PSIsContainer : True
Keys : {Name=JEAFileShare}
Name : JEAFileShare
TypeNameOfElement : Container
Type : Container

You're done! Add a user to JEA_FILESHARE_CREATOR that does not have access to the server through normal means and try it out as that user by typing:

        PS51> Enter-PSSession -ComputerName fs02.contoso.com -ConfigurationName JEAFileShare
PS51> New-FolderAndShare -ShareName "Project 12345" -Path D:Share

You can now run the command as a temporary local administrator that's locked down and only enabled to run a few default commands (visible with Get-Command while in session) and the New-FolderAndShare function that added in the Role Capabilities file.

If you want to see the account that's created temporarily, add VisibleExternalCommands @('c:windowssystem32whoami.exe') to your RoleCapabilities parameters in Step 2. You can run whoami and see the local administrator name:

        PS51 >whoami
winrm virtual userswinrm va_1_contoso_joe_helpdesk

Summary

Using JEA can be an awesome and easy way to delegate out tasks and secure your environment. This does not only include your own scripts but built-in modules and installed modules as well. Even though JEA can be a great value-add, be careful! You can create a great risk to your environment if you delegate the wrong commands or specify the wrong parameters to unexpected individuals.

Want to learn more?