Skip to content

Instantly share code, notes, and snippets.

@zplume
Last active June 29, 2023 07:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zplume/05df197c8fa847c49e3e238377e540fa to your computer and use it in GitHub Desktop.
Save zplume/05df197c8fa847c49e3e238377e540fa to your computer and use it in GitHub Desktop.
PowerShell script to update multiple Flows that have been exported from one environment for deployment to another environment. The script will unzip a set of Flow zip files from a source directory into a temp folder, replace source values with destination values, then save updated zip files into a destination directory.
param(
[Parameter(Mandatory = $true)]
[string]$SourceEnv,
[Parameter(Mandatory = $true)]
[string]$DestinationEnv
)
$ErrorActionPreference = "Stop"
# Note: these values could be loaded from elsewhere, e.g. CSV/XML (or dynamically if you want to get fancy)
$environmentMap = @{
DEV = @{
"URL" = "https://tenantdev.sharepoint.com/sites/SiteName";
"Areas" = "e99958d1-84b2-45b4-acc5-772ede02f15f";
"Cancel Event Booking" = "def30784-7011-4c32-885b-7f6648c9a157";
"Configuration" = "b6be55af-2a3b-40ec-abae-d5bbb4229a8b";
"Event Alerts" = "6f3abdd5-5cea-4d28-b978-dcb0be2a2030";
"Event Bookings" = "0eef05c1-c7de-4bde-8eaa-0bed47d16ad7";
"Events" = "144e4403-ee39-47d0-a0ef-99ca58902c29";
};
TEST = @{
"URL" = "https://tenanttest.sharepoint.com/sites/SiteName";
"Areas" = "00f7b3f5-592f-41f7-9dd8-e8c8f3f5cbc6";
"Cancel Event Booking" = "73cb21a1-c7ee-4086-a09e-04b1f3c3ae3d";
"Configuration" = "246cadfd-2f3f-4600-9192-bb6d9d982496";
"Event Alerts" = "0638b70f-09ef-4208-8303-2faf03ce7016";
"Event Bookings" = "82996484-bd03-4d5e-aa1f-1dbfeae71c33";
"Events" = "5c6d4297-bec4-44e6-beb9-39e01b434e82";
};
UAT = @{
"URL" = "https://tenantuat.sharepoint.com/sites/SiteName";
"Areas" = "dcb670be-c08b-4c2d-be4d-136230d80ad8";
"Cancel Event Booking" = "78793aea-442d-4e46-8627-091de8ae3359";
"Configuration" = "82c280c1-9d35-441c-bdf1-c63bd1a7c2dd";
"Event Alerts" = "b773573f-bb7c-4dcf-b83e-8c2c9a13d1f1";
"Event Bookings" = "a4277736-00d2-4a7d-8623-439bad3a10fe";
"Events" = "7662380e-73e1-44cd-9f75-e3bd9ae7d55b";
};
PROD = @{
"URL" = "https://tenant.sharepoint.com/sites/SiteName";
"Areas" = "14f764e9-ede0-4f18-a9b7-5532f3639ff3";
"Cancel Event Booking" = "0f4896e1-6421-4e70-9271-301141901bc4";
"Configuration" = "47cf9ee9-62ea-4a2a-b376-88e5df62b60c";
"Events" = "a44d172c-7997-4aa8-9945-b3c60cb0bcaa";
"Event Alerts" = "9cc62288-92f9-496d-9ae5-19c183252e29";
"Event Bookings" = "37e19d6f-6b1c-4934-8744-1cbf54935ff4";
};
}
Add-Type -AssemblyName System.IO.Compression.FileSystem
Add-Type -AssemblyName System.IO
function Extract-ZipFile {
param([string]$Zip, [string]$Path)
Write-Host " - Extracting zip file"
[System.IO.Compression.ZipFile]::ExtractToDirectory($Zip, $Path)
}
function Zip-Directory {
param([string]$SourcePath, [string]$DestinationPath, [string]$ZipName)
Write-Host " - Creating Flow zip"
Write-Host " - $DestinationPath\$ZipName"
# Create zip, max compression, don't include source directory name in zip
[System.IO.Compression.ZipFile]::CreateFromDirectory($SourcePath, "$DestinationPath\$ZipName", [System.IO.Compression.CompressionLevel]::Optimal, $false)
}
function Replace-Strings {
param([string]$Path)
$definitionFile = Get-ChildItem -Path $Path -Recurse -Name "definition.json"
$definitionFilePath = $($Path + "\" + $definitionFile)
$definitionContent = Get-Content -Path $definitionFilePath
$sourceEnvData = $environmentMap[$SourceEnv]
$destinationEnvData = $environmentMap[$DestinationEnv]
$sourceEnvData.Keys |% {
if($definitionContent -imatch [regex]::Escape($sourceEnvData[$_])) {
Write-Host " - Replacing " -NoNewline
Write-Host -f Green $_
$definitionContent = $definitionContent -ireplace [regex]::Escape($sourceEnvData[$_]), $destinationEnvData[$_]
}
else {
Write-Host -f Yellow " - Value with friendly-name '$_' not found, skipping"
}
}
$definitionContent | Set-Content -Path $definitionFilePath
}
function Ensure-EmptyDirectory {
param([string]$Path)
Write-Host " - Preparing directory $Path"
[System.IO.Directory]::CreateDirectory($Path) | Out-Null
Remove-Item -Path "$Path\*" -Recurse
}
function Confirm-Parameters {
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "This means Yes"
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "This means No"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
Write-Host "Please confirm the following paths are correct:"
Write-Host " - Source folder: " -NoNewLine
Write-Host -f Green $InputPath
Write-Host " - Destination folder: " -NoNewLine
Write-Host -f Green "$OutputPath`n"
Write-Warning "`nAny existing folders or items in the destination folder will be deleted!"
return $host.ui.PromptForChoice("", "Continue?", $Options, 0)
}
function Process-Directory {
Write-Host "`nProcessing directory " -NoNewline
Write-Host -f Yellow $InputPath
Ensure-EmptyDirectory -Path $OutputPath
$tempFolderPath = $((Get-Location).Path + "\temp")
Ensure-EmptyDirectory -Path $tempFolderPath
Get-ChildItem -Path "$InputPath\*.zip" |% {
Write-Host "`nProcessing Flow zip " -NoNewline
Write-Host -f Cyan $_.Name
# Folder to extract zip to
$path = $("$tempFolderPath\" + $_.Name.Replace(".zip", ""))
# Clear folder and Extract Flow zip
Ensure-EmptyDirectory -Path $path
Extract-ZipFile -Zip $_.FullName -Path $path
# Replace URL/List IDs
Replace-Strings -Path $path
# Create Flow zip in destination folder
Zip-Directory -SourcePath $path -DestinationPath $OutputPath -ZipName $_.Name
}
# Clean up
Remove-Item $tempFolderPath -Recurse
Write-Host -f Green "`nFlow creation complete`n"
}
$path = (Get-Location).Path
Write-Host "`nCurrent location: " -NoNewLine
Write-Host -f Green "$path`n"
$InputPath = "$path\$SourceEnv"
$OutputPath = "$path\$DestinationEnv"
switch(Confirm-Parameters) {
0 { Process-Directory }
1 { Write-Error "Script aborted" }
}
# Example usage - assumes your Flows exist in the \DEV folder:
# .\Update-Flows.ps1 -SourceEnv "DEV" -DestinationEnv "TEST"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment