Skip to main content

Pipeline Configuration

Configure scan schedule, commit behavior, inventory storage, module versions, and more.

Quick Reference​

SettingFileDefaultPurpose
Schedule (cron)monitor-pipeline.yml / .github/workflows/scan.yml0 */6 * * *How often scan runs
Upstream update checkNOTIFY_UPSTREAM_UPDATEEnabledNotify when a newer release is published upstream
Inventory pathsrc/Scan-PimState.ps1./inventory/Where state is stored
Commit messagemonitor-pipeline.yml / .github/workflows/scan.ymlISO 8601 timestampGit commit format
Git authorsrc/git.ps1"PIM Monitor"Author name
Module versionmonitor-pipeline.yml / .github/workflows/scan.yml2.35.1PowerShell module version
HTML reportPipeline variableUnsetGenerate scan report artifact
Expiring windowPipeline variable14 daysExpiring assignment detection

Schedule & Triggers​

Change the scan schedule​

Edit the cron expression in monitor-pipeline.yml (Azure DevOps) or .github/workflows/scan.yml (GitHub Actions):

Azure DevOps:

schedules:
- cron: "0 */6 * * *"
displayName: "PIM Change Scan (4x daily)"
branches:
include: [main]
always: true

GitHub Actions:

on:
schedule:
- cron: '0 */6 * * *'

Cron Pattern Guide​

0 */6 * * * = Every 6 hours (default)
0 * * * * = Every hour
0 */3 * * * = Every 3 hours
0 9 * * * = Daily at 9 AM UTC
0 9 * * 1-5 = Weekdays at 9 AM UTC
0 0 * * 0 = Weekly (Sunday midnight UTC)
*/30 * * * * = Every 30 minutes

Why not every minute?

  • Graph API throttling (429 errors on frequent requests)
  • Noise reduction (PIM changes rarely occur every minute)
  • Cost efficiency (fewer pipeline runs = lower compute costs)

Check for upstream updates on GitHub​

At the start of each run, the pipeline compares the VERSION file in your copy against the latest published release of the upstream repository. If a newer release exists, a warning is written to the run log. If notification channels are configured, a notification is also sent via webhook and/or email.

This check runs before the scan so the warning appears early in the run log. The notification is sent at the very end of the run (after artifact publishing), using the same channels configured for PIM change notifications.

What it checks: the latest release tag of https://github.com/0125joel/PIM-Monitor against your local VERSION file, compared with semantic version ordering.

Run log output (when an update is available):

PIM Monitor 0.4.0 is available (running 0.3.0). See https://github.com/0125joel/PIM-Monitor/releases/tag/v0.4.0

Disabling the notification: set NOTIFY_UPSTREAM_UPDATE to false in your pipeline variables (Azure DevOps) or repository variables (GitHub Actions). The check step itself still runs and logs; only the webhook/email notification is suppressed.

note

This runs on both Azure DevOps and GitHub Actions. Both run from a checked-out copy of the repo and can drift behind upstream releases, so both perform the version check.

Allow manual triggers​

Azure DevOps:

trigger: none
pr: none

schedules:
- cron: "0 */6 * * *"
displayName: "PIM Change Scan"
branches:
include: [main]
always: true

Users can then click Run in the Azure DevOps UI without waiting for schedule.

GitHub Actions (enabled by default):

on:
schedule:
- cron: '0 */6 * * *'
workflow_dispatch: # Manual trigger

Commit & Repository​

Change the commit message format​

Edit the git step in monitor-pipeline.yml (Azure DevOps) or .github/workflows/scan.yml (GitHub Actions):

Current format (ISO 8601 timestamp):

git commit -m "scan: $(date -u +%Y-%m-%dT%H:%M:%SZ)"

Example commit messages:

scan: 2026-04-27T18:42:15Z
chore: pim scan at 2026-04-27
feat: pim changes on 2026-04-27
SCAN: Daily security check

Any format works as long as it's unique enough to identify scans in git log.

Customize git commit author​

Edit src/git.ps1:

git config user.name "PIM Monitor"
git config user.email "pim-monitor@noreply.github.com"

Change to:

git config user.name "Azure Security Team"
git config user.email "security@contoso.com"

The name and email appear in git history and commit metadata.

Store inventory in a subfolder​

Edit src/Scan-PimState.ps1 (line ~51):

$inventoryRoot = Join-Path -Path (Get-Location) -ChildPath "inventory"

Change to:

$inventoryRoot = Join-Path -Path (Get-Location) -ChildPath "security/pim-inventory"

Then update the git add step to match:

Azure DevOps monitor-pipeline.yml:

git add security/pim-inventory/ expected-changes.json 2>/dev/null || true

GitHub Actions .github/workflows/scan.yml:

git add security/pim-inventory/ expected-changes.json

Reporting & Artifacts​

Enable HTML scan report artifact​

Set REPORT_ARTIFACT=true in your pipeline variables.

Azure DevOps:

  1. Pipelines → PIM Monitor → Edit → Variables
  2. Add: REPORT_ARTIFACT = true

GitHub Actions:

  1. Settings → Secrets and variables → Actions → Variables
  2. Add: REPORT_ARTIFACT = true

The scan generates scan-report.html and publishes it as an artifact.

Report includes:

  • Severity summary with counts
  • All detected changes organized by severity
  • Before/after diffs
  • Tenant info and timestamp
  • Commit SHA (if available)

See Reporting & Artifacts for details.

Expiring assignments window​

Set EXPIRING_WINDOW_DAYS in your pipeline variables to control early warning for expiring PIM assignments.

Default: 14 days

Examples:

  • 7 = 1 week advance notice
  • 14 = 2 weeks (default)
  • 30 = 1 month

Assignments expiring within this window are flagged as Medium severity changes.

See Expiring Assignments for details.

Environment-Specific Configuration​

Staging vs. Production​

If you have multiple Azure AD tenants or want different schedules per environment, create separate pipeline files:

Azure DevOps:

# monitor-pipeline-prod.yml
schedules:
- cron: "0 */6 * * *"

# monitor-pipeline-staging.yml
schedules:
- cron: "0 0 * * 0" # Weekly

Then configure two pipelines in Azure DevOps UI pointing to different files.

GitHub Actions:

# .github/workflows/scan-prod.yml
# .github/workflows/scan-staging.yml

Platform Comparison​

SettingAzure DevOpsGitHub Actions
Schedule locationmonitor-pipeline.yml.github/workflows/scan.yml
Manual triggerBuilt-in (click Run)workflow_dispatch: in YAML
Module cacheVia pipeline cacheactions/cache@v4
ArtifactsBuild artifacts storageArtifact storage
Cron syntaxSame cron formatSame cron format

Troubleshooting​

Pipeline not running on schedule​

Check:

  • Is the main branch the default branch? Scheduled runs only on default branch
  • Are workflows enabled? (GitHub Actions)
  • Check pipeline run history for errors
  • Verify cron syntax (test at https://crontab.guru/)

Inventory not committing​

Check:

  • Are there any changes to commit? No-change scans skip commit
  • Verify git config is correct (user.name, user.email set in src/git.ps1)
  • Check pipeline permissions: must have write access to repository

Artifact not generating​

Check:

  • Is REPORT_ARTIFACT=true set in variables?
  • Were changes detected? Report only generates on changes
  • Check pipeline logs for permission errors