You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure跨恢复库还原SQL备份时遇Restore-AzRecoveryServicesBackupItem输入无效错误

Azure跨恢复服务库还原SQL备份脚本错误排查

我正在编写PowerShell脚本,用于从Azure的一个恢复服务库(Recovery Vault)向另一个恢复服务库还原SQL数据库备份项,核心脚本如下:

#modules and variables
import-module Az

$Sub = "MyAzureSubscription"
$RsvSource = "MySourceRecoveryVault"
$RsvTarget = "MyTargetRecoveryVault"
$SubContext = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$SourceDB = "SourceDB"
$TargetDB = "TargetDB"
$SQLTargetInstance = "instance"
$SQLTargetServer = "SQLServer"

#Get Backup item from Azure RSV
Connect-AzAccount -Identity -Subscription $Sub

Set-AzContext -subscription $SubContext

$SourceVault = Get-AzRecoveryServicesVault | Where-Object { $_.name -eq $RsvSource }
$TargetVault = Get-AzRecoveryServicesVault | Where-Object { $_.name -eq $RsvTarget }

Set-AzRecoveryServicesVaultContext -Vault $SourceVault

$BackupItem = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $SourceVault.ID | Where-Object { ($_.Name -match $SourceDB ) }
#Get Point in time
$PointInTime = Get-Date -Date "12/1/2023" -format MM/dd/yyyy
#Get Parameters
$Container = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -VaultId $($TargetVault.id) | Where-Object {$_.ServerName -eq "$SQLTargetServer" -and $_.HealthStatus -eq 'Healthy'}

$TargetInstance = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -ItemType SQLInstance -ServerName "$SQLTargetServer" -VaultId $($TargetVault.id)

$PointBackup = Get-AzRecoveryServicesBackupRecoveryPoint  -Item $BackupItem | Where-object { $_.RecoveryPointTime -match $PointInTime }


# Configuration
$AnotherInstanceWithFullConfig = Get-AzRecoveryServicesBackupWorkloadRecoveryConfig -PointInTime $($PointBackup.RecoveryPointTime) -Item $BackupItem -TargetItem $SQLTargetInstance -Targetcontainer $Container -AlternateWorkloadRestore -VaultId $($SourceVault.ID)
$AnotherInstanceWithFullConfig.OverwriteWLIfpresent = "yes"
$AnotherInstanceWithFullConfig.RestoredDBName = $TargetDB


$AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath = ($AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath) -replace (($AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath | split-path -leaf), "$TargetDB).mdf")

$AnotherInstanceWithFullConfig.targetPhysicalPath[1].TargetPath = ($AnotherInstanceWithFullConfig.targetPhysicalPath[1].TargetPath) | ForEach-Object { $_ -replace (($AnotherInstanceWithFullConfig.targetPhysicalPath[1].TargetPath | split-path -leaf), "$TargetDB.ldf") -replace "I:", "L:" }

#restore
$restore = Restore-AzRecoveryServicesBackupItem -WLRecoveryConfig $AnotherInstanceWithFullConfig -VaultId $($TargetVault.id)

执行脚本时触发以下错误:

Restore-AzRecoveryServicesBackupItem : The User input provided for the call is invalid. Please check the required inputs

我怀疑问题出在$AnotherInstanceWithFullConfig配置上,执行$AnotherInstanceWithFullConfig | Format-list后输出如下:

TargetServer : SQLServer.domain
TargetInstance : instance
RestoredDBName : TargetDB
TargetVirtualMachineId : /subscriptions/xxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/RSGXXXXXXXXXXXX/providers/Microsoft.Compute/virtualMachines/SQLServer
OverwriteWLIfpresent : yes
NoRecoveryMode : Disabled
targetPhysicalPath : {Name_Data, Name_log}
ContainerId : /subscriptions/xxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/RSGXXXXXXXXX/providers/Microsoft.RecoveryServices/vaults/RSVXXXXXXXXXX/backupFabrics/Azure/protectionContainers/vmappcontainer;compute;rsgxxxxxxxx;SQlserver
FullRP :
SourceResourceId : /subscriptions/xxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/RSGXXXXXXXXXXX/providers/Microsoft.Compute/virtualMachines/SQLServer
RestoreRequestType : Alternate WL Restore to diff item
RecoveryPoint : Microsoft.Azure.Commands.RecoveryServices.Backup.Cmdlets.Models.AzureWorkloadRecoveryPoint
PointInTime : 12/1/2023 12:04:51 PM
RecoveryMode :
FilePath :


排查思路

  • 修复物理路径替换的语法错误:脚本中替换MDF文件路径时存在语法错误,"$TargetDB).mdf"多了一个右括号,正确写法应为"$TargetDB.mdf"。错误的路径格式会导致还原请求的输入参数无效。

    # 修正后的MDF路径替换代码
    $AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath = ($AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath) -replace (($AnotherInstanceWithFullConfig.targetPhysicalPath[0].TargetPath | split-path -leaf), "$TargetDB.mdf")
    
  • 显式设置RecoveryMode参数:从配置输出可见RecoveryMode为空,这是SQL还原的必填参数,需根据需求设置为Recovery(还原后数据库可读写)或NoRecovery(还原后数据库处于还原状态,可继续追加日志备份):

    $AnotherInstanceWithFullConfig.RecoveryMode = "Recovery"
    
  • 使用正确的TargetItem对象:原脚本中Get-AzRecoveryServicesBackupWorkloadRecoveryConfig的-TargetItem参数传递的是字符串$SQLTargetInstance,但该参数需要传入Get-AzRecoveryServicesBackupProtectableItem返回的对象,应修改为:

    $AnotherInstanceWithFullConfig = Get-AzRecoveryServicesBackupWorkloadRecoveryConfig -PointInTime $($PointBackup.RecoveryPointTime) -Item $BackupItem -TargetItem $TargetInstance -Targetcontainer $Container -AlternateWorkloadRestore -VaultId $($SourceVault.ID)
    
  • 验证恢复点的有效性:检查$PointBackup是否正确获取到了目标恢复点。原脚本使用-match匹配日期可能存在格式问题,建议改用日期对象直接比较:

    $PointInTime = Get-Date -Date "12/1/2023"
    $PointBackup = Get-AzRecoveryServicesBackupRecoveryPoint -Item $BackupItem | Where-Object { $_.RecoveryPointTime.Date -eq $PointInTime.Date }
    

    确保$PointBackup不为空,且是有效的恢复点对象。

  • 检查跨Vault权限:确认执行脚本的托管身份(Managed Identity)同时拥有源恢复服务库和目标恢复服务库的权限,至少需要Recovery Services Contributor以及目标SQL虚拟机的SQL Contributor权限。

  • 验证容器ID的一致性:配置输出中ContainerId里的服务器名是SQlserver(大小写混合),而目标服务器名为SQLServer,虽然Azure大部分场景不区分大小写,但建议确保$Container获取的是完全匹配的健康容器,避免因大小写问题导致的容器识别错误。


内容的提问来源于stack exchange,提问作者UltraPS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:14:56