对灾难恢复使用 VSS 自动化系统恢复

执行灾难恢复的 VSS 备份和恢复应用程序 (也称为裸机恢复) 可以将自动化系统恢复 (ASR) 编写器与 Windows 预安装环境 (Windows PE) 一起使用,以备份和还原可启动系统状态的关键卷和其他组件。 备份应用程序作为 VSS 请求者实现。

注意 使用 ASR 的应用程序必须许可 Windows PE。

Windows Server 2003 和 Windows XP: ASR 不是作为 VSS 编写器实现的。

有关可与 ASR 一起使用的跟踪工具的信息,请参阅 将跟踪工具与 VSS ASR 应用程序配合使用

本文内容:

备份阶段任务概述

在备份时,请求者执行以下步骤。

注意

除非另有说明,否则需要执行所有步骤。

 

  1. 调用 CreateVssBackupComponents 函数以创建 IVssBackupComponents 接口的实例,并调用 IVssBackupComponents::InitializeForBackup 方法以初始化实例以管理备份。

  2. 调用 IVssBackupComponents::SetContext 以设置卷影复制操作的上下文。

  3. 调用 IVssBackupComponents::SetBackupState 以配置备份。 将 bBackupBootableSystemState 参数设置为 true 以指示备份将包含可启动的系统状态。

  4. 在 ASR 编写器的编写器元数据文档中选择要备份的关键组件,并为每个组件调用 IVssBackupComponents::AddComponent

  5. 调用 IVssBackupComponents::StartSnapshotSet 以创建新的空卷影副本集。

  6. 调用 IVssBackupComponents::GatherWriterMetadata 以启动与编写器的异步联系。

  7. 调用 IVssBackupComponents::GetWriterMetadata 以检索 ASR 编写器的编写器元数据文档。 ASR 编写器的编写器 ID 为 BE000CBE-11FE-4426-9C58-531AA6355FC4,编写器名称字符串为“ASR 编写器”。

  8. 调用 IVssExamineWriterMetadata::SaveAsXML 以保存 ASR 编写器的编写器元数据文档的副本。

  9. 为可以参与卷影副本的每个卷调用 IVssBackupComponents::AddToSnapshotSet ,以将卷添加到卷影副本集。

  10. 调用 IVssBackupComponents::P repareForBackup 以通知编写器准备备份操作。

  11. 调用 IVssBackupComponents::GatherWriterStatusIVssBackupComponents::GetWriterStatus (或 IVssBackupComponentsEx3::GetWriterStatus) 以验证 ASR 编写器的状态。

  12. 此时,可以查询编写器在其 CVssWriter::OnPrepareBackup 方法中设置的失败消息。 有关演示如何查看这些消息的示例代码,请参阅 IVssComponentEx::GetPrepareForBackupFailureMsg

  13. 调用 IVssBackupComponents::D oSnapshotSet 以创建卷影副本。

  14. 调用 IVssBackupComponents::GatherWriterStatusIVssBackupComponents::GetWriterStatus 以验证 ASR 编写器的状态。

  15. 备份数据。

  16. 通过调用 IVssBackupComponents::SetBackupSucceeded 指示备份操作是否成功。

  17. 调用 IVssBackupComponents::BackupComplete 以指示备份操作已完成。

  18. 调用 IVssBackupComponents::GatherWriterStatusIVssBackupComponents::GetWriterStatus。 编写器会话状态内存是有限的资源,编写器最终必须重用会话状态。 此步骤将编写器的备份会话状态标记为已完成,并通知 VSS 此备份会话槽可由后续备份操作重复使用。

    注意

    这仅在 Windows Server 2008 Service Pack 2 (SP2) 及更早版本上是必需的。

     

  19. 调用 IVssBackupComponents::SaveAsXML 以保存请求者的备份组件文档的副本。 当请求者调用 IVssBackupComponents::InitializeForRestore 方法时,将在还原时使用备份组件文档中的信息。

选择要备份的关键组件

在备份初始化阶段,ASR 编写器在其编写器元数据文档中报告以下类型的组件:

  • 关键卷,例如启动、系统和 Windows 恢复环境 (Windows RE) 卷以及与当前运行的 Windows Vista 或 Windows Server 2008 实例关联的Windows RE分区。 如果卷包含系统状态信息,则卷是 关键卷 。 自动包含启动卷和系统卷。 请求者必须包括包含编写器报告的系统关键组件的所有卷,例如包含 Active Directory 的卷。 系统关键组件标记为“不可选择备份”。在 VSS 中,“不可选择”表示“非可选”。因此,请求者需要将其作为系统状态的一部分进行备份。 有关详细信息,请参阅 备份和还原系统状态。 为其设置了VSS_CF_NOT_SYSTEM_STATE标志的组件不是系统关键组件。

    注意

    ASR 组件是由 ASR 编写器报告的系统关键组件。

     

  • 磁盘。 计算机上的每个固定磁盘都作为 ASR 中的组件公开。 如果在备份期间未排除磁盘,则会在还原期间分配该磁盘,并且可以重新创建和重新格式化。 请注意,在还原期间,请求者仍可以通过调用 IVssBackupComponents::SetRestoreOptions 方法重新创建备份期间排除的磁盘。 如果选择了动态磁盘包中的一个磁盘,则还必须选择该包中的所有其他磁盘。 如果选择卷是因为卷是关键卷 (即包含系统状态信息的卷) ,则还必须选择包含该卷盘区的每个磁盘。 若要查找卷的盘区,请使用 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 控制代码。

    注意

    在备份期间,请求者应包含所有固定磁盘。 如果包含请求者的备份集的磁盘是本地磁盘,则应包含此磁盘。 在还原期间,请求者必须排除包含请求者的备份集的磁盘,以防止其被覆盖。

     

    在聚类分析环境中,ASR 不会重新创建群集共享磁盘的布局。 在Windows RE中还原操作系统后,应联机还原这些磁盘。

  • 启动 BCD) 存储 (配置数据。 此组件指定包含 BCD 存储的目录的路径。 请求者必须指定此组件并备份 BCD 存储目录中的所有文件。 有关 BCD 存储的详细信息,请参阅 关于 BCD

    注意

    在使用扩展固件接口 (EFI) 的计算机上,EFI 系统分区 (ESP) 始终处于隐藏状态,不能包含在卷影副本中。 请求者必须备份此分区的内容。 由于卷影副本中不能包含此分区,因此只能从实时卷执行备份,而不能从卷影副本执行备份。 有关 EFI 和 ESP 的详细信息,请参阅 启动指南

组件名称使用以下格式:

  • 对于磁盘组件,格式为

    <COMPONENT logicalPath=“Disks” componentName=“harddiskn” componentType=“filegroup” />

    其中 n 是磁盘编号。 仅记录磁盘编号。 若要获取磁盘编号,请使用 IOCTL_STORAGE_GET_DEVICE_NUMBER 控制代码。

  • 对于卷组件,格式为

    <COMPONENT logicalPath=“Volumes” componentName=“Volume{GUID}” componentType=“filegroup” />

    其中 GUID 是卷 GUID。

  • 对于 BCD 存储组件,格式为

    <COMPONENT logicalPath=“BCD” componentName=“BCD” componentType=“filegroup” componentCaption = “这是指向启动 BCD 存储和启动管理器的路径...需要备份此目录中的所有文件...”>

    如果系统分区具有卷 GUID 名称,则此组件是可选的。 否则,它不可选择。

    注意

    ASR 将文件添加到 BCD 存储组件的文件组,如下所示:

    • 对于 EFI 磁盘,ASR 添加了

      SystemPartitionPath\EFI\Microsoft\Boot\*.*

      其中 SystemPartitionPath 是系统分区的路径。

    • 对于 GPT 磁盘,ASR 添加了

      SystemPartitionPath\Boot\*.*

      其中 SystemPartitionPath 是系统分区的路径。

    • 可以在以下注册表项下找到系统分区路径: HKEY_LOCAL_MACHINE\System\Setup\SystemPartition

     

还原时,必须还原标记为关键卷的所有组件。 如果一个或多个关键卷无法还原,还原操作将失败。

在还原序列的 PreRestore 阶段,默认情况下会重新创建和重新格式化备份期间未排除的磁盘。 但是,如果它们满足以下条件,则不会重新创建或重新格式化:

  • 如果基本磁盘的磁盘布局完好无损,或者仅对基本磁盘进行了附加更改,则不会重新创建。 如果满足以下条件,则磁盘布局保持不变:

    • 磁盘签名、磁盘样式 (GPT 或 MBR) 、逻辑扇区大小和卷开始偏移不会更改。
    • 卷大小不会减小。
    • 对于 GPT 磁盘,分区标识符不会更改。
  • 如果动态磁盘的磁盘布局保持不变,或者仅对动态磁盘进行了附加更改,则不会重新创建动态磁盘。 要使动态磁盘保持不变,必须满足基本磁盘的所有条件。 此外,整个磁盘包的卷结构必须保持不变。 如果磁盘包满足以下条件(适用于 MBR 和 GPT 磁盘),则其卷结构保持不变:

    • 还原期间物理包中可用的卷数必须大于或等于备份期间 ASR 编写器元数据中指定的卷数。

    • 每个卷的 数必须保持不变。

    • 成员数必须保持不变。

    • 物理磁盘盘区数必须大于 ASR 编写器元数据中指定的磁盘盘区数。

    • 添加其他卷时,或者如果包中的卷 (扩展(例如,从简单卷扩展到跨卷) ),则完整的包保持不变。

      注意

      如果镜像了简单卷,则包不会保持不变,并且会重新创建,以确保 BCD 和启动卷状态在还原后保持一致。 如果删除卷,则会重新创建包。

       

  • 如果动态磁盘包的卷结构保持不变,并且只对它进行了附加更改,则不会重新创建包中的磁盘。

    Windows Vista: 始终重新创建动态磁盘。 请注意,此行为已随 Windows Server 2008 和 Windows Vista Service Pack 1 (SP1) 发生更改。

在还原阶段开始前的任何时候,请求者都可以通过设置 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ASR\RestoreSession 注册表项来指定磁盘快速格式化。 在此键下,有一个名为 QuickFormat 的值,其数据类型REG_DWORD。 如果此值不存在,则应创建它。 对于快速格式设置,将 QuickFormat 值的数据设置为 1;对于慢格式设置,请将 0 设置为 0。

如果 QuickFormat 值不存在,磁盘将采用慢格式设置。

快速格式设置明显快于慢格式 (也称为完整格式) 。 但是,快速格式化不会验证卷上的每个扇区。

还原阶段任务概述

在还原时,请求者执行以下步骤:

注意

除非另有说明,否则需要执行所有步骤。

 

  1. 调用 CreateVssBackupComponents 函数以创建 IVssBackupComponents 接口的实例,并调用 IVssBackupComponents::InitializeForRestore 方法,通过将请求者的备份组件文档加载到实例中来初始化实例以还原。

  2. [仅当请求者需要更改为一个或多个磁盘指定“IncludeDisk”还是“ExcludeDisk”时,此步骤才是必需的。] 调用 IVssBackupComponents::SetRestoreOptions 以设置 ASR 编写器组件的还原选项。 ASR 编写器支持以下选项:“IncludeDisk”允许请求者在目标系统上包括要考虑还原的磁盘,即使在备份阶段未选择磁盘也是如此。 “ExcludeDisk”允许请求者阻止重新创建目标系统上的磁盘。 请注意,如果为包含关键卷的磁盘指定了“ExcludeDisk”,则对 IVssBackupComponents::P reRestore 的后续调用将失败。

    以下示例演示如何使用 SetRestoreOptions 来防止重新创建磁盘 0 和磁盘 1,并将第三方驱动程序注入还原的启动卷。

    Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: 不支持注入第三方驱动程序。

    该示例假定 IVssBackupComponents 指针(m_pBackupComponents)有效。

        m_pBackupComponents->SetRestoreOptions(
            AsrWriterId,
            VSS_CT_FILEGROUP,
            NULL,
            TEXT("ASR"),
            TEXT("\"ExcludeDisk\"=\"0\", \"ExcludeDisk\"=\"1\" "),
            TEXT("\"InjectDrivers\"=\"1\" ")
            );
    

    若要排除指定卷的所有磁盘,请参阅以下“排除卷的所有磁盘”。

  3. 调用 IVssBackupComponents::P reRestore 以通知 ASR 编写器准备还原操作。 根据需要多次调用 IVssAsync::QueryStatus ,直到 pHrResult 参数中返回的状态值未VSS_S_ASYNC_PENDING。

  4. 还原数据。 在还原阶段,ASR 将为每个卷重新配置卷 GUID 路径 (\\?\?\Volume{GUID}) ,以匹配备份阶段使用的卷 GUID 路径。 但是,不会保留驱动器号,因为这会导致与恢复环境中自动分配的驱动器号发生冲突。 因此,在还原数据时,请求者必须使用卷 GUID 路径(而不是驱动器号)来访问卷。

  5. 设置 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ASR\RestoreSession 注册表项以指示已还原或重新格式化的卷集。

    在此键下,有一个名为 RestoredVolumes 的值 ,其数据类型REG_MULTI_SZ。 如果此值不存在,则应创建它。 在此值下,请求者应为每个已还原的卷创建卷 GUID 条目。 此条目应采用以下格式:\\?\Volume{78618c8f-aefd-11da-a898-806e6f6e6963}。 每次执行裸机恢复时,ASR 都会将 RestoredVolumes 值设置为 ASR 还原的卷集。 如果请求者还原了其他卷,则应将此值设置为请求者还原的卷集与 ASR 还原的卷集的并集。 如果请求者未使用 ASR,则它应替换卷列表。

    还应创建一个名为 LastInstance 的值,其数据类型为 REG_SZ。 此密钥应包含唯一标识当前还原操作的随机 Cookie。 可以使用 UuidCreateUuidToString 函数创建此类 Cookie。 每次执行裸机恢复时,ASR 都会重置此注册表值,以通知请求者和非 VSS 备份应用程序已发生恢复。

  6. 调用 IVssBackupComponents::P ostRestore 以指示还原操作的结束。 根据需要多次调用 IVssAsync::QueryStatus ,直到 pHrResult 参数中返回的状态值未VSS_S_ASYNC_PENDING。

在还原阶段,ASR 可能会创建或删除分区,以将计算机还原到以前的状态。 请求者不得尝试将磁盘编号从备份阶段映射到还原阶段。

还原时,请求者必须排除包含请求者的备份集的磁盘。 否则,还原操作可能会覆盖备份集。

还原时,如果在备份期间未选择磁盘作为组件,或者通过在还原期间使用“ExcludeDisk”选项调用 IVssBackupComponents::SetRestoreOptions 显式排除该磁盘,则会排除该磁盘。

请务必注意,在 WinPE 灾难恢复期间,存在 ASR 编写器功能,但没有其他编写器可用,并且 VSS 服务未运行。 WinPE 灾难恢复完成后,计算机已重启,Windows 操作系统正常运行后,可以启动 VSS 服务,并且请求者可以执行任何其他需要 ASR 编写器以外的编写器参与的还原操作。

如果在还原会话期间,备份应用程序检测到卷唯一 ID 未更改,因此从备份时间开始的所有卷在 WinPE 中都存在且保持不变,则备份应用程序可以继续仅还原卷的内容,而不涉及 ASR。 在这种情况下,备份应用程序应通过在还原的操作系统中设置以下注册表项来指示计算机已还原:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ASR\RestoreSession

在此键下,指定 LastInstance 作为值名称,为值类型指定REG_SZ,并为值数据指定随机 cookie (,例如 由 UuidCreate 函数创建的 GUID) 。

如果在还原会话期间,备份应用程序检测到一个或多个卷已更改或丢失,则备份应用程序应使用 ASR 执行还原。 ASR 将按照备份时的方式重新创建卷,并设置 RestoreSession 注册表项。

排除卷的所有磁盘

以下示例演示如何排除指定卷的所有磁盘。

HRESULT BuildRestoreOptionString
(
    const WCHAR             *pwszVolumeNamePath,
    CMyString               *pstrExclusionList
)
{
    HANDLE                  hVolume           = INVALID_HANDLE_VALUE;
    DWORD                   cbSize            = 0;
    VOLUME_DISK_EXTENTS     * pExtents        = NULL;
    DISK_EXTENT             * pExtent         = NULL;
    ULONG                   i                 = 0;
    BOOL                    fIoRet            = FALSE;
    WCHAR                   wszDest[MAX_PATH] = L"";
    CMyString               strVolumeName;
    CMyString               strRestoreOption;

    // Open a handle to the volume device.
    strVolumeName.Set( pwszVolumeNamePath );
    // If the volume name contains a trailing backslash, remove it.
    strVolumeName.UnTrailing( L'\\' );
    hVolume = ::CreateFile(strVolumeName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, 0);
    // Check whether the call to CreateFile succeeded.

    // Get the list of disks used by this volume.
    cbSize = sizeof(VOLUME_DISK_EXTENTS);
    pExtents = (VOLUME_DISK_EXTENTS *)::CoTaskMemAlloc(cbSize);

    ::ZeroMemory(pExtents, cbSize);

    fIoRet = ::DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, pExtents, cbSize, &cbSize, 0);
    if ( !fIoRet && GetLastError() == ERROR_MORE_DATA )
    {
        // Allocate more memory.
        cbSize = FIELD_OFFSET(VOLUME_DISK_EXTENTS, Extents) + pExtents->NumberOfDiskExtents * sizeof(DISK_EXTENT);
        ::CoTaskMemFree(pExtents);
        pExtents = NULL;

        pExtents = (VOLUME_DISK_EXTENTS *) ::CoTaskMemAlloc(cbSize);
        // Check whether CoTaskMemAlloc returned an out-of-memory error.
        ::ZeroMemory(pExtents, cbSize);

        // Now the buffer should be big enough.
        ::DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, pExtents, cbSize, &cbSize, 0);
        // Check whether the IOCTL succeeded.
    }
    // Check for errors; note that the IOCTL can fail for a reason other than insufficient memory.

    // For each disk, mark it to be excluded in the Restore Option string.
    for (i = 0; i < pExtents->NumberOfDiskExtents; i++)
    {
        pExtent = &pExtents->Extents[i];

        *wszDest = L'\0';
        StringCchPrintf(wszDest, MAX_PATH, L"\"ExcludeDisk\"=\"%d\", ", pExtent->DiskNumber); // check errors

        strRestoreOption.Append(wszDest);
        // Check for an out-of-memory error.
    }

    // Remove the trailing comma.
    strRestoreOption.TrimRight();
    strRestoreOption.UnTrailing(',');

    // Set the output parameter.
    strRestoreOption.Transfer( pstrExclusionList );

Exit:
    if( pExtents )
    {
        ::CoTaskMemFree(pExtents);
        pExtents = NULL;
    }

    if( hVolume != INVALID_HANDLE_VALUE )
    {
        ::CloseHandle(hVolume);
        hVolume = INVALID_HANDLE_VALUE;
    }

    return ( hr );
}