Uso de PowerShell para sincronizar datos entre varias bases de datos en Azure SQL DatabaseUse PowerShell to sync data between multiple databases in Azure SQL Database

SE APLICA A: sí Azure SQL Database APPLIES TO: yesAzure SQL Database

En este ejemplo de Azure PowerShell, se configura SQL Data Sync para sincronizar datos entre varias bases de datos en Azure SQL Database.This Azure PowerShell example configures SQL Data Sync to sync data between multiple databases in Azure SQL Database.

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.If you don't have an Azure subscription, create a free account before you begin.

Nota

Este artículo se ha actualizado para usar el nuevo módulo Az de Azure PowerShell.This article has been updated to use the new Azure PowerShell Az module. Aún puede usar el módulo de AzureRM que continuará recibiendo correcciones de errores hasta diciembre de 2020 como mínimo.You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. Para más información acerca del nuevo módulo Az y la compatibilidad con AzureRM, consulte Introducing the new Azure PowerShell Az module (Presentación del nuevo módulo Az de Azure PowerShell).To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. Para obtener instrucciones sobre la instalación del módulo Az, consulte Instalación de Azure PowerShell.For Az module installation instructions, see Install Azure PowerShell.

Uso de Azure Cloud ShellUse Azure Cloud Shell

En Azure se hospeda Azure Cloud Shell, un entorno de shell interactivo que puede utilizar mediante el explorador.Azure hosts Azure Cloud Shell, an interactive shell environment that you can use through your browser. Puede usar Bash o PowerShell con Cloud Shell para trabajar con los servicios de Azure.You can use either Bash or PowerShell with Cloud Shell to work with Azure services. Puede usar los comandos preinstalados de Cloud Shell para ejecutar el código de este artículo sin tener que instalar nada en su entorno local.You can use the Cloud Shell preinstalled commands to run the code in this article without having to install anything on your local environment.

Para iniciar Azure Cloud Shell:To start Azure Cloud Shell:

OpciónOption Ejemplo o vínculoExample/Link
Seleccione Pruébelo en la esquina superior derecha de un bloque de código.Select Try It in the upper-right corner of a code block. Solo con seleccionar Pruébelo no se copia automáticamente el código en Cloud Shell.Selecting Try It doesn't automatically copy the code to Cloud Shell. Ejemplo de Probarlo para Azure Cloud Shell
Vaya a https://shell.azure.com o seleccione el botón Iniciar Cloud Shell para abrir Cloud Shell en el explorador.Go to https://shell.azure.com, or select the Launch Cloud Shell button to open Cloud Shell in your browser. Iniciar Cloud Shell en una nueva ventanaLaunch Cloud Shell in a new window
Seleccione el botón Cloud Shell en la barra de menús de la esquina superior derecha de Azure Portal.Select the Cloud Shell button on the menu bar at the upper right in the Azure portal. Botón Cloud Shell en Azure Portal

Para ejecutar el código de este artículo en Azure Cloud Shell:To run the code in this article in Azure Cloud Shell:

  1. Inicie Cloud Shell.Start Cloud Shell.

  2. Seleccione el botón Copiar de un bloque de código para copiar el código.Select the Copy button on a code block to copy the code.

  3. Pegue el código en la sesión de Cloud Shell. Para ello, seleccione Ctrl+Mayús+V en Windows y Linux, o bien seleccione Cmd+Mayús+V en macOS.Paste the code into the Cloud Shell session by selecting Ctrl+Shift+V on Windows and Linux or by selecting Cmd+Shift+V on macOS.

  4. Seleccione Entrar para ejecutar el código.Select Enter to run the code.

Si decide instalar y usar PowerShell de manera local, en este tutorial se requiere la versión 1.4.0 de Azure PowerShell o una posterior.If you choose to install and use PowerShell locally, this tutorial requires Az PowerShell 1.4.0 or later. Si necesita actualizarla, consulte Instalación del módulo de Azure PowerShell.If you need to upgrade, see Install Azure PowerShell module. Si PowerShell se ejecuta localmente, también debe ejecutar Connect-AzAccount para crear una conexión con Azure.If you are running PowerShell locally, you also need to run Connect-AzAccount to create a connection with Azure.

Para obtener información general acerca de SQL Data Sync, consulte Sincronización de datos entre varias bases de datos locales y de la nube con Azure SQL Data Sync.For an overview of SQL Data Sync, see Sync data across multiple cloud and on-premises databases with SQL Data Sync in Azure.

Importante

SQL Data Sync no admite en este momento Instancia administrada de Azure SQL.SQL Data Sync does not support Azure SQL Managed Instance at this time.

Requisitos previosPrerequisites

  • Crear una base de datos de Azure SQL Database a partir de la base de datos de ejemplo AdventureWorksLT como base de datos central.Create a database in Azure SQL Database from an AdventureWorksLT sample database as a hub database.
  • Crear una base de datos de Azure SQL Database en la misma región que la base de datos de sincronización.Create a database in Azure SQL Database in the same region as the sync database.
  • Actualizar los marcadores de posición de parámetros antes de ejecutar el ejemplo.Update the parameter placeholders before running the example.

EjemploExample

using namespace Microsoft.Azure.Commands.Sql.DataSync.Model
using namespace System.Collections.Generic

# hub database info
$subscriptionId = "<subscriptionId>"
$resourceGroupName = "<resourceGroupName>"
$serverName = "<serverName>"
$databaseName = "<databaseName>"

# sync database info
$syncDatabaseResourceGroupName = "<syncResourceGroupName>"
$syncDatabaseServerName = "<syncServerName>"
$syncDatabaseName = "<syncDatabaseName>"

# sync group info
$syncGroupName = "<syncGroupName>"
$conflictResolutionPolicy = "HubWin" # can be HubWin or MemberWin
$intervalInSeconds = 300 # sync interval in seconds (must be no less than 300)

# member database info
$syncMemberName = "<syncMemberName>"
$memberServerName = "<memberServerName>"
$memberDatabaseName = "<memberDatabaseName>"
$memberDatabaseType = "SqlServerDatabase" # can be AzureSqlDatabase or SqlServerDatabase
$syncDirection = "Bidirectional" # can be Bidirectional, Onewaymembertohub, Onewayhubtomember

# sync agent info
$syncAgentName = "<agentName>"
$syncAgentResourceGroupName = "<syncAgentResourceGroupName>"
$syncAgentServerName = "<syncAgentServerName>"

# temp file to save the sync schema
$tempFile = $env:TEMP+"\syncSchema.json"

# list of included columns and tables in quoted name
$includedColumnsAndTables =  "[SalesLT].[Address].[AddressID]",
                             "[SalesLT].[Address].[AddressLine2]",
                             "[SalesLT].[Address].[rowguid]",
                             "[SalesLT].[Address].[PostalCode]",
                             "[SalesLT].[ProductDescription]"
$metadataList = [System.Collections.ArrayList]::new($includedColumnsAndTables)

Connect-AzAccount
Select-AzSubscription -SubscriptionId $subscriptionId

# use if it's safe to show password in script, otherwise use PromptForCredential
# $user = "username"
# $password = ConvertTo-SecureString -String "password" -AsPlainText -Force
# $credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $user, $password

$credential = $Host.ui.PromptForCredential("Need credential",
              "Please enter your user name and password for server "+$serverName+".database.windows.net",
              "",
              "")

# create a new sync group
Write-Host "Creating Sync Group "$syncGroupName"..."
New-AzSqlSyncGroup -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName -Name $syncGroupName `
    -SyncDatabaseName $syncDatabaseName -SyncDatabaseServerName $syncDatabaseServerName -SyncDatabaseResourceGroupName $syncDatabaseResourceGroupName `
    -ConflictResolutionPolicy $conflictResolutionPolicy -DatabaseCredential $credential

# use if it's safe to show password in script, otherwise use PromptForCredential
# $user = "username"
# $password = ConvertTo-SecureString -String "password" -AsPlainText -Force
# $credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $user, $password

$credential = $Host.ui.PromptForCredential("Need credential",
              "Please enter your user name and password for server "+$serverName+".database.windows.net",
              "",
              "")

# add a new sync member
Write-Host "Adding member"$syncMemberName" to the sync group..."

New-AzSqlSyncMember -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName `
    -SyncGroupName $syncGroupName -Name $syncMemberName -MemberDatabaseType $memberDatabaseType -SyncAgentResourceGroupName $syncAgentResourceGroupName `
    -SyncAgentServerName $syncAgentServerName -SyncAgentName $syncAgentName  -SyncDirection $syncDirection -SqlServerDatabaseID  $syncAgentInfo.DatabaseId

# refresh database schema from hub database, specify the -SyncMemberName parameter if you want to refresh schema from the member database
Write-Host "Refreshing database schema from hub database..."
$startTime = Get-Date
Update-AzSqlSyncSchema -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName -SyncGroupName $syncGroupName

# waiting for successful refresh
$startTime = $startTime.ToUniversalTime()
$timer=0
$timeout=90

# check the log and see if refresh has gone through
Write-Host "Check for successful refresh..."
$isSucceeded = $false
while ($isSucceeded -eq $false) {
    Start-Sleep -s 10
    $timer=$timer+10
    $details = Get-AzSqlSyncSchema -SyncGroupName $syncGroupName -ServerName $serverName -DatabaseName $databaseName -ResourceGroupName $resourceGroupName
    if ($details.LastUpdateTime -gt $startTime) {
        Write-Host "Refresh was successful"
        $isSucceeded = $true
    }
    if ($timer -eq $timeout) {
        Write-Host "Refresh timed out"
        break;
    }
}

# get the database schema
Write-Host "Adding tables and columns to the sync schema..."
$databaseSchema = Get-AzSqlSyncSchema -ResourceGroupName $ResourceGroupName -ServerName $ServerName `
    -DatabaseName $DatabaseName -SyncGroupName $SyncGroupName `

$databaseSchema | ConvertTo-Json -depth 5 -Compress | Out-File "C:\Users\OnPremiseServer\AppData\Local\Temp\syncSchema.json"

$newSchema = [AzureSqlSyncGroupSchemaModel]::new()
$newSchema.Tables = [List[AzureSqlSyncGroupSchemaTableModel]]::new();

# add columns and tables to the sync schema
foreach ($tableSchema in $databaseSchema.Tables) {
    $newTableSchema = [AzureSqlSyncGroupSchemaTableModel]::new()
    $newTableSchema.QuotedName = $tableSchema.QuotedName
    $newTableSchema.Columns = [List[AzureSqlSyncGroupSchemaColumnModel]]::new();
    $addAllColumns = $false
    if ($MetadataList.Contains($tableSchema.QuotedName)) {
        if ($tableSchema.HasError) {
            $fullTableName = $tableSchema.QuotedName
            Write-Host "Can't add table $fullTableName to the sync schema" -foregroundcolor "Red"
            Write-Host $tableSchema.ErrorId -foregroundcolor "Red"
            continue;
        }
        else {
            $addAllColumns = $true
        }
    }
    foreach($columnSchema in $tableSchema.Columns) {
        $fullColumnName = $tableSchema.QuotedName + "." + $columnSchema.QuotedName
        if ($addAllColumns -or $MetadataList.Contains($fullColumnName)) {
            if ((-not $addAllColumns) -and $tableSchema.HasError) {
                Write-Host "Can't add column $fullColumnName to the sync schema" -foregroundcolor "Red"
                Write-Host $tableSchema.ErrorId -foregroundcolor "Red"
            }
            elseif ((-not $addAllColumns) -and $columnSchema.HasError) {
                Write-Host "Can't add column $fullColumnName to the sync schema" -foregroundcolor "Red"
                Write-Host $columnSchema.ErrorId -foregroundcolor "Red"
            }
            else {
                Write-Host "Adding"$fullColumnName" to the sync schema"
                $newColumnSchema = [AzureSqlSyncGroupSchemaColumnModel]::new()
                $newColumnSchema.QuotedName = $columnSchema.QuotedName
                $newColumnSchema.DataSize = $columnSchema.DataSize
                $newColumnSchema.DataType = $columnSchema.DataType
                $newTableSchema.Columns.Add($newColumnSchema)
            }
        }
    }
    if ($newTableSchema.Columns.Count -gt 0) {
        $newSchema.Tables.Add($newTableSchema)
    }
}

# convert sync schema to JSON format
$schemaString = $newSchema | ConvertTo-Json -depth 5 -Compress

# work around a PowerShell bug
$schemaString = $schemaString.Replace('"Tables"', '"tables"').Replace('"Columns"', '"columns"').Replace('"QuotedName"', '"quotedName"').Replace('"MasterSyncMemberName"','"masterSyncMemberName"')

# save the sync schema to a temp file
$schemaString | Out-File $tempFile

# update sync schema
Write-Host "Updating the sync schema..."
Update-AzSqlSyncGroup -ResourceGroupName $resourceGroupName -ServerName $serverName `
    -DatabaseName $databaseName -Name $syncGroupName -Schema $tempFile

$syncLogStartTime = Get-Date

# trigger sync manually
Write-Host "Trigger sync manually..."
Start-AzSqlSyncGroupSync -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName -SyncGroupName $syncGroupName

# check the sync log and wait until the first sync succeeded
Write-Host "Check the sync log..."
$isSucceeded = $false
for ($i = 0; ($i -lt 300) -and (-not $isSucceeded); $i = $i + 10) {
    Start-Sleep -s 10
    $syncLogEndTime = Get-Date
    $syncLogList = Get-AzSqlSyncGroupLog -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName `
        -SyncGroupName $syncGroupName -StartTime $syncLogStartTime.ToUniversalTime() -EndTime $syncLogEndTime.ToUniversalTime()

    if ($synclogList.Length -gt 0) {
        foreach ($syncLog in $syncLogList) {
            if ($syncLog.Details.Contains("Sync completed successfully")) {
                Write-Host $syncLog.TimeStamp : $syncLog.Details
                $isSucceeded = $true
            }
        }
    }
}

if ($isSucceeded) {
    # enable scheduled sync
    Write-Host "Enable the scheduled sync with 300 seconds interval..."
    Update-AzSqlSyncGroup  -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName `
        -Name $syncGroupName -IntervalInSeconds $intervalInSeconds
}
else {
    # output all log if sync doesn't succeed in 300 seconds
    $syncLogEndTime = Get-Date
    $syncLogList = Get-AzSqlSyncGroupLog  -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName `
        -SyncGroupName $syncGroupName -StartTime $syncLogStartTime.ToUniversalTime() -EndTime $syncLogEndTime.ToUniversalTime()

    if ($synclogList.Length -gt 0) {
        foreach ($syncLog in $syncLogList) {
            Write-Host $syncLog.TimeStamp : $syncLog.Details
        }
    }
}

Limpieza de la implementaciónClean up deployment

Después de ejecutar el script de ejemplo, puede ejecutar el comando siguiente para quitar el grupo de recursos y todos los recursos asociados a él.After you run the sample script, you can run the following command to remove the resource group and all resources associated with it.

Remove-AzResourceGroup -ResourceGroupName $ResourceGroupName
Remove-AzResourceGroup -ResourceGroupName $SyncDatabaseResourceGroupName

Explicación del scriptScript explanation

Este script usa los siguientes comandos.This script uses the following commands. Cada comando de la tabla crea un vínculo a documentación específica del comando.Each command in the table links to command-specific documentation.

Get-HelpCommand NotasNotes
New-AzSqlSyncAgentNew-AzSqlSyncAgent Crea un agente de sincronización.Creates a new Sync Agent.
New-AzSqlSyncAgentKeyNew-AzSqlSyncAgentKey Genera la clave del agente asociada al agente de sincronización.Generates the agent key associated with the Sync Agent.
Get-AzSqlSyncAgentLinkedDatabaseGet-AzSqlSyncAgentLinkedDatabase Permite obtener toda la información del agente de sincronización.Get all the information for the Sync Agent.
New-AzSqlSyncMemberNew-AzSqlSyncMember Agrega un nuevo miembro al grupo de sincronización.Add a new member to the sync group.
Update-AzSqlSyncSchemaUpdate-AzSqlSyncSchema Actualiza la información de esquema de la base de datos.Refreshes the database schema information.
Get-AzSqlSyncSchemaGet-AzSqlSyncSchema Obtiene la información de esquema de la base de datos.Get the database schema information.
Update-AzSqlSyncGroupUpdate-AzSqlSyncGroup Actualiza el grupo de sincronización.Updates the sync group.
Start-AzSqlSyncGroupSyncStart-AzSqlSyncGroupSync Desencadena una sincronización.Triggers a sync.
Get-AzSqlSyncGroupLogGet-AzSqlSyncGroupLog Comprueba el registro de sincronización.Checks the Sync Log.

Pasos siguientesNext steps

Para más información sobre Azure PowerShell, consulte la documentación de Azure PowerShell.For more information about Azure PowerShell, see Azure PowerShell documentation.

Encontrará más ejemplos de scripts de PowerShell de SQL Database en los scripts de PowerShell de Azure SQL Database.Additional SQL Database PowerShell script samples can be found in Azure SQL Database PowerShell scripts.

Para más información acerca de SQL Data Sync, consulte:For more information about SQL Data Sync, see:

Para obtener más información sobre SQL Database, vea:For more information about SQL Database, see: