This guide describes how to use the Archive-StorageAccount.ps1 PowerShell 7 script to archive the contents of an Azure Storage Account from one tenant into an archive/backup Storage Account in a different tenant, using AzCopy and SAS tokens.
The script performs the following steps:
Given a source account named mySourceAccount with containers data and backups, the result on the destination looks like this:
myarchiveaccount (Storage Account)
└── mysourceaccount (Container — named after the source account)
├── data/
│ └── ... (all blobs from source container "data")
└── backups/
└── ... (all blobs from source container "backups")
| Requirement | Details |
|---|---|
| PowerShell | Version 7.0 or later |
| AzCopy | Version 10+ in PATH or specify full path |
| Source SAS token | Requires Read and List permissions on Blob service |
| Destination SAS token | Requires Write and Create permissions on Blob service |
?sv=...)All configuration is done directly in the script file — no command-line arguments are needed. Open Archive-StorageAccount.ps1 and edit the top section:
# --- Source Storage Account ---
$SourceAccountName = "mySourceAccount"
$SourceSasToken = "?sv=2022-11-02&ss=b&..."
# --- Destination / Archive Storage Account ---
$DestAccountName = "myArchiveAccount"
$DestSasToken = "?sv=2022-11-02&ss=b&..."
# --- Behaviour ---
$AzCopyPath = "azcopy" # Full path e.g. "C:\Tools\azcopy.exe" if not in PATH
$OverwriteExisting = $false # true = overwrite files that already exist at destination
$DeleteAfterCopy = $false # true = delete source blobs after successful copy
$LogDirectory = "$PSScriptRoot\Logs"
Warning: Set
$DeleteAfterCopy = $trueonly when you have verified the archive is complete. This action is irreversible.
# Navigate to the script directory
cd C:\Scripts
# Run with PowerShell 7
pwsh .\Archive-StorageAccount.ps1
The script runs non-interactively and exits with code 0 on success or 1 if any container copy failed.
Logs are written to the Logs\ subfolder next to the script, one file per day:
Logs\
└── archive-20260325.log
Example log output:
[2026-03-25 14:00:01] [INFO] AzCopy found: azcopy version 10.27.1
[2026-03-25 14:00:02] [INFO] Fetching container list from: mySourceAccount
[2026-03-25 14:00:03] [INFO] Found 2 container(s): data, backups
[2026-03-25 14:00:04] [INFO] Ensuring destination container exists: 'mysourceaccount'
[2026-03-25 14:00:04] [INFO] Container 'mysourceaccount' already exists -- continuing.
[2026-03-25 14:00:05] [INFO] Starting copy: mySourceAccount/data --> myArchiveAccount/mysourceaccount/data
[2026-03-25 14:02:41] [SUCCESS] Copy completed successfully: mySourceAccount/data --> ...
[2026-03-25 14:02:42] [INFO] Starting copy: mySourceAccount/backups --> ...
[2026-03-25 14:04:10] [SUCCESS] Copy completed successfully: mySourceAccount/backups --> ...
[2026-03-25 14:04:10] [INFO] ========================================================
[2026-03-25 14:04:10] [INFO] SUMMARY
[2026-03-25 14:04:10] [INFO] [OK ] data --> mysourceaccount/data
[2026-03-25 14:04:10] [INFO] [OK ] backups --> mysourceaccount/backups
[2026-03-25 14:04:10] [INFO] Done: 2 succeeded, 0 failed.
| Function | Description |
|---|---|
Write-Log |
Writes a timestamped, colour-coded log entry to console and log file |
Assert-AzCopy |
Verifies AzCopy is available before proceeding |
Get-StorageContainers |
Lists all containers in the source account via Blob REST API + regex parsing |
Ensure-DestinationContainer |
Creates the archive container on the destination if it does not already exist (HTTP 409 = already exists, not an error) |
Invoke-AzCopyTransfer |
Runs azcopy copy --recursive for a given source/destination URL pair |
Invoke-RestMethod in PowerShell 7 pre-parses the XML response into a XmlDocument object. Casting this again with [xml] throws a type error. Invoke-WebRequest is used instead to retrieve the raw string, and container names are extracted with a simple regex pattern:
<Container><n>([^<]+)</n>
This is reliable because the Azure Blob List Containers response always places <n> as the first child element of <Container>.
To run this script on a schedule, create a Windows Task Scheduler task with the following action:
pwsh.exe-NonInteractive -File "C:\Scripts\Archive-StorageAccount.ps1"C:\ScriptsEnsure the task runs under an account with network access to both storage endpoints.
Download Get-AzurePIMReport.zip{.button .button-primary}
AzCopy not found
: Confirm AzCopy v10 is installed. Either add its directory to the system PATH or set $AzCopyPath to the full .exe path.
HTTP 403 on container list
: The source SAS token is missing List permission or has expired. Regenerate the token.
HTTP 403 during copy
: The destination SAS token is missing Write or Create permission, or the token has expired.
HTTP 409 on container creation : The destination container already exists — this is expected on subsequent runs and is handled gracefully.
No containers found : The script logs the first 500 characters of the raw API response. Check this output for error details returned by Azure (e.g. malformed SAS token).
AzCopy exit code 1
: Check the AzCopy journal/log files in %USERPROFILE%\.azcopy\ for detailed transfer errors.