├── Installer.Tests ├── test.xml ├── PhoneSpecs.cs ├── WimImageMetadataReaderSpecs.cs ├── Properties │ └── AssemblyInfo.cs ├── DismImageServiceSpecs.cs ├── WindowsDeployerTests.cs ├── packages.config ├── LowLevelApiSpecs.cs └── Installer.Tests.csproj ├── .gitmodules ├── Installer.Wpf ├── Assets │ ├── 950.png │ ├── dual.png │ ├── full.png │ ├── 950xl.png │ ├── gears.png │ ├── appicon.ico │ ├── appicon.png │ ├── refresh.png │ ├── disabledual.png │ ├── inject-drivers.png │ └── windows-only.png ├── Views │ ├── TextViewerWindow.xaml.cs │ ├── Parts │ │ ├── Sections │ │ │ ├── InstallPart.xaml.cs │ │ │ ├── AdvancedPart.xaml.cs │ │ │ ├── PhoneModelPart.xaml.cs │ │ │ ├── WimOptionsPart.xaml.cs │ │ │ ├── AdvancedPart.xaml │ │ │ ├── PhoneModelPart.xaml │ │ │ ├── WimOptionsPart.xaml │ │ │ └── InstallPart.xaml │ │ ├── LogPart.xaml.cs │ │ ├── StatusPart.xaml.cs │ │ ├── DualBootPart.xaml.cs │ │ ├── StatusPart.xaml │ │ ├── LogPart.xaml │ │ └── DualBootPart.xaml │ ├── MainWindow.xaml.cs │ ├── TextViewerWindow.xaml │ └── MainWindow.xaml ├── ViewModels │ ├── RenderedLogEvent.cs │ ├── MessageViewModel.cs │ ├── DeployerItem.cs │ ├── DriverPackageImporterItem.cs │ ├── WimMetadataViewModel.cs │ ├── PhoneModel.cs │ └── DualBootViewModel.cs ├── App.xaml.cs ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Services │ ├── ViewServices.cs │ └── FilePickMixin.cs ├── App.config ├── CommandWrapper.cs ├── BusyButton.cs ├── Themes │ └── Generic.xaml ├── App.xaml ├── CompositionRoot.cs └── app.manifest ├── Installer.Core ├── ICoreDeployer.cs ├── Services │ ├── Wim │ │ ├── IWindowsImageMetadataReader.cs │ │ ├── XmlWindowsImageMetadata.cs │ │ ├── XmlWindowsImageMetadataReader.cs │ │ ├── DiskImageMetadata.cs │ │ ├── Languages.cs │ │ ├── Time.cs │ │ ├── WimMetadata.cs │ │ ├── ServicingData.cs │ │ ├── Version.cs │ │ ├── Windows.cs │ │ ├── ImageMetadata.cs │ │ ├── WindowsImageMetadataReaderBase.cs │ │ └── WindowsImageMetadataReader.cs │ ├── IDriverPackageImporter.cs │ ├── IWindowsDeployer.cs │ ├── IWindowsImageService.cs │ ├── WindowsVolumes.cs │ ├── DriverPaths.cs │ ├── BcdInvoker.cs │ ├── BcdConfigurator.cs │ ├── BrandNewPackageImporter.cs │ ├── DriverPackageImporter.cs │ └── WindowsDeployer.cs ├── Exceptions │ ├── PathNotFoundException.cs │ ├── DeploymentException.cs │ ├── NotEnoughSpaceException.cs │ ├── InvalidDriverPackageException.cs │ ├── PhoneDiskNotFoundException.cs │ ├── InvalidWimFileException.cs │ └── InvalidDeploymentRepositoryException.cs ├── FileSystem │ ├── FileSystemMixin.cs │ ├── FileSystemFormat.cs │ ├── ILowLevelApi.cs │ ├── Partition.cs │ ├── Disk.cs │ ├── Volume.cs │ └── PartitionType.cs ├── DualBootStatus.cs ├── IDeployer.cs ├── InstallOptions.cs ├── Utils │ ├── FormattingUtils.cs │ ├── FileUtils.cs │ ├── ReactiveMixin.cs │ └── ProcessUtils.cs ├── Installer.Core.csproj ├── CoreDeployer.cs ├── Deployer.cs ├── Resources.Designer.cs ├── Resources.resx └── Phone.cs ├── Installer.Core.FullFx ├── InvalidImageException.cs ├── PowerShellUtils.cs ├── Properties │ └── AssemblyInfo.cs ├── Installer.Core.FullFx.csproj └── DismImageService.cs ├── README.md ├── .gitattributes ├── WoA Installer.sln └── .gitignore /Installer.Tests/test.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Tests/test.xml -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Registry"] 2 | path = Registry 3 | url = https://github.com/EricZimmerman/Registry.git 4 | -------------------------------------------------------------------------------- /Installer.Wpf/Assets/950.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/950.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/dual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/dual.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/full.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/950xl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/950xl.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/gears.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/gears.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/appicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/appicon.ico -------------------------------------------------------------------------------- /Installer.Wpf/Assets/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/appicon.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/refresh.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/disabledual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/disabledual.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/inject-drivers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/inject-drivers.png -------------------------------------------------------------------------------- /Installer.Wpf/Assets/windows-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imperador/Lumia-WoA-Installer/HEAD/Installer.Wpf/Assets/windows-only.png -------------------------------------------------------------------------------- /Installer.Core/ICoreDeployer.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Installer.Core 4 | { 5 | public interface ICoreDeployer 6 | { 7 | Task AreDeploymentFilesValid(); 8 | Task Deploy(Phone phone); 9 | } 10 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/IWindowsImageMetadataReader.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | public interface IWindowsImageMetadataReader 6 | { 7 | XmlWindowsImageMetadata Load(Stream stream); 8 | } 9 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/XmlWindowsImageMetadata.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | public class XmlWindowsImageMetadata 6 | { 7 | public IList Images { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/TextViewerWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Intaller.Wpf.Views 2 | { 3 | 4 | public partial class TextViewerWindow 5 | { 6 | public TextViewerWindow() 7 | { 8 | InitializeComponent(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/RenderedLogEvent.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | 3 | namespace Intaller.Wpf.ViewModels 4 | { 5 | public class RenderedLogEvent 6 | { 7 | public string Message { get; set; } 8 | public LogEventLevel Level { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/PathNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | internal class PathNotFoundException : Exception 6 | { 7 | public PathNotFoundException(string msg) : base(msg) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Core.FullFx/InvalidImageException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.FullFx 4 | { 5 | internal class InvalidImageException : Exception 6 | { 7 | public InvalidImageException(string msg) : base(msg) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/DeploymentException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | public class DeploymentException : Exception 6 | { 7 | public DeploymentException(string msg) : base(msg) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/NotEnoughSpaceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | public class NotEnoughSpaceException : Exception 6 | { 7 | public NotEnoughSpaceException(string msg) : base(msg) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/InvalidDriverPackageException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | internal class InvalidDriverPackageException : Exception 6 | { 7 | public InvalidDriverPackageException(string msg) : base(msg) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/PhoneDiskNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | public class PhoneDiskNotFoundException : Exception 6 | { 7 | public PhoneDiskNotFoundException(string message) : base(message) 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/XmlWindowsImageMetadataReader.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | public class XmlWindowsImageMetadataReader : WindowsImageMetadataReaderBase 6 | { 7 | protected override Stream GetXmlMetadataStream(Stream wim) 8 | { 9 | return wim; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Core/FileSystem/FileSystemMixin.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Installer.Core.FileSystem 4 | { 5 | public static class FileSystemMixin 6 | { 7 | public static string GetBcdFullFilename(this Volume self) 8 | { 9 | return Path.Combine(self.RootDir.Name, "EFI", "Microsoft", "Boot", "BCD"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/InstallPart.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Intaller.Wpf.Views.Parts.Sections 2 | { 3 | /// 4 | /// Interaction logic for InstallPart.xaml 5 | /// 6 | public partial class InstallPart 7 | { 8 | public InstallPart() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/MessageViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Intaller.Wpf.ViewModels 2 | { 3 | public class MessageViewModel 4 | { 5 | public string Title { get; } 6 | public string Text { get; } 7 | 8 | public MessageViewModel(string title, string text) 9 | { 10 | Title = title; 11 | Text = text; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Installer.Core/Services/IDriverPackageImporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Installer.Core.Services 5 | { 6 | public interface IDriverPackageImporter 7 | { 8 | Task ImportDriverPackage(string packagePath, string destination, IObserver progressObserver = null); 9 | Task GetReadmeText(string fileName); 10 | } 11 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/LogPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts 4 | { 5 | /// 6 | /// Interaction logic for LogPart.xaml 7 | /// 8 | public partial class LogPart : UserControl 9 | { 10 | public LogPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Core/DualBootStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Installer.Core 2 | { 3 | public class DualBootStatus 4 | { 5 | public DualBootStatus(bool canDualBoot, bool isEnabled) 6 | { 7 | IsEnabled = isEnabled; 8 | CanDualBoot = canDualBoot; 9 | } 10 | 11 | public bool IsEnabled { get; } 12 | public bool CanDualBoot { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/DiskImageMetadata.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | public class DiskImageMetadata 6 | { 7 | public int Index { get; set; } 8 | public string DisplayName { get; set; } 9 | public Architecture Architecture { get; set; } 10 | public string Build { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/Languages.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "LANGUAGES")] 6 | public class Languages 7 | { 8 | [XmlElement(ElementName = "LANGUAGE")] public string Language { get; set; } 9 | 10 | [XmlElement(ElementName = "DEFAULT")] public string Default { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/StatusPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts 4 | { 5 | /// 6 | /// Interaction logic for StatusPart.xaml 7 | /// 8 | public partial class StatusPart : UserControl 9 | { 10 | public StatusPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Core/Services/IWindowsDeployer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Installer.Core.Services 5 | { 6 | public interface IWindowsDeployer 7 | { 8 | Task Deploy(InstallOptions options, Phone phone, IObserver progressObserver = null); 9 | Task InjectPostOobeDrivers(Phone phone); 10 | Task AreDeploymentFilesValid(); 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/DualBootPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts 4 | { 5 | /// 6 | /// Interaction logic for DualBootPart.xaml 7 | /// 8 | public partial class DualBootPart : UserControl 9 | { 10 | public DualBootPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/Time.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "CREATIONTIME")] 6 | public class Time 7 | { 8 | [XmlElement(ElementName = "HIGHPART")] public string HighPart { get; set; } 9 | 10 | [XmlElement(ElementName = "LOWPART")] public string LowPart { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/AdvancedPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts.Sections 4 | { 5 | /// 6 | /// Interaction logic for AdvancedPart.xaml 7 | /// 8 | public partial class AdvancedPart : UserControl 9 | { 10 | public AdvancedPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/DeployerItem.cs: -------------------------------------------------------------------------------- 1 | using Installer.Core; 2 | 3 | namespace Intaller.Wpf.ViewModels 4 | { 5 | public class DeployerItem 6 | { 7 | public PhoneModel Model { get; } 8 | public IDeployer Deployer { get; } 9 | 10 | public DeployerItem(PhoneModel model, IDeployer deployer) 11 | { 12 | Model = model; 13 | Deployer = deployer; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/PhoneModelPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts.Sections 4 | { 5 | /// 6 | /// Interaction logic for PhoneModelPart.xaml 7 | /// 8 | public partial class PhoneModelPart : UserControl 9 | { 10 | public PhoneModelPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/WimOptionsPart.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Intaller.Wpf.Views.Parts.Sections 4 | { 5 | /// 6 | /// Interaction logic for WimOptionsPart.xaml 7 | /// 8 | public partial class WimOptionsPart : UserControl 9 | { 10 | public WimOptionsPart() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Installer.Core/Services/IWindowsImageService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Installer.Core.FileSystem; 4 | 5 | namespace Installer.Core.Services 6 | { 7 | public interface IWindowsImageService 8 | { 9 | Task ApplyImage(Volume windowsVolume, string imagePath, int imageIndex = 1, IObserver progressObserver = null); 10 | Task InjectDrivers(string path, Volume windowsPartition); 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Core/Services/WindowsVolumes.cs: -------------------------------------------------------------------------------- 1 | using Installer.Core.FileSystem; 2 | 3 | namespace Installer.Core.Services 4 | { 5 | public class WindowsVolumes 6 | { 7 | public WindowsVolumes(Volume bootVolume, Volume windowsVolume) 8 | { 9 | Boot = bootVolume; 10 | Windows = windowsVolume; 11 | } 12 | 13 | public Volume Boot { get; } 14 | public Volume Windows { get; } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Core/IDeployer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Installer.Core 5 | { 6 | public interface IDeployer 7 | { 8 | Task DeployCoreAndWindows(InstallOptions options, Phone phone, IObserver progressObserver = null); 9 | Task DeployWindows(InstallOptions options, Phone phone, IObserver progressObserver = null); 10 | Task InjectPostOobeDrivers(Phone phone); 11 | } 12 | } -------------------------------------------------------------------------------- /Installer.Tests/PhoneSpecs.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Installer.Core; 3 | using Installer.Core.FullFx; 4 | using Xunit; 5 | 6 | namespace Application.Tests 7 | { 8 | public class PhoneSpecs 9 | { 10 | [Fact] 11 | public async Task GetDualBootStatus() 12 | { 13 | var sut = await Phone.Load(new LowLevelApi()); 14 | var status = await sut.GetDualBootStatus(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Installer.Core/InstallOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core 4 | { 5 | public class InstallOptions 6 | { 7 | public InstallOptions() 8 | { 9 | } 10 | 11 | public InstallOptions(string imagePath) 12 | { 13 | ImagePath = imagePath; 14 | } 15 | 16 | public string ImagePath { get; set; } 17 | public int ImageIndex { get; set; } = 1; 18 | } 19 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/WimMetadata.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Xml.Serialization; 3 | 4 | namespace Installer.Core.Services.Wim 5 | { 6 | [XmlRoot(ElementName = "WIM")] 7 | public class WimMetadata 8 | { 9 | [XmlElement(ElementName = "TOTALBYTES")] 10 | public string TotalBytes { get; set; } 11 | 12 | [XmlElement(ElementName = "IMAGE")] public List Images { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/ServicingData.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "SERVICINGDATA")] 6 | public class ServicingData 7 | { 8 | [XmlElement(ElementName = "GDRDUREVISION")] 9 | public string GdrDuRevision { get; set; } 10 | 11 | [XmlElement(ElementName = "PKEYCONFIGVERSION")] 12 | public string PKeyConfigVersion { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/InvalidWimFileException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Installer.Core.Exceptions 5 | { 6 | public class InvalidWimFileException : Exception 7 | { 8 | public InvalidWimFileException(string msg) : base(msg) 9 | { 10 | } 11 | 12 | public InvalidWimFileException(string msg, Exception innerException) : base(msg, innerException) 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Core/Exceptions/InvalidDeploymentRepositoryException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Installer.Core.Exceptions 4 | { 5 | internal class InvalidDeploymentRepositoryException : Exception 6 | { 7 | public InvalidDeploymentRepositoryException(string str) : base(str) 8 | { 9 | } 10 | 11 | public InvalidDeploymentRepositoryException(string str, Exception inner) : base(str, inner) 12 | { 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Installer.Core/Services/DriverPaths.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Installer.Core.Services 4 | { 5 | public class DriverPaths 6 | { 7 | private readonly string rootPath; 8 | 9 | public DriverPaths(string rootPath) 10 | { 11 | this.rootPath = rootPath; 12 | } 13 | 14 | public string PreOobe => Path.Combine(rootPath, "Drivers", "Pre-OOBE"); 15 | public string PostOobe => Path.Combine(rootPath, "Drivers", "Post-OOBE"); 16 | } 17 | } -------------------------------------------------------------------------------- /Installer.Wpf/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Intaller.Wpf 4 | { 5 | /// 6 | /// Lógica de interacción para App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | protected override void OnStartup(StartupEventArgs e) 11 | { 12 | base.OnStartup(e); 13 | 14 | ConfigureLogger(); 15 | } 16 | 17 | private void ConfigureLogger() 18 | { 19 | 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/DriverPackageImporterItem.cs: -------------------------------------------------------------------------------- 1 | using Installer.Core.Services; 2 | 3 | namespace Intaller.Wpf.ViewModels 4 | { 5 | public class DriverPackageImporterItem 6 | { 7 | public DriverPackageImporterItem(string extension, IDriverPackageImporter importer) 8 | { 9 | Extension = extension; 10 | DriverPackageImporter = importer; 11 | } 12 | 13 | public string Extension { get; } 14 | public IDriverPackageImporter DriverPackageImporter { get; } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Core/FileSystem/FileSystemFormat.cs: -------------------------------------------------------------------------------- 1 | namespace Installer.Core.FileSystem 2 | { 3 | public class FileSystemFormat 4 | { 5 | public string Moniker { get; } 6 | 7 | public static FileSystemFormat Ntfs = new FileSystemFormat("NTFS"); 8 | public static FileSystemFormat Fat16 = new FileSystemFormat("FAT"); 9 | public static FileSystemFormat Fat32 = new FileSystemFormat("FAT32"); 10 | 11 | private FileSystemFormat(string moniker) 12 | { 13 | Moniker = moniker; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Core/Utils/FormattingUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace Installer.Core.Utils 6 | { 7 | internal static class FormattingUtils 8 | { 9 | public static Guid GetGuid(string str) 10 | { 11 | var guids = Regex.Matches(str, @"(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}"); 12 | var match = guids.Cast().First(x => x.Success).Value; 13 | return Guid.Parse(match); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Installer.Wpf/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Installer.Tests/WimImageMetadataReaderSpecs.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Installer.Core.FullFx; 5 | using Installer.Core.Services.Wim; 6 | using Xunit; 7 | 8 | namespace Application.Tests 9 | { 10 | public class WimImageMetadataReaderSpecs 11 | { 12 | [Fact] 13 | public void TestXml() 14 | { 15 | var sut = new XmlWindowsImageMetadataReader(); 16 | using (var s = File.OpenRead("test.xml")) 17 | { 18 | var metadata = sut.Load(s); 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Installer.Core/Services/BcdInvoker.cs: -------------------------------------------------------------------------------- 1 | using Installer.Core.Utils; 2 | using Serilog; 3 | 4 | namespace Installer.Core.Services 5 | { 6 | public class BcdInvoker 7 | { 8 | private readonly string commonArgs; 9 | private readonly string bcdEdit; 10 | 11 | public BcdInvoker(string store) 12 | { 13 | bcdEdit = @"c:\Windows\SysNative\bcdedit.exe"; 14 | commonArgs = $@"/STORE ""{store}"""; 15 | } 16 | 17 | public string Invoke(string command) 18 | { 19 | return ProcessUtils.Run(bcdEdit, $@"{commonArgs} {command}"); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/Version.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "VERSION")] 6 | public class Version 7 | { 8 | [XmlElement(ElementName = "MAJOR")] public string Major { get; set; } 9 | 10 | [XmlElement(ElementName = "MINOR")] public string Minor { get; set; } 11 | 12 | [XmlElement(ElementName = "BUILD")] public string Build { get; set; } 13 | 14 | [XmlElement(ElementName = "SPBUILD")] public string SpBuild { get; set; } 15 | 16 | [XmlElement(ElementName = "SPLEVEL")] public string SpLevel { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Installer.Core.FullFx/PowerShellUtils.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.PowerShell.Cim; 2 | 3 | namespace Installer.Core.FullFx 4 | { 5 | public static class PowerShellUtils 6 | { 7 | private static readonly CimInstanceAdapter Adapter = new CimInstanceAdapter(); 8 | 9 | public static object GetPropertyValue(this object obj, string propertyName) 10 | { 11 | var psAdaptedProperty = Adapter.GetProperty(obj, propertyName); 12 | if (psAdaptedProperty == null) 13 | { 14 | return null; 15 | } 16 | 17 | return Adapter.GetPropertyValue(psAdaptedProperty); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Serilog; 3 | using Serilog.Events; 4 | 5 | namespace Intaller.Wpf.Views 6 | { 7 | public partial class MainWindow 8 | { 9 | public MainWindow() 10 | { 11 | InitializeComponent(); 12 | 13 | IObservable logEvents = null; 14 | 15 | Log.Logger = new LoggerConfiguration() 16 | .MinimumLevel.Verbose() 17 | .WriteTo.Observers(x => logEvents = x, LogEventLevel.Information) 18 | .WriteTo.RollingFile(@"Logs\{Date}.txt") 19 | .CreateLogger(); 20 | 21 | DataContext = CompositionRoot.GetMainViewModel(logEvents); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Installer.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Application.Tests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Application.Tests")] 10 | [assembly: AssemblyCopyright("Copyright © 2018")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("3c13bab1-a222-4ae5-be4b-f64fad6f9606")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /Installer.Tests/DismImageServiceSpecs.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using Installer.Core.FullFx; 4 | using Xunit; 5 | 6 | namespace Application.Tests 7 | { 8 | public class DismImageServiceSpecs 9 | { 10 | [Fact] 11 | public async Task InjectDrivers() 12 | { 13 | var sut = new DismImageService(); 14 | var lowlevel = new LowLevelApi(); 15 | var volumes = await lowlevel.GetVolumes(await lowlevel.GetPhoneDisk()); 16 | var winVolume = volumes.Single(v => v.Label == "WindowsARM"); 17 | 18 | await sut.InjectDrivers(@"C:\Users\super\source\repos\Install\Application\bin\Debug\bin\Debug\Files\Drivers\Stable", winVolume); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Installer.Wpf/Services/ViewServices.cs: -------------------------------------------------------------------------------- 1 | using Cinch.Reloaded.Services.Interfaces; 2 | using MahApps.Metro.Controls.Dialogs; 3 | 4 | namespace Intaller.Wpf.Services 5 | { 6 | public class ViewServices 7 | { 8 | public ViewServices(IOpenFileService openFileService, IDialogCoordinator dialogCoordinator, IExtendedUIVisualizerService visualizerService) 9 | { 10 | OpenFileService = openFileService; 11 | DialogCoordinator = dialogCoordinator; 12 | VisualizerService = visualizerService; 13 | } 14 | 15 | public IOpenFileService OpenFileService { get; } 16 | public IDialogCoordinator DialogCoordinator { get; } 17 | public IExtendedUIVisualizerService VisualizerService { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/TextViewerWindow.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Installer.Tests/WindowsDeployerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using Installer.Core; 4 | using Installer.Core.FullFx; 5 | using Installer.Core.Services; 6 | using Xunit; 7 | 8 | namespace Application.Tests 9 | { 10 | public class WindowsDeployerTests 11 | { 12 | [Fact] 13 | public async Task MakeBootable() 14 | { 15 | var lowLevelApi = new LowLevelApi(); 16 | var sut = new WindowsDeployer(new DismImageService(), new DriverPaths("")); 17 | 18 | var lowlevel = lowLevelApi; 19 | var volumes = await lowlevel.GetVolumes(await lowlevel.GetPhoneDisk()); 20 | var winVolume = volumes.Single(v => v.Label == "WindowsARM"); 21 | var bootVolume = volumes.Single(v => v.Label == "BOOT"); 22 | 23 | //await sut.MakeBootable(new WindowsVolumes()); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Installer.Core/FileSystem/ILowLevelApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using ByteSizeLib; 4 | 5 | namespace Installer.Core.FileSystem 6 | { 7 | public interface ILowLevelApi 8 | { 9 | Task GetPhoneDisk(); 10 | Task ResizePartition(Partition partition, ByteSize sizeInBytes); 11 | Task> GetPartitions(Disk disk); 12 | Task GetVolume(Partition partition); 13 | Task CreateReservedPartition(Disk disk, ulong sizeInBytes); 14 | Task CreatePartition(Disk disk, ulong sizeInBytes); 15 | Task SetPartitionType(Partition partition, PartitionType partitionType); 16 | Task Format(Volume volume, FileSystemFormat ntfs, string fileSystemLabel); 17 | char GetFreeDriveLetter(); 18 | Task AssignDriveLetter(Volume volume, char letter); 19 | Task> GetVolumes(Disk disk); 20 | Task RemovePartition(Partition partition); 21 | } 22 | } -------------------------------------------------------------------------------- /Installer.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Installer.Core/Installer.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | Resources.resx 23 | 24 | 25 | 26 | 27 | 28 | ResXFileCodeGenerator 29 | Resources.Designer.cs 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Installer.Wpf/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/WimMetadataViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Installer.Core.Services.Wim; 5 | using ReactiveUI; 6 | 7 | namespace Intaller.Wpf.ViewModels 8 | { 9 | public class WimMetadataViewModel : ReactiveObject 10 | { 11 | private DiskImageMetadata selectedDiskImage; 12 | 13 | public WimMetadataViewModel(XmlWindowsImageMetadata windowsImageMetadata, string path) 14 | { 15 | WindowsImageMetadata = windowsImageMetadata; 16 | Path = path; 17 | SelectedImageObs = this.WhenAnyValue(x => x.SelectedDiskImage); 18 | SelectedDiskImage = Images.First(); 19 | } 20 | 21 | private XmlWindowsImageMetadata WindowsImageMetadata { get; } 22 | public string Path { get; } 23 | 24 | public IObservable SelectedImageObs { get; } 25 | 26 | public ICollection Images => WindowsImageMetadata.Images; 27 | 28 | public DiskImageMetadata SelectedDiskImage 29 | { 30 | get => selectedDiskImage; 31 | set => this.RaiseAndSetIfChanged(ref selectedDiskImage, value); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/Windows.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "WINDOWS")] 6 | public class Windows 7 | { 8 | [XmlElement(ElementName = "ARCH")] public string Arch { get; set; } 9 | 10 | [XmlElement(ElementName = "PRODUCTNAME")] 11 | public string ProductName { get; set; } 12 | 13 | [XmlElement(ElementName = "EDITIONID")] 14 | public string EditionId { get; set; } 15 | 16 | [XmlElement(ElementName = "INSTALLATIONTYPE")] 17 | public string InstallationType { get; set; } 18 | 19 | [XmlElement(ElementName = "SERVICINGDATA")] 20 | public ServicingData ServicingData { get; set; } 21 | 22 | [XmlElement(ElementName = "PRODUCTTYPE")] 23 | public string ProductType { get; set; } 24 | 25 | [XmlElement(ElementName = "PRODUCTSUITE")] 26 | public string ProductSuite { get; set; } 27 | 28 | [XmlElement(ElementName = "LANGUAGES")] 29 | public Languages Languages { get; set; } 30 | 31 | [XmlElement(ElementName = "VERSION")] public Version Version { get; set; } 32 | 33 | [XmlElement(ElementName = "SYSTEMROOT")] 34 | public string SystemRoot { get; set; } 35 | } 36 | } -------------------------------------------------------------------------------- /Installer.Wpf/CommandWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using MahApps.Metro.Controls.Dialogs; 4 | using ReactiveUI; 5 | using Serilog; 6 | 7 | namespace Intaller.Wpf 8 | { 9 | public class CommandWrapper : ReactiveObject 10 | { 11 | private readonly object parent; 12 | private readonly IDialogCoordinator dialogCoordinator; 13 | private readonly ObservableAsPropertyHelper isExecutingHelper; 14 | public ReactiveCommand Command { get; } 15 | 16 | public CommandWrapper(object parent, ReactiveCommand command, IDialogCoordinator dialogCoordinator) 17 | { 18 | this.parent = parent; 19 | this.dialogCoordinator = dialogCoordinator; 20 | Command = command; 21 | command.ThrownExceptions.Subscribe(async e => await HandleException(e)); 22 | isExecutingHelper = command.IsExecuting.ToProperty(this, x => x.IsExecuting); 23 | } 24 | 25 | private async Task HandleException(Exception e) 26 | { 27 | Log.Error(e, "An error has ocurred"); 28 | Log.Information($"Error: {e.Message}"); 29 | await dialogCoordinator.ShowMessageAsync(parent, "Error", $"{e.Message}"); 30 | } 31 | 32 | public bool IsExecuting => isExecutingHelper.Value; 33 | } 34 | } -------------------------------------------------------------------------------- /Installer.Wpf/Services/FilePickMixin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Cinch.Reloaded.Services.Interfaces; 6 | using Serilog; 7 | 8 | namespace Intaller.Wpf.Services 9 | { 10 | public static class FilePickMixin 11 | { 12 | public static string Pick(this IOpenFileService openFileService, IEnumerable<(string, IEnumerable)> extensions, Func getCurrentFolder, Action setCurrentFolder) 13 | { 14 | var lines = extensions.Select(tuple => 15 | { 16 | var exts = string.Join((string) ";", (IEnumerable) tuple.Item2); 17 | return $"{tuple.Item1}|{exts}"; 18 | }); 19 | 20 | var filter = string.Join("|", lines); 21 | 22 | openFileService.Filter = filter; 23 | openFileService.FileName = ""; 24 | openFileService.InitialDirectory = getCurrentFolder(); 25 | if (openFileService.ShowDialog(null) == true) 26 | { 27 | var pickFileName = openFileService.FileName; 28 | var directoryName = Path.GetDirectoryName(pickFileName); 29 | setCurrentFolder(directoryName); 30 | Log.Verbose("Default directory for WimFolder has been set to {Folder}", directoryName); 31 | return pickFileName; 32 | } 33 | 34 | return null; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/AdvancedPart.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | You can import drive packages into the application so new Windows deployments will use them. Please, notice that this will not inject the drivers, will stage them for further deployments (inside the Windows Deployment section) 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Installer.Wpf/ViewModels/PhoneModel.cs: -------------------------------------------------------------------------------- 1 | namespace Intaller.Wpf.ViewModels 2 | { 3 | public class PhoneModel 4 | { 5 | public static readonly PhoneModel Lumia950 = new PhoneModel(PhoneType.Lumia950, "Microsoft Lumia 950"); 6 | public static readonly PhoneModel Lumia950Xl = new PhoneModel(PhoneType.Lumia950Xl, "Microsoft Lumia 950 XL"); 7 | 8 | private PhoneModel(PhoneType phoneType, string name) 9 | { 10 | PhoneType = phoneType; 11 | Name = name; 12 | } 13 | 14 | public PhoneType PhoneType { get; } 15 | public string Name { get; } 16 | 17 | protected bool Equals(PhoneModel other) 18 | { 19 | return PhoneType == other.PhoneType; 20 | } 21 | 22 | public override bool Equals(object obj) 23 | { 24 | if (ReferenceEquals(null, obj)) 25 | { 26 | return false; 27 | } 28 | 29 | if (ReferenceEquals(this, obj)) 30 | { 31 | return true; 32 | } 33 | 34 | if (obj.GetType() != this.GetType()) 35 | { 36 | return false; 37 | } 38 | 39 | return Equals((PhoneModel) obj); 40 | } 41 | 42 | public override int GetHashCode() 43 | { 44 | return (int) PhoneType; 45 | } 46 | } 47 | 48 | public enum PhoneType 49 | { 50 | Lumia950Xl, 51 | Lumia950 52 | } 53 | } -------------------------------------------------------------------------------- /Installer.Core/FileSystem/Partition.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using ByteSizeLib; 3 | using Serilog; 4 | 5 | namespace Installer.Core.FileSystem 6 | { 7 | public class Partition 8 | { 9 | public Partition(Disk disk) 10 | { 11 | Disk = disk; 12 | } 13 | 14 | public Disk Disk { get; private set; } 15 | public uint Number { get; set; } 16 | public string Id { get; set; } 17 | public char? Letter { get; set; } 18 | public PartitionType PartitionType { get; set; } 19 | public ILowLevelApi LowLevelApi => Disk.LowLevelApi; 20 | 21 | public override string ToString() 22 | { 23 | return $"{nameof(Disk)}: {Disk}, {nameof(Number)}: {Number}"; 24 | } 25 | 26 | public async Task Resize(ByteSize sizeInBytes) 27 | { 28 | await LowLevelApi.ResizePartition(this, sizeInBytes); 29 | } 30 | 31 | public Task GetVolume() 32 | { 33 | return LowLevelApi.GetVolume(this); 34 | } 35 | 36 | public async Task SetGptType(PartitionType partitionType) 37 | { 38 | Log.Verbose("Setting partition type to {Partition} from {OldType} to {NewType}", this, PartitionType, partitionType); 39 | await LowLevelApi.SetPartitionType(this, partitionType); 40 | Log.Verbose("Partition type set"); 41 | } 42 | 43 | public Task Remove() 44 | { 45 | return LowLevelApi.RemovePartition(this); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/StatusPart.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 20 | 21 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lumia Windows 10 ARM64 Installer 2 | This is a GUI tool to install Windows On ARM for Lumia 950 XL 3 | 4 | ![image](https://user-images.githubusercontent.com/3109851/42969544-c8a0660a-8ba6-11e8-84ab-487e3c0b8bb7.png) 5 | 6 | # Requirements 7 | - A Lumia 950 XL with an unlocked bootloader that can correctly enter Mass Storage Mode 8 | - A Windows 10 ARM64 Image (.wim) 9 | - A USB-C cable 10 | - A **Driver Package** (you can download it from [here](https://drive.google.com/drive/folders/13lrwP7Lc_OLSMxpjhjkaLDrnwM5Cy2Wz)) 11 | 12 | # Importing the Driver Package 13 | Run WoA Installer and go to the Advanced section. Click on `[Import Driver Pacakge]` and select the .7z file directly. Don't attempt to uncompress it. After the import operation, you will be able to use the application. 14 | 15 | # Usage 16 | The application is pretty straigforward to use. 17 | Just a few quick notes: 18 | - If you want to install Windows, just go to the Windows Deployment section and select `Full Install` or `Windows-only Install` 19 | - Don't forget to switch to Mass Storage Mode to perform the operations 20 | 21 | # Donations are welcome! 22 | If you find this useful, feel free to [buy me a coffee](http://paypal.me/superjmn 23 | ) Thanks in advance!! 24 | 25 | # Acknowledgements 26 | - [Eric Zimmerman](https://github.com/EricZimmerman) for [Registry project](https://github.com/EricZimmerman/Registry) 27 | - Gustave M. (retrieving metada from Windows Images) 28 | - MahApps.Metro https://mahapps.com/ 29 | - https://reactiveui.net/ 30 | - the people at [LumiaWOA](https://t.me/joinchat/Ey6mehEPg0Fe4utQNZ9yjA) for their testing. 31 | ` 32 | -------------------------------------------------------------------------------- /Installer.Wpf/BusyButton.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Input; 4 | using System.Windows.Media; 5 | 6 | namespace Intaller.Wpf 7 | { 8 | public class BusyButton : ContentControl 9 | { 10 | static BusyButton() 11 | { 12 | DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyButton), new FrameworkPropertyMetadata(typeof(BusyButton))); 13 | } 14 | 15 | public static readonly DependencyProperty ImageProperty = DependencyProperty.Register( 16 | "Image", typeof(ImageSource), typeof(BusyButton), new PropertyMetadata(default(ImageSource))); 17 | 18 | public ImageSource Image 19 | { 20 | get { return (ImageSource) GetValue(ImageProperty); } 21 | set { SetValue(ImageProperty, value); } 22 | } 23 | 24 | public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( 25 | "Command", typeof(ICommand), typeof(BusyButton), new PropertyMetadata(default(ICommand))); 26 | 27 | public ICommand Command 28 | { 29 | get { return (ICommand) GetValue(CommandProperty); } 30 | set { SetValue(CommandProperty, value); } 31 | } 32 | 33 | public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register( 34 | "IsBusy", typeof(bool), typeof(BusyButton), new PropertyMetadata(default(bool))); 35 | 36 | public bool IsBusy 37 | { 38 | get { return (bool) GetValue(IsBusyProperty); } 39 | set { SetValue(IsBusyProperty, value); } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/ImageMetadata.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Serialization; 2 | 3 | namespace Installer.Core.Services.Wim 4 | { 5 | [XmlRoot(ElementName = "IMAGE")] 6 | public class ImageMetadata 7 | { 8 | [XmlElement(ElementName = "DIRCOUNT")] public string DirectoryCount { get; set; } 9 | 10 | [XmlElement(ElementName = "FILECOUNT")] 11 | public string FileCount { get; set; } 12 | 13 | [XmlElement(ElementName = "TOTALBYTES")] 14 | public string TotalBytes { get; set; } 15 | 16 | [XmlElement(ElementName = "HARDLINKBYTES")] 17 | public string HardLinkBytes { get; set; } 18 | 19 | [XmlElement(ElementName = "CREATIONTIME")] 20 | public Time CreationTime { get; set; } 21 | 22 | [XmlElement(ElementName = "LASTMODIFICATIONTIME")] 23 | public Time LastModificationTime { get; set; } 24 | 25 | [XmlElement(ElementName = "WIMBOOT")] public string WimBoot { get; set; } 26 | 27 | [XmlElement(ElementName = "WINDOWS")] public Windows Windows { get; set; } 28 | 29 | [XmlElement(ElementName = "NAME")] public string Name { get; set; } 30 | 31 | [XmlElement(ElementName = "DESCRIPTION")] 32 | public string Description { get; set; } 33 | 34 | [XmlElement(ElementName = "FLAGS")] public string Flags { get; set; } 35 | 36 | [XmlElement(ElementName = "DISPLAYNAME")] 37 | public string DiplayName { get; set; } 38 | 39 | [XmlElement(ElementName = "DISPLAYDESCRIPTION")] 40 | public string DisplayDescription { get; set; } 41 | 42 | [XmlAttribute(AttributeName = "INDEX")] 43 | public string Index { get; set; } 44 | } 45 | } -------------------------------------------------------------------------------- /Installer.Core.FullFx/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // La información general de un ensamblado se controla mediante el siguiente 6 | // conjunto de atributos. Cambie estos valores de atributo para modificar la información 7 | // asociada con un ensamblado. 8 | [assembly: AssemblyTitle("Installer.Core.FullFx")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Installer.Core.FullFx")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Si establece ComVisible en false, los tipos de este ensamblado no estarán visibles 18 | // para los componentes COM. Si es necesario obtener acceso a un tipo en este ensamblado desde 19 | // COM, establezca el atributo ComVisible en true en este tipo. 20 | [assembly: ComVisible(false)] 21 | 22 | // El siguiente GUID sirve como id. de typelib si este proyecto se expone a COM. 23 | [assembly: Guid("15d1b19b-6f1b-47ad-be7b-f9bca447cbc0")] 24 | 25 | // La información de versión de un ensamblado consta de los cuatro valores siguientes: 26 | // 27 | // Versión principal 28 | // Versión secundaria 29 | // Número de compilación 30 | // Revisión 31 | // 32 | // Puede especificar todos los valores o usar los números de compilación y de revisión predeterminados 33 | // mediante el carácter "*", como se muestra a continuación: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Installer.Core/FileSystem/Disk.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using ByteSizeLib; 5 | 6 | namespace Installer.Core.FileSystem 7 | { 8 | public class Disk 9 | { 10 | public ILowLevelApi LowLevelApi { get; } 11 | public uint Number { get; } 12 | public ByteSize Size { get; } 13 | public ByteSize AllocatedSize { get; } 14 | 15 | public Disk(ILowLevelApi lowLevelApi, uint number, ByteSize size, ByteSize allocatedSize) 16 | { 17 | LowLevelApi = lowLevelApi; 18 | Number = number; 19 | Size = size; 20 | AllocatedSize = allocatedSize; 21 | } 22 | 23 | public async Task> GetVolumes() 24 | { 25 | var volumes = await LowLevelApi.GetVolumes(this); 26 | return volumes; 27 | } 28 | 29 | public Task> GetPartitions() 30 | { 31 | return LowLevelApi.GetPartitions(this); 32 | } 33 | 34 | public Task CreatePartition(ulong sizeInBytes) 35 | { 36 | return LowLevelApi.CreatePartition(this, sizeInBytes); 37 | } 38 | 39 | public Task CreateReservedPartition(ulong sizeInBytes) 40 | { 41 | return LowLevelApi.CreateReservedPartition(this, sizeInBytes); 42 | } 43 | 44 | public async Task GetReservedPartition() 45 | { 46 | var parts = await LowLevelApi.GetPartitions(this); 47 | return parts.FirstOrDefault(x => Equals(x.PartitionType, PartitionType.Reserved)); 48 | } 49 | 50 | public override string ToString() 51 | { 52 | return $"{nameof(Number)}: {Number}, {nameof(Size)}: {Size}, {nameof(AllocatedSize)}: {AllocatedSize}"; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/PhoneModelPart.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/LogPart.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Installer.Wpf/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Intaller.Wpf.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("")] 29 | public string WimFolder { 30 | get { 31 | return ((string)(this["WimFolder"])); 32 | } 33 | set { 34 | this["WimFolder"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("")] 41 | public string DriverPackFolder { 42 | get { 43 | return ((string)(this["DriverPackFolder"])); 44 | } 45 | set { 46 | this["DriverPackFolder"] = value; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Installer.Core/FileSystem/Volume.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reactive; 4 | using System.Reactive.Linq; 5 | using System.Threading.Tasks; 6 | using ByteSizeLib; 7 | using Installer.Core.Utils; 8 | using Serilog; 9 | 10 | namespace Installer.Core.FileSystem 11 | { 12 | public class Volume 13 | { 14 | private DirectoryInfo rootDir; 15 | 16 | public Volume(Partition partition) 17 | { 18 | Partition = partition; 19 | } 20 | 21 | public string Label { get; set; } 22 | public ByteSize Size { get; set; } 23 | public Partition Partition { get; set; } 24 | public char? Letter { get; set; } 25 | 26 | public DirectoryInfo RootDir => rootDir ?? (rootDir = new DirectoryInfo($"{Letter}:")); 27 | 28 | public Task Format(FileSystemFormat ntfs, string fileSystemLabel) 29 | { 30 | return Partition.LowLevelApi.Format(this, ntfs, fileSystemLabel); 31 | } 32 | 33 | public ILowLevelApi LowLevelApi => Partition.LowLevelApi; 34 | 35 | public async Task Mount() 36 | { 37 | Log.Verbose("Mounting volume {Volume}", this); 38 | var driveLetter = LowLevelApi.GetFreeDriveLetter(); 39 | await LowLevelApi.AssignDriveLetter(this, driveLetter); 40 | 41 | await Observable.Defer(() => Observable.Return(UpdateLetter(driveLetter))).RetryWithBackoffStrategy(); 42 | } 43 | 44 | private Unit UpdateLetter(char driveLetter) 45 | { 46 | try 47 | { 48 | rootDir = new DirectoryInfo($"{driveLetter}:"); 49 | return Unit.Default; 50 | } 51 | catch (Exception) 52 | { 53 | Log.Verbose("Cannot get path for drive letter {DriveLetter} while mounting partition {Partition}", driveLetter, this); 54 | throw; 55 | } 56 | } 57 | 58 | public override string ToString() 59 | { 60 | return $"{nameof(Label)}: {Label}, {nameof(Size)}: {Size}, {nameof(Partition)}: {Partition}, {nameof(Letter)}: {Letter}"; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Installer.Core/Services/BcdConfigurator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Installer.Core.FileSystem; 3 | using Installer.Core.Utils; 4 | 5 | namespace Installer.Core.Services 6 | { 7 | public class BcdConfigurator 8 | { 9 | private readonly BcdInvoker invoker; 10 | private readonly Volume efiespVolume; 11 | private readonly string bcdEdit; 12 | 13 | public BcdConfigurator(BcdInvoker invoker, Volume efiespVolume) 14 | { 15 | this.invoker = invoker; 16 | this.efiespVolume = efiespVolume; 17 | bcdEdit = @"c:\Windows\SysNative\bcdedit.exe"; 18 | } 19 | 20 | public void SetupBcd() 21 | { 22 | var bootShimEntry = CreateBootShim(); 23 | SetupBootShim(bootShimEntry); 24 | SetupBootMgr(); 25 | SetDisplayOptions(bootShimEntry); 26 | } 27 | 28 | private void SetDisplayOptions(Guid entry) 29 | { 30 | invoker.Invoke($@"/displayorder {{{entry}}}"); 31 | invoker.Invoke($@"/default {{{entry}}}"); 32 | invoker.Invoke($@"/timeout 30"); 33 | } 34 | 35 | private void SetupBootShim(Guid guid) 36 | { 37 | invoker.Invoke($@"/set {{{guid}}} path \EFI\boot\BootShim.efi"); 38 | invoker.Invoke($@"/set {{{guid}}} device partition={efiespVolume.RootDir.Name}"); 39 | invoker.Invoke($@"/set {{{guid}}} testsigning on"); 40 | invoker.Invoke($@"/set {{{guid}}} nointegritychecks on"); 41 | } 42 | 43 | private void SetupBootMgr() 44 | { 45 | invoker.Invoke($@"/set {{bootmgr}} displaybootmenu on"); 46 | invoker.Invoke($@"/deletevalue {{bootmgr}} customactions"); 47 | invoker.Invoke($@"/deletevalue {{bootmgr}} custom:54000001"); 48 | invoker.Invoke($@"/deletevalue {{bootmgr}} custom:54000002"); 49 | } 50 | 51 | private Guid CreateBootShim() 52 | { 53 | var run = ProcessUtils.Run(bcdEdit, $@"/STORE {efiespVolume.GetBcdFullFilename()} /create /d ""Windows 10"" /application BOOTAPP"); 54 | return FormattingUtils.GetGuid(run); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Installer.Wpf/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Installer.Core/Services/Wim/WindowsImageMetadataReaderBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Xml.Serialization; 6 | using Installer.Core.Exceptions; 7 | using Serilog; 8 | 9 | namespace Installer.Core.Services.Wim 10 | { 11 | public abstract class WindowsImageMetadataReaderBase 12 | { 13 | private static XmlSerializer Serializer { get; } = new XmlSerializer(typeof(WimMetadata)); 14 | 15 | public XmlWindowsImageMetadata Load(Stream stream) 16 | { 17 | Log.Verbose("Getting WIM stream"); 18 | 19 | WimMetadata metadata; 20 | try 21 | { 22 | metadata = (WimMetadata)Serializer.Deserialize(GetXmlMetadataStream(stream)); 23 | } 24 | catch (InvalidOperationException e) 25 | { 26 | throw new InvalidWimFileException("Could not read the metadata from the WIM file. Please, check it's a valid .WIM file", e); 27 | } 28 | 29 | Log.Verbose("Wim metadata deserialized correctly {@Metadata}", metadata); 30 | 31 | return new XmlWindowsImageMetadata 32 | { 33 | Images = metadata.Images.Select(x => new DiskImageMetadata 34 | { 35 | Architecture = WindowsImageMetadataReader.GetArchitecture(x.Windows.Arch), 36 | Build = x.Windows.Version.Build, 37 | DisplayName = x.Name, 38 | Index = int.Parse(x.Index) 39 | }).ToList() 40 | }; 41 | } 42 | 43 | private static Architecture GetArchitecture(string str) 44 | { 45 | switch (str) 46 | { 47 | case "0": 48 | return Architecture.X86; 49 | case "9": 50 | return Architecture.X64; 51 | case "12": 52 | return Architecture.Arm64; 53 | } 54 | 55 | throw new IndexOutOfRangeException($"The architecture '{str}' is unknown"); 56 | } 57 | 58 | protected abstract Stream GetXmlMetadataStream(Stream wim); 59 | } 60 | } -------------------------------------------------------------------------------- /Installer.Wpf/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Installer.Wpf/CompositionRoot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Cinch.Reloaded.Services.Implementation; 6 | using Installer.Core; 7 | using Installer.Core.FullFx; 8 | using Installer.Core.Services; 9 | using Intaller.Wpf.Services; 10 | using Intaller.Wpf.ViewModels; 11 | using Intaller.Wpf.Views; 12 | using MahApps.Metro.Controls.Dialogs; 13 | using Serilog.Events; 14 | using SharpCompress.Archives.SevenZip; 15 | using SharpCompress.Archives.Zip; 16 | using SharpCompress.Common.SevenZip; 17 | using SharpCompress.Common.Zip; 18 | 19 | namespace Intaller.Wpf 20 | { 21 | public static class CompositionRoot 22 | { 23 | public static MainViewModel GetMainViewModel(IObservable logEvents) 24 | { 25 | var visualizerService = new ExtendedWpfUIVisualizerService(); 26 | visualizerService.Register("TextViewer", typeof(TextViewerWindow)); 27 | 28 | IDictionary deployerDict = new Dictionary 29 | { 30 | {PhoneModel.Lumia950Xl, GetDeployer(Path.Combine("Files", "Lumia 950 XL"))}, 31 | {PhoneModel.Lumia950, GetDeployer(Path.Combine("Files", "Lumia 950"))}, 32 | }; 33 | 34 | var api = new LowLevelApi(); 35 | var deployersItems = deployerDict.Select(pair => new DeployerItem(pair.Key, pair.Value)).ToList(); 36 | var importerItems = new List() 37 | { 38 | new DriverPackageImporterItem("7z", 39 | new DriverPackageImporter( 40 | s => SevenZipArchive.Open(s), "Files")), 41 | new DriverPackageImporterItem("zip", 42 | new DriverPackageImporter(s => ZipArchive.Open(s), "Files")) 43 | }; 44 | 45 | var mainViewModel = new MainViewModel(logEvents, deployersItems, importerItems, 46 | new ViewServices(new WpfOpenFileService(), DialogCoordinator.Instance, visualizerService), 47 | async () => new Phone(await api.GetPhoneDisk())); 48 | return mainViewModel; 49 | } 50 | 51 | private static Deployer GetDeployer(string root) 52 | { 53 | return new Deployer(new CoreDeployer(root), new WindowsDeployer(new DismImageService(), new DriverPaths(root)) ); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Installer.Core/FileSystem/PartitionType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Serilog; 4 | 5 | namespace Installer.Core.FileSystem 6 | { 7 | public class PartitionType 8 | { 9 | private static readonly Guid EspGuid = Guid.Parse("C12A7328-F81F-11D2-BA4B-00A0C93EC93B"); 10 | private static readonly Guid BasicGuid = Guid.Parse("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); 11 | private static readonly Guid ReservedGuid = Guid.Parse("E3C9E316-0B5C-4DB8-817D-F92DF00215AE"); 12 | 13 | public string Name { get; } 14 | public Guid Guid { get; } 15 | 16 | public static readonly PartitionType Reserved = new PartitionType("Reserved", ReservedGuid); 17 | public static readonly PartitionType Esp = new PartitionType("EFI System Partition", EspGuid); 18 | public static readonly PartitionType Basic = new PartitionType("Basic", BasicGuid); 19 | 20 | private static readonly IDictionary PartitionTypes = new Dictionary() 21 | { 22 | { EspGuid, Esp}, 23 | { BasicGuid, Basic }, 24 | { ReservedGuid, Reserved }, 25 | }; 26 | 27 | private PartitionType(string name, Guid guid) 28 | { 29 | Name = name; 30 | Guid = guid; 31 | } 32 | 33 | public static PartitionType FromGuid(Guid guid) 34 | { 35 | if (PartitionTypes.TryGetValue(guid, out var type)) 36 | { 37 | return type; 38 | } 39 | 40 | //Log.Warning("The partition type {Guid} is unknown", guid); 41 | return null; 42 | } 43 | 44 | protected bool Equals(PartitionType other) 45 | { 46 | return Guid.Equals(other.Guid); 47 | } 48 | 49 | public override bool Equals(object obj) 50 | { 51 | if (ReferenceEquals(null, obj)) 52 | { 53 | return false; 54 | } 55 | 56 | if (ReferenceEquals(this, obj)) 57 | { 58 | return true; 59 | } 60 | 61 | if (obj.GetType() != this.GetType()) 62 | { 63 | return false; 64 | } 65 | 66 | return Equals((PartitionType) obj); 67 | } 68 | 69 | public override int GetHashCode() 70 | { 71 | return Guid.GetHashCode(); 72 | } 73 | 74 | public override string ToString() 75 | { 76 | return $"{nameof(Guid)}: {Guid}"; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Installer.Wpf/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // La información general de un ensamblado se controla mediante el siguiente 8 | // conjunto de atributos. Cambie estos valores de atributo para modificar la información 9 | // asociada con un ensamblado. 10 | [assembly: AssemblyTitle("Install")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Install")] 15 | [assembly: AssemblyCopyright("Copyright © 2018")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Si establece ComVisible en false, los tipos de este ensamblado no estarán visibles 20 | // para los componentes COM. Si es necesario obtener acceso a un tipo en este ensamblado desde 21 | // COM, establezca el atributo ComVisible en true en este tipo. 22 | [assembly: ComVisible(false)] 23 | 24 | //Para comenzar a compilar aplicaciones que se puedan traducir, establezca 25 | //CultureYouAreCodingWith en el archivo .csproj 26 | //dentro de . Por ejemplo, si utiliza inglés de EE.UU. 27 | //en los archivos de código fuente, establezca en en-US. A continuación, quite la marca de comentario 28 | //del atributo NeutralResourceLanguage. Actualice "en-US" en 29 | //la siguiente línea para que coincida con el valor UICulture del archivo de proyecto. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //donde se encuentran los diccionarios de recursos específicos del tema 36 | //(se utiliza si no se encuentra ningún recurso en la página, 37 | // ni diccionarios de recursos de la aplicación) 38 | ResourceDictionaryLocation.SourceAssembly //donde se encuentra el diccionario de recursos genérico 39 | //(se utiliza si no se encuentra ningún recurso en la página, 40 | // aplicación o diccionarios de recursos específicos del tema) 41 | )] 42 | 43 | 44 | // La información de versión de un ensamblado consta de los cuatro valores siguientes: 45 | // 46 | // Versión principal 47 | // Versión secundaria 48 | // Número de compilación 49 | // Revisión 50 | // 51 | // Puede especificar todos los valores o utilizar los números de compilación y de revisión predeterminados 52 | // mediante el carácter '*', como se muestra a continuación: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Installer.Core/CoreDeployer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using Installer.Core.FileSystem; 4 | using Installer.Core.Services; 5 | using Installer.Core.Utils; 6 | using Serilog; 7 | 8 | namespace Installer.Core 9 | { 10 | public class CoreDeployer : ICoreDeployer 11 | { 12 | private readonly string rootFilesPath; 13 | 14 | public CoreDeployer(string rootFilesPath) 15 | { 16 | this.rootFilesPath = rootFilesPath; 17 | } 18 | 19 | private string[] FilesPathsToCheck => new[] 20 | { 21 | Path.Combine(rootFilesPath, "Core", "BootShim.efi"), 22 | Path.Combine(rootFilesPath, "Core", "UEFI.elf"), 23 | Path.Combine(rootFilesPath, "Developer Menu") 24 | }; 25 | 26 | private async Task AddDeveloperMenu(Volume efiespVolume) 27 | { 28 | Log.Information("Adding Development Menu..."); 29 | 30 | var bcdInvoker = new BcdInvoker(efiespVolume.GetBcdFullFilename()); 31 | new BcdConfigurator(bcdInvoker, efiespVolume).SetupBcd(); 32 | 33 | var rootDir = efiespVolume.RootDir.Name; 34 | 35 | var destination = Path.Combine(rootDir, "Windows", "System32", "BOOT"); 36 | await FileUtils.CopyDirectory(new DirectoryInfo(Path.Combine(rootFilesPath, "Developer Menu")), new DirectoryInfo(destination)); 37 | var guid = FormattingUtils.GetGuid(bcdInvoker.Invoke(@"/create /d ""Developer Menu"" /application BOOTAPP")); 38 | bcdInvoker.Invoke($@"/set {{{guid}}} path \Windows\System32\BOOT\developermenu.efi"); 39 | bcdInvoker.Invoke($@"/set {{{guid}}} device partition={rootDir}"); 40 | bcdInvoker.Invoke($@"/set {{{guid}}} testsigning on"); 41 | bcdInvoker.Invoke($@"/set {{{guid}}} nointegritychecks on"); 42 | bcdInvoker.Invoke($@"/displayorder {{{guid}}} /addlast"); 43 | } 44 | 45 | private async Task DeployUefi(Volume efiespVolume) 46 | { 47 | Log.Information("Deploying UEFI..."); 48 | 49 | var rootDir = efiespVolume.RootDir.Name; 50 | await FileUtils.Copy(Path.Combine(rootFilesPath, "Core", "UEFI.elf"), Path.Combine(rootDir, "UEFI.elf")); 51 | await FileUtils.Copy(Path.Combine(rootFilesPath, "Core", "BootShim.efi"), Path.Combine(rootDir, "EFI", "BOOT", "BootShim.efi")); 52 | } 53 | 54 | public Task AreDeploymentFilesValid() 55 | { 56 | var valid = FilesPathsToCheck.EnsureExistingPaths(); 57 | return Task.FromResult(valid); 58 | } 59 | 60 | public async Task Deploy(Phone phone) 61 | { 62 | var efiespVolume = await phone.GetEfiespVolume(); 63 | 64 | Log.Information("Deploying Core (UEFI and Development Menu...)"); 65 | 66 | await DeployUefi(efiespVolume); 67 | await AddDeveloperMenu(efiespVolume); 68 | 69 | Log.Information("Core deployed (UEFI and Development Menu)"); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Installer.Core/Utils/FileUtils.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Serilog; 6 | 7 | namespace Installer.Core.Utils 8 | { 9 | public static class FileUtils 10 | { 11 | public static bool EnsureExistingPaths(this string[] pathsToCheck) 12 | { 13 | return pathsToCheck.All(IsExistingPath); 14 | } 15 | 16 | public static void EnsureEmptyDirectory(string path) 17 | { 18 | Log.Verbose("Ensuring that '{Directory}' is empty", path); 19 | 20 | if (Directory.Exists(path)) 21 | { 22 | Directory.Delete(path, true); 23 | } 24 | } 25 | 26 | public static async Task Copy(string source, string destination, CancellationToken cancellationToken) 27 | { 28 | var fileOptions = FileOptions.Asynchronous | FileOptions.SequentialScan; 29 | var bufferSize = 4096; 30 | 31 | using (var sourceStream = 32 | new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, fileOptions)) 33 | 34 | using (var destinationStream = 35 | new FileStream(destination, FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize, fileOptions)) 36 | 37 | await sourceStream.CopyToAsync(destinationStream, bufferSize, cancellationToken).ConfigureAwait(false); 38 | } 39 | 40 | public static async Task Copy(string source, string destination, FileMode fileMode = FileMode.Create) 41 | { 42 | Log.Verbose("Copying file {Source} to {Destination}", source, destination); 43 | 44 | var fileOptions = FileOptions.Asynchronous | FileOptions.SequentialScan; 45 | var bufferSize = 4096; 46 | 47 | using (var sourceStream = 48 | new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, fileOptions)) 49 | 50 | using (var destinationStream = 51 | new FileStream(destination, fileMode, FileAccess.Write, FileShare.None, bufferSize, fileOptions)) 52 | 53 | await sourceStream.CopyToAsync(destinationStream, bufferSize).ConfigureAwait(false); 54 | } 55 | 56 | public static async Task CopyDirectory(DirectoryInfo source, DirectoryInfo destination) 57 | { 58 | Log.Verbose("Copying directory {Source} to {Destination}", source, destination); 59 | 60 | 61 | foreach (var dir in source.GetDirectories()) 62 | { 63 | await CopyDirectory(dir, destination.CreateSubdirectory(dir.Name)); 64 | } 65 | 66 | foreach (var file in source.GetFiles()) 67 | { 68 | var destFileName = Path.Combine(destination.FullName, file.Name); 69 | await Copy(file.FullName, destFileName); 70 | } 71 | } 72 | 73 | private static bool IsExistingPath(string path) 74 | { 75 | return File.Exists(path) || Directory.Exists(path); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Installer.Core/Utils/ReactiveMixin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Reactive.Concurrency; 4 | using System.Reactive.Linq; 5 | 6 | namespace Installer.Core.Utils 7 | { 8 | public static class ReactiveMixin 9 | { 10 | // Licensed under the MIT license with <3 by GitHub 11 | 12 | /// 13 | /// An exponential back off strategy which starts with 1 second and then 4, 9, 16... 14 | /// 15 | [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] 16 | public static readonly Func ExponentialBackoff = n => TimeSpan.FromSeconds(Math.Pow(n, 2)); 17 | 18 | /// 19 | /// Returns a cold observable which retries (re-subscribes to) the source observable on error up to the 20 | /// specified number of times or until it successfully terminates. Allows for customizable back off strategy. 21 | /// 22 | /// The source observable. 23 | /// The number of attempts of running the source observable before failing. 24 | /// The strategy to use in backing off, exponential by default. 25 | /// A predicate determining for which exceptions to retry. Defaults to all 26 | /// The scheduler. 27 | /// 28 | /// A cold observable which retries (re-subscribes to) the source observable on error up to the 29 | /// specified number of times or until it successfully terminates. 30 | /// 31 | [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] 32 | public static IObservable RetryWithBackoffStrategy( 33 | this IObservable source, 34 | int retryCount = 3, 35 | Func strategy = null, 36 | Func retryOnError = null, 37 | IScheduler scheduler = null) 38 | { 39 | strategy = strategy ?? ExponentialBackoff; 40 | scheduler = scheduler ?? Scheduler.Default; 41 | 42 | if (retryOnError == null) 43 | retryOnError = e => true; 44 | 45 | int attempt = 0; 46 | 47 | return Observable.Defer(() => 48 | { 49 | return ((++attempt == 1) ? source : source.DelaySubscription(strategy(attempt - 1), scheduler)) 50 | .Select(item => new Tuple(true, item, null)) 51 | .Catch, Exception>(e => retryOnError(e) 52 | ? Observable.Throw>(e) 53 | : Observable.Return(new Tuple(false, default(T), e))); 54 | }) 55 | .Retry(retryCount) 56 | .SelectMany(t => t.Item1 57 | ? Observable.Return(t.Item2) 58 | : Observable.Throw(t.Item3)); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Installer.Wpf/Views/Parts/Sections/WimOptionsPart.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | Please, specify the Windows Image file (.wim) you wish to deploy. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |