Compare commits

...
12 Commits
Author SHA1 Message Date
Belim bad09ce2c4 Delete Write-an-Extension.md 2025-09-07 15:50:04 +02:00
Belim f001c0c076 Delete Flyoobe.Extensions/Info.MD 2025-09-07 15:49:48 +02:00
Belim 4b5fdc2366 Create Write-an-Extension.md 2025-09-07 15:49:40 +02:00
Belim f1b5e4edb4 Create Info.MD 2025-09-07 15:49:11 +02:00
Belim c15b200a08 Delete Flyoobe.Extensions 2025-09-07 15:48:44 +02:00
Belim 25a23cf32e Create Flyoobe.Extensions 2025-09-07 15:48:32 +02:00
Belim d34e522d0e Update Write-an-Extension.md 2025-09-07 15:47:31 +02:00
Belim 4250d61c02 Create Write-an-Extension.md 2025-09-07 15:45:36 +02:00
Belim 377014f571 Merge pull request #284 from bovirus/main
Update Strings.it.resx
2025-09-05 08:06:58 +02:00
Belim dea23eaf28 Merge branch 'main' of https://github.com/builtbybel/Flyby11 2025-09-04 18:10:17 +02:00
Belim 257d6cd6c3 Commit InstallView, UpgradeView 2025-09-04 18:10:14 +02:00
bovirus 310521ab05 Update Strings.it.resx 2025-08-30 11:01:33 +02:00
23 changed files with 1209 additions and 115 deletions

No files matched your search

+12 -12
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@@ -242,44 +242,44 @@
</data>
<data name="msg_InstallReady" xml:space="preserve">
<value>L'installazione di Windows 11 può ora procedere. Segui le istruzioni nella finestra di configurazione.</value>
<comment>Installa</comment>
<comment>Install</comment>
</data>
<data name="_debugInstallReady" xml:space="preserve">
<value>Sei pronto per installare Windows 11 con hardware non supportato! Ignora il prompt "Windows Server"; tutto è pronto!</value>
<comment>Installa</comment>
<comment>Install</comment>
</data>
<data name="_debugInstallRunElevated" xml:space="preserve">
<value>Avvio processo configurazione con privilegi elevati ...</value>
<comment>Installa</comment>
<comment>Install</comment>
</data>
<data name="_debugStatusHandleIsoEx" xml:space="preserve">
<value>Oops! Qualcosa è andato storto:</value>
<comment>Montaggio</comment>
<comment>Mounting</comment>
</data>
<data name="_debugStatusMounting" xml:space="preserve">
<value>Montaggio file...</value>
<comment>Montaggio</comment>
<comment>Mounting</comment>
</data>
<data name="_debugStatusMountingFailed" xml:space="preserve">
<value>Impossibile montare il file ISO. Riprova.</value>
<comment>Montaggio</comment>
<comment>Mounting</comment>
</data>
<data name="_debugStatusMountingSuccess" xml:space="preserve">
<value>File ISO montato correttamente! Procediamo con l'installazione di Windows 11!</value>
<comment>Montaggio</comment>
<comment>Mounting</comment>
</data>
<data name="_debugStatusRunning" xml:space="preserve">
<value>Ci siamo quasi! Preparazione installazione ...</value>
<comment>Installazione</comment>
<comment>Install</comment>
</data>
<data name="_debugStatusSetupFileNotFound" xml:space="preserve">
<value>File configurazione non trovato in</value>
<comment>Montaggio</comment>
<comment>Mounting</comment>
</data>
<data name="ctl_linkSelectComputer" xml:space="preserve">
<value>Seleziona dal computer</value>
</data>
<data name="msgClosing" xml:space="preserve">
<value />
<value>Grazie per aver usato questa app!\n\nHo sviluppato questa app nel mio tempo libero per aiutarti ad aggiornare da Windows 10 a Windows 11 - anche su PC che, secondo i requisiti hardware di Microsoft, normalmente non sarebbero supportati.\nQuesta app ti aiuta ad evitare di acquistare un nuovo computer e contribuisce attivamente ad evitare di produrre rifiuti elettronici inutili.\nNormalmnte non chiedo nulla per i miei progetti - né per lo sviluppo né per il supporto.\nQuesta app è significativamente completa, offre tante funzionalità e richiede più supporto, ti sarei grato se considereresti di fare una piccola donazione volontaria, se sei in grado di farlo.\n\nOvviamente , solo se vuoi e puoi permettertelo.\nVuoi donare un piccolo contributo con Paypal?</value>
</data>
</root>
</root>
+38
View File
@@ -0,0 +1,38 @@
# 🆕 Setup Extensions: Host + Options Support
The **Setup Extensions** system now supports extended script metadata in the header.
This allows script authors to define dropdown menus and control how the script is executed.
---
## ✅ New Metadata Parameters
### `# Description: <string>`
- Short, user-friendly description of what the script does.
- Displayed in the Extensions page below the title.
### `# Host: embedded | console`
- **embedded** = run inside OOBE, output is captured and shown in the app.
- **console** = run in an external PowerShell window with `-NoExit`.
- **Default:** `embedded` (if not specified).
### `# Options: value1; value2; value3; ...`
- Defines multiple selectable actions for a single script.
- A dropdown is automatically shown in the Extensions page.
- The selected value is passed to the script as `$choice`.
---
## 📄 Example Script Header
```powershell
# Description: File Explorer tweaks
# Host: embedded
# Options: Show file extensions; Hide file extensions; Open This PC
param([string]$choice)
switch ($choice) {
"Show file extensions" { ... }
"Hide file extensions" { ... }
"Open This PC" { ... }
}
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36414.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flyoobe.Spot", "Flyoobe.ToolSpot\Flyoobe.Spot.csproj", "{1133824D-6F42-48D4-8F18-A93AB7403DB7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1133824D-6F42-48D4-8F18-A93AB7403DB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1133824D-6F42-48D4-8F18-A93AB7403DB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1133824D-6F42-48D4-8F18-A93AB7403DB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1133824D-6F42-48D4-8F18-A93AB7403DB7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B22B36E3-C594-46AF-AF57-3C03B2F97541}
EndGlobalSection
EndGlobal
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1133824D-6F42-48D4-8F18-A93AB7403DB7}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Flyoobe.Spot</RootNamespace>
<AssemblyName>spot</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+105
View File
@@ -0,0 +1,105 @@
namespace Flyoobe.ToolSpot
{
partial class MainForm
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.listResults = new System.Windows.Forms.ListBox();
this.textSearch = new System.Windows.Forms.TextBox();
this.labelStatus = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// listResults
//
this.listResults.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listResults.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(249)))), ((int)(((byte)(243)))), ((int)(((byte)(240)))));
this.listResults.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.listResults.Font = new System.Drawing.Font("Segoe UI Variable Small Semilig", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.listResults.FormattingEnabled = true;
this.listResults.ItemHeight = 17;
this.listResults.Location = new System.Drawing.Point(25, 72);
this.listResults.Name = "listResults";
this.listResults.Size = new System.Drawing.Size(504, 170);
this.listResults.TabIndex = 5;
this.listResults.TabStop = false;
this.listResults.DoubleClick += new System.EventHandler(this.listResults_DoubleClick);
this.listResults.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listResults_KeyDown);
//
// textSearch
//
this.textSearch.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textSearch.Font = new System.Drawing.Font("Segoe UI Variable Small Semilig", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textSearch.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.textSearch.Location = new System.Drawing.Point(25, 26);
this.textSearch.Name = "textSearch";
this.textSearch.Size = new System.Drawing.Size(504, 29);
this.textSearch.TabIndex = 1;
this.textSearch.Text = "Search";
this.textSearch.Click += new System.EventHandler(this.textSearch_Click);
this.textSearch.TextChanged += new System.EventHandler(this.textSearch_TextChanged);
//
// labelStatus
//
this.labelStatus.Dock = System.Windows.Forms.DockStyle.Bottom;
this.labelStatus.Font = new System.Drawing.Font("Segoe UI Variable Small Semilig", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelStatus.Location = new System.Drawing.Point(0, 251);
this.labelStatus.Name = "labelStatus";
this.labelStatus.Size = new System.Drawing.Size(557, 21);
this.labelStatus.TabIndex = 2;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
this.ClientSize = new System.Drawing.Size(557, 272);
this.Controls.Add(this.labelStatus);
this.Controls.Add(this.textSearch);
this.Controls.Add(this.listResults);
this.Name = "MainForm";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Spot";
this.Load += new System.EventHandler(this.Form1_Load);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListBox listResults;
private System.Windows.Forms.TextBox textSearch;
private System.Windows.Forms.Label labelStatus;
}
}
@@ -0,0 +1,209 @@
/// This tool is part of my Flyoobe app
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace Flyoobe.ToolSpot
{
public partial class MainForm : Form
{ // Path of the text DB
public string DatabasePath { get; set; } =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "spot.txt");
// In-memory list of all tools
private readonly List<ToolItem> _all = new List<ToolItem>();
public MainForm()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
LoadDatabase();
//ApplyFilter(); // show all initially
textSearch.Focus();
}
private void SetStatus(string text)
{
if (labelStatus != null) labelStatus.Text = text;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
// close it
var form = this.FindForm();
form?.Close();
}
}
private void listResults_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) { LaunchSelected(); e.Handled = true; }
}
private void listResults_DoubleClick(object sender, EventArgs e) => LaunchSelected();
private void textSearch_TextChanged(object sender, EventArgs e) => ApplyFilter();
/// <summary>
/// Reads toolspot.txt (Name;Command). Ignores empty and comment lines.
/// </summary>
private void LoadDatabase()
{
_all.Clear();
if (!File.Exists(DatabasePath))
{
SetStatus($"Database not found: {DatabasePath}");
return;
}
foreach (var line in File.ReadAllLines(DatabasePath))
{
var trimmed = line.Trim();
if (string.IsNullOrEmpty(trimmed)) continue;
if (trimmed.StartsWith("#")) continue;
var item = ParseLine(trimmed);
if (item != null) _all.Add(item);
}
SetStatus($"Loaded {_all.Count} tools.");
}
/// <summary>
/// Parses "Name;Command" lines. Returns null if malformed.
/// </summary>
private ToolItem ParseLine(string line)
{
var parts = line.Split(new[] { ';' }, 2);
if (parts.Length != 2) return null;
var name = parts[0].Trim();
var cmd = parts[1].Trim();
if (name.Length == 0 || cmd.Length == 0) return null;
return new ToolItem(name, cmd);
}
/// <summary>
/// Filters list by substring (case-insensitive) from textSearch.
/// </summary>
private void ApplyFilter()
{
var q = (textSearch.Text ?? string.Empty).Trim().ToLower();
var list = string.IsNullOrEmpty(q)
? _all
: _all.Where(t => t.Name.ToLower().Contains(q)).ToList();
listResults.BeginUpdate();
listResults.Items.Clear();
foreach (var t in list) listResults.Items.Add(t);
listResults.EndUpdate();
if (listResults.Items.Count > 0) listResults.SelectedIndex = 0;
SetStatus(listResults.Items.Count > 0 ? $"{listResults.Items.Count} result(s)" : "No results");
}
/// <summary>
/// Launches the selected tool's command. Supports URIs, .msc/.cpl, exe + args.
/// </summary>
private void LaunchSelected()
{
if (!(listResults.SelectedItem is ToolItem t)) return;
try
{
// Split command into FileName + Arguments (handles quoted paths)
SplitCommand(t.Command, out var fileName, out var args);
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
UseShellExecute = true // required for ms-settings:, .msc/.cpl
};
Process.Start(psi);
}
catch (Exception ex)
{
MessageBox.Show("Could not launch: " + ex.Message, "Quick Tools",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Splits a command line into executable and arguments.
/// Examples:
/// notepad.exe
/// "C:\Path With Spaces\app.exe" --flag
/// chrome.exe --settings
/// For URIs / shell verbs (e.g., ms-settings:...), no split is needed.
/// </summary>
private void SplitCommand(string command, out string fileName, out string args)
{
command = command.Trim();
// If it's a URI-like command (ms-settings:, http:, etc.), pass as-is.
if (command.Contains(":") && !command.Contains("\\"))
{
fileName = command;
args = string.Empty;
return;
}
// Quoted path case: "C:\Program Files\App\app.exe" arg1 arg2
if (command.StartsWith("\""))
{
int end = command.IndexOf('"', 1);
if (end > 0)
{
fileName = command.Substring(1, end - 1);
args = command.Substring(end + 1).TrimStart();
return;
}
}
// Unquoted: split on first space
int space = command.IndexOf(' ');
if (space > 0)
{
fileName = command.Substring(0, space);
args = command.Substring(space + 1);
}
else
{
fileName = command;
args = string.Empty;
}
}
private class ToolItem
{
public string Name { get; }
public string Command { get; }
public ToolItem(string name, string command)
{ Name = name; Command = command; }
public override string ToString() => Name; // shown in ListBox
}
private void textSearch_Click(object sender, EventArgs e)
{
textSearch.Clear();
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flyoobe.ToolSpot
{
internal static class Program
{
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("Spot")]
[assembly: AssemblyDescription("Flyoobe Spot")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Builtbybel")]
[assembly: AssemblyProduct("Flyoobe Spot")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("A Belim app creation")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("1133824d-6f42-48d4-8f18-a93ab7403db7")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Flyoobe.Spot.Properties {
using System;
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
// Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Flyoobe.Spot.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Flyoobe.Spot.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC-Manifestoptionen
Wenn Sie die Ebene der Benutzerkontensteuerung für Windows ändern möchten, ersetzen Sie den
Knoten "requestedExecutionLevel" wie folgt.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Durch Angabe des Elements "requestedExecutionLevel" wird die Datei- und Registrierungsvirtualisierung deaktiviert.
Entfernen Sie dieses Element, wenn diese Virtualisierung aus Gründen der Abwärtskompatibilität
für die Anwendung erforderlich ist.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Eine Liste der Windows-Versionen, unter denen diese Anwendung getestet
und für die sie entwickelt wurde. Wenn Sie die Auskommentierung der entsprechenden Elemente aufheben,
wird von Windows automatisch die kompatibelste Umgebung ausgewählt. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- Gibt an, dass die Anwendung mit DPI-Werten kompatibel ist und von Windows nicht automatisch auf höhere
DPI-Werte skaliert wird. WPF-Anwendungen (Windows Presentation Foundation) sind automatisch mit DPI-Werten kompatibel, eine Aktivierung
ist nicht erforderlich. Für Windows Forms-Anwendungen für .NET Framework 4.6, die diese Einstellung aktivieren, muss
auch die Einstellung "'EnableWindowsFormsHighDpiAutoResizing" in der Datei "app.config" auf TRUE festgelegt werden.
Hierdurch können für die Anwendung lange Pfade verwendet werden. Weitere Informationen finden Sie unter https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation.-->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
<!-- Designs für allgemeine Windows-Steuerelemente und -Dialogfelder (Windows XP und höher) aktivieren -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>
+2 -1
View File
@@ -180,7 +180,8 @@ namespace Flyoobe
// Update label text
linkAppVersion.Text = text;
// If clickable, show bold & underline and make cursor a hand
// If clickable,
// show bold ; underline ; make cursor a hand
if (clickable)
{
linkAppVersion.Font = new Font(linkAppVersion.Font, FontStyle.Bold | FontStyle.Underline);
-11
View File
@@ -1,6 +1,5 @@
using Flyoobe; // for FeatureNode
using Settings.Ads;
using Settings.AI;
using Settings.Edge;
using Settings.Gaming;
using Settings.Issues;
@@ -118,16 +117,6 @@ namespace Features
new FeatureNode(new WelcomeExperienceAds())
}
},
new FeatureNode("AI")
{
Children = new List<FeatureNode>
{
new FeatureNode(new CopilotTaskbar()),
new FeatureNode(new Recall()),
new FeatureNode(new ClickToDo())
}
}
};
}
}
+50 -12
View File
@@ -5,13 +5,19 @@ using System.Windows.Forms;
namespace Flyoobe
{
// Native provider that exports all installed drivers to C:\DriversBackup using:
// pnputil.exe /export-driver * C:\DriversBackup
// Provider that exports all installed drivers into a fixed subfolder named "DriversBackup"
// INSIDE the parent folder chosen by the user, using:
// pnputil.exe /export-driver * <chosenParent>\DriversBackup
// Behavior:
// - Prompts user to choose a parent folder (defaults to C:\).
// - Always creates/uses "<chosenParent>\DriversBackup".
// - Runs pnputil elevated.
// - Shows a completion summary with INF package count.
public sealed class BackupDriversProvider : IInstallProvider
{
public string Id => "drivers-backup";
public string DisplayName => "Backup installed drivers (exports to C:\\DriversBackup)";
public string DisplayName => "Backup installed drivers (choose folder)";
public string HomepageUrl => null;
public string DirectDownloadUrl => null;
public string[] ExactExeNames => new[] { "pnputil.exe" };
@@ -20,18 +26,48 @@ namespace Flyoobe
public bool IsExternalTool => false;
public string Hint =>
"Exports all currently installed device drivers (INF + binaries) to C:\\DriversBackup. " +
"After a clean install, point Device Manager to this folder to restore drivers even without internet.";
"Exports all currently installed device drivers (INF + binaries) to a folder you choose. " +
"After a clean install, point Device Manager to that folder to restore drivers even without internet.";
public string ShowOptionsAndBuildArgs(IWin32Window owner, LastSelections last)
{
const string target = @"C:\DriversBackup";
// Default suggestion for the parent, the actual export target will be <parent>\DriversBackup
var defaultParent = @"C:\";
string parentPath;
// pick the PARENT folder where the 'DriversBackup' subfolder will be created
using (var fbd = new FolderBrowserDialog
{
Description = "Choose the PARENT folder. A 'DriversBackup' subfolder will be created inside it.",
ShowNewFolderButton = true,
SelectedPath = defaultParent
})
{
var dlgResult = fbd.ShowDialog(owner);
if (dlgResult != DialogResult.OK || string.IsNullOrWhiteSpace(fbd.SelectedPath))
return null; //user cancelled
parentPath = fbd.SelectedPath.Trim();
try
{
//Normalize parent path
parentPath = Path.GetFullPath(parentPath);
}
catch
{ //Keep raw selection if normalization fails (we'll error out later if invalid)
}
}
// Build the fixed subfolder path: <parent>\DriversBackup (always appended)
string target = Path.Combine(parentPath, "DriversBackup");
// Confirm before running the elevated export
if (!ToolHelpers.Confirm(owner,
"Export all installed drivers to:\r\n\r\n" + target +
"\r\n\r\nThis runs 'pnputil /export-driver *' with administrative rights."))
"\r\n\r\nThis will run 'pnputil /export-driver *' with administrative rights."))
return null;
// Ensure the target DriversBackup folder exists
try
{
Directory.CreateDirectory(target);
@@ -47,7 +83,7 @@ namespace Flyoobe
try
{
// Start pnputil as elevated process
// Start pnputil as an elevated process targeting the 'DriversBackup' subfolder
var psi = new ProcessStartInfo
{
FileName = "pnputil.exe",
@@ -69,15 +105,17 @@ namespace Flyoobe
proc.WaitForExit();
}
// Now export is complete > count drivers
// Count exported INF files to provide a quick summary
int infCount = 0;
try
{
infCount = Directory.GetFiles(target, "*.inf", SearchOption.AllDirectories).Length;
}
catch { /* ignore */ }
catch
{ // Ignore counting errors; we can still show success without the count
}
MessageBox.Show(owner,
MessageBox.Show(owner,
"Driver export completed.\r\n\r\n" +
$"Target: {target}\r\n" +
$"Exported driver packages: {infCount}\r\n\r\n" +
@@ -94,7 +132,7 @@ namespace Flyoobe
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return null;
return null; // returning null indicates no further action needed
}
}
}
+1 -1
View File
@@ -282,7 +282,7 @@ namespace Flyoobe
return null;
}
// Selects the provider in the combo (for UI consistency) and runs it via existing pipeline.
// Selects the provider in the combo (for UI consistency) and runs it via existing pipeline
private async System.Threading.Tasks.Task RunQuickAsync(string providerId)
{
var p = FindProviderById(providerId);
+1
View File
@@ -35,6 +35,7 @@ namespace Flyoobe
_navigator.RegisterView("Device", () => new DeviceControlView());
_navigator.RegisterView("Personalization", () => new PersonalizationControlView());
_navigator.RegisterView("Browser", () => new DefaultsControlView());
_navigator.RegisterView("AI", () => new AiControlView());
_navigator.RegisterView("Network", () => new NetworkControlView());
_navigator.RegisterView("Account", () => new AccountControlView());
_navigator.RegisterView("Apps", () => new AppsControlView());
+200
View File
@@ -0,0 +1,200 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
public class EsuEnrollmentHandler
{
/// <summary>
/// Keep Windows 10 secure until 2026 (Enroll in ESU) using abbodi1406's ConsumerESU scripts.
/// Downloads from GitHub if missing and executes.
/// </summary>
///
public static async Task HandleEnrollInESU()
{
string repoBase = "https://raw.githubusercontent.com/abbodi1406/ConsumerESU/master/";
string cmdFile = "Consumer_ESU_Enrollment_run.cmd";
string psFile = "Consumer_ESU_Enrollment.ps1";
string appDir = AppDomain.CurrentDomain.BaseDirectory;
string cmdPath = Path.Combine(appDir, cmdFile);
string psPath = Path.Combine(appDir, psFile);
// Ensure scripts exist (download if missing)
if (!File.Exists(cmdPath) || !File.Exists(psPath))
{
var confirm = MessageBox.Show(
"The ESU enrollment scripts are missing.\n\n" +
"They will be downloaded directly from GitHub (abbodi1406/ConsumerESU).\n\n" +
"Do you want to continue?",
"Download Scripts",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (confirm != DialogResult.Yes) return;
using (var wc = new WebClient())
{
try
{
if (!File.Exists(cmdPath))
await wc.DownloadFileTaskAsync(new Uri(repoBase + cmdFile), cmdPath);
if (!File.Exists(psPath))
await wc.DownloadFileTaskAsync(new Uri(repoBase + psFile), psPath);
}
catch (Exception ex)
{
MessageBox.Show("Failed to download ESU scripts:\n" + ex.Message,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
// Show parameter selection dialog
string esuArgs = "";
using (var dlg = new EsuParamDialog())
{
if (dlg.ShowDialog() != DialogResult.OK)
return;
esuArgs = dlg.SelectedParam;
if (dlg.AddProceed) esuArgs += " -Proceed";
}
// Confirm and run
var result = MessageBox.Show(
"This will launch the Consumer ESU Enrollment Tool with parameters:\n\n" +
esuArgs + "\n\nContinue?",
"Enroll in ESU",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
if (result != DialogResult.Yes) return;
try
{
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c \"" + cmdPath + "\" " + esuArgs,
WorkingDirectory = appDir,
UseShellExecute = true,
Verb = "runas" // run as admin
};
Process.Start(psi);
}
catch (Exception ex)
{
MessageBox.Show("Failed to run ESU enrollment script:\n" + ex.Message,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Dialog form to select ESU enrollment parameter (no-designer)
/// </summary>
private class EsuParamDialog : Form
{
private ComboBox combo;
private CheckBox chkProceed;
private Button btnOk;
private Button btnCancel;
private LinkLabel link;
public string SelectedParam { get; private set; }
public bool AddProceed { get; private set; }
public EsuParamDialog()
{
Text = "Select ESU Enrollment Parameter";
Width = 550;
Height = 250;
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowIcon = false;
ShowInTaskbar = false;
combo = new ComboBox
{
Left = 20,
Top = 20,
Width = 500,
DropDownStyle = ComboBoxStyle.DropDownList
};
combo.Items.AddRange(new object[]
{
"-Online : Only enroll using Microsoft user account token (exit if failed)",
"-Store : Only enroll using Microsoft store account token (exit if failed)",
"-Local : Only enroll using Local user account token (exit if failed)",
"-License : Force acquire Consumer ESU License regardless or without enrollment",
"-Remove : Remove Consumer ESU License if exists"
});
combo.SelectedIndex = 0;
chkProceed = new CheckBox
{
Left = 20,
Top = 60,
Text = "Add -Proceed (force running enrollment even if already enrolled)",
AutoSize = true
};
btnOk = new Button
{
Text = "OK",
Left = 340,
Width = 80,
Top = 150,
DialogResult = DialogResult.OK
};
btnCancel = new Button
{
Text = "Cancel",
Left = 430,
Width = 80,
Top = 150,
DialogResult = DialogResult.Cancel
};
link = new LinkLabel
{
Left = 20,
Top = 100,
AutoSize = true,
Text = "Help && Credits: https://github.com/abbodi1406/ConsumerESU"
};
link.LinkClicked += (s, e) =>
{
try { Process.Start(new ProcessStartInfo { FileName = "https://github.com/abbodi1406/ConsumerESU", UseShellExecute = true }); }
catch { }
};
Controls.Add(combo);
Controls.Add(chkProceed);
Controls.Add(link);
Controls.Add(btnOk);
Controls.Add(btnCancel);
AcceptButton = btnOk;
CancelButton = btnCancel;
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (DialogResult == DialogResult.OK)
{
// Extract only the switch (first word, e.g. "-Online")
SelectedParam = combo.SelectedItem.ToString().Split(' ')[0];
AddProceed = chkProceed.Checked;
}
base.OnClosing(e);
}
}
}
+3 -76
View File
@@ -403,81 +403,6 @@ try {{
}
}
/// <summary>
/// Keep Windows 10 secure until 2026 (Enroll in ESU) using abbodi1406's ConsumerESU scripts.
/// Downloads from GitHub if missing and executes.
/// </summary>
public async void HandleEnrollInESU()
{
string repoBase = "https://raw.githubusercontent.com/abbodi1406/ConsumerESU/master/";
string cmdFile = "Consumer_ESU_Enrollment_run.cmd";
string psFile = "Consumer_ESU_Enrollment.ps1";
string appDir = AppDomain.CurrentDomain.BaseDirectory;
string cmdPath = Path.Combine(appDir, cmdFile);
string psPath = Path.Combine(appDir, psFile);
// Check if scripts exist, otherwise download
if (!System.IO.File.Exists(cmdPath) || !System.IO.File.Exists(psPath))
{
var confirm = MessageBox.Show(
"The ESU enrollment scripts are missing.\n\n" +
"They will now be downloaded directly from GitHub (abbodi1406/ConsumerESU).\n\n" +
"Do you want to continue?",
"Download Scripts",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (confirm != DialogResult.Yes)
return;
using (var wc = new System.Net.WebClient())
{
try
{
if (!System.IO.File.Exists(cmdPath))
await wc.DownloadFileTaskAsync(new Uri(repoBase + cmdFile), cmdPath);
if (!System.IO.File.Exists(psPath))
await wc.DownloadFileTaskAsync(new Uri(repoBase + psFile), psPath);
}
catch (Exception ex)
{
MessageBox.Show("Failed to download ESU scripts:\n" + ex.Message,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
var result = MessageBox.Show(
"📦 This will now launch the Consumer ESU Enrollment Tool by abbodi1406.\n\n" +
"✔ Extends Windows 10 support until October 2026\n" +
"✔ Requires Windows 10 22H2 with KB5039299+ (19045.4598+)\n" +
"✔ Requires Microsoft Account + Internet access\n\n" +
"Do you want to continue?",
"Enroll in ESU",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
if (result != DialogResult.Yes)
return;
// Start the .cmd (which internally calls the PowerShell)
try
{
Process.Start(new ProcessStartInfo
{
FileName = cmdPath,
Verb = "runas",
UseShellExecute = true
});
}
catch (Exception ex)
{
MessageBox.Show("Failed to run ESU enrollment script:\n" + ex.Message,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Handle unexpected exceptions by logging the error, updating the status, and optionally launching Copilot for help.
@@ -508,6 +433,7 @@ try {{
CopilotHelper.LaunchCopilot();
}
}
}
public static class ProcessExtensions
@@ -520,4 +446,5 @@ try {{
await tcs.Task;
}
}
}
}
+2 -2
View File
@@ -48,7 +48,7 @@ namespace Flyoobe
var combo = sender as ComboBox;
int selectedIndex = combo.SelectedIndex;
// Let user pick ISO from local disk (compatibility check is now in HandleIsoInput)
// Pick ISO from local disk (compatibility check is now in HandleIsoInput)
if (selectedIndex == 1)
{
await HandleIsoInput(sender, null);
@@ -63,7 +63,7 @@ namespace Flyoobe
break;
case 3:
_isoHandler.HandleEnrollInESU();
await EsuEnrollmentHandler.HandleEnrollInESU();
break;
}
}