Azure Key Vault – Script for copying secrets from one to another

The following script can be used to copy secrets from one Key Vault to another.

You can use this to copy secrets or just the secret names (-NameOnly) from one Key Vault to another, in the same or another subscription.

It’s as simple as the following PowerShell commands below to execute:

.\Copy-KeyVault-Secrets.ps1 -SrcSubscriptionName $srcSubscriptionName -SrcKvName $srcKvName -DestSubscriptionName $destSubscriptionName -DestKvName $destKvName -NameOnly
.GUName 48b4b27a-b77e-41e6-8a37-b3767da5caee
.AUTHOR Nicholas Rogoff

Initial version.
Copy Key Vault Secrets from one Vault to another. 
Loops through all secrets and copies them or fills them with a 'Needs Configuration'.

Run 'Import-Module Az.Accounts'
Run 'Import-Module Az.KeyVault'
You need to be logged into Azure and have the access necessary rights to both Key Vaults.

None. You cannot pipe objects to this!


.PARAMETER SrcSubscriptionName
This is the Source Subscription Name

The name of the Source Key Vault

.PARAMETER DestSubscriptionName
This is the destination Subscription Name

The name of the destination Key Vault

Set to only copy across the secret name and NOT the actual secret. The secret will be populated with 'Needs Configuration'

  Version:        1.1
  Author:         Nicholas Rogoff
  Creation Date:  2021-08-09
  Purpose/Change: Refined for publication
PS> .\Copy-KeyVault-Secrets.ps1 -SrcSubscriptionName $srcSubscriptionName -SrcKvName $srcKvName -DestSubscriptionName $destSubscriptionName -DestKvName $destKvName -NameOnly
This will copy across only the secret names, filling the secret with 'Needs Configuration'
#---------------------------------------------------------[Script Parameters]------------------------------------------------------
  [Parameter(Mandatory = $true, HelpMessage = "This is the Source Subscription Name")]
  [string] $SrcSubscriptionName,
  [Parameter(Mandatory = $true, HelpMessage = "The name of the Source Key Vault")]
  [string] $SrcKvName,
  [Parameter(Mandatory = $false, HelpMessage = "This is the destination Subscription Name. If not set or blank then same subscription is assumed")]
  [string] $DestSubscriptionName,
  [Parameter(Mandatory = $true, HelpMessage = "The name of the destination Key Vault")]
  [string] $DestKvName,
  [Parameter(Mandatory = $false, HelpMessage = "Only copy across the secret name and NOT the actual secret. The secret will be populated with 'Needs Configuration'")]
  [switch] $NameOnly

Write-Host ($(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff') + " Starting copying from " + $SrcKvName + " to " + $DestKvName + "... ") -ForegroundColor Blue

# Set Error Action to Silently Continue
$ErrorActionPreference = 'Continue'

# Any Global Declarations go here



$success = 0
$failed = 0

# ensure source subscription is selected
Select-AzSubscription -Subscription $SrcSubscriptionName

$Tags = @{ 'Migrated' = 'true'; 'Source Key Vault' = $SrcKvName }

$sourceSecrets = Get-AzKeyVaultSecret -VaultName $SrcKvName
if ($DestSubscriptionName) {
  #Need to switch subscriptions
  Select-AzSubscription -Subscription $DestSubscriptionName

ForEach ($sourceSecret in $sourceSecrets) {

  $name = $sourceSecret.Name
  $tags = $sourceSecret.Tags
  $secret = Get-AzKeyVaultSecret -VaultName $srckvName -Name $name

  Write-Host "Adding SecretName: $name ..."
  if ($NameOnly) {
    $value = ConvertTo-SecureString 'Needs Configuration' -AsPlainText -Force
  else {
    $value = $secret.SecretValue
  $secret = Set-AzKeyVaultSecret -VaultName $destkvName -Name $sourceSecret.Name -SecretValue $value -ContentType $sourceSecret.ContentType -Tags $tags 
  if (!$Error[0]) {
    $success += 1
  else {
    $failed += 1
    Write-Error "!! Failed to copy secret $name"

Write-Output "================================="
Write-Output "Completed Key Vault Secrets Copy"
Write-Output "Succeeded: $success"
Write-Output "Failed: $failed"
Write-Output "================================="

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.