Files
OrchestrAD/docs/examples/Create-OrchestrADRule.ps1
Alphaeus Mote c74dd63281 feat(api): OpenAPI/Swagger docs generated from the router + PowerShell example
- GET /api/docs serves a Swagger UI and GET /api/openapi.json serves an
  OpenAPI 3 spec built by walking the live chi router, so documented paths
  always match what the build serves. A small registry adds rich detail
  (request bodies, params, schemas) for the automation-critical operations
  (auth login, rule create/update/preview, connection introspection);
  RuleInput and friends are defined as reusable component schemas.
- Add docs/examples/Create-OrchestrADRule.ps1: a no-alias PowerShell sample
  that builds headers/body as typed dictionaries, serializes with
  ConvertTo-Json, logs in, creates a SyncGroupMembership rule, and runs it.
- README: new "API & Automation" section (Swagger + PowerShell), and a
  "Logging & Retention" section documenting log rotation and the new
  database maintenance/retention knobs.

Tests cover spec generation from a router and registry well-formedness.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 18:33:53 -04:00

111 lines
4.6 KiB
PowerShell

<#
.SYNOPSIS
Creates an OrchestrAD dynamic-group rule through the REST API.
.DESCRIPTION
Demonstrates authenticating to OrchestrAD and creating a rule that syncs all
users whose department is "Sales" into a target group (creating the group if
missing, and keeping its membership exactly in step with the filter).
Style notes (as requested):
* Body and headers are built as strongly-typed dictionaries via
New-Object with the full type name.
* The body is converted to JSON with ConvertTo-Json.
* Full cmdlet names are used throughout — no aliases.
Requires PowerShell 7+ (uses -SkipCertificateCheck for the self-signed dev
certificate; drop that switch when a trusted certificate is in use).
.EXAMPLE
./Create-OrchestrADRule.ps1 -BaseUrl 'https://localhost:18090' -Username 'admin' -Password 'admin' -ConnectionId '57feb058-...' -TargetGroupDn 'CN=Sales,OU=Groups,DC=corp,DC=com'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)] [string] $BaseUrl,
[Parameter(Mandatory = $true)] [string] $Username,
[Parameter(Mandatory = $true)] [string] $Password,
[Parameter(Mandatory = $true)] [string] $ConnectionId,
[Parameter(Mandatory = $true)] [string] $TargetGroupDn,
[Parameter(Mandatory = $false)] [string] $Department = 'Sales'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# --- 1. Authenticate and obtain a bearer token ----------------------------------
$loginBody = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$loginBody.Add('username', $Username)
$loginBody.Add('password', $Password)
$loginResponse = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/auth/login" `
-ContentType 'application/json' -Body ($loginBody | ConvertTo-Json) -SkipCertificateCheck
$token = $loginResponse.data.token
Write-Output "Authenticated as '$Username'."
# --- 2. Build request headers as a dictionary -----------------------------------
$headers = New-Object 'System.Collections.Generic.Dictionary[String,String]'
$headers.Add('Authorization', "Bearer $token")
$headers.Add('Accept', 'application/json')
# --- 3. Build the rule body as nested dictionaries / lists ----------------------
# One condition: department equals $Department.
$condition = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$condition.Add('attributeName', 'department')
$condition.Add('operator', 'Equals')
$condition.Add('comparisonValue', $Department)
$conditions = New-Object 'System.Collections.Generic.List[Object]'
$conditions.Add($condition)
$group = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$group.Add('joinOperator', 'AND')
$group.Add('conditions', $conditions)
$conditionGroups = New-Object 'System.Collections.Generic.List[Object]'
$conditionGroups.Add($group)
# One action: sync membership to the target group (full add + remove).
$actionConfig = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$actionConfig.Add('targetGroupDn', $TargetGroupDn)
$actionConfig.Add('syncMode', 'FullSync')
$actionConfig.Add('createIfMissing', $true)
$actionConfig.Add('groupScope', 'Global')
$actionConfig.Add('groupType', 'Security')
$action = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$action.Add('actionType', 'SyncGroupMembership')
# configurationJson is a JSON *string*, so serialize the config dictionary.
$action.Add('configurationJson', ($actionConfig | ConvertTo-Json -Compress))
$actions = New-Object 'System.Collections.Generic.List[Object]'
$actions.Add($action)
$ruleBody = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$ruleBody.Add('name', "Sales - $Department")
$ruleBody.Add('description', 'Created via the OrchestrAD REST API')
$ruleBody.Add('adConnectionId', $ConnectionId)
$ruleBody.Add('objectType', 'User')
$ruleBody.Add('executionMode', 'Apply')
$ruleBody.Add('groupJoinOperator', 'AND')
$ruleBody.Add('conditionGroups', $conditionGroups)
$ruleBody.Add('actions', $actions)
# --- 4. Create the rule ---------------------------------------------------------
$json = $ruleBody | ConvertTo-Json -Depth 10
$rule = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/rules" `
-Headers $headers -ContentType 'application/json' -Body $json -SkipCertificateCheck
Write-Output ("Created rule '{0}' (id {1})." -f $rule.data.name, $rule.data.id)
# --- 5. (Optional) run it now ---------------------------------------------------
$run = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/rules/$($rule.data.id)/run" `
-Headers $headers -SkipCertificateCheck
Write-Output ("Run status: {0}" -f $run.data.status)