private void CreateVhdx(bool allowKeepDebug, long length) { var diskStream = CreateVhdxStream(allowKeepDebug); Disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, length, 128 << 20); var gpt = GuidPartitionTable.Initialize(Disk); gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null); var volume = VolumeManager.GetPhysicalVolumes(Disk).First(); uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512); var clusterCount = 1 << 25; var clusterSize = length / clusterCount; var clusterBits = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2)); if (clusterBits > 18) { clusterBits = 18; } else if (clusterBits < 11) { clusterBits = 11; } FileSystem = ExFatEntryFilesystem.Format(volume.Open(), new ExFatFormatOptions { SectorsPerCluster = (1u << clusterBits) / bytesPerSector }); }
public static void Main4(string[] args) { string label = "Zap!"; long capacity = 2L << 40; int blockSize = 4 << 20; using (var diskStream = File.Create("big.vhdx")) using (var disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, capacity, blockSize)) { var gpt = GuidPartitionTable.Initialize(disk); gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null); var volume = VolumeManager.GetPhysicalVolumes(disk).First(); uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512); var clusterCount = 1 << 25;// uint.MaxValue - 16; var clusterSize = capacity / clusterCount; var clusterBits = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2)); if (clusterBits > 18) { clusterBits = 18; } //clusterBits = 20; using (var fs = ExFatFileSystem.Format(volume, new ExFatFormatOptions { SectorsPerCluster = (1u << clusterBits) / bytesPerSector }, label: label)) { } } }
public void Initialize() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); Assert.Equal(0, table.Count); } }
private static void CreateVirtualDisk(string filePath, int size) { using (FileStream fsStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) using (VirtualDisk disk = DiscUtils.Vhd.Disk.InitializeDynamic(fsStream, DiscUtils.Streams.Ownership.Dispose, size * 1024 * 1024)) { GuidPartitionTable.Initialize(disk, WellKnownPartitionType.WindowsNtfs); PhysicalVolumeInfo volume = VolumeManager.GetPhysicalVolumes(disk)[0]; NtfsFileSystem.Format(volume, "CryptoBox"); } }
public void CreateSmallWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(WellKnownPartitionType.WindowsFat, true); // Make sure the partition fills from first to last usable. Assert.Equal(table.FirstUsableSector, table[idx].FirstSector); Assert.Equal(table.LastUsableSector, table[idx].LastSector); } }
public void CreateBySize() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); // Make sure the partition is within 10% of the size requested. Assert.True((2 * 1024 * 2) * 0.9 < table[idx].SectorCount); Assert.Equal(table.FirstUsableSector, table[idx].FirstSector); } }
public void CreateLargeWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(WellKnownPartitionType.WindowsFat, true); Assert.Equal(2, table.Partitions.Count); Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType); Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512); // Make sure the partition fills from first to last usable, allowing for MicrosoftReserved sector. Assert.Equal(table[0].LastSector + 1, table[idx].FirstSector); Assert.Equal(table.LastUsableSector, table[idx].LastSector); } }
public void CreateBySizeInGap() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 300 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); table.Create(10 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); table.Create((20 * 1024 * 1024) / 512, ((30 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition"); table.Create((60 * 1024 * 1024) / 512, ((70 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition"); int idx = table.Create(20 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); Assert.Equal(((30 * 1024 * 1024) / 512), table[idx].FirstSector); Assert.Equal(((50 * 1024 * 1024) / 512) - 1, table[idx].LastSector); } }
public void Delete() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 10 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); Assert.Equal(0, table.Create(1 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); Assert.Equal(1, table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); Assert.Equal(2, table.Create(3 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); long[] sectorCount = new long[] { table[0].SectorCount, table[1].SectorCount, table[2].SectorCount }; table.Delete(1); Assert.Equal(2, table.Count); Assert.Equal(sectorCount[2], table[1].SectorCount); } }
public void DeviceValue_Gpt() { SparseMemoryStream ms = new SparseMemoryStream(); ms.SetLength(80 * 1024 * 1024); GuidPartitionTable gpt = GuidPartitionTable.Initialize(ms, Geometry.FromCapacity(ms.Length)); gpt.Create(WellKnownPartitionType.WindowsNtfs, true); VolumeManager volMgr = new VolumeManager(ms); RegistryHive hive = RegistryHive.Create(new MemoryStream()); Store s = Store.Initialize(hive.Root); BcdObject obj = s.CreateInherit(InheritType.AnyObject); Element el = obj.AddElement(WellKnownElement.LibraryApplicationDevice, ElementValue.ForDevice(Guid.Empty, volMgr.GetPhysicalVolumes()[0])); el = obj.GetElement(WellKnownElement.LibraryApplicationDevice); Assert.IsNotNullOrEmpty(el.Value.ToString()); }
public void CreateAlignedWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.CreateAligned(WellKnownPartitionType.WindowsFat, true, 1024 * 1024); Assert.Equal(2, table.Partitions.Count); Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType); Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512); // Make sure the partition is aligned Assert.Equal(0, table[idx].FirstSector % 2048); Assert.Equal(0, (table[idx].LastSector + 1) % 2048); // Ensure partition fills most of the disk Assert.True((table[idx].SectorCount * 512) > disk.Capacity * 0.9); } }
private static int StartInternal() { if (!GuidPartitionTable.Detect(mSourceStream)) { throw new InvalidDataException( "Source does not contain a supported partitioning scheme"); } Logger.Debug("Detecting disc geometry of source..."); var geometry = GuidPartitionTable.DetectGeometry(mSourceStream); Logger.Debug("Reading GPT partition table from source..."); var partitionTable = new GuidPartitionTable(mSourceStream, geometry); if (partitionTable.Count <= 0) { return(SUCCESS); // nothing to clone here } // adjust source length if (FixedLengthStream.IsFixedDiskStream(mSourceStream)) { mSourceStream.SetLength(geometry.Capacity); } Geometry destGeometry = null; if (FixedLengthStream.IsFixedDiskStream(mDestinationStream)) { // If we write to a disk, we need our own geometry for that destination destGeometry = Geometry.FromCapacity(mDestinationStream.Length, geometry.BytesPerSector); } else { // If we are just writing to a file, we take the most exact copy we get destGeometry = geometry; } // Set the new size of the destination stream Logger.Verbose("Updating length of destination: {0} -> {1}", mDestinationStream.Length, destGeometry.Capacity); mDestinationStream.SetLength(destGeometry.Capacity); if (mFullClone) { Logger.Warn("Starting full clone..."); CloneStream(0, 0, mSourceStream, mDestinationStream); return(SUCCESS); } Logger.Debug("Initializing new GPT partition table on destination..."); var destPartitionTable = GuidPartitionTable.Initialize(mDestinationStream, destGeometry); var availableSpace = destGeometry.Capacity; var usedSpace = 0L; // correct available space by remove unusable sectors // heading sectors availableSpace -= (destPartitionTable.FirstUsableSector * destGeometry.BytesPerSector); // ending sectors availableSpace -= ((destGeometry.TotalSectorsLong - destPartitionTable.FirstUsableSector - destPartitionTable.LastUsableSector) * destGeometry.BytesPerSector); // 1. calculate unresizeable space if we are required too if (destGeometry.Capacity < geometry.Capacity) { Logger.Info("Calculating space for new destination partitions..."); var unresizeableSpace = 0L; for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var srcPartitionSize = srcPartition.SectorCount * geometry.BytesPerSector; var isResizeable = true; // If the file system is not support, we have to perform // a byte-for-byte cloning and cannot resize this partition if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { Logger.Verbose("Partition{0}: contains no or unsupported file system"); isResizeable = false; } // If we have a critical partition, we shouldn't resize that either if (!IsSupportedPartitionType(srcPartitionType)) { Logger.Verbose("Partition{0}: unsupported partition type"); isResizeable = false; } // if caller want to do a byte-for-byte clone, mark every partition // as unresizeable if (mForceExactCloning) { isResizeable = false; } Logger.Debug("Partition #{0} on source: isResizeable={1}", i, isResizeable); if (!isResizeable) { // if it's not resizeable, account the space and continue unresizeableSpace += srcPartitionSize; Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " + "(total unresizable {2}/used {3})", i, srcPartitionSize, unresizeableSpace, usedSpace); } else { // if it is resizeable, we have to report how much space we need var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); usedSpace += srcPartitionFS.UsedSpace; Logger.Debug("Partition #{0} on source: resizeable, space is {1} " + "(total unresizable {2}/used {3})", i, usedSpace, unresizeableSpace, usedSpace); } } // reduce the dynamically available space ... availableSpace -= unresizeableSpace; // ... and assert it if (availableSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#,##0}", -availableSpace) + " Bytes too small"); } // assert the used space too if (availableSpace - usedSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#,##0}", availableSpace - usedSpace) + " Bytes too small"); } } else { Logger.Info("Destination can contain source, no need to resize partitions!"); } // 2. calculate the size for each new partition var destPartitionSizes = new long[partitionTable.Count]; for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var srcPartitionSize = srcPartition.SectorCount * geometry.BytesPerSector; // if the destination can take more data, skip every check if (geometry.Capacity <= destGeometry.Capacity) { Logger.Debug("Partition{0}: Destination can contain full partition, continue...", i); destPartitionSizes[i] = srcPartitionSize; availableSpace -= srcPartitionSize; continue; } var isResizeable = true; // If the device-systme is not support, we have to perform // a byte-for-byte cloning and cannot resize this partition if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { isResizeable = false; } // If we have a critical partition, we shouldn't resize that either if (!IsSupportedPartitionType(srcPartitionType)) { isResizeable = false; } // if caller want to do a byte-for-byte clone, mark every partition // as unresizeable if (mForceExactCloning) { isResizeable = false; } Logger.Debug("Partition #{0} on source: isResizeable={1}", i, isResizeable); // If our friend is not resizeable, set size and stop processing it if (!isResizeable) { destPartitionSizes[i] = srcPartitionSize; Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " + "(total available {2}/used {3})", i, usedSpace, availableSpace, usedSpace); // DO NOT ALIGN <availableSpace> HERE!!! // Has already been done in step 1 continue; } // // OK. If we are here, a resizeable partition awaits processing // var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); // First we need to check if we need to reqsize the current partition. // For that, calculate the space that is left for future partitions. If the // result is OK (less or equal to the available size), we can skip // resizing the the current one. // Make sure to remove the factor of this partition from usedSpace first if (((usedSpace - srcPartitionFS.UsedSpace) + srcPartitionSize) <= availableSpace) { // update usedSpace usedSpace -= srcPartitionFS.UsedSpace; // align availableSpace availableSpace -= srcPartitionSize; // we are good to skip resizing this one. assign size and early exit destPartitionSizes[i] = srcPartitionSize; Logger.Debug( "Partition #{0} on source: resizeable, space is {1}, size is {2} " + "(total available {3}/used {4})", i, srcPartitionFS.UsedSpace, srcPartitionSize, availableSpace, usedSpace); continue; } // So this partition is too large, let's resize it to the biggest size possible var maxPartitionSize = Math.Max( // Occupied space is the absolute minimal space we need srcPartitionFS.UsedSpace, // This is the largest space possible. Take the still available space // and remove still required space, while also remove the factor for // the current partition availableSpace - (usedSpace - srcPartitionFS.UsedSpace) ); Logger.Debug( "Partition #{0} on source: resizeable, max. space is {1} " + "(total available {2}/used {3})", i, maxPartitionSize, availableSpace, usedSpace); // update usedSpace usedSpace -= srcPartitionFS.UsedSpace; // align availableSpace availableSpace -= maxPartitionSize; destPartitionSizes[i] = maxPartitionSize; } // a last assert of the available space, just to be sure if (availableSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#.##0}", -availableSpace) + " Bytes too small"); } // 2. create the new partitions with the aligned sizes for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); // manueal type adjusting if (NtfsFileSystem.Detect(srcPartitionStream)) { srcPartitionType = WellKnownPartitionType.WindowsNtfs; } else if (FatFileSystem.Detect(srcPartitionStream)) { srcPartitionType = WellKnownPartitionType.WindowsFat; } var destPartitionSize = destPartitionSizes[i]; Logger.Debug("Creating partition table: #{0}; {1}/{2}@0x{3}-{4}", i, srcPartition.Name, srcPartition.Identity, srcPartition.FirstSector.ToString("X2"), destPartitionSize); destPartitionTable.Create( destPartitionSize, srcPartitionType, true //doesn't matter on GPT tables ); } // 3. make sure the count of partitions is the same if (partitionTable.Count != destPartitionTable.Count) { throw new InvalidOperationException( "Failed to create proper GUID partition table"); } // 4. do the real cloning for (int i = 0; i < destPartitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var destPartition = (GuidPartitionInfo)destPartitionTable[i]; var destPartitionStream = destPartition.Open(); var destPartitionSize = destPartitionSizes[i]; var requiresExactCloning = false; // To support all possible file-systems, perform a byte-for-byte // cloning if the file-system is not supported by us. if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { requiresExactCloning = true; } // If we have a critical partition, we should skip that one too if (srcPartitionType == WellKnownPartitionType.BiosBoot || srcPartitionType == WellKnownPartitionType.EfiSystem || srcPartitionType == WellKnownPartitionType.MicrosoftReserved) { requiresExactCloning = true; } // if caller want to do a byte-for-byte clone, let's enable it if (mForceExactCloning) { requiresExactCloning = true; } if (requiresExactCloning) { var taskId = (mTaskIdCounter++); Logger.Info("[{0}/{1}] cp-fs : {2}/{3}@0x{4}", i, taskId, srcPartition.Name, srcPartition.Identity, srcPartition.FirstSector.ToString("X2")); CloneStream(i, taskId, srcPartitionStream, destPartitionStream); } else { var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); var srcPartitionBootCode = srcPartitionFS.ReadBootCode(); var destPartitionFS = DiscHandler.FormatFileSystemWithTemplate( srcPartitionStream, destPartitionStream, destPartition.FirstSector, destPartition.SectorCount, destPartitionSize ); // Tracks all NTFS file IDs for hard link recognition // <Source FS File ID, Destination FS File ID> var ntfsHardlinkTracker = new Dictionary <uint, uint>(); // last clone each single with here Action <DiscDirectoryInfo, DiscDirectoryInfo> cloneSrcFsToDestFs = null; cloneSrcFsToDestFs = new Action <DiscDirectoryInfo, DiscDirectoryInfo>( (sourceDir, destDir) => { // recursive enumeration. save to create directory without checks for // parent directories. var taskId = (mTaskIdCounter++); Logger.Info("[{0}/{1}] mk-dir : {2}", i, taskId, destDir.FullName); destDir.Create(); // copy files if there are any foreach (var sourceFile in sourceDir.GetFiles()) { var skipCopying = false; taskId = (mTaskIdCounter++); var sourceFileStream = sourceFile.Open(FileMode.Open, FileAccess.Read); var destFileName = Path.Combine(destDir.FullName, sourceFile.Name); Logger.Info("[{0}/{1}] mk-file: {2}", i, taskId, destFileName); var destFileStream = destPartitionFS.OpenFile( destFileName, FileMode.Create, FileAccess.Write); var destFile = new DiscFileInfo(destPartitionFS, destFileName); // NTFS hard link handling if (destPartitionFS is NtfsFileSystem) { var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS; var ntfsDestFS = (NtfsFileSystem)destPartitionFS; var sourceFileNtfsEntry = ntfsSourceFS.GetDirectoryEntry( sourceFile.FullName); var sourceFileNtfsRef = ntfsSourceFS.GetFile( sourceFileNtfsEntry.Reference); var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry( destFile.FullName); var destFileNtfsRef = ntfsDestFS.GetFile( destFileNtfsEntry.Reference); var sourceFileNtfsId = sourceFileNtfsRef.IndexInMft; // check if this files was already processed once if (ntfsHardlinkTracker.ContainsKey(sourceFileNtfsId)) { var trackedDestFileNtfsRef = ntfsDestFS.GetFile( ntfsHardlinkTracker[sourceFileNtfsId]); // if we have a hardlink-match, close the old stream // and delete the file destFileStream.Close(); destFile.Delete(); // then create the hardlink and mention that we don't // want/need to copy the content anymore Logger.Info("[{0}/{1}] mk-lnk : {2} => {3}", i, taskId, sourceFileNtfsRef.Names[0], destFile.FullName); ntfsDestFS.CreateHardLink( trackedDestFileNtfsRef.DirectoryEntry, destFile.FullName); skipCopying = true; } else { Logger.Verbose("[{0}/{1}] rg-lnk : {2}#{3} -> {4}#{5}", i, taskId, sourceFileNtfsRef.Names[0], sourceFileNtfsRef.IndexInMft, destFileNtfsRef.Names[0], destFileNtfsRef.IndexInMft); // if not, track it ntfsHardlinkTracker.Add(sourceFileNtfsRef.IndexInMft, destFileNtfsRef.IndexInMft); } } if (!skipCopying) { Logger.Info("[{0}/{1}] cp-file: {2}", i, taskId, destFile.FullName); CloneStream(i, taskId, sourceFileStream, destFileStream); } // clone basic file informationsdestFile Logger.Verbose("[{0}/{1}] cp-meta: {2}", i, taskId, destFile.FullName); destFile.Attributes = sourceFile.Attributes; destFile.CreationTime = sourceFile.CreationTime; destFile.CreationTimeUtc = sourceFile.CreationTimeUtc; destFile.IsReadOnly = sourceFile.IsReadOnly; destFile.LastAccessTime = sourceFile.LastAccessTime; destFile.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc; destFile.LastWriteTime = sourceFile.LastWriteTime; destFile.LastWriteTimeUtc = sourceFile.LastWriteTimeUtc; // file-system based cloning if (destPartitionFS is NtfsFileSystem) { Logger.Verbose("[{0}/{1}] cp-fsec: {2}", i, taskId, destFile.FullName); var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS; var ntfsDestFS = (NtfsFileSystem)destPartitionFS; var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry( destFile.FullName); var destFileNtfsRef = ntfsDestFS.GetFile( destFileNtfsEntry.Reference); // clone security descriptors var sourceNtfsSecurity = ntfsSourceFS.GetSecurity( sourceFile.FullName); ntfsDestFS.SetSecurity(destFile.FullName, sourceNtfsSecurity); // clone short names if destination file is not a hard link if (destFileNtfsEntry.Details.FileNameNamespace != FileNameNamespace.Posix || !destFileNtfsRef.HasWin32OrDosName) { Logger.Verbose("[{0}/{1}] cp-shrt: {2}", i, taskId, destFile.FullName); var sourceNtfsShortName = ntfsSourceFS.GetShortName( sourceFile.FullName); if (sourceNtfsShortName != null) { ntfsSourceFS.SetShortName(destFile.FullName, sourceNtfsShortName); } } } } // advance recursion into directories foreach (var sourceDirectory in sourceDir.GetDirectories()) { if (srcPartitionFS is FatFileSystem) { // Don't copy SYSTEM~1 on FAT. Just don't do it... if (sourceDirectory.Name.Equals("SYSTEM~1")) { continue; } } cloneSrcFsToDestFs(sourceDirectory, new DiscDirectoryInfo( destPartitionFS, Path.Combine(destDir.FullName, sourceDirectory.Name) ) ); } }); cloneSrcFsToDestFs(srcPartitionFS.Root, destPartitionFS.Root); } } return(SUCCESS); }
protected override void ProcessRecord() { PSObject diskObject = null; VirtualDisk disk = null; if (InputObject != null) { diskObject = InputObject; disk = diskObject.BaseObject as VirtualDisk; } if (disk == null && string.IsNullOrEmpty(LiteralPath)) { WriteError(new ErrorRecord( new ArgumentException("No disk specified"), "NoDiskSpecified", ErrorCategory.InvalidArgument, null)); return; } if (disk == null) { diskObject = SessionState.InvokeProvider.Item.Get(LiteralPath)[0]; VirtualDisk vdisk = diskObject.BaseObject as VirtualDisk; if (vdisk == null) { WriteError(new ErrorRecord( new ArgumentException("Path specified is not a virtual disk"), "BadDiskSpecified", ErrorCategory.InvalidArgument, null)); return; } disk = vdisk; } PartitionTable pt = null; if (VolumeManager == VolumeManagerType.Bios) { pt = BiosPartitionTable.Initialize(disk); } else { pt = GuidPartitionTable.Initialize(disk); } if (Signature != 0) { disk.Signature = Signature; } else { disk.Signature = new Random().Next(); } // Changed volume layout, force a rescan var drive = diskObject.Properties["PSDrive"].Value as VirtualDiskPSDriveInfo; if (drive != null) { drive.RescanVolumes(); } WriteObject(disk); }