# Policy: Create a Policy with Job Running PowerShell

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FE69i9Hix4QbibmZGmr71%2Fimage.png?alt=media&#x26;token=962865a1-6722-4b53-b67a-9ebe4bc76276" alt=""><figcaption></figcaption></figure>

**Audience:** IT admins. This example shows how a **policy** can use a **custom filter job** that runs **PowerShell** to perform a **specific task once** per policy evaluation—for example, to allow or deny a request based on a script’s result.

***

### Overview

Some policies support a **custom filter**: instead of only using built-in filters (user, machine, application, time), the policy can call a **job** during evaluation. That job runs **once** for that evaluation request. If the job runs **PowerShell** as its single task, you can implement custom logic (e.g. check a file, call an API, run a one-off script) and use the result to decide whether the policy applies.

**Flow:**

1. A request is evaluated (e.g. privilege elevation for an app).
2. The policy has **Extension.CustomFilterJobId** set to a job id (e.g. `allow-elevation-if-script-ok`).
3. The policy engine calls the agent’s **evaluate** endpoint for that job, passing the evaluation context (user, machine, application path, etc.).
4. The job runs **once**; its task runs **PowerShell** with your command or script.
5. The job’s result (success or failure) is used by the policy: typically **success** = filter passes (policy can apply), **failure** = filter fails (policy does not apply for this request).

**Use cases:** Allow elevation only when a script confirms something (e.g. machine is in a list, time window, external check). Or deny when a PowerShell check fails (e.g. “is process from allowed path?”).

***

{% stepper %}
{% step %}
**Create a Job that Runs PowerShell Once**

The job will be **invoked only by the policy engine** (via the evaluate API), not by schedule or events. It should have **one task** that runs PowerShell and exits with **0** (success) or non-zero (failure). The policy engine uses that to decide if the custom filter passes.

**Example job: `allow-elevation-if-script-ok.json`**

Save as `Jobs/allow-elevation-if-script-ok.json` (or another id; use that id in the policy).

```
{
  "id": "allow-elevation-if-script-ok",
  "name": "Custom filter: run PowerShell once",
  "description": "Runs a PowerShell command once per policy evaluation; exit 0 = filter pass, non-zero = filter fail",
  "enabled": true,
  "priority": 5,
  "events": [],
  "parameters": [
    { "name": "UserName", "type": "String", "required": false },
    { "name": "FilePath", "type": "String", "required": false },
    { "name": "MachineName", "type": "String", "required": false }
  ],
  "tasks": [
    {
      "id": "run-powershell",
      "name": "Run PowerShell once",
      "executionType": "Service",
      "command": "powershell.exe",
      "executablePath": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
      "arguments": "-NoProfile -ExecutionPolicy Bypass -Command \"& { if (Test-Path 'C:\\AllowElevation.txt') { exit 0 } else { exit 1 } }\""
    }
  ]
}
```

**What this does:**

* **One task** runs `powershell.exe` with a **single command**: check if `C:\AllowElevation.txt` exists; exit 0 if yes, exit 1 if no.
* The policy engine passes context (UserName, FilePath, MachineName, etc.) into the job; you can use those in the script via **parameter substitution** (e.g. `-Command "& { ... $env:UserName ... }"` or by referencing `{UserName}` in a script file).
* **executablePath** — Use the full path to PowerShell on your machines, or a path variable if supported (e.g. `{systemroot}\System32\WindowsPowerShell\v1.0\powershell.exe`). On Linux/macOS you would use `pwsh` or the appropriate shell and a different script.

**Running a script file instead of inline:**

```
"arguments": "-NoProfile -ExecutionPolicy Bypass -File \"{approot}\\Scripts\\CheckElevationAllowed.ps1\""
```

Then the script can read context (e.g. from environment variables or arguments the job passes) and exit 0 or 1. The job runs that script **once** per evaluation.

**Using parameters in the script:**

If the evaluate API passes context into the job as parameters, you can reference them in the task arguments, for example:

```
"arguments": "-NoProfile -ExecutionPolicy Bypass -Command \"& { param($User,$Path); ... }\" -User \"{UserName}\" -Path \"{FilePath}\""
```

Exact parameter names depend on what the policy engine sends; check your product’s evaluate request body for the exact keys (e.g. UserName, FilePath, MachineName).
{% endstep %}

{% step %}
**Add the Job to the Agent**

* Place the JSON file in the **Jobs** directory (e.g. `Jobs/allow-elevation-if-script-ok.json`) so the agent loads it, or create the job via **POST /api/Jobs**.
* Ensure the job is **enabled** and that the agent has **PowerShell** at the path you used. No **schedule** or **events** are required—the job is run only when the policy engine calls the evaluate endpoint.
  {% endstep %}

{% step %}
**Create or Edit a Policy that Uses the Custom Filter Job**

In the policy’s **Extension**, set **CustomFilterJobId** to the job id you used (e.g. `allow-elevation-if-script-ok`). The policy engine will call that job during evaluation and use the result to decide if the policy’s filter passes.

**Example (conceptual policy JSON):**

```
{
  "PolicyId": "elevate-only-when-script-allows",
  "PolicyName": "Allow elevation only when PowerShell check passes",
  "PolicyType": "PrivilegeElevation",
  "Status": "enabled",
  "Controls": ["ALLOW"],
  "Rules": [ { "Operator": "And", "Expressions": [] } ],
  "Filters": {
    "UserCheck": { "Users": ["*"] },
    "MachineCheck": { "Machines": ["*"] },
    "ApplicationCheck": { "Applications": ["*"] }
  },
  "Extension": {
    "CustomFilterJobId": "allow-elevation-if-script-ok"
  }
}
```

* When a privilege elevation request is evaluated, the engine will run the **allow-elevation-if-script-ok** job **once** with the request context.
* If the job’s PowerShell task exits with **0**, the custom filter **passes** and the policy can apply (here: ALLOW).
* If the job fails (non-zero exit or timeout), the custom filter **fails** and this policy does not apply for that request.

Policies are usually created or edited in the **Keeper Admin Console**. If your deployment supports **Extension** or custom filter configuration in the UI, set the custom filter job id there. Otherwise, use file-based or API policy with the Extension shown above.
{% endstep %}

{% step %}
**Timeout and Behavior**

* **Custom filter timeout:** The policy engine waits for the job to finish within a **timeout** (e.g. 30 seconds by default). This is configured in the KeeperPolicy plugin (e.g. **customfilter.timeout\_seconds**). If the job (or PowerShell) runs longer, the evaluation times out and the custom filter is treated as **failed**.
* **Run once:** Each time the policy is evaluated for a request, the job is invoked **once**. So one PowerShell execution per evaluation—no repeated runs unless there are multiple evaluations.
* **PowerShell path:** Use a path that exists on all target machines (e.g. `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` on Windows). For PowerShell Core use `pwsh` and the appropriate path.
  {% endstep %}
  {% endstepper %}

### Summary

| Step | Action                                                                                                                                                                      |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1    | Create a **job** with one task: run **PowerShell** (`powershell.exe` or `pwsh`) with a **specific command or script** that exits **0** (success) or **non-zero** (failure). |
| 2    | Deploy the job to the agent (Jobs directory or API). No schedule or events needed—the job is invoked by the policy engine.                                                  |
| 3    | In the **policy**, set **Extension.CustomFilterJobId** to that job’s **id**.                                                                                                |
| 4    | When the policy is evaluated, the engine runs the job **once**; the result (success/failure) determines whether the policy’s filter passes.                                 |

This gives you a **policy that contains a job which runs PowerShell to perform a specific task once** per evaluation. For more on job format and policy Extension, see [Jobs: Definition & Format](https://docs.keeper.io/en/keeperpam/endpoint-privilege-manager/reference/jobs-definition-and-format) and [Policy JSON & Extension](https://docs.keeper.io/en/keeperpam/endpoint-privilege-manager/reference/policy-json-and-extension).
