|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | +Activates/Deactivates LifeScienceTriggerHandler records by DeveloperName. |
| 4 | +
|
| 5 | +.DESCRIPTION |
| 6 | +- Uses the Tooling API for setup entity updates (no REST calls). |
| 7 | +- Accepts names via -Names or -File. If none provided, extracts DeveloperName values |
| 8 | + from TriggerHandlers.ts in the current directory. |
| 9 | +
|
| 10 | +# Requirements: Salesforce CLI (sf or sfdx) |
| 11 | +
|
| 12 | +.EXAMPLE |
| 13 | +.\activate_trigger_handlers.ps1 -org myAlias -names "HandlerA,HandlerB" |
| 14 | +.\activate_trigger_handlers.ps1 -org myAlias -file handlers.txt |
| 15 | +.\activate_trigger_handlers.ps1 -org myAlias |
| 16 | +#> |
| 17 | + |
| 18 | +param ( |
| 19 | + [string]$org = "", |
| 20 | + [string]$names = "", |
| 21 | + [string]$file = "", |
| 22 | + [string]$apiVersion = "65.0", |
| 23 | + [switch]$deactivate, |
| 24 | + [switch]$verboseOut |
| 25 | +) |
| 26 | + |
| 27 | +$ErrorActionPreference = "Stop" |
| 28 | + |
| 29 | +# Use sf if available, fallback to sfdx |
| 30 | +$sfCli = "sf" |
| 31 | +if (-not (Get-Command $sfCli -ErrorAction SilentlyContinue)) { |
| 32 | + $sfCli = "sfdx" |
| 33 | + if (-not (Get-Command $sfCli -ErrorAction SilentlyContinue)) { |
| 34 | + Write-Error "Salesforce CLI (sf or sfdx) not found" |
| 35 | + exit 1 |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +# --- 1. Get Authentication Info --- |
| 40 | +function Get-OrgAuth { |
| 41 | + param([string]$orgAlias) |
| 42 | + |
| 43 | + $authJson = "" |
| 44 | + if ($sfCli -eq "sf") { |
| 45 | + if ([string]::IsNullOrWhiteSpace($orgAlias)) { |
| 46 | + $authJson = sf org display --json |
| 47 | + } else { |
| 48 | + $authJson = sf org display --json --target-org "$orgAlias" |
| 49 | + } |
| 50 | + } else { |
| 51 | + if ([string]::IsNullOrWhiteSpace($orgAlias)) { |
| 52 | + $authJson = sfdx force:org:display --json |
| 53 | + } else { |
| 54 | + $authJson = sfdx force:org:display --json -u "$orgAlias" |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + return $authJson | ConvertFrom-Json |
| 59 | +} |
| 60 | + |
| 61 | +Write-Host "Retrieving Org Authentication..." |
| 62 | +$authObj = Get-OrgAuth -orgAlias $org |
| 63 | + |
| 64 | +$accessToken = $authObj.result.accessToken |
| 65 | +$instanceUrl = $authObj.result.instanceUrl |
| 66 | + |
| 67 | +if ([string]::IsNullOrEmpty($accessToken) -or [string]::IsNullOrEmpty($instanceUrl)) { |
| 68 | + Write-Error "Could not retrieve access token or instance URL. Ensure you are logged into a default org or provide -org." |
| 69 | + exit 1 |
| 70 | +} |
| 71 | + |
| 72 | +if ($verboseOut) { |
| 73 | + Write-Host "Instance URL: $instanceUrl" |
| 74 | + Write-Host "API Version: $apiVersion" |
| 75 | +} |
| 76 | + |
| 77 | + |
| 78 | +# --- 2. Determine Developer Names to Process --- |
| 79 | +$developerNames = @() |
| 80 | + |
| 81 | +if (-not [string]::IsNullOrWhiteSpace($names)) { |
| 82 | + $developerNames = $names -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } |
| 83 | +} |
| 84 | +elseif (-not [string]::IsNullOrWhiteSpace($file)) { |
| 85 | + if (-not (Test-Path $file)) { |
| 86 | + Write-Error "File not found: $file" |
| 87 | + exit 1 |
| 88 | + } |
| 89 | + $developerNames = Get-Content $file | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } |
| 90 | +} |
| 91 | +else { |
| 92 | + # Default behavior: parse TriggerHandlers.ts |
| 93 | + Write-Host "No -names or -file provided. Parsing DeveloperName from TriggerHandlers.ts..." |
| 94 | + $tsPath = "TriggerHandlers.ts" |
| 95 | + if (-not (Test-Path $tsPath)) { |
| 96 | + # Assume it might be executed from the root, try that path. |
| 97 | + $tsPath = "TriggerHandlers\TriggerHandlers.ts" |
| 98 | + } |
| 99 | + |
| 100 | + if (Test-Path $tsPath) { |
| 101 | + $content = Get-Content $tsPath |
| 102 | + # Regex to match DeveloperName: "value" or 'DeveloperName': "value" |
| 103 | + foreach ($line in $content) { |
| 104 | + if ($line -match "['""]?DeveloperName['""]?\s*:\s*""([^""]+)""") { |
| 105 | + $developerNames += $matches[1] |
| 106 | + } |
| 107 | + } |
| 108 | + $developerNames = $developerNames | Select-Object -Unique |
| 109 | + } else { |
| 110 | + Write-Error "TriggerHandlers.ts not found. Please specify -names or -file." |
| 111 | + exit 1 |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +if ($developerNames.Count -eq 0) { |
| 116 | + Write-Error "No DeveloperName values found." |
| 117 | + exit 1 |
| 118 | +} |
| 119 | + |
| 120 | +# --- 3. Processing Handlers --- |
| 121 | +$headers = @{ |
| 122 | + "Authorization" = "Bearer $accessToken" |
| 123 | + "Content-Type" = "application/json" |
| 124 | +} |
| 125 | + |
| 126 | +$successCount = 0 |
| 127 | +$skippedCount = 0 |
| 128 | +$notFoundCount = 0 |
| 129 | +$failedCount = 0 |
| 130 | + |
| 131 | +foreach ($devName in $developerNames) { |
| 132 | + if ($verboseOut) { Write-Host "Processing DeveloperName: $devName" } |
| 133 | + |
| 134 | + $soql = "SELECT Id, IsActive, DeveloperName FROM LifeScienceTriggerHandler WHERE DeveloperName = '$devName'" |
| 135 | + $encodedSoql = [uri]::EscapeDataString($soql) |
| 136 | + |
| 137 | + $record = $null |
| 138 | + |
| 139 | + # Tooling API Query |
| 140 | + $toolingUrl = "$instanceUrl/services/data/v$apiVersion/tooling/query?q=$encodedSoql" |
| 141 | + try { |
| 142 | + $toolingResponse = Invoke-RestMethod -Uri $toolingUrl -Headers $headers -Method Get |
| 143 | + if ($toolingResponse.totalSize -gt 0) { |
| 144 | + $record = $toolingResponse.records[0] |
| 145 | + } |
| 146 | + } catch { |
| 147 | + # Fallback to standard REST API Query |
| 148 | + $restUrl = "$instanceUrl/services/data/v$apiVersion/query?q=$encodedSoql" |
| 149 | + try { |
| 150 | + $restResponse = Invoke-RestMethod -Uri $restUrl -Headers $headers -Method Get |
| 151 | + if ($restResponse.totalSize -gt 0) { |
| 152 | + $record = $restResponse.records[0] |
| 153 | + } |
| 154 | + } catch { } |
| 155 | + } |
| 156 | + |
| 157 | + if ($null -eq $record) { |
| 158 | + if ($verboseOut) { Write-Host " Not found in org." } |
| 159 | + $notFoundCount++ |
| 160 | + continue |
| 161 | + } |
| 162 | + |
| 163 | + $id = $record.Id |
| 164 | + $isActive = $record.IsActive |
| 165 | + $targetActive = -not $deactivate |
| 166 | + |
| 167 | + if ($targetActive -eq $isActive) { |
| 168 | + if ($verboseOut) { Write-Host " Already in desired state. Skipping." } |
| 169 | + $skippedCount++ |
| 170 | + continue |
| 171 | + } |
| 172 | + |
| 173 | + $bodyMap = @{ "IsActive" = $targetActive } |
| 174 | + $bodyJson = $bodyMap | ConvertTo-Json -Compress |
| 175 | + |
| 176 | + $updateSuccess = $false |
| 177 | + |
| 178 | + # Attempt Standard sObject REST Update |
| 179 | + $updateStdUrl = "$instanceUrl/services/data/v$apiVersion/sobjects/LifeScienceTriggerHandler/$id" |
| 180 | + try { |
| 181 | + $updateResp = Invoke-RestMethod -Uri $updateStdUrl -Headers $headers -Method Patch -Body $bodyJson |
| 182 | + $updateSuccess = $true |
| 183 | + if ($verboseOut) { Write-Host " Updated via Standard REST." } |
| 184 | + } catch { |
| 185 | + # Attempt Tooling API Update |
| 186 | + $updateToolUrl = "$instanceUrl/services/data/v$apiVersion/tooling/sobjects/LifeScienceTriggerHandler/$id" |
| 187 | + try { |
| 188 | + $updateResp = Invoke-RestMethod -Uri $updateToolUrl -Headers $headers -Method Patch -Body $bodyJson |
| 189 | + $updateSuccess = $true |
| 190 | + if ($verboseOut) { Write-Host " Updated via Tooling API." } |
| 191 | + } catch { } |
| 192 | + } |
| 193 | + |
| 194 | + if ($updateSuccess) { |
| 195 | + $successCount++ |
| 196 | + } else { |
| 197 | + if ($verboseOut) { Write-Host " Update failed." } |
| 198 | + $failedCount++ |
| 199 | + } |
| 200 | +} |
| 201 | + |
| 202 | +Write-Host "`nDone. Summary:" |
| 203 | +$successLabel = if ($deactivate) { "Deactivated" } else { "Activated" } |
| 204 | +$skippedLabel = if ($deactivate) { "Already Inactive" } else { "Already Active" } |
| 205 | +Write-Host " $successLabel : $successCount" |
| 206 | +Write-Host " $skippedLabel : $skippedCount" |
| 207 | +Write-Host " Not Found : $notFoundCount" |
| 208 | +Write-Host " Failed : $failedCount" |
| 209 | + |
| 210 | +if ($failedCount -gt 0) { |
| 211 | + exit 1 |
| 212 | +} |
| 213 | +exit 0 |
0 commit comments