我正在尝试找到一种方法将活动的 Windows 系统磁盘克隆到另一个磁盘,而不会像 Clonezilla 要求的那样强制用户使磁盘脱机。
我正在考虑 Microsoft 卷影复制服务 (VSS) 至少部分答案。(我完全愿意接受更好的想法/解决方案。)
在继续代码示例之前,我对 VSS(.Net 接口使用可通过 NuGet 包管理器获得的 AlphaVSS)有点犹豫,因为两个使用 VSS(Shadow Copy 和另一个工具)的实用程序没有正确复制驱动器. 并非所有文件都被复制,尤其是根目录中的 sys 文件正确,并且也没有复制完整权限。一个简单的 Araxis 磁盘比较显示了副本的不准确性。此外,我无法启动克隆的驱动器。我得到一个屏幕说驱动器无法启动并且必须修复。
该示例有点难以理解。我期待看到包含开关(子目录与非子目录,权限等,等等,等等)
我确实看过dotNetDiskImager,但那是USB到图像文件和图像文件到USB磁盘。修改代码,让一个人开车去潜水是完全失败的。不能只是愚蠢地复制扇区。必须知道您正在复制什么并进行修改。仅仅复制扇区并不是一项简单的任务,因此回到 VSS。
有更好的想法吗?
这是一个更新的 AlphaVSS 代码,它修复了由于 AlphaVSS 同步而不是异步导致的编译器错误。我还将代码从 VB 翻译成 C#。
[System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint="CopyFileEx", ExactSpelling=false, CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true)]
private static extern int CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine_Delegate lpProgressRoutine, Int32 lpData, Int32 lpBool, Int32 dwCopyFlags);
private delegate long CopyProgressRoutine_Delegate(long totalFileSize, long totalBytesTransferred, long streamSize, long streamBytesTransferred, Int32 dwStreamNumber, Int32 dwCallbackReason, Int32 hSourceFile, Int32 hDestinationFile, Int32 lpData);
private CopyProgressRoutine_Delegate m_oCPR;
public void Main()
{
//
// Display Setting
Console.BackgroundColor = ConsoleColor.White;
Console.Clear();
Console.SetWindowSize(90, 30);
Console.SetWindowPosition(0, 0);
Console.ForegroundColor = ConsoleColor.DarkGreen;
// Prevent example from ending if CTL+C is pressed.
Console.TreatControlCAsInput = true;
StartPoint:
Console.Clear();
Console.WriteLine("*******************************************************************");
Console.WriteLine("** **");
Console.WriteLine("** Greetings, **");
Console.WriteLine("** **");
Console.WriteLine("** This small app is only for primary basic Testing **");
Console.WriteLine("** of VSS using Dot.Net Technology **");
Console.WriteLine("** The app is base on the AlphaVSS open project: **");
Console.Write("** ");
Console.ForegroundColor = ConsoleColor.Blue;
Console.Write("http://www.codeplex.com/alphavss");
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine(" **");
Console.WriteLine("** **");
Console.WriteLine("** The application is designed only for internal purposes!! **");
Console.WriteLine("** In no way use on production servers. **");
Console.Write("** ");
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.Write("Any use is at your own risk!!!");
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine(" **");
Console.WriteLine("** **");
Console.WriteLine("** Have Fun, **");
Console.WriteLine("** Ariely Ronen **");
Console.WriteLine("** ____________________________________________________________ **");
Console.WriteLine("** **");
Console.WriteLine("** Do you want to start the TEST **");
Console.WriteLine("** by selecting the file you want to copy? (y/n) **");
Console.WriteLine("** **");
Console.WriteLine("*******************************************************************");
ConsoleKeyInfo MyConsoleKeyInfo = new ConsoleKeyInfo();
MyConsoleKeyInfo = Console.ReadKey();
if (!(MyConsoleKeyInfo.Key.ToString() == "Y"))
{
return;
}
SelectFileToCopy:
Console.Clear();
Console.Write("Starting Test Ver 0.01");
FolderBrowserDialog sDestFolder = new FolderBrowserDialog();
string sDestFolderPath = null;
sDestFolder.Description = "Select a destination folder (where the file will be copy to).";
// Do not show the button for new folder
sDestFolder.ShowNewFolderButton = false;
DialogResult dlgResult = sDestFolder.ShowDialog();
if (dlgResult == Windows.Forms.DialogResult.OK)
{
sDestFolderPath = sDestFolder.SelectedPath;
}
else
{
sDestFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).ToString();
}
OpenFileDialog oOFD = new OpenFileDialog();
string sFileName = null;
// copy progress handler
// we add the function "CopyProgressRoutine" to the Delegate "CopyProgressRoutine_Delegate"
// so every time the event come the function run
m_oCPR = new CopyProgressRoutine_Delegate(CopyProgressRoutine);
oOFD.ValidateNames = false;
oOFD.Title = "Select an in-use file you would like to copy.";
oOFD.Filter = "All files (*.*)|*.*";
if (oOFD.ShowDialog == DialogResult.OK)
{
sFileName = oOFD.FileName;
Console.Clear();
Console.WriteLine("File to Copy: ");
Console.WriteLine(sFileName);
Console.WriteLine();
Console.WriteLine("The file will be copy to:");
Console.WriteLine(sDestFolderPath);
Console.WriteLine();
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
Console.Clear();
// Lets Start to copy
PerformVSSCopy(sFileName, sDestFolderPath);
}
Console.WriteLine();
Console.WriteLine("Press 1 to go to Start Point,2 to go to Select new File To Copy, any other key to exit.");
MyConsoleKeyInfo = Console.ReadKey();
switch (MyConsoleKeyInfo.Key.ToString())
{
case "D1":
goto StartPoint;
case "D2":
goto SelectFileToCopy;
default:
break;
}
}
private Int32 CopyProgressRoutine(long totalFileSize, long totalBytesTransferred, long streamSize, long streamBytesTransferred, Int32 dwStreamNumber, Int32 dwCallbackReason, Int32 hSourceFile, Int32 hDestinationFile, Int32 lpData)
{
double dPerc = 100;
if (totalFileSize != 0)
{
dPerc = (totalBytesTransferred / (double)totalFileSize) * 100;
}
Console.CursorLeft = 0;
Console.Write("Copied " + totalBytesTransferred + " of " + totalFileSize + " [" + dPerc.ToString("0.0") + "%]");
return 0;
}
private void PerformVSSCopy(string sFilename, string sDestFolder)
{
// Based on the documention from
// http://msdn.microsoft.com/en-us/library/aa384589(VS.85).aspx
// and the help of those on
// http://www.codeplex.com/alphavss
// The parts I have marked and INFO ONLY are not required for the
// VSS Copy to work, they just give insight into the process
Alphaleonis.Win32.Vss.IVssImplementation oVSSImpl = null;
Alphaleonis.Win32.Vss.IVssBackupComponents oVSS = null;
string sVolume = null;
IO.FileInfo oFI = new IO.FileInfo(sFilename);
Guid gSnapshot = new Guid();
Guid gSnapshotSet = new Guid();
string sVSSFile = null;
string sDestFile = null;
Alphaleonis.Win32.Vss.VssSnapshotProperties oProps = null;
try
{
// Load the Implementation specifi for this machine i.e Windowx XP , Vista, 32 or 64 Bit
oVSSImpl = Alphaleonis.Win32.Vss.VssUtils.LoadImplementation();
// This is the main man for VSS Backups.
Console.WriteLine("Initializing VssBackupComponents Object");
oVSS = oVSSImpl.CreateVssBackupComponents;
oVSS.InitializeForBackup(null);
// Tell VSS that we are requesting a backup with particular options
Console.WriteLine("Setting Backup State");
oVSS.SetBackupState(false, true, Alphaleonis.Win32.Vss.VssBackupType.Full, false);
// Tell all VSS Writers that we want their MetaData. We wait until all Writers have responded.
Console.WriteLine("Gat Writers Metadata");
oVSS.GatherWriterMetadata();
// INFO ONLY : Enumerate who responded to our GatherWriterMetadata request
// Create the Snapshot Set that we will place all our Snapshotted volumes into. (even tho here will only snapshot one volume)
Console.WriteLine("Starting Snapshot Set");
gSnapshotSet = oVSS.StartSnapshotSet();
// Add a Snapshot for the required Volume
sVolume = oFI.Directory.Root.Name;
Console.WriteLine("Add To Snapshot Set the Volume: " + sVolume);
gSnapshot = oVSS.AddToSnapshotSet(sVolume, Guid.Empty);
// Notify all VSS Writers that the backup is about to start, we wait untuil they have indicated they are ready.
Console.WriteLine("VSS Writers Prepare For Backup .");
oVSS.PrepareForBackup();
//Request that the Snapshot are created and wait until they are ready.
Console.WriteLine("Do Snapshot Set [this can take some time]");
oVSS.DoSnapshotSet();
// --------------------------------------------------------------
// --------------------------------------------------------------
// Now we can start copying the file.
// --------------------------------------------------------------
// We need the properties to tell us how to access our files in the snapshot
oProps = oVSS.GetSnapshotProperties(gSnapshot);
sVSSFile = sFilename.Replace(sVolume, oProps.SnapshotDeviceObject + "\\");
sDestFile = IO.Path.Combine(sDestFolder, IO.Path.GetFileName(sFilename));
// INFO ONLY Lets check the Properties of the snapshot set
// Copy, but the normal .NET routines will not work here. Back to the API !!!
Console.WriteLine("Copying file using API Routines.");
Console.WriteLine();
CopyFileEx(sVSSFile, sDestFile, m_oCPR, 0, 0, 0);
Console.WriteLine();
Console.WriteLine("Done !");
// --------------------------------------------------------------
// --------------------------------------------------------------
// Release the snapshot set, we could also just call Dispose on the VssBackupComponents object
// For clarity, I'll do both here.
Console.WriteLine("Deleting Snapshot Set.");
oVSS.DeleteSnapshotSet(gSnapshotSet, true);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
Console.WriteLine();
}
finally
{
oVSS.Dispose();
}
}
简而言之,我想取一个通常具有“系统保留”、“主”和恢复分区的实时系统磁盘,并在系统中的另一个磁盘上进行实时克隆。
我会确保新磁盘有足够的空间,已经分区并格式化为 3 个 NTFS 分区。