ZPA to Entra Private Access (EPA) Configuration Transformer
Overview
This PowerShell function (Convert-ZPA2EPA) transforms exported Zscaler Private Access (ZPA) application segment configurations into a format suitable for Microsoft Entra Private Access (EPA). It processes JSON export files from ZPA and generates CSV files containing Enterprise Application configurations that can be imported into Microsoft's Global Secure Access (GSA) solution.
What It Does
The function performs the following key functions:
- Loads ZPA Configuration: Reads JSON export files containing ZPA application segments, segment groups, access policies, and SCIM groups
- Processes Access Policies: Automatically maps ZPA access policies to SCIM groups and populates Entra ID group assignments
- Transforms Data: Converts ZPA application segments into EPA-compatible Enterprise Application configurations
- Detects Conflicts: Identifies potential configuration conflicts using GSA-style interval-based detection
- Generates Output: Creates CSV files with all necessary configurations for EPA deployment
- Provides Guidance: Offers detailed logging and next-step recommendations
Key Features
Access Policy Integration
- Automatic Group Mapping: Processes ZPA access policies to automatically populate Entra ID group assignments
- User and Group Support: Processes both SCIM groups and individual SCIM usernames from access policies
- APP_GROUP Expansion: Automatically expands application segment groups to individual applications
- SCIM Group Resolution: Resolves SCIM group IDs to group names from identity provider
- Policy Filtering: Intelligently filters and processes only valid access policies
- Smart Placeholders: Uses different placeholder values based on whether access policies are found
Advanced Filtering
- Exact Name Matching: Process specific application segments by name
- Wildcard Pattern Matching: Use patterns like
*web*to match multiple segments - Skip Filters: Exclude specific segments or patterns from processing
- Combination Filtering: Apply multiple filters simultaneously
Intelligent Conflict Detection
- IP Range Overlaps: Detects conflicts between IP addresses and CIDR ranges
- Port Range Conflicts: Identifies overlapping port ranges across protocols
- FQDN Conflicts: Catches duplicate hostnames with conflicting configurations
- Wildcard Domain Handling: Manages conflicts with wildcard DNS patterns (*.domain.com)
Comprehensive Validation
- CIDR Validation: Ensures proper subnet notation and valid IP ranges
- Port Range Validation: Validates TCP/UDP port ranges (1-65535)
- IP Address Validation: Checks IP address format and octet values
- Data Integrity: Handles malformed or incomplete configurations gracefully
Comprehensive Output
- Structured Logging: Color-coded console output with file logging
- Progress Tracking: Real-time progress indicators for large datasets
- CSV Export: Clean, Excel-compatible CSV output
- Conflict Reporting: Detailed conflict analysis and resolution guidance
Prerequisites
System Requirements
- PowerShell: Version 5.1 or later (PowerShell 7+ recommended)
- Operating System: Windows 10/11 or Windows Server 2016+
- Memory: Minimum 4GB RAM (8GB+ recommended for large configurations)
- Storage: Sufficient disk space for input JSON files and output CSV files
Required Files
- Required: ZPA Application Segments JSON export file (typically named
application_segments.json) - Optional: ZPA Segment Groups JSON export file (
segment_groups.json) - for deduplication and APP_GROUP expansion - Optional: ZPA Access Policies JSON export file (
access_policies.json) - for automatic group mapping - Optional: SCIM Groups JSON export file (
scim_groups.json) - for SCIM group name resolution - All files generated by the companion
Export-ZPAConfigfunction
Parameters
Input/Output Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
AppSegmentPath | String | No | Path to the ZPA Application Segments JSON file (default: App_Segments.json in current directory) |
OutputBasePath | String | No | Base directory for output files (default: current directory) |
PassThru | Switch | No | Return results to pipeline instead of just saving to file |
Access Policy Parameters (Optional)
| Parameter | Type | Required | Description |
|---|---|---|---|
SegmentGroupPath | String | No | Path to ZPA Segment Groups JSON file (used for deduplication and APP_GROUP expansion) |
AccessPolicyPath | String | No | Path to ZPA Access Policies JSON file (default: access_policies.json in current directory) |
ScimGroupPath | String | No | Path to SCIM Groups JSON file (default: scim_groups.json in current directory) |
Filtering Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
TargetAppSegmentName | String | No | Process only the segment with this exact name |
AppSegmentNamePattern | String | No | Wildcard pattern for segment names (e.g., *web*, prod-*) |
SkipAppSegmentName | String | No | Comma-separated list of exact segment names to skip |
SkipAppSegmentNamePattern | String | No | Comma-separated list of wildcard patterns to skip |
Debug Parameter
| Parameter | Type | Required | Description |
|---|---|---|---|
EnableDebugLogging | Switch | No | Enable verbose debug logging for troubleshooting |
Usage Examples
Basic Usage
Transform all application segments using default settings:
Convert-ZPA2EPA
Specify Custom Paths
Use custom input and output paths:
Convert-ZPA2EPA -AppSegmentPath "C:\ZPA\exports\App_Segments.json" -OutputBasePath "C:\EPA\output"
Process Specific Segment
Transform only a specific application segment:
Convert-ZPA2EPA -TargetAppSegmentName "Web-Application-Prod"
Pattern-Based Filtering
Process all production web applications:
Convert-ZPA2EPA -AppSegmentNamePattern "*web*prod*"
Skip Specific Segments
Process all segments except test environments:
Convert-ZPA2EPA -SkipAppSegmentNamePattern "*test*,*dev*"
Debug Mode
Enable detailed logging for troubleshooting:
Convert-ZPA2EPA -EnableDebugLogging
With Access Policy Integration
Automatically populate Entra ID group assignments from ZPA access policies:
Convert-ZPA2EPA `
-AppSegmentPath "C:\ZPA\application_segments.json" `
-SegmentGroupPath "C:\ZPA\segment_groups.json" `
-AccessPolicyPath "C:\ZPA\access_policies.json" `
-ScimGroupPath "C:\ZPA\scim_groups.json" `
-OutputBasePath "C:\EPA\output"
Complex Filtering Example
Process production segments while skipping legacy applications:
Convert-ZPA2EPA `
-AppSegmentNamePattern "*prod*" `
-SkipAppSegmentName "Legacy-App-1,Legacy-App-2" `
-SkipAppSegmentNamePattern "*deprecated*" `
-AccessPolicyPath ".\access_policies.json" `
-ScimGroupPath ".\scim_groups.json" `
-EnableDebugLogging
Input File Format
The script expects a JSON file containing an array of ZPA application segments. Each segment should have the following structure:
[
{
"name": "Web-Application-Prod",
"domainNames": ["webapp.company.com", "*.api.company.com"],
"tcpPortRange": [
{"from": 80, "to": 80},
{"from": 443, "to": 443}
],
"udpPortRange": [
{"from": 53, "to": 53}
],
"segmentGroupName": "Production Apps",
"serverGroups": [
{"name": "Web-Servers-Group"}
]
}
]
Required Fields
name: Application segment namedomainNames: Array of domains (IP addresses, CIDR ranges, or FQDNs)
Optional Fields
tcpPortRange: Array of TCP port rangesudpPortRange: Array of UDP port rangessegmentGroupName: Segment group nameserverGroups: Array of server group objects
Output
Generated Files
-
CSV Export:
YYYYMMDD_HHMMSS_GSA_EnterpriseApps_All.csv- Timestamped filename for easy identification
- Contains all transformed Enterprise Application configurations
- Ready for EPA import or manual configuration
-
Log File:
Convert-ZPA2EPA.log- Detailed execution log with timestamps
- Error tracking and debugging information
- Color-coded console output mirrored to file
CSV Output Structure
| Column | Description |
|---|---|
SegmentId | Unique segment identifier (SEG-XXXXXX format) |
OriginalAppName | Original ZPA application segment name |
EnterpriseAppName | Generated EPA Enterprise Application name (prefixed with "GSA-") |
destinationHost | Target host (IP, CIDR, or FQDN) |
DestinationType | Type of destination (ipAddress, ipRangeCidr, or FQDN) |
Protocol | Network protocol (TCP or UDP) |
Ports | Port range (single port or range like "80-443") |
SegmentGroup | Original ZPA segment group |
ServerGroups | Associated server groups |
EntraGroups | Auto-populated from access policies or placeholder (see EntraGroups Values below) |
EntraUsers | Auto-populated from access policies or placeholder for individual user assignments |
ConnectorGroup | Placeholder for connector group (replace with actual values) |
Conflict | "Yes" if conflicts detected, "No" otherwise |
ConflictingEnterpriseApp | Names of conflicting applications |
Provision | "Yes" if ready to provision, "No" if conflicts need resolution |
EntraGroups and EntraUsers Values
The EntraGroups and EntraUsers columns are automatically populated based on access policy configuration:
EntraGroups Column:
Group1; Group2; Group3: Semicolon-separated SCIM group names when access policies are foundNo_Access_Policy_Found_Replace_Me: Access policy files provided but no policy found for this applicationPlaceholder_Replace_Me: Access policy files not provided (backward compatible mode)
EntraUsers Column:
user1@domain.com; user2@domain.com: Semicolon-separated usernames when individual user access policies are found- Empty or placeholder: No individual user access policies found for this application
Access Policy Integration
The function can automatically process ZPA access policies to populate Entra ID group assignments, eliminating manual placeholder replacement for the EntraGroups column.
How It Works
- Load Access Policies: Reads ZPA access policies from JSON export
- Load SCIM Groups: Reads SCIM group mappings from identity provider
- Filter Policies: Processes only valid ALLOW policies with simple AND logic
- Extract Targets: Identifies which applications and application groups are targeted
- Expand APP_GROUPs: Uses segment group membership to expand groups to individual apps
- Resolve Groups: Converts SCIM group IDs to group names and extracts SCIM usernames
- Build Lookup: Creates mapping of Application ID → SCIM group names and usernames
- Populate CSV: Automatically fills EntraGroups and EntraUsers columns with semicolon-separated values
Policy Filtering Criteria
The script processes policies that meet all of these criteria:
- ✅ Policy Type = "1" (Access Policy)
- ✅ Action = "ALLOW"
- ✅ Root Operator = "AND"
- ✅ Contains APP or APP_GROUP targets
- ✅ Contains SCIM_GROUP or SCIM username conditions
- ✅ No negated conditions
Policies that don't meet these criteria are skipped with logged reasons.
Conflict Detection
The function implements sophisticated conflict detection to prevent configuration issues:
IP Range Conflicts
- Detects overlapping IP addresses (ipAddress) and CIDR ranges (ipRangeCidr)
- Handles subnet containment and intersection scenarios
- Validates CIDR notation and IP address formats
Port Range Conflicts
- Identifies overlapping port ranges within the same protocol
- Handles single ports and port ranges
- Separates TCP and UDP conflict detection
Domain Conflicts
- Catches duplicate FQDN configurations
- Manages wildcard domain conflicts (*.domain.com)
- Validates domain name formats
Conflict Resolution
When conflicts are detected:
- The conflicting configuration is marked with
Conflict: Yes - The
ConflictingEnterpriseAppcolumn lists all conflicting applications - The
Provisioncolumn is set to "No" to prevent automatic deployment - Detailed conflict information is logged for manual review
Post-Processing Steps
After running the function, follow these steps:
1. Review Output
- Open the generated CSV file in Excel or a text editor
- Review the summary statistics in the console output
- Check the log file for any errors or warnings
2. Review and Update Values
The CSV may contain values that need review or replacement:
- EntraGroups:
- Auto-populated: If access policies were provided, review the automatically assigned groups for accuracy
No_Access_Policy_Found_Replace_Me: Replace with appropriate Entra ID group names for applications without policiesPlaceholder_Replace_Me: Replace with appropriate Entra ID group names if access policies weren't provided
- EntraUsers:
- Auto-populated: If access policies with individual users were found, review the automatically assigned usernames for accuracy
- Empty or placeholder: Add individual user assignments if needed
- ConnectorGroup: Replace
Placeholder_Replace_Mewith appropriate connector group names
3. Resolve Conflicts
For records marked with Conflict: Yes:
- Review the
ConflictingEnterpriseAppcolumn for details - Determine if conflicts are legitimate or can be consolidated
- Modify configurations as needed to resolve conflicts
- Update the
Provisioncolumn to "Yes" after resolution
4. Validate Configurations
- Confirm port ranges are correct for each application
- Ensure Entra ID groups and connector groups exist
- Test a small subset before bulk deployment
5. Import to Entra Private Access
Use the completed CSV to configure Enterprise Applications in Microsoft Entra Private Access.
Support and Contributing
This function is provided as-is for experimental use. When encountering issues:
- Enable Debug Logging: Use
-EnableDebugLoggingfor detailed information - Check Log Files: Review
script.logfor error details - Validate Input Data: Ensure ZPA export files are complete and valid
- Test Incrementally: Use filtering to isolate problematic segments
For improvements or bug fixes, consider contributing to the repository.
Related Tools
Export-ZPAConfig: Companion function for exporting ZPA configurations- Microsoft Entra Private Access Documentation
- Microsoft Global Secure Access Documentation