Scripts/ActivateFlows.ps1
#idea is to refactor SolutionDeploy into smaller scripts - to make maintenance easier function Activate-Flows-Step { Param( [string] [Parameter(Mandatory = $true)] $PipelinePath, [string] [Parameter(Mandatory = $true)] $SolutionFolder, [System.Object] [Parameter(Mandatory = $true)] $CRMConn, [System.Object] [Parameter(Mandatory = $true)] $Deploy, [bool] [Parameter(Mandatory = $true)] $RunLocally ) $FlowsToRetry = @() Write-Host "Establishing Connection References and Activating Flows" -ForegroundColor Green $ProgressPreference = "SilentlyContinue" # Activate Flows and Establish Connection References Write-Host "Getting Environment Id" $orgs = Get-CrmRecords -conn $CRMConn -EntityLogicalName organization if ($orgs.Count -gt 0) { $orgId = $orgs.CrmRecords[0].organizationid $Environment = Get-AdminPowerAppEnvironment | Where-Object OrganizationId -eq $orgId.Guid $EnvId = $Environment.EnvironmentName Write-Host "Environment Id - $EnvId" Write-Host "Checking if there are Connections References in the Solution that Need to be Wired Up" $solutions = Get-CrmRecords -conn $CRMConn -EntityLogicalName solution -FilterAttribute "uniquename" -FilterOperator "eq" -FilterValue "$($package.SolutionName)" $solutionId = $solutions.CrmRecords[0].solutionid $connRefs = (Get-CrmRecords -conn $CRMConn -EntityLogicalName connectionreference -FilterAttribute "solutionid" -FilterOperator eq -FilterValue $solutionid -Fields connectionreferencelogicalname, connectionid, connectorid, connectionreferenceid).CrmRecords $connRefs | ForEach-Object { #Where-Object { $null -eq $_.connectionid } | $connectionType = $_.connectorid.Replace("/providers/Microsoft.PowerApps/apis/", "") Write-Host "Found Connection Reference $($_.connectionreferencelogicalname) " # without a Connection to $connectionType" Write-Host "Getting Connections in Environment" $connection = Get-AdminPowerAppConnection -EnvironmentName $EnvId | Select-Object -ExpandProperty Statuses -Property ConnectionName, DisplayName, ConnectorName, CreatedBy, CreatedTime | Where-Object { ($_.status -eq "Connected") -and ($_.ConnectorName -eq $connectionType) } | Sort-Object -Property CreatedTime #| Where-Object ConnectorName -eq $connectionType if ($connection) { # Get Dataverse systemuserid for the system user that maps to the aad user guid that created the connection $systemusers = Get-CrmRecords -conn $CRMConn -EntityLogicalName systemuser -FilterAttribute "azureactivedirectoryobjectid" -FilterOperator "eq" -FilterValue $connection[0].CreatedBy.id -Fields domainname if ($systemusers.Count -gt 0) { Write-Host "Impersonating the Owner of the Connection - $($systemusers.CrmRecords[0].domainname)" # Impersonate the Dataverse systemuser that created the connection when updating the connection reference $impersonationCallerId = $systemusers.CrmRecords[0].systemuserid $impersonationConn = $CRMConn $impersonationConn.OrganizationWebProxyClient.CallerId = $impersonationCallerId Write-PPDOMessage "Setting Connection Reference to use $($connection[0].DisplayName)" -Type command -RunLocally $RunLocally Set-CrmRecord -conn $impersonationConn -EntityLogicalName $_.logicalname -Id $_.connectionreferenceid -Fields @{"connectionid" = $connection[0].ConnectionName } } } else { Write-PPDOMessage "No Connection has been set up of type $connectionType, some of your Flows may not Activate succesfully" -Type warning -RunLocally $RunLocally -LogWarning $true } } Write-Host "Checking if there are Flows that need to be Activated" if ($Deploy.Flows.ActivateFlows -eq $true) { if ($Deploy.Flows.OverrideFile) { Write-Host "Using $($Deploy.Flows.OverrideFile) for Flow Activation" try { $FlowsToActivate = Get-Content -Path $PipelinePath\$SolutionFolder\$($Deploy.Flows.OverrideFile) -ErrorAction SilentlyContinue | ConvertFrom-Json } catch { } } else { Write-Host "Using Flows_Default.json for Flow Activation" try { $FlowsToActivate = Get-Content -Path $PipelinePath\$SolutionFolder\Flows_Default.json -ErrorAction SilentlyContinue | ConvertFrom-Json } catch { $FlowsToActivate = $null } } Write-Host "There are $($FlowsToActivate.Count) Flows that need activating" $ErrorCount = 0 if ($FlowsToActivate.Count -gt 0) { $FlowsToActivate | ForEach-Object { $FlowStore = $_ $workflow = Get-CrmRecord -conn $CRMConn -EntityLogicalName workflow -Id $_.FlowId -Fields clientdata, category, statecode, name if ($_.ActivateAsUser) { Write-Host "ActivateAsUser defined and set to : $($_.ActivateAsUser), attempting to Active Flow as this user" $systemuserResult = Get-CrmRecords -conn $CRMConn -EntityLogicalName systemuser -FilterAttribute "domainname" -FilterOperator "eq" -FilterValue $_.ActivateAsUser if ($systemuserResult.Count -gt 0) { $systemUserId = $systemuserResult.CrmRecords[0].systemuserid #Activate the workflow using the owner. if ($workflow.statecode -ne "Activated") { $impersonationConn = $CRMConn $impersonationCallerId = $systemUserId $impersonationConn.OrganizationWebProxyClient.CallerId = $impersonationCallerId Write-PPDOMessage "Enabling Flow '$($workflow.name)'" -Type command -RunLocally $RunLocally try { Set-CrmRecordState -conn $impersonationConn -EntityLogicalName workflow -Id $_.FlowId -StateCode Activated -StatusCode Activated } catch { Write-PPDOMessage "There was an error activating the Flow, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true Write-Host $_ if ($_.ToString().Contains("ChildFlowNeverPublished")) { $FlowsToRetry += $FlowStore } else { $ErrorCount++ } } } } Write-PPDOMessage "User $($_.ActivateAsUser) was not found in $($Deploy.EnvironmentName)" -Type warning -RunLocally $RunLocally -LogWarning $true } else { Write-Host "Checking if '$($workflow.name)' needs Activating..." $solutions = Get-CrmRecords -conn $CRMConn -EntityLogicalName solution -FilterAttribute "uniquename" -FilterOperator "eq" -FilterValue "$($package.SolutionName)" $solutionId = $solutions.CrmRecords[0].solutionid $connRefs = (Get-CrmRecords -conn $CRMConn -EntityLogicalName connectionreference -FilterAttribute "solutionid" -FilterOperator eq -FilterValue $solutionid -Fields connectionreferencelogicalname, connectionid, connectorid, connectionreferenceid).CrmRecords $connRefToUse = $connRefs | Where-Object { $null -ne $_.connectionid } | Select-Object -First 1 -ErrorAction SilentlyContinue if ($null -ne $connRefToUse) { Write-Host "---- Connection Ref Details ----" Write-Host "Connectiod ID : " $connRefToUse.ConnectionId Write-Host $connRefToUse Write-Host "--------------------------------" $connection = Get-AdminPowerAppConnection -EnvironmentName $EnvId -Filter $connRefToUse.ConnectionId } else { Write-PPDOMessage "There was an error getting a Connection to use, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true $ErrorCount++ } # Get Dataverse systemuserid for the system user that maps to the aad user guid that created the connection if ($null -ne $connection) { Write-Host "---- Connection Details -----" Write-Host "Connection UserID : " $connection[0].CreatedBy.id Write-Host $connection[0] Write-Host "-----------------------------" $systemusers = Get-CrmRecords -conn $CRMConn -EntityLogicalName systemuser -FilterAttribute "azureactivedirectoryobjectid" -FilterOperator "eq" -FilterValue $connection[0].CreatedBy.id } else { Write-PPDOMessage "There was an error getting the owner of the Connection to use, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true $ErrorCount++ } if ($systemusers.Count -gt 0) { # Impersonate the Dataverse systemuser that created the connection when updating the connection reference $impersonationCallerId = $systemusers.CrmRecords[0].systemuserid if ($workflow.statecode -ne "Activated") { Write-PPDOMessage "Enabling Flow '$($workflow.name)' as Owner of Connection Reference" -Type command -RunLocally $RunLocally $impersonationConn = $CRMConn $impersonationConn.OrganizationWebProxyClient.CallerId = $impersonationCallerId try { Set-CrmRecordState -conn $impersonationConn -EntityLogicalName workflow -Id $_.FlowId -StateCode Activated -StatusCode Activated Write-Host "...Activated" -ForegroundColor Green } catch { Write-PPDOMessage "There was an error activating the Flow, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true Write-Host $_ if ($_.ToString().Contains("ChildFlowNeverPublished")) { $FlowsToRetry += $FlowStore } else { $ErrorCount++ } } } } } } } ########################## - Retry Flow $FlowsToRetry | ForEach-Object { Write-Host Write-Host "Retrying Flows that failed due to Child Flows" -ForegroundColor Green $workflow = Get-CrmRecord -conn $CRMConn -EntityLogicalName workflow -Id $_.FlowId -Fields clientdata, category, statecode, name if ($_.ActivateAsUser) { Write-Host "ActivateAsUser defined and set to : $($_.ActivateAsUser), attempting to Active Flow as this user" $systemuserResult = Get-CrmRecords -conn $CRMConn -EntityLogicalName systemuser -FilterAttribute "domainname" -FilterOperator "eq" -FilterValue $_.ActivateAsUser if ($systemuserResult.Count -gt 0) { $systemUserId = $systemuserResult.CrmRecords[0].systemuserid #Activate the workflow using the owner. if ($workflow.statecode -ne "Activated") { $impersonationConn = $CRMConn $impersonationCallerId = $systemUserId $impersonationConn.OrganizationWebProxyClient.CallerId = $impersonationCallerId Write-PPDOMessage "Enabling Flow '$($workflow.name)'" -Type command -RunLocally $RunLocally try { Set-CrmRecordState -conn $impersonationConn -EntityLogicalName workflow -Id $_.FlowId -StateCode Activated -StatusCode Activated } catch { Write-PPDOMessage "There was an error activating the Flow, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true Write-Host $_ $ErrorCount++ } } } Write-PPDOMessage "User $($_.ActivateAsUser) was not found in $($Deploy.EnvironmentName)" -Type warning -RunLocally $RunLocally -LogWarning $true } else { Write-Host "Checking if '$($workflow.name)' needs Activating..." $solutions = Get-CrmRecords -conn $CRMConn -EntityLogicalName solution -FilterAttribute "uniquename" -FilterOperator "eq" -FilterValue "$($package.SolutionName)" $solutionId = $solutions.CrmRecords[0].solutionid $connRefs = (Get-CrmRecords -conn $CRMConn -EntityLogicalName connectionreference -FilterAttribute "solutionid" -FilterOperator eq -FilterValue $solutionid -Fields connectionreferencelogicalname, connectionid, connectorid, connectionreferenceid).CrmRecords $connRefToUse = $connRefs | Where-Object { $null -ne $_.connectionid } | Select-Object -First 1 -ErrorAction SilentlyContinue $connection = Get-AdminPowerAppConnection -EnvironmentName $EnvId -Filter $connRefToUse.ConnectionId # Get Dataverse systemuserid for the system user that maps to the aad user guid that created the connection $systemusers = Get-CrmRecords -conn $CRMConn -EntityLogicalName systemuser -FilterAttribute "azureactivedirectoryobjectid" -FilterOperator "eq" -FilterValue $connection[0].CreatedBy.id if ($systemusers.Count -gt 0) { # Impersonate the Dataverse systemuser that created the connection when updating the connection reference $impersonationCallerId = $systemusers.CrmRecords[0].systemuserid if ($workflow.statecode -ne "Activated") { Write-PPDOMessage "Enabling Flow '$($workflow.name)' as Owner of Connection Reference" -Type command -RunLocally $RunLocally $impersonationConn = $CRMConn $impersonationConn.OrganizationWebProxyClient.CallerId = $impersonationCallerId try { Set-CrmRecordState -conn $impersonationConn -EntityLogicalName workflow -Id $_.FlowId -StateCode Activated -StatusCode Activated } catch { Write-PPDOMessage "There was an error activating the Flow, please confirm that the user exists and that the appropriate connections have been created as this user in the Environment" -Type warning -RunLocally $RunLocally -LogWarning $true Write-Host $_ $ErrorCount++ } } } } } if ($Deploy.Flows.FailonError -eq $true -and $ErrorCount -gt 0) { Write-PPDOMessage "There were $ErrorCount Flow activation errors and FailonError is set to True... exiting." -Type error -RunLocally $RunLocally -LogError $true exit 1 } } else { Write-Host @" No Flows were specified for activation. If you wish to include flows for activation, please add the following in deployPackages.json "Flows":{ "ActivateFlows": "true", "OverrideFile" : "", "FailonError" : "false" } "@ } } } |