#!/usr/bin/env pwsh <# .SYNOPSIS Streamlined metadata retrieval wrapper for Salesforce CLI .DESCRIPTION A user-friendly wrapper around 'sf project retrieve' commands that simplifies metadata retrieval from Salesforce orgs with intelligent defaults and validation. .PARAMETER MetadataTypes Comma-separated list of metadata types to retrieve (e.g., "ApexClass,CustomObject") .PARAMETER Manifest Path to package.xml or manifest file for retrieval .PARAMETER Package Package name for package-based retrieval .PARAMETER OutputDir Output directory for retrieved metadata (default: current directory) .PARAMETER TargetOrg Target org username or alias (uses default if not specified) .PARAMETER Wait Wait time in minutes for the retrieve operation (default: 10) .PARAMETER Verbose Enable verbose output .PARAMETER Help Show this help message .EXAMPLE .\sf-retrieve.ps1 -MetadataTypes "ApexClass,CustomObject" .\sf-retrieve.ps1 -Manifest "manifest/package.xml" .\sf-retrieve.ps1 -Package "MyPackage" -TargetOrg "myorg" .\sf-retrieve.ps1 -MetadataTypes "Flow" -OutputDir "./retrieved" -Verbose .NOTES This script automatically checks for Salesforce CLI installation and runs diagnostics if the CLI is not found. #> param( [Parameter(ParameterSetName="Types")] [string]$MetadataTypes, [Parameter(ParameterSetName="Manifest")] [string]$Manifest, [Parameter(ParameterSetName="Package")] [string]$Package, [string]$OutputDir, [string]$TargetOrg, [int]$Wait = 10, [switch]$Verbose, [switch]$Help ) # Show help if requested if ($Help) { Get-Help $MyInvocation.MyCommand.Path -Detailed exit 0 } # Function to check if Salesforce CLI is installed function Test-SalesforceCLI { try { $null = Get-Command sf -ErrorAction Stop return $true } catch { return $false } } # Function to run sf-check diagnostics function Invoke-SalesforceCheck { $checkScript = if (Test-Path "sf-check.ps1") { ".\sf-check.ps1" } elseif (Test-Path "sf-check.sh") { "bash sf-check.sh" } else { $null } if ($checkScript) { Write-Host "Running Salesforce CLI diagnostics..." -ForegroundColor Yellow Invoke-Expression $checkScript } else { Write-Host "Salesforce CLI not found and no diagnostic script available." -ForegroundColor Red Write-Host "Please install the Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli" -ForegroundColor Red } } # Silently check for Salesforce CLI if (-not (Test-SalesforceCLI)) { Invoke-SalesforceCheck exit 1 } # Validate that exactly one retrieval method is specified $methodCount = @($MetadataTypes, $Manifest, $Package | Where-Object { $_ }).Count if ($methodCount -eq 0) { Write-Host "Error: Must specify one of: -MetadataTypes, -Manifest, or -Package" -ForegroundColor Red Write-Host "" Write-Host "Usage examples:" -ForegroundColor Yellow Write-Host " .\sf-retrieve.ps1 -MetadataTypes `"ApexClass,CustomObject`"" -ForegroundColor Gray Write-Host " .\sf-retrieve.ps1 -Manifest `"manifest/package.xml`"" -ForegroundColor Gray Write-Host " .\sf-retrieve.ps1 -Package `"MyPackage`"" -ForegroundColor Gray Write-Host "" Write-Host "Use -Help for detailed usage information." -ForegroundColor Yellow exit 1 } if ($methodCount -gt 1) { Write-Host "Error: Can only specify one of: -MetadataTypes, -Manifest, or -Package" -ForegroundColor Red exit 1 } # Validate manifest file exists if specified if ($Manifest -and -not (Test-Path $Manifest)) { Write-Host "Error: Manifest file not found: $Manifest" -ForegroundColor Red exit 1 } # Build the sf command $sfArgs = @("project", "retrieve", "start") # Add retrieval method if ($MetadataTypes) { $sfArgs += "--metadata" $sfArgs += $MetadataTypes Write-Host "Retrieving metadata types: $MetadataTypes" -ForegroundColor Green } elseif ($Manifest) { $sfArgs += "--manifest" $sfArgs += $Manifest Write-Host "Retrieving from manifest: $Manifest" -ForegroundColor Green } elseif ($Package) { $sfArgs += "--package-name" $sfArgs += $Package Write-Host "Retrieving package: $Package" -ForegroundColor Green } # Add optional parameters if ($OutputDir) { if (-not (Test-Path $OutputDir)) { Write-Host "Creating output directory: $OutputDir" -ForegroundColor Yellow New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } $sfArgs += "--output-dir" $sfArgs += $OutputDir } if ($TargetOrg) { $sfArgs += "--target-org" $sfArgs += $TargetOrg Write-Host "Target org: $TargetOrg" -ForegroundColor Cyan } if ($Wait -ne 10) { $sfArgs += "--wait" $sfArgs += $Wait.ToString() } # Add verbose flag if requested if ($Verbose) { $sfArgs += "--verbose" } # Display the command being run Write-Host "" Write-Host "Executing: sf $($sfArgs -join ' ')" -ForegroundColor Gray Write-Host "" # Execute the command try { & sf @sfArgs $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { Write-Host "" Write-Host "✅ Metadata retrieval completed successfully!" -ForegroundColor Green } else { Write-Host "" Write-Host "❌ Metadata retrieval failed with exit code: $exitCode" -ForegroundColor Red exit $exitCode } } catch { Write-Host "Error executing sf command: $($_.Exception.Message)" -ForegroundColor Red exit 1 }