| name | dataverse-solution-importer |
| description | Import Dataverse solutions from Power Platform environments using PAC CLI. Automatically retrieves environment details, exports solutions, stores ZIP files, and extracts components. Use when user requests to import, export, download, or extract a Dataverse solution from an environment. |
Dataverse Solution Importer
Overview
This skill automates the complete workflow for importing Dataverse solutions from Power Platform environments into the local workspace. It uses the Power Platform CLI (pac) to connect to environments, export solutions, organize ZIP files, and extract solution components for analysis or version control.
When to Use This Skill
Use this skill when:
- User requests to import/export a Dataverse solution
- Need to download a solution from a specific environment
- Want to extract solution components for review or version control
- User mentions "import [solution] from [environment]"
- Need to backup or analyze a Dataverse solution locally
- Preparing to generate AL tables from Dataverse entities
Prerequisites
Before running this skill, ensure:
- Power Platform CLI (pac) is installed and authenticated
- User has access to the target Dataverse environment
- User has permissions to export solutions from the environment
dataversesolutions/ folder exists in the workspace
dataversesolutions/ZIPFiles/ folder exists (will be created if not)
Core Workflow
Step 1: Get Environment ID from Environment Name
When the user specifies an environment by name (e.g., "BCS MCP Sandbox"), retrieve the environment ID:
List all available environments:
pac org list
Parse the output to find matching environment:
# User provides environment name
$envName = "BCS MCP Sandbox"
# Get list of all environments
$orgList = pac org list 2>&1 | Out-String
# Parse to find matching environment
# The pac org list output format:
# Active Display Name Environment ID Environment URL Unique Name
# Extract environment ID using regex or string parsing
if ($orgList -match "$envName\s+([a-f0-9\-]+)") {
$envId = $matches[1]
Write-Host "Found environment: $envName"
Write-Host "Environment ID: $envId"
} else {
Write-Host "Error: Environment '$envName' not found"
exit 1
}
Alternative: Use exact name matching
# More robust parsing
$environments = pac org list 2>&1 |
Select-String -Pattern "^\s*\S+\s+(.+?)\s+([a-f0-9\-]{36})" |
ForEach-Object {
[PSCustomObject]@{
Name = $_.Matches.Groups[1].Value.Trim()
EnvironmentId = $_.Matches.Groups[2].Value
}
}
$targetEnv = $environments | Where-Object { $_.Name -eq $envName }
if ($targetEnv) {
$envId = $targetEnv.EnvironmentId
} else {
Write-Host "Available environments:"
$environments | Format-Table
throw "Environment '$envName' not found"
}
Environment name variations to handle:
- Exact match: "BCS MCP Sandbox"
- Partial match: "MCP Sandbox" → "BCS MCP Sandbox"
- Case insensitive: "bcs mcp sandbox" → "BCS MCP Sandbox"
Step 2: List Solutions and Find Target Solution
Once connected to the environment, list all solutions to find the target:
Get all solutions in the environment:
# List solutions from the specific environment
pac solution list --environment $envId
# Output format:
# Unique Name Friendly Name Version Managed
# Cra6877 Common Data Services... 1.0.0.0 False
# CustomerCentricSolution Customer Centric Solution 1.0.0.0 False
Filter for custom solutions only:
Custom solutions typically:
- Have
Managed = False (unmanaged)
- Are NOT system solutions (Default, CDS default, Dynamics365Company)
- Have custom naming conventions (e.g., company prefix)
# Get solution list and filter out system solutions
$solutionList = pac solution list --environment $envId 2>&1 | Out-String
# Parse solutions
$solutions = @()
$lines = $solutionList -split "`n" | Select-Object -Skip 4 # Skip header lines
foreach ($line in $lines) {
if ($line -match "^(\S+)\s+(.+?)\s+(\d+\.\d+\.\d+\.\d+)\s+(True|False)") {
$uniqueName = $matches[1]
$friendlyName = $matches[2].Trim()
$version = $matches[3]
$isManaged = $matches[4] -eq "True"
# Filter out system solutions
$systemSolutions = @("Default", "Cra6877", "Dynamics365Company", "Active", "Basic", "msdyn_")
$isSystemSolution = $systemSolutions | Where-Object { $uniqueName -like "$_*" }
if (-not $isSystemSolution) {
$solutions += [PSCustomObject]@{
UniqueName = $uniqueName
FriendlyName = $friendlyName
Version = $version
Managed = $isManaged
}
}
}
}
# Display custom solutions
Write-Host "Custom Solutions Found:"
$solutions | Format-Table -AutoSize
Find target solution by friendly name or unique name:
# User provides solution name (friendly or unique)
$requestedSolution = "Customer Centric Solution"
# Try to find by friendly name first
$targetSolution = $solutions | Where-Object {
$_.FriendlyName -like "*$requestedSolution*" -or
$_.UniqueName -like "*$requestedSolution*"
}
if (-not $targetSolution) {
Write-Host "Solution '$requestedSolution' not found."
Write-Host "Available custom solutions:"
$solutions | Format-Table
exit 1
}
$solutionUniqueName = $targetSolution.UniqueName
Write-Host "Found solution: $($targetSolution.FriendlyName)"
Write-Host "Unique Name: $solutionUniqueName"
Step 3: Export Solution and Store in ZIPFiles Folder
Export the solution from Dataverse and save it to the dataversesolutions/ZIPFiles/ directory with a timestamp:
Create ZIPFiles directory if it doesn't exist:
$zipFilesPath = "dataversesolutions/ZIPFiles"
if (-not (Test-Path $zipFilesPath)) {
New-Item -Path $zipFilesPath -ItemType Directory -Force
Write-Host "Created directory: $zipFilesPath"
}
Generate timestamped filename:
# Create timestamp in format: YYYYMMDD-HHmmss
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$zipFileName = "$solutionUniqueName-$timestamp.zip"
Write-Host "ZIP filename: $zipFileName"
Export the solution:
# Navigate to ZIPFiles directory
Set-Location $zipFilesPath
# Export solution (unmanaged version) with timestamped name
Write-Host "Exporting solution '$solutionUniqueName'..."
pac solution export `
--path $zipFileName `
--name $solutionUniqueName `
--managed false `
--environment $envId
if ($LASTEXITCODE -eq 0) {
Write-Host "✅ Solution exported successfully: $zipFileName"
# Get file info
$fileInfo = Get-Item $zipFileName
Write-Host "File size: $([math]::Round($fileInfo.Length/1KB, 2)) KB"
Write-Host "Location: $($fileInfo.FullName)"
} else {
Write-Host "❌ Solution export failed"
exit 1
}
# Return to root directory
Set-Location ../..
Timestamped files preserve history:
# Timestamped files automatically prevent conflicts
# Each export creates a unique file
# Benefits:
# - Full history of solution versions
# - No accidental overwrites
# - Easy comparison between versions
# - Rollback capability
Write-Host "Timestamped export preserves previous versions"
# Optional: Clean up old exports (keep last 10)
$oldZips = Get-ChildItem "$zipFilesPath" -Filter "$solutionUniqueName-*.zip" |
Sort-Object LastWriteTime -Descending |
Select-Object -Skip 10
if ($oldZips) {
Write-Host "Cleaning up $($oldZips.Count) old export(s)"
$oldZips | Remove-Item -Force
}
Step 4: Extract Solution Components to Folder (Auto-Update)
Extract the solution ZIP file and automatically update the existing folder with new changes:
Set up extraction paths:
$zipFilePath = "dataversesolutions/ZIPFiles/$zipFileName"
$extractFolder = "dataversesolutions/$solutionUniqueName"
# Check if extraction folder already exists
if (Test-Path $extractFolder) {
Write-Host "📁 Found existing solution folder: $extractFolder"
Write-Host "🔄 Updating with new changes from latest export..."
# Create temporary extraction folder
$tempFolder = "dataversesolutions/temp_$solutionUniqueName"
if (Test-Path $tempFolder) {
Remove-Item $tempFolder -Recurse -Force
}
# Extract to temp folder first
pac solution unpack --zipfile $zipFilePath --folder $tempFolder --packagetype Unmanaged | Out-Null
# Compare and update files
Write-Host "Comparing changes..."
$newFiles = 0
$updatedFiles = 0
$unchangedFiles = 0
Get-ChildItem $tempFolder -Recurse -File | ForEach-Object {
$relativePath = $_.FullName.Substring($tempFolder.Length + 1)
$targetPath = Join-Path $extractFolder $relativePath
if (-not (Test-Path $targetPath)) {
# New file
$newFiles++
$targetDir = Split-Path $targetPath -Parent
if (-not (Test-Path $targetDir)) {
New-Item -Path $targetDir -ItemType Directory -Force | Out-Null
}
Copy-Item $_.FullName $targetPath -Force
} else {
# Compare existing file
$sourceHash = (Get-FileHash $_.FullName -Algorithm MD5).Hash
$targetHash = (Get-FileHash $targetPath -Algorithm MD5).Hash
if ($sourceHash -ne $targetHash) {
# Updated file
$updatedFiles++
Copy-Item $_.FullName $targetPath -Force
} else {
# Unchanged file
$unchangedFiles++
}
}
}
# Check for deleted files
$deletedFiles = 0
Get-ChildItem $extractFolder -Recurse -File | ForEach-Object {
$relativePath = $_.FullName.Substring($extractFolder.Length + 1)
$sourcePath = Join-Path $tempFolder $relativePath
if (-not (Test-Path $sourcePath)) {
$deletedFiles++
Write-Host " Removed: $relativePath" -ForegroundColor Yellow
Remove-Item $_.FullName -Force
}
}
# Clean up temp folder
Remove-Item $tempFolder -Recurse -Force
Write-Host "✅ Solution updated:"
Write-Host " New files: $newFiles" -ForegroundColor Green
Write-Host " Updated files: $updatedFiles" -ForegroundColor Cyan
Write-Host " Unchanged files: $unchangedFiles" -ForegroundColor Gray
if ($deletedFiles -gt 0) {
Write-Host " Deleted files: $deletedFiles" -ForegroundColor Yellow
}
} else {
Write-Host "📁 Creating new solution folder: $extractFolder"
# Fresh extraction for new solution
}
Extract using PAC CLI (for new solutions):
if (-not (Test-Path $extractFolder)) {
Write-Host "Extracting solution components..."
pac solution unpack `
--zipfile $zipFilePath `
--folder $extractFolder `
--packagetype Unmanaged
if ($LASTEXITCODE -eq 0) {
Write-Host "✅ Solution extracted successfully to: $extractFolder"
# List extracted components
Write-Host "`nExtracted Components:"
Get-ChildItem $extractFolder -Directory | ForEach-Object {
$componentCount = (Get-ChildItem $_.FullName -Recurse -File).Count
Write-Host " - $($_.Name): $componentCount files"
}
} else {
Write-Host "❌ Solution extraction failed"
exit 1
}
}
Analyze extracted structure:
# Show entities found
$entitiesPath = "$extractFolder/Entities"
if (Test-Path $entitiesPath) {
$entities = Get-ChildItem $entitiesPath -Directory
Write-Host "`n📊 Entities found ($($entities.Count)):"
$entities | ForEach-Object {
Write-Host " - $($_.Name)"
}
}
# Show option sets
$optionSetsPath = "$extractFolder/OptionSets"
if (Test-Path $optionSetsPath) {
$optionSets = Get-ChildItem $optionSetsPath -Directory
if ($optionSets.Count -gt 0) {
Write-Host "`n🎨 OptionSets found ($($optionSets.Count)):"
$optionSets | ForEach-Object {
Write-Host " - $($_.Name)"
}
}
}
# Show other components
$otherPath = "$extractFolder/Other"
if (Test-Path $otherPath) {
$other = Get-ChildItem $otherPath -Recurse -File
if ($other.Count -gt 0) {
Write-Host "`n📁 Other components: $($other.Count) files"
}
}
Step 5: Generate Summary and Next Steps
After successful import and extraction, provide a summary:
Write-Host "`n" + ("=" * 60)
Write-Host "✅ SOLUTION IMPORT COMPLETE"
Write-Host ("=" * 60)
Write-Host "Environment: $envName"
Write-Host "Solution: $($targetSolution.FriendlyName) (v$($targetSolution.Version))"
Write-Host "ZIP File: dataversesolutions/ZIPFiles/$zipFileName"
Write-Host "Extracted To: $extractFolder"
Write-Host "`nNext Steps:"
Write-Host "1. Review extracted entities in: $extractFolder/Entities/"
Write-Host "2. Generate AL tables using: @workspace Generate [entity] from Dataverse"
Write-Host "3. Use extract_ps_fields.ps1 to analyze solution structure"
Write-Host "4. Version control the extracted solution folder"
Complete Automation Script
Here's the complete workflow in a single script:
# Parameters
param(
[Parameter(Mandatory = $true)]
[string]$EnvironmentName,
[Parameter(Mandatory = $true)]
[string]$SolutionName
)
# Set error action preference
$ErrorActionPreference = "Stop"
try {
Write-Host "Starting Dataverse Solution Import..."
Write-Host ("=" * 60)
# Step 1: Get Environment ID
Write-Host "`n[1/4] Finding environment: $EnvironmentName"
$orgList = pac org list 2>&1 | Out-String
if ($orgList -match "$EnvironmentName\s+([a-f0-9\-]{36})") {
$envId = $matches[1]
Write-Host "✅ Found environment ID: $envId"
} else {
throw "Environment '$EnvironmentName' not found"
}
# Step 2: List solutions and find target
Write-Host "`n[2/4] Finding solution: $SolutionName"
$solutionListRaw = pac solution list --environment $envId 2>&1 | Out-String
# Parse solutions (skip system solutions)
$systemSolutions = @("Default", "Cra6877", "Dynamics365Company", "Active", "Basic")
$foundSolution = $null
foreach ($line in ($solutionListRaw -split "`n")) {
if ($line -match "^(\S+)\s+(.+?)\s+(\d+\.\d+\.\d+\.\d+)\s+(True|False)") {
$uniqueName = $matches[1]
$friendlyName = $matches[2].Trim()
# Skip system solutions
$isSystem = $false
foreach ($sys in $systemSolutions) {
if ($uniqueName -like "$sys*") {
$isSystem = $true
break
}
}
if (-not $isSystem -and ($friendlyName -like "*$SolutionName*" -or $uniqueName -like "*$SolutionName*")) {
$foundSolution = @{
UniqueName = $uniqueName
FriendlyName = $friendlyName
Version = $matches[3]
}
break
}
}
}
if (-not $foundSolution) {
throw "Solution '$SolutionName' not found"
}
$solutionUniqueName = $foundSolution.UniqueName
Write-Host "✅ Found solution: $($foundSolution.FriendlyName) v$($foundSolution.Version)"
Write-Host " Unique Name: $solutionUniqueName"
# Step 3: Export to ZIPFiles folder with timestamp
Write-Host "`n[3/4] Exporting solution..."
$zipFilesPath = "dataversesolutions/ZIPFiles"
if (-not (Test-Path $zipFilesPath)) {
New-Item -Path $zipFilesPath -ItemType Directory -Force | Out-Null
}
$originalLocation = Get-Location
Set-Location $zipFilesPath
# Generate timestamped filename
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$zipFileName = "$solutionUniqueName-$timestamp.zip"
pac solution export --path $zipFileName --name $solutionUniqueName --managed false --environment $envId | Out-Null
if ($LASTEXITCODE -eq 0) {
$fileInfo = Get-Item $zipFileName
Write-Host "✅ Solution exported: $zipFileName ($([math]::Round($fileInfo.Length/1KB, 2)) KB)"
} else {
throw "Solution export failed"
}
Set-Location $originalLocation
# Step 4: Extract/Update components
Write-Host "`n[4/4] Extracting/Updating solution components..."
$extractFolder = "dataversesolutions/$solutionUniqueName"
$zipFilePath = "$zipFilesPath/$zipFileName"
if (Test-Path $extractFolder) {
# Update existing solution
Write-Host "🔄 Updating existing solution folder..."
$tempFolder = "dataversesolutions/temp_$solutionUniqueName"
if (Test-Path $tempFolder) {
Remove-Item $tempFolder -Recurse -Force
}
pac solution unpack --zipfile $zipFilePath --folder $tempFolder --packagetype Unmanaged | Out-Null
# Sync changes
$newFiles = 0
$updatedFiles = 0
Get-ChildItem $tempFolder -Recurse -File | ForEach-Object {
$relativePath = $_.FullName.Substring($tempFolder.Length + 1)
$targetPath = Join-Path $extractFolder $relativePath
if (-not (Test-Path $targetPath)) {
$newFiles++
$targetDir = Split-Path $targetPath -Parent
if (-not (Test-Path $targetDir)) {
New-Item -Path $targetDir -ItemType Directory -Force | Out-Null
}
} else {
$updatedFiles++
}
Copy-Item $_.FullName $targetPath -Force
}
Remove-Item $tempFolder -Recurse -Force
Write-Host "✅ Updated: $newFiles new, $updatedFiles modified"
} else {
# Fresh extraction
pac solution unpack --zipfile $zipFilePath --folder $extractFolder --packagetype Unmanaged | Out-Null
Write-Host "✅ Solution extracted to: $extractFolder"
}
if ($LASTEXITCODE -eq 0) {
# List entities
$entitiesPath = "$extractFolder/Entities"
if (Test-Path $entitiesPath) {
$entities = Get-ChildItem $entitiesPath -Directory
Write-Host "`n📊 Entities found: $($entities.Count)"
$entities | ForEach-Object { Write-Host " - $($_.Name)" }
}
} else {
throw "Solution extraction failed"
}
# Summary
Write-Host "`n" + ("=" * 60)
Write-Host "✅ IMPORT COMPLETE"
Write-Host ("=" * 60)
Write-Host "Environment: $EnvironmentName"
Write-Host "Solution: $($foundSolution.FriendlyName) v$($foundSolution.Version)"
Write-Host "ZIP: $zipFilePath"
Write-Host "Extracted: $extractFolder"
Write-Host "`nNext: Generate AL tables from entities"
} catch {
Write-Host "`n❌ Error: $_"
exit 1
}
User Interaction Patterns
Pattern 1: Simple Solution Import (First Time)
User: "Import CustomerCentricSolution from BCS MCP Sandbox"
Agent Response:
Starting Dataverse Solution Import...
[1/4] Finding environment: BCS MCP Sandbox
✅ Found environment ID: 81975f46-4f75-ece1-baf1-cd27a5f21300
[2/4] Finding solution: CustomerCentricSolution
✅ Found solution: Customer Centric Solution v1.0.0.0
Unique Name: CustomerCentricSolution
[3/4] Exporting solution...
✅ Solution exported: CustomerCentricSolution-20260116-113045.zip (28.36 KB)
[4/4] Extracting solution components...
📁 Creating new solution folder: dataversesolutions/CustomerCentricSolution
✅ Solution extracted to: dataversesolutions/CustomerCentricSolution
📊 Entities found: 5
- Account
- bcs_country
- bcs_FinancialRatingAssessment
- bcs_RatingAgency
- SystemUser
✅ IMPORT COMPLETE
Environment: BCS MCP Sandbox
Solution: Customer Centric Solution v1.0.0.0
ZIP: dataversesolutions/ZIPFiles/CustomerCentricSolution-20260116-113045.zip
Extracted: dataversesolutions/CustomerCentricSolution
Next: Generate AL tables from entities
Pattern 2: Updating Existing Solution
User: "Import CustomerCentricSolution from BCS MCP Sandbox" (solution already exists)
Agent Response:
Starting Dataverse Solution Import...
[1/4] Finding environment: BCS MCP Sandbox
✅ Found environment ID: 81975f46-4f75-ece1-baf1-cd27a5f21300
[2/4] Finding solution: CustomerCentricSolution
✅ Found solution: Customer Centric Solution v1.0.0.0
Unique Name: CustomerCentricSolution
[3/4] Exporting solution...
✅ Solution exported: CustomerCentricSolution-20260116-143022.zip (29.12 KB)
[4/4] Extracting/Updating solution components...
📁 Found existing solution folder: dataversesolutions/CustomerCentricSolution
🔄 Updating with new changes from latest export...
Comparing changes...
✅ Solution updated:
New files: 3 (new entity added)
Updated files: 7 (field changes detected)
Unchanged files: 42
Deleted files: 1 (obsolete component removed)
📊 Entities found: 6
- Account
- bcs_country
- bcs_FinancialRatingAssessment
- bcs_RatingAgency
- bcs_NewEntity (NEW)
- SystemUser
✅ UPDATE COMPLETE
Environment: BCS MCP Sandbox
Solution: Customer Centric Solution v1.0.0.0
ZIP: dataversesolutions/ZIPFiles/CustomerCentricSolution-20260116-143022.zip
Updated: dataversesolutions/CustomerCentricSolution
Changes detected - review updated entities before generating AL tables.
Pattern 3: Import with Entity Generation
User: "Import PowerAppPOCSolution from BCS MCP Sandbox and generate AL tables for all entities"
Agent Response:
[Import completes as above]
Generating AL tables for all entities...
Entity 1: bcs_product
- Table ID: 70008
- Generated: BCSCDSProduct.Table.al ✅
Entity 2: bcs_order
- Table ID: 70009
- Generated: BCSCDSOrder.Table.al ✅
Build project to validate.
Pattern 4: Multiple Solution Imports
User: "Import PowerAppPOCSolution from BCS MCP Sandbox"
Agent Response:
[Import process completes...]
✅ IMPORT COMPLETE
Multiple solutions imported:
Solution 1: Customer Centric Solution
- ZIP: CustomerCentricSolution-20260116-113045.zip
- Folder: dataversesolutions/CustomerCentricSolution/
Solution 2: Power App POC Solution
- ZIP: PowerAppPOCSolution-20260116-113127.zip
- Folder: dataversesolutions/PowerAppPOCSolution/
ZIP Files:
- dataversesolutions/ZIPFiles/CustomerCentricSolution-20260116-113045.zip
- dataversesolutions/ZIPFiles/PowerAppPOCSolution-20260116-113127.zip
Extracted Folders:
- dataversesolutions/CustomerCentricSolution/
- dataversesolutions/PowerAppPOCSolution/
Timestamped exports preserve version history.
Pattern 5: Error Handling
User: "Import MySolution from TestEnv"
Agent Response:
[1/4] Finding environment: TestEnv
❌ Environment 'TestEnv' not found
Available environments:
- BCS MCP Sandbox
- BCS Sandbox
- BCSDeveloper
- Phoenix Developments (default)
Please specify one of the available environments.
Pattern 4: List Solutions Before Import
User: "What solutions are in BCS MCP Sandbox?"
Agent Response:
Connecting to: BCS MCP Sandbox
Custom Solutions Found:
┌────────────────────────────┬─────────────────────────────┬─────────┬─────────┐
│ Unique Name │ Friendly Name │ Version │ Managed │
├────────────────────────────┼─────────────────────────────┼─────────┼─────────┤
│ CustomerCentricSolution │ Customer Centric Solution │ 1.0.0.0 │ No │
│ PowerAppPOCSolution │ Power App POC Solution │ 1.0.0.0 │ No │
└────────────────────────────┴─────────────────────────────┴─────────┴─────────┘
To import: @workspace Import [solution name] from BCS MCP Sandbox
Folder Structure After Import
After successful import, the folder structure will be:
dataversesolutions/
├── ZIPFiles/
│ ├── CustomerCentricSolution-20260116-113045.zip
│ ├── CustomerCentricSolution-20260116-143022.zip (later update)
│ ├── PowerAppPOCSolution-20260116-113127.zip
│ └── ...
├── CustomerCentricSolution/
│ ├── Entities/
│ │ ├── Account/
│ │ ├── bcs_country/
│ │ └── ...
│ ├── OptionSets/
│ └── Other/
├── PowerAppPOCSolution/
│ ├── Entities/
│ ├── OptionSets/
│ └── Other/
├── Documentation/
└── extract_ps_fields.ps1
Troubleshooting
Issue: PAC CLI Not Found
Error: "'pac' is not recognized as an internal or external command"
Solution:
- Install Power Platform CLI:
winget install Microsoft.PowerPlatformCLI
- Or download from: https://aka.ms/PowerPlatformCLI
- Restart terminal after installation
Issue: Authentication Required
Error: "Not authenticated" or "Access denied"
Solution:
- Authenticate with PAC CLI:
pac auth create
- Follow browser authentication flow
- Verify authentication:
pac auth list
Issue: Solution Not Found
Error: "Solution 'XYZ' not found"
Solution:
- List all solutions to verify name:
pac solution list --environment [env-id]
- Use exact unique name or friendly name
- Check if solution is in a different environment
Issue: Export Permission Denied
Error: "User does not have permission to export solution"
Solution:
- Verify user has System Customizer or System Administrator role
- Check solution is not managed (managed solutions may have export restrictions)
- Ensure environment is accessible and not locked
Issue: Extraction Fails
Error: "Failed to unpack solution"
Solution:
- Verify ZIP file is not corrupted:
Test-Path "dataversesolutions/ZIPFiles/[solution].zip"
- Check disk space available
- Ensure no files are locked in target directory
- Try manual extraction first to verify ZIP integrity
Best Practices
- Use meaningful environment names - Clear naming helps avoid confusion
- Version control extracted solutions - Track changes to solution structure
- Automatic timestamping - All exports are automatically timestamped for history
- Review change summaries - Check new/updated/deleted files after updates
- Document custom entities - Add README in extracted folders
- Regular imports - Keep local copies synchronized with environments
- Archive old ZIPs - Automatic cleanup keeps last 10 versions
- Validate after extraction - Review entity structure before generating AL
- Check for dependencies - Some solutions require other solutions installed
- Test in sandbox first - Import to test environment before production
- Incremental updates - Solution folders update automatically without data loss
- Compare timestamps - Use ZIP timestamps to track when changes were made
Integration with Other Skills
This skill works alongside:
- bc-dataverse-entity-generator: Generate AL tables from imported entities
- bc-tooltip-manager: Add tooltips to generated entity pages
- AL build tools: Compile and validate generated AL code
- Version control: Track solution changes over time
Expected Outcomes
After running this skill successfully:
✅ Environment located and connected
✅ Solution found and identified
✅ Solution exported to ZIPFiles folder
✅ Components extracted to named folder
✅ Entity list available for AL generation
✅ Ready for Business Central integration development
Next Steps After Import
- Review extracted entities in
dataversesolutions/[Solution]/Entities/
- Analyze entity schemas to understand field structures
- Generate AL tables using bc-dataverse-entity-generator skill
- Create integration mappings in Business Central
- Set up synchronization between BC and Dataverse
- Test data flow end-to-end
- Version control the extracted solution
- Document custom entities and their business purpose
Quick Reference Commands
# List all environments
pac org list
# Find environment by name
pac org list | Select-String "BCS MCP Sandbox"
# List solutions in environment
pac solution list --environment [env-id]
# Export solution
pac solution export --path "[solution].zip" --name [solution-unique-name] --managed false --environment [env-id]
# Extract solution
pac solution unpack --zipfile "[solution].zip" --folder "[solution-folder]" --packagetype Unmanaged
# Complete workflow
.\Import-DataverseSolution.ps1 -EnvironmentName "BCS MCP Sandbox" -SolutionName "CustomerCentricSolution"
Common Environment IDs Reference
Store frequently used environment IDs for quick access:
# BCS environments
$BCSMCPSandbox = "81975f46-4f75-ece1-baf1-cd27a5f21300"
$BCSSandbox = "e91f5a9b-f426-e8dc-b6d8-7832b1386b04"
$BCSDeveloper = "581bbdb7-1f72-eb06-b651-01a0c2e0e55b"
# Use in commands
pac solution list --environment $BCSMCPSandbox