# Using PowerShell Jobs as Custom Policy Filters

<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

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="77.99993896484375">Step</th><th>Action</th></tr></thead><tbody><tr><td>1</td><td>Create a <strong>job</strong> with one task: run <strong>PowerShell</strong> (<code>powershell.exe</code> or <code>pwsh</code>) with a <strong>specific command or script</strong> that exits <strong>0</strong> (success) or <strong>non-zero</strong> (failure).</td></tr><tr><td>2</td><td>Deploy the job to the agent (Jobs directory or API). No schedule or events needed—the job is invoked by the policy engine.</td></tr><tr><td>3</td><td>In the <strong>policy</strong>, set <strong>Extension.CustomFilterJobId</strong> to that job’s <strong>id</strong>.</td></tr><tr><td>4</td><td>When the policy is evaluated, the engine runs the job <strong>once</strong>; the result (success/failure) determines whether the policy’s filter passes.</td></tr></tbody></table>

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](/keeperpam/endpoint-privilege-manager/reference/jobs-definition-and-format.md) and [Policy JSON & Extension](/keeperpam/endpoint-privilege-manager/reference/policy-json-and-extension.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/endpoint-privilege-manager/policies/policy-examples/advanced-examples/policy-create-a-policy-with-job-running-powershell.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
