From 91588110b158cad19f9b41d674168388a94ddf6d Mon Sep 17 00:00:00 2001 From: Signum21 Date: Thu, 13 Mar 2025 23:49:55 +0100 Subject: [PATCH 1/2] Added command to dump recursive file list --- Program.cs | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/Program.cs b/Program.cs index 78b1328..ade30f1 100644 --- a/Program.cs +++ b/Program.cs @@ -70,7 +70,7 @@ static void Main(string[] args) { .Add("awskey=", "AWS access key to use", v => awsAccessKey = v) .Add("awssecret=", "AWS secret", v => awsAccessSecret = v) .Add("awsregion=", "AWS region", v => awsRegion = v) - .Add("command=", "The command to execute: [volumes|ls|extract]", v => command = v) + .Add("command=", "The command to execute: [volumes|file_list|ls|extract]", v => command = v) .Add("image=", @"The path to the virtual disk, e.g. C:\temp\backup.vhdx or ebs://snapshotid", v => image = v) .Add("path=", @"Volume and path to query within the virtual disk filesystem ", v => path = v); @@ -139,7 +139,7 @@ static void Main(string[] args) { } catch (Exception) { } } - } else if (command == "ls" || command == "download") { + } else if (command == "ls" || command == "extract") { var pathStart = path.LastIndexOf(":"); var volumePath = path.Substring(0, pathStart); @@ -171,9 +171,44 @@ static void Main(string[] args) { } else { var fileStream = fs.OpenFile(filePath, FileMode.Open, FileAccess.Read); - Console.WriteLine($"[+] Opened file with path {filePath} for with size: {fileStream.Length}"); + Console.WriteLine($"[+] Opened file with path {filePath} for with size: {fileStream.Length / 1024.0 / 1024.0: 0.00}MB"); File.WriteAllBytes(Path.GetFileName(filePath), StreamUtilities.ReadExact(fileStream, (int)fileStream.Length)); } + } else if (command == "file_list") { + foreach (var volume in VolumeManager.GetLogicalVolumes()) { + using (var sparseStream = volume.Open()) { + var fsInfo = FileSystemManager.DetectFileSystems(sparseStream); + + if (fsInfo != null && fsInfo.Length > 0) { + DiscFileSystem fileSystem = fsInfo[0].Open(sparseStream); + + if (fileSystem is NtfsFileSystem) { + ((NtfsFileSystem)fileSystem).NtfsOptions.HideHiddenFiles = false; + ((NtfsFileSystem)fileSystem).NtfsOptions.HideSystemFiles = false; + } + List files = new List(); + List newDirs = new List(); + List files_dirs = new List(); + List dirs = new List(); + dirs.Add(""); + + while(dirs.Count > 0) { + files = fileSystem.GetFiles(dirs.First()).ToList(); + newDirs = fileSystem.GetDirectories(dirs.First()).ToList(); + dirs.RemoveAt(0); + dirs.InsertRange(0, newDirs); + files_dirs.AddRange(newDirs.Select(x => x + "\\").ToList()); + files_dirs.AddRange(files); + files_dirs.Sort(); + + foreach (string f in files_dirs) { + Console.WriteLine($"{volume.Identity}:{f}"); + } + files_dirs.Clear(); + } + } + } + } } } else { From 2a743f057d6d04ca84572ee2d494f4f207e1b0d9 Mon Sep 17 00:00:00 2001 From: Signum21 Date: Mon, 24 Mar 2025 02:22:27 +0100 Subject: [PATCH 2/2] Migrated to new DiscUtils fork --- DiscUtils.Ebs/Disk.cs | 15 +++--- DiscUtils.Ebs/DiskImageFile.cs | 16 +++---- DiscUtils.Ebs/DiskLayer.cs | 9 +--- DiscUtils.Ebs/EbsMappedStream.cs | 13 +++-- DiscUtils.RawDisk/Disk.cs | 17 +++---- DiscUtils.RawDisk/RawDiskStream.cs | 18 +++---- Program.cs | 76 ++++++++++++++++-------------- README.md | 21 +++++++-- UI.cs | 15 +++--- Volumiser.csproj | 7 ++- 10 files changed, 106 insertions(+), 101 deletions(-) diff --git a/DiscUtils.Ebs/Disk.cs b/DiscUtils.Ebs/Disk.cs index 6d0011e..f8226a2 100644 --- a/DiscUtils.Ebs/Disk.cs +++ b/DiscUtils.Ebs/Disk.cs @@ -3,9 +3,6 @@ using DiscUtils.Streams; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace DiscUtils.Ebs { public class Disk : VirtualDisk { @@ -33,7 +30,7 @@ public Disk(string snapshotId, string region, AWSCredentials credentials) { Size = ebsMappedStream.SnapshotBlocks.Count * BlockSize; } - public override Geometry Geometry => Geometry.FromCapacity(sparseStream.Length); + public override Geometry? Geometry => DiscUtils.Geometry.FromCapacity(sparseStream.Length); public override VirtualDiskClass DiskClass => VirtualDiskClass.HardDisk; @@ -50,17 +47,19 @@ public override VirtualDiskTypeInfo DiskTypeInfo { CanBeHardDisk = true, DeterministicGeometry = true, PreservesBiosGeometry = false, - CalcGeometry = c => Geometry.FromCapacity(c) + CalcGeometry = c => DiscUtils.Geometry.FromCapacity(c) }; } - } - + } + + public override bool CanWrite => throw new NotImplementedException(); + public override VirtualDisk CreateDifferencingDisk(DiscFileSystem fileSystem, string path) { throw new NotImplementedException(); } - public override VirtualDisk CreateDifferencingDisk(string path) { + public override VirtualDisk CreateDifferencingDisk(string path, bool useAsync) { throw new NotImplementedException(); } } diff --git a/DiscUtils.Ebs/DiskImageFile.cs b/DiscUtils.Ebs/DiskImageFile.cs index 2721292..847da4c 100644 --- a/DiscUtils.Ebs/DiskImageFile.cs +++ b/DiscUtils.Ebs/DiskImageFile.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Net; -using Amazon; +using Amazon; using Amazon.EBS; using Amazon.EBS.Model; using Amazon.Runtime; -using DiscUtils.Internal; using DiscUtils.Streams; +using System; +using System.Collections.Generic; +using System.Net; namespace DiscUtils.Ebs { @@ -52,10 +51,6 @@ public DiskImageFile(string snapshotId, AWSCredentials credentials, RegionEndpoi public override FileLocator RelativeFileLocator => throw new NotImplementedException(); - public override string[] GetParentLocations() { - throw new NotImplementedException(); - } - public override SparseStream OpenContent(SparseStream parent, Ownership ownsParent) { SparseStream theParent = parent; @@ -77,6 +72,7 @@ public override IList Extents { get { return result; } } - + + public override bool CanWrite => throw new NotImplementedException(); } } diff --git a/DiscUtils.Ebs/DiskLayer.cs b/DiscUtils.Ebs/DiskLayer.cs index 46f13fb..4874217 100644 --- a/DiscUtils.Ebs/DiskLayer.cs +++ b/DiscUtils.Ebs/DiskLayer.cs @@ -1,9 +1,5 @@ using DiscUtils.Streams; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace DiscUtils.Ebs { public class DiskLayer : VirtualDiskLayer { @@ -20,13 +16,12 @@ public class DiskLayer : VirtualDiskLayer { public override FileLocator RelativeFileLocator => throw new NotImplementedException(); + public override bool CanWrite => throw new NotImplementedException(); + public DiskLayer(SparseStream sparseStream) { this.sparseStream = sparseStream; } - public override string[] GetParentLocations() { - throw new NotImplementedException(); - } public override SparseStream OpenContent(SparseStream parent, Ownership ownsParent) { throw new NotImplementedException(); diff --git a/DiscUtils.Ebs/EbsMappedStream.cs b/DiscUtils.Ebs/EbsMappedStream.cs index 6303b37..ca8f39f 100644 --- a/DiscUtils.Ebs/EbsMappedStream.cs +++ b/DiscUtils.Ebs/EbsMappedStream.cs @@ -6,10 +6,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; -using System.Text; -using System.Threading.Tasks; namespace DiscUtils.Ebs { public class EbsMappedStream : SparseStream { @@ -104,7 +101,7 @@ void GetBlockData(Block block, byte[] buffer, int offset) { throw new IOException($"Failed to read EBS block {block.Index} with HTTP error {result.HttpStatusCode}"); } - StreamUtilities.ReadExact(result.BlockData, buffer, offset, BlockSize); + StreamUtilities.ReadExactly(result.BlockData, buffer, offset, BlockSize); } public override long Seek(long offset, SeekOrigin origin) { @@ -135,5 +132,13 @@ public override void SetLength(long value) { public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } + + public override int Read(Span buffer) { + throw new NotImplementedException(); + } + + public override void Write(ReadOnlySpan buffer) { + throw new NotImplementedException(); + } } } diff --git a/DiscUtils.RawDisk/Disk.cs b/DiscUtils.RawDisk/Disk.cs index fd71683..a2a2b8d 100644 --- a/DiscUtils.RawDisk/Disk.cs +++ b/DiscUtils.RawDisk/Disk.cs @@ -1,13 +1,9 @@ -using DiscUtils; -using DiscUtils.Streams; +using DiscUtils.Streams; using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; namespace DiscUtils.RawDisk { public class Disk : VirtualDisk { @@ -103,7 +99,7 @@ public Disk(string path) { } - public override Geometry Geometry => geometry; + public override Geometry? Geometry => geometry; public override VirtualDiskClass DiskClass => VirtualDiskClass.HardDisk; @@ -120,20 +116,19 @@ public override VirtualDiskTypeInfo DiskTypeInfo { CanBeHardDisk = true, DeterministicGeometry = true, PreservesBiosGeometry = false, - CalcGeometry = c => Geometry.FromCapacity(c) + CalcGeometry = c => DiscUtils.Geometry.FromCapacity(c) }; } } + public override bool CanWrite => throw new NotImplementedException(); + public override VirtualDisk CreateDifferencingDisk(DiscFileSystem fileSystem, string path) { throw new NotImplementedException(); } - public override VirtualDisk CreateDifferencingDisk(string path) { + public override VirtualDisk CreateDifferencingDisk(string path, bool useAsync) { throw new NotImplementedException(); } - - - } } diff --git a/DiscUtils.RawDisk/RawDiskStream.cs b/DiscUtils.RawDisk/RawDiskStream.cs index 0c05062..f7859df 100644 --- a/DiscUtils.RawDisk/RawDiskStream.cs +++ b/DiscUtils.RawDisk/RawDiskStream.cs @@ -1,17 +1,9 @@ -using Amazon; -using Amazon.EBS; -using Amazon.EBS.Model; -using Amazon.Runtime; -using DiscUtils.Streams; +using DiscUtils.Streams; using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Net; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; namespace DiscUtils.RawDisk { public class RawDiskStream : SparseStream { @@ -91,5 +83,13 @@ public override void SetLength(long value) { public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } + + public override int Read(Span buffer) { + throw new NotImplementedException(); + } + + public override void Write(ReadOnlySpan buffer) { + throw new NotImplementedException(); + } } } diff --git a/Program.cs b/Program.cs index ade30f1..c74c342 100644 --- a/Program.cs +++ b/Program.cs @@ -125,7 +125,7 @@ static void Main(string[] args) { if (command != null) { - Console.WriteLine($"[+] Opened disk image, Size: {disk.Capacity / 1024 / 1024 / 1024}GB"); + Console.WriteLine($"[+] Opened disk image, Size: {GetHumanSize(disk.Capacity)}"); if (command == "volumes") { @@ -135,7 +135,7 @@ static void Main(string[] args) { var fsType = FileSystemManager.DetectFileSystems(volumeStream); try { - Console.WriteLine($"\tVolume ID: {volume.Identity}, Size: {volume.Length / 1024 / 1024} MB, Type: {(fsType.Length > 0 ? fsType[0].Description : "Unknown")}"); + Console.WriteLine($"\tVolume ID: {volume.Identity}, Size: {GetHumanSize(volume.Length)}, Type: {(fsType.Count > 0 ? fsType[0].Description : "Unknown")}"); } catch (Exception) { } } @@ -165,46 +165,44 @@ static void Main(string[] args) { foreach (var file in fs.GetFiles(filePath)) { var fileInfo = fs.GetFileInfo(file); - Console.WriteLine($"{fileInfo.LastWriteTimeUtc} { $"{fileInfo.Length / 1024.0 / 1024.0: 0.00}MB",-16} {Path.GetFileName(file)}"); + Console.WriteLine($"{fileInfo.LastWriteTimeUtc} { $"{GetHumanSize(fileInfo.Length)}",-16} {Path.GetFileName(file)}"); } } else { var fileStream = fs.OpenFile(filePath, FileMode.Open, FileAccess.Read); - Console.WriteLine($"[+] Opened file with path {filePath} for with size: {fileStream.Length / 1024.0 / 1024.0: 0.00}MB"); - File.WriteAllBytes(Path.GetFileName(filePath), StreamUtilities.ReadExact(fileStream, (int)fileStream.Length)); + Console.WriteLine($"[+] Opened file with path {filePath} for with size: {GetHumanSize(fileStream.Length)}"); + File.WriteAllBytes(Path.GetFileName(filePath), StreamUtilities.ReadExactly(fileStream, (int)fileStream.Length)); } } else if (command == "file_list") { foreach (var volume in VolumeManager.GetLogicalVolumes()) { using (var sparseStream = volume.Open()) { var fsInfo = FileSystemManager.DetectFileSystems(sparseStream); - if (fsInfo != null && fsInfo.Length > 0) { + if (fsInfo != null && fsInfo.Count > 0) { DiscFileSystem fileSystem = fsInfo[0].Open(sparseStream); if (fileSystem is NtfsFileSystem) { ((NtfsFileSystem)fileSystem).NtfsOptions.HideHiddenFiles = false; ((NtfsFileSystem)fileSystem).NtfsOptions.HideSystemFiles = false; } - List files = new List(); - List newDirs = new List(); - List files_dirs = new List(); + + List entries = new List(); List dirs = new List(); dirs.Add(""); - while(dirs.Count > 0) { - files = fileSystem.GetFiles(dirs.First()).ToList(); - newDirs = fileSystem.GetDirectories(dirs.First()).ToList(); - dirs.RemoveAt(0); - dirs.InsertRange(0, newDirs); - files_dirs.AddRange(newDirs.Select(x => x + "\\").ToList()); - files_dirs.AddRange(files); - files_dirs.Sort(); - - foreach (string f in files_dirs) { - Console.WriteLine($"{volume.Identity}:{f}"); + while (dirs.Count > 0) { + if (dirs.First() == "" || (fileSystem.Exists(dirs.First()) && (fileSystem.GetAttributes(dirs.First()) & FileAttributes.Directory) == FileAttributes.Directory)) { + entries = fileSystem.GetFileSystemEntries(dirs.First()).ToList(); + dirs.RemoveAt(0); + dirs.InsertRange(0, entries); + + foreach (string f in entries) { + Console.WriteLine($"{volume.Identity}:{f}"); + } + } else { + dirs.RemoveAt(0); } - files_dirs.Clear(); } } } @@ -230,22 +228,22 @@ static void Main(string[] args) { } private static void UI_ItemChanged(string itemValue) { - string itemLabel; if (itemValue != ".." && CurrentPath != null && CurrentFileSystem != null) { + itemLabel = $" | Path: {CurrentPath}\\{itemValue}"; + bool isNotDirectory = (CurrentFileSystem.GetAttributes($"{CurrentPath}\\{itemValue}") & FileAttributes.Directory) != FileAttributes.Directory; + bool isNotReparsePoint = (CurrentFileSystem.GetAttributes($"{CurrentPath}\\{itemValue}") & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint; - itemLabel = $"Path: {CurrentPath}\\{itemValue}"; - - if ((CurrentFileSystem.GetAttributes($"{CurrentPath}\\{itemValue}") & FileAttributes.Directory) != FileAttributes.Directory) { + if (CurrentFileSystem.Exists($"{CurrentPath}\\{itemValue}") && isNotDirectory && isNotReparsePoint) { var fileLen = CurrentFileSystem.GetFileLength($"{CurrentPath}\\{itemValue}"); - itemLabel += $" {GetHumanSize(fileLen)}"; + itemLabel += $" | Size: {GetHumanSize(fileLen)}"; if(fileLen < 10240 && fileLen > 0 && (itemValue.EndsWith(".txt") || itemValue.EndsWith(".log") || itemValue.EndsWith(".config") || itemValue.EndsWith(".ini") || itemValue.EndsWith(".xml"))) { using (var fileStream = CurrentFileSystem.OpenFile($"{CurrentPath}\\{itemValue}", FileMode.Open, FileAccess.Read)) { - var fileData = StreamUtilities.ReadExact(fileStream, (int)fileLen); + var fileData = StreamUtilities.ReadExactly(fileStream, (int)fileLen); var encoding = Encoding.UTF8; if((fileData[0] == 0xff && fileData[1] == 0xfe) || fileData[1] == 0) { @@ -262,16 +260,19 @@ private static void UI_ItemChanged(string itemValue) { } else { UI.PreviewText = ""; } + } else { + UI.PreviewText = ""; } } else { if (CurrentFileSystem == null) { var volume = VolumeManager.GetVolume(itemValue); + itemLabel = $" | Path: {volume.Identity}"; using (var sparseStream = volume.Open()) { var fsInfo = FileSystemManager.DetectFileSystems(sparseStream); - if (fsInfo != null && fsInfo.Length > 0) { + if (fsInfo != null && fsInfo.Count > 0) { var fileSystem = fsInfo[0].Open(sparseStream); CurrentPath = ""; UI.VolumeLabel = $"Volume: {fileSystem.FriendlyName} {GetHumanSize(fileSystem.Size)}"; @@ -279,9 +280,13 @@ private static void UI_ItemChanged(string itemValue) { UI.VolumeLabel = $"Volume: Unknown {GetHumanSize(volume.Length)}"; } } + } else { + if(CurrentPath == "") { + itemLabel = ""; + } else { + itemLabel = $" | Path: {CurrentPath}"; + } } - - itemLabel = $"Path: {CurrentPath}"; } UI.ItemLabel = itemLabel.Replace("\\",PathSeparator); @@ -313,7 +318,7 @@ private static void Ui_ItemSelected(string itemValue) { using (var sparseStream = volume.Open()) { var fsInfo = FileSystemManager.DetectFileSystems(sparseStream); - if (fsInfo != null && fsInfo.Length > 0) { + if (fsInfo != null && fsInfo.Count > 0) { CurrentFileSystem = fsInfo[0].Open(sparseStream); CurrentPath = ""; UI.VolumeLabel = $"Volume: {CurrentFileSystem.FriendlyName} {GetHumanSize(CurrentFileSystem.Size)}"; @@ -332,7 +337,8 @@ private static void Ui_ItemSelected(string itemValue) { UI.UpdateCurrentPathItems(Volumes.ToList()); CurrentFileSystem = null; CurrentPath = null; - UI.VolumeLabel = ""; + var volumes = VolumeManager.GetLogicalVolumes(); + UI.ItemLabel = $" | Path: {volumes[0].Identity}"; } else { if (itemValue != "..") { @@ -368,6 +374,7 @@ private static void Ui_ItemSelected(string itemValue) { } } else { + UI.ItemLabel = ""; CurrentPath = CurrentPath.Substring(0, CurrentPath.LastIndexOf('\\')); UpdateView(); } @@ -377,7 +384,7 @@ private static void Ui_ItemSelected(string itemValue) { static string GetHumanSize(long size) { if (size < 1024) { - return $"{size}"; + return $"{size}B"; } else if (size < 1024L * 1024L) { return $"{size / 1024.0:0.00}KB"; } else if (size < 1024L * 1024L * 1024L) { @@ -391,8 +398,7 @@ static string GetHumanSize(long size) { private static void UpdateView() { UI.UpdateCurrentPathItems(new string[] { ".." } - .Concat(CurrentFileSystem.GetDirectories(CurrentPath).Select(pi => Path.GetFileName(pi)) - .Concat(CurrentFileSystem.GetFiles(CurrentPath)).Select(pi => Path.GetFileName(pi))) + .Concat(CurrentFileSystem.GetFileSystemEntries(CurrentPath).Select(pi => Path.GetFileName(pi))) .ToList()); } } diff --git a/README.md b/README.md index bf4dbd4..7a4a968 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,17 @@ The tool was written to combat a regular problem where massive 100G+ disk images ![Volumiser Interactive GUI](Volumiser.gif) -Volumiser would not be possible without the brilliant [DiscUtils](https://github.com/DiscUtils/DiscUtils) project that does most of the heavy lifting parsing volumes and file systems within the virtual disks. Whilst the EBS volume support is a feature added as part of volumiser, this also leverages this excellent library to add this particular disk image format. +Volumiser would not be possible without the brilliant [DiscUtils](https://github.com/DiscUtils/DiscUtils) project and the fork from [LTRData](https://github.com/LTRData/DiscUtils/) that do most of the heavy lifting parsing volumes and file systems within the virtual disks. Whilst the EBS volume support is a feature added as part of volumiser, this also leverages this excellent library to add this particular disk image format. Volumiser supports the following disk image formats: * Amazon EBS Snapshots * Direct Raw Disk (a la NinjaCopy) -* VHDX * VMDK * VHD * VHDX +* VDI +* IMG along with the following file systems: @@ -81,7 +82,7 @@ Volumiser.exe --image "c:\Virtual Machines\Domain Controller.vhdx" --command vol Volume ID: VLG{bdd5d39c-a214-4ac2-a6b9-2477fe02ffc1}, Size: 553 MB, Type: Microsoft NTFS ``` -**Listing File System** +**Listing File System folder** Once the volumes have been discovered, the file system for each volume can be listed @@ -102,11 +103,21 @@ Volumiser.exe --image "c:\Virtual Machines\Domain Controller.vhdx" --command ls **"Downloading" Files** -Files can be "downloaded" to your local machine using the download command +Files can be "downloaded" to your local machine using the extract command ``` -Volumiser.exe --image "c:\Virtual Machines\Domain Controller.vhdx" --command download --path "VLG{166c0197-909e-419d-a431-2d9b9df4d1fe}:\Windows\system32\config\SYSTEM" +Volumiser.exe --image "c:\Virtual Machines\Domain Controller.vhdx" --command extract --path "VLG{166c0197-909e-419d-a431-2d9b9df4d1fe}:\Windows\system32\config\SYSTEM" [+] Opened disk image, Size: 127GB [+] Opened volume with ID VLG{166c0197-909e-419d-a431-2d9b9df4d1fe} [+] Opened file with path \Windows\System32\config\SYSTEM for with size: 12058624 ``` + +**Listing File System file list** + +The file list of all volumes of the file system can be listed + +``` +Volumiser.exe --image "c:\Virtual Machines\Domain Controller.vhdx" --command file_list +[+] Opened disk image, Size: 127GB +... +``` \ No newline at end of file diff --git a/UI.cs b/UI.cs index 4e2d657..d989a8a 100644 --- a/UI.cs +++ b/UI.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections; using Terminal.Gui; namespace Volumiser { @@ -125,8 +121,6 @@ public UI() { Application.Top.Add(topLevel); Application.Top.KeyPress += Top_KeyPress; - - } private void Top_KeyPress(View.KeyEventEventArgs obj) { @@ -139,7 +133,12 @@ private void List_SelectedItemChanged(ListViewItemEventArgs obj) { } public void Run() { - Application.Run(); + try{ + Application.Run(); + } + finally { + Application.Shutdown(); + } } public void UpdateCurrentPathItems(IList items) { diff --git a/Volumiser.csproj b/Volumiser.csproj index fcd4fa6..b441fdd 100644 --- a/Volumiser.csproj +++ b/Volumiser.csproj @@ -8,14 +8,13 @@ - - - all runtime; build; native; contentfiles; analyzers; buildtransitive - + + +