pyPASreporter-PACLIparser 0.3.2
PACLI configuration parser for CyberArk PAM - part of pyPASreporter ecosystem
License: MIT
Requires Python: >=3.10
Keywords: configuration, cyberark, pacli, pam, parser, security, vault

# pyPASreporter-PACLIparser

[![PyPI](https://img.shields.io/pypi/v/pyPASreporter-PACLIparser)](https://pypi.org/project/pyPASreporter-PACLIparser/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

PACLI configuration parser for CyberArk PAM - part of the pyPASreporter ecosystem.

Parse **DBParm.ini**, **License.xml**, **Policies.xml**, and **CPM policy INI files** into DuckDB or CSV for analysis.

## Installation

```bash
pip install pyPASreporter-PACLIparser
```

Or with uv:

```bash
uv add pyPASreporter-PACLIparser
```

## CLI Usage

### Parse License.xml

```bash
pypasreporter-pacliparser license \
    --input License.xml \
    --db vault.duckdb \
    --table-name license
```

### Parse DBParm.ini

```bash
pypasreporter-pacliparser dbparm \
    --input DBParm.ini \
    --db vault.duckdb \
    --table-name dbparm
```

### Parse Policies.xml

```bash
# Wide format (one row per policy, default)
pypasreporter-pacliparser policies \
    --input Policies.xml \
    --db vault.duckdb

# Long format (key-value rows)
pypasreporter-pacliparser policies \
    --input Policies.xml \
    --db vault.duckdb \
    --format long

# Both formats
pypasreporter-pacliparser policies \
    --input Policies.xml \
    --db vault.duckdb \
    --format both
```

### Parse CPM Policy INI Files

```bash
pypasreporter-pacliparser cpm-policies \
    --input ./cpm_ini_policies/ \
    --db vault.duckdb \
    --format both
```

### Parse All Files at Once

```bash
pypasreporter-pacliparser all \
    --input ./pacli_exports/ \
    --db vault.duckdb
```

**Expected input folder structure:**

```
pacli_exports/
├── DBParm.ini              # Vault database configuration (optional)
├── License.xml             # License information (optional)
├── Policies.xml            # Platform policies (optional)
└── cpm_ini_policies/       # CPM policy directory (optional)
    ├── Policy-WinDomain.ini
    ├── Policy-UnixSSH.ini
    └── Policy-*.ini        # All Policy-*.ini files are parsed
```

All files are optional - the command will parse whatever it finds and skip missing files.

### Export to CSV

All commands support `--csv-export-path`:

```bash
pypasreporter-pacliparser license \
    --input License.xml \
    --csv-export-path license.csv
```

## CLI Options

| Option | Short | Description |
|--------|-------|-------------|
| `--input` | `-i` | Path to input file or directory (required) |
| `--db` | `-d` | Path to DuckDB database file |
| `--table-name` | `-t` | Table name in DuckDB (default varies by command) |
| `--schema` | `-s` | DuckDB schema name (default: `cyberark_pacli`) |
| `--format` | `-f` | Output format: `wide`, `long`, or `both` |
| `--csv-export-path` | `-c` | Export results to CSV |
| `--verbose` | `-v` | Enable verbose output (INFO level) |
| `--debug` | | Enable debug output (DEBUG level) |
| `--log-file` | `-l` | Write logs to file (always DEBUG level) |
| `--quiet` | `-q` | Suppress console output (log file still works) |

## Python API

```python
from pathlib import Path
from pypasreporter_pacliparser import (
    parse_dbparm_ini,
    parse_license_xml,
    parse_policies_xml,
    parse_policies_xml_wide,
    parse_cpm_ini_files,
    parse_cpm_ini_files_wide,
)

# Parse DBParm.ini
records = parse_dbparm_ini(Path("DBParm.ini"))
# Returns: [{"section": "MAIN", "key": "BasePort", "value": "1858"}, ...]

# Parse License.xml
records = parse_license_xml(Path("License.xml"))
# Returns: [{"category": "Limitations", "section": "LicenseLimitations", 
#            "key": "ExpirationDate", "value": "2027-09-30"}, ...]

# Parse Policies.xml (long format)
records = parse_policies_xml(Path("Policies.xml"))
# Returns: [{"policy_id": "CyberArk", "key": "AutoChangeOnAdd", "value": "No"}, ...]

# Parse Policies.xml (wide format - one row per policy)
records = parse_policies_xml_wide(Path("Policies.xml"))
# Returns: [{"policy_id": "CyberArk", "autochangeonadd": "No", ...}, ...]

# Parse CPM INI files (long format)
records = parse_cpm_ini_files(Path("./cpm_ini_policies/"))
# Returns: [{"file_name": "Policy-Windows.ini", "section": "DEFAULT", 
#            "key": "PolicyID", "value": "Windows"}, ...]

# Parse CPM INI files (wide format)
records = parse_cpm_ini_files_wide(Path("./cpm_ini_policies/"))
# Returns: [{"file_name": "Policy-Windows.ini", "policyid": "Windows", ...}, ...]
```

## Output Tables

When loading to DuckDB with schema `cyberark_pacli`:

| Table | Source | Format | Description |
|-------|--------|--------|-------------|
| `dbparm` | DBParm.ini | Long | Vault configuration (section/key/value) |
| `license` | License.xml | Long | License info (category/section/key/value) |
| `policies` | Policies.xml | Wide | Platform policies (one row per policy) |
| `policies_long` | Policies.xml | Long | Platform policies (policy_id/key/value) |
| `cpm_policies` | cpm_ini_policies/*.ini | Wide | CPM configs (one row per file) |
| `cpm_policies_long` | cpm_ini_policies/*.ini | Long | CPM configs (file/section/key/value) |

## Column Naming

All column names are normalized to snake_case:

| Original | Normalized |
|----------|------------|
| `UserName` | `user_name` |
| `PolicyID` | `policy_id` |
| `PSMConcurrentSessions` | `psm_concurrent_sessions` |
| `ChangeTask.EnforcePolicy` | `change_task_enforce_policy` |

## Part of pyPASreporter Ecosystem

| Package | Description |
|---------|-------------|
| [pyPASreporter](https://pypi.org/project/pyPASreporter/) | Main reporting package |
| [pyPASreporter-EVDparser](https://pypi.org/project/pyPASreporter-EVDparser/) | EVD CSV export parser |
| [pyPASreporter-PACLIparser](https://pypi.org/project/pyPASreporter-PACLIparser/) | PACLI config parser (this package) |

## License

MIT