Skip to content

Instantly share code, notes, and snippets.

@scriptingstudio
Last active July 10, 2026 12:29
Show Gist options
  • Select an option

  • Save scriptingstudio/00ddd4d7e6da555146a23f31ab8a6517 to your computer and use it in GitHub Desktop.

Select an option

Save scriptingstudio/00ddd4d7e6da555146a23f31ab8a6517 to your computer and use it in GitHub Desktop.
Ps2exe.NET
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Management;
using System.Management.Automation;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
// Insipred by and credits to Win-PS2EXE by Markus Scholts (https://github.com/MScholtes/PS2EXE/tree/master/Win-PS2EXE)
namespace ps2exedotnet
{
public class UserOptions
{
// input objects
public string inputscript = "";
public string outputfile = ""; // folder/file
public string iconfile = "";
public string embedfiles = ""; // dictionary array
// metadata
public string fileversion = ""; // n.n.n.n
public string title = "";
public string description = "";
public string product = "";
public string company = "";
public string copyright = "";
public string trademark = "";
public string locale = ""; // numeric
// runtime options
public string platform = "";
public bool mta;
public bool encrypt; // experimental
public bool nocompress;
public bool basic;
public bool noconsole;
public bool nooutput;
public bool conhost;
public bool noerror;
public bool admin;
public bool unicode;
public bool configfile;
public bool longpaths;
public bool supportos;
public bool credgui;
public bool exitoncancel;
public bool virt;
public bool novisualstyles;
public bool dpi;
public bool winformsdpi;
public bool preparedebug;
public bool raw; // experimental
public bool run;
public bool pshost; // experimental
public bool openfolder; // experimental
public bool core; // experimental
public bool arm; // experimental
public string dotnetplatform = "w"; // experimental
} // UserOptions
//enum paramset {None,All,Gui,Console,User}
// Interaction logic for MainWindow.xaml
public partial class MainWindow : Window
{
private static bool disableListEvent = false; // Resolve_Dependency' semaphore for checkboxes
private static bool groupSelection = false; // Resolve_Dependency' semaphore for listbox
//private static string usersettings = Environment.CurrentDirectory + @"\ps2exedotnet.ini";
public MainWindow()
{
InitializeComponent();
//Set_localeMenu();
// Set the width of the command buttons evenly across the width of the button bar; experimental
/*Window pWindow = (Window)Find_ParentWindow();
if (pWindow == null) return;
StackPanel cmdBar = (StackPanel)pWindow.FindName("ButtonBar");
int i = 0;
foreach (Button btn in cmdBar.Children) {
if (i == 0) {
btn.Margin = new Thickness(0, 0, 0, 0);
} else {
btn.Margin = new Thickness(16, 0, 0, 0);
}
i++;
}*/
//MessageBox.Show("StackPanel width: "+cmdBar.ActualWidth , "Run", MessageBoxButton.OK, MessageBoxImage.Information);
}
//private static void Update_StatusBar(object sender) {} // Update_StatusBar
//???private static void Start_progress() {} // Start_progress
//private static void Set_localeMenu() {} // Set_localeMenu
private static void Start_CompiledApp()
{
Window pWindow = (Window)Find_ParentWindow();
if (pWindow == null) return;
TextBox userTargetFile = (TextBox)pWindow.FindName("TargetFile");
string tgt = userTargetFile.Text;
if (tgt != "") tgt = tgt.Trim();
if (tgt != "")
{
if (System.IO.Directory.Exists(tgt))
{
TextBox userSourceFile = (TextBox)pWindow.FindName("SourceFile");
string src = userSourceFile.Text;
if (src != "") src = src.Trim();
if (src == "")
MessageBox.Show("Target file not specified", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
else
{
string targetexe = System.IO.Path.Combine(tgt, System.IO.Path.GetFileNameWithoutExtension(src)) + ".exe";
if (System.IO.File.Exists(targetexe)) Process.Start(targetexe);
else MessageBox.Show("Target 'exe' file not found", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
else
{
MessageBox.Show("Target 'exe' file not found", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
else
{
TextBox userSourceFile = (TextBox)pWindow.FindName("SourceFile");
string src = userSourceFile.Text;
if (src != "") src = src.Trim();
if (src == "")
MessageBox.Show("Target file not specified", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
else
{
string targetexe = System.IO.Path.ChangeExtension(src,"exe");
if (System.IO.File.Exists(targetexe)) Process.Start(targetexe);
else MessageBox.Show("Target 'exe' file not found", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
} // Start_CompiledApp
private void Start_help()
{
// TODO: prevent multiple help windows open; list subprocesses or check slave windows
HelpWindow helpWindow = new HelpWindow(){Owner = this};
helpWindow.Show();
} // Start_help
// Validate, test, convert
private static bool Confirm_Parameters(ref UserOptions options) {
if (null == options) return false;
// Test files
if (!string.IsNullOrEmpty(options.inputscript) && !System.IO.File.Exists(options.inputscript))
{
MessageBox.Show("The source file not found", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
if (!string.IsNullOrEmpty(options.outputfile) && !System.IO.Directory.Exists(options.outputfile))
{ // it's a file
if (!Regex.IsMatch(options.outputfile, @"\.exe$")) // test extension
{
MessageBox.Show("Output file must have '.exe' extension", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
// test parent directory
string parent = System.IO.Path.GetDirectoryName(options.outputfile);
if (!System.IO.Directory.Exists(parent))
{
MessageBox.Show("The output directory not found", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
if (!string.IsNullOrEmpty(options.inputscript) &&
!string.IsNullOrEmpty(options.outputfile) &&
options.outputfile == options.inputscript)
{
MessageBox.Show("Input and output filenames cannot be the same", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
if (!string.IsNullOrEmpty(options.iconfile) && !System.IO.File.Exists(options.iconfile))
{
MessageBox.Show("Icon file not found", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
// Test version value; regex looks ugly coz system.version cannot parse a single int
/*if (!string.IsNullOrEmpty(options.fileversion))
{
if (Regex.IsMatch(options.fileversion, @"\.\.")) options.fileversion = options.fileversion.Replace("..",".0.").Replace("..",".0.");
if (Regex.IsMatch(options.fileversion, @"\.$")) options.fileversion += "0";
if (!Regex.IsMatch(options.fileversion, @"\.")) options.fileversion += ".0";
}*/
if (!string.IsNullOrEmpty(options.fileversion) &&
!Regex.IsMatch(options.fileversion, @"^\d+\.\d+\.\d+\.\d+$|^\d+\.\d+\.\d+$|^\d+\.\d+$|^\d+$"))
{
MessageBox.Show("Invalid version specified. Valid version format is n.n.n.n, n.n.n, n.n, or n ('n' is numeric val)", "Confirm", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
if (!string.IsNullOrEmpty(options.locale))
{
//int x;out int x
if (!int.TryParse(options.locale, out _))
{
MessageBox.Show("Parameter 'Locale' must be numeric", "CoConfirmmpile", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
return true;
} // Confirm_Parameters
// Collects all user parameters in struct
private static UserOptions Get_Parameters(bool nocheck=false)
{
Window pWindow = (Window)Find_ParentWindow();
if (pWindow == null) return null;
UserOptions userparam = new UserOptions();
TextBox userSourceFile = (TextBox)pWindow.FindName("SourceFile");
userparam.inputscript = userSourceFile.Text;
if (userparam.inputscript != "") userparam.inputscript = userSourceFile.Text.Trim();
if (userparam.inputscript == "")
{
MessageBox.Show("Source file not specified", "Compile", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
TextBox userTargetFile = (TextBox)pWindow.FindName("TargetFile");
userparam.outputfile = userTargetFile.Text;
if (userparam.outputfile != "") userparam.outputfile = userTargetFile.Text.Trim();
if (userparam.outputfile == "") userparam.outputfile = System.IO.Path.GetDirectoryName(userparam.inputscript);
if (System.IO.Directory.Exists(userparam.outputfile))
{ // if directory then append source file name
userparam.outputfile = System.IO.Path.Combine(userparam.outputfile, System.IO.Path.GetFileNameWithoutExtension(userparam.inputscript)) + ".exe";
}
else if (!System.IO.File.Exists(System.IO.Path.GetDirectoryName(userparam.outputfile)))
MessageBox.Show("Output directory does not exist", "Compile", MessageBoxButton.OK, MessageBoxImage.Error);
TextBox tb = (TextBox)pWindow.FindName("EmbedFiles");
if (tb.Text != "") userparam.embedfiles = tb.Text.Trim();
tb = (TextBox)pWindow.FindName("IconFile");
if (tb.Text != "") userparam.iconfile = tb.Text.Trim();
tb = (TextBox)pWindow.FindName("FileVersion");
if (tb.Text != "") userparam.fileversion = tb.Text.Trim();
else userparam.fileversion = "0.0.0.0";
tb = (TextBox)pWindow.FindName("FileDescription");
if (tb.Text != "") userparam.description = tb.Text.Trim();
tb = (TextBox)pWindow.FindName("ProductName");
if (tb.Text != "") userparam.product = tb.Text.Trim();
tb = (TextBox)pWindow.FindName("Copyright");
if (tb.Text != "") userparam.copyright = tb.Text.Trim();
tb = (TextBox)pWindow.FindName("Locale");
if (tb.Text != "") userparam.locale = tb.Text.Trim();
CheckBox cb = (CheckBox)pWindow.FindName("NoConsole");
userparam.noconsole = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("NoOutput");
userparam.nooutput = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("NoError");
userparam.noerror = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("RequireAdmin");
userparam.admin = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("ConfigFile");
userparam.configfile = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("MTA");
userparam.mta = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("ConHost");
userparam.conhost = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("Unicode");
userparam.unicode = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("LongPaths");
userparam.longpaths = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("SupportOS");
userparam.supportos = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("CredentialGUI");
userparam.credgui = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("ExitOnCancel");
userparam.exitoncancel = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("Virtualize");
userparam.virt = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("NoVisualStyles");
userparam.novisualstyles = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("DPIAware");
userparam.dpi = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("WinFormsDPIAware");
userparam.winformsdpi = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("PrepareDebug");
userparam.preparedebug = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("NoCompress");
userparam.nocompress = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("Basic");
userparam.basic = cb.IsChecked.Value;
cb = (CheckBox)pWindow.FindName("Run");
userparam.run = cb.IsChecked.Value;
//cb = (CheckBox)pWindow.FindName("PSHost"); // ????
//userparam.pshost = cb.IsChecked.Value;
//cb = (CheckBox)pWindow.FindName("Encrypt"); // experimental; TBD
//userparam.encrypt = cb.IsChecked.Value;
//cb = (CheckBox)pWindow.FindName("OpenFolder"); // experimental
//userparam.openfolder = cb.IsChecked.Value;
ComboBox cob = (ComboBox)pWindow.FindName("Platform");
userparam.platform = ((ComboBoxItem)cob.SelectedItem).Content.ToString();
return userparam;
} // Get_Parameters
private bool Test_ParamState() // experimental
{
Window pWindow = (Window)Find_ParentWindow();
if (pWindow == null) return true;
bool dirty = true;
string[] param = new[] {"SourceFile","TargetFile","EmbedFiles","IconFile","FileVersion","FileDescription","ProductName","Copyright","Locale"};
foreach (string p in param)
{
TextBox tb = (TextBox)pWindow.FindName(p);
if (tb.Text != "") dirty = false;
}
return dirty;
} // Test_ParamState
// Helper that "climbs up" the parent object chain from a window object until the root window object is reached
private static FrameworkElement Find_ParentWindow(object sender = null)
{
if (null == sender) return Application.Current.MainWindow;
FrameworkElement GUIControl = (FrameworkElement)sender;
while ((GUIControl.Parent != null) && (GUIControl.GetType() != typeof(MainWindow)))
{
GUIControl = (FrameworkElement)GUIControl.Parent;
}
if (GUIControl.GetType() == typeof(MainWindow)) return GUIControl;
return null;
} // Find_ParentWindow
private static FrameworkElement Find_Control(string name)
{
return Application.Current.MainWindow.FindName(name) as FrameworkElement;
} // Find_Control
private static void Resolve_param(CheckBox param)
{
disableListEvent = true; // prevent looping
Window pWindow = Application.Current.MainWindow;
CheckBox master = param;
CheckBox dependent;
if (master.Name == "WinFormsDPIAware" && master.IsChecked == true)
{
dependent = pWindow.FindName("SupportOS") as CheckBox;
if (dependent.IsChecked == false) dependent.IsChecked = true;
}
else if (master.Name == "ConfigFile" && master.IsChecked == false)
{
dependent = (CheckBox)pWindow.FindName("WinFormsDPIAware");
if (dependent.IsChecked == true) master.IsChecked = true;
}
else if (master.Name == "ConfigFile" && master.IsChecked == false)
{
dependent = (CheckBox)pWindow.FindName("LongPaths");
if (dependent.IsChecked == true) master.IsChecked = true;
}
else if (master.Name == "Basic" && master.IsChecked == true)
{
dependent = (CheckBox)pWindow.FindName("NoCompress");
if (dependent.IsChecked == true) master.IsChecked = false;
}
else if (master.Name == "NoCompress")
{ // mutual exclusion
dependent = (CheckBox)pWindow.FindName("Basic");
if (master.IsChecked == true)
{
if (dependent.IsChecked == true) dependent.IsChecked = false;
}
else
{
dependent.IsChecked = false; // resets prev state anyway
}
}
else if (master.Name == "MTA" && master.IsChecked == true)
{ // possible mutual exclusion
dependent = (CheckBox)pWindow.FindName("NoConsole");
if (dependent.IsChecked == true) dependent.IsChecked = false;
}
else if (master.Name == "NoConsole" && master.IsChecked == true)
{
dependent = (CheckBox)pWindow.FindName("MTA");
if (dependent.IsChecked == true) dependent.IsChecked = false;
dependent = (CheckBox)pWindow.FindName("ConHost");
if (dependent.IsChecked == true) master.IsChecked = false;
}
// Incompatibilities, mutual exclusions
else if (master.Name == "ConHost" && master.IsChecked == true)
{
dependent = (CheckBox)pWindow.FindName("NoConsole");
if (dependent.IsChecked == true) master.IsChecked = false;
}
disableListEvent = false;
} // Resolve_param
#region EVENT HANDLERS
// Parameter set selector handler
private void Parameter_Select(object sender, SelectionChangedEventArgs e)
{
e.Handled = true; // ???
if (!Regex.IsMatch(Parameters.SelectedValue.ToString(), @":")) return;
Window pWindow = Application.Current.MainWindow;
ComboBoxItem cbi = (sender as ComboBox).SelectedItem as ComboBoxItem;
string mode = cbi.Content.ToString();
if (mode == "<User>")
{ // abit overkill
List<string> selection = new List<string>();
foreach (CheckBox lbi in listParamSet.Items) {
if (lbi.IsChecked == true) selection.Add(lbi.Name);
}
if (0 == selection.Count) Parameters.SelectedIndex = 0;
else if (3 == selection.Count) Parameters.SelectedIndex = Regex.IsMatch(string.Join(" ", selection), @"(?=.*NoConsole)(?=.*NoError)(?=.*NoOutput)",RegexOptions.IgnoreCase) ? 3 : Parameters.Items.Count - 1;
return; // do nothing
}
groupSelection = true;
int selected = 0; // previous selection state
foreach (CheckBox lbi in listParamSet.Items) {
if (lbi.IsChecked == true) selected++;
if (mode == "None")
{
if (lbi.IsChecked == true) lbi.IsChecked = false;
if (lbi.IsEnabled == false) lbi.IsEnabled = true;
}
else if (mode == "All")
{
if (lbi.IsChecked == false) lbi.IsChecked = true;
Resolve_param(lbi);
}
else if (mode == "Inverse")
{
lbi.IsChecked = !lbi.IsChecked;
Resolve_param(lbi);
}
else if (mode == "GUI App")
{
if (lbi.Name == "NoConsole")
{
CheckBox cb = (CheckBox)pWindow.FindName("ConHost");
if (cb.IsChecked == true) cb.IsChecked = false;
lbi.IsChecked = true;
}
else if (Regex.IsMatch(lbi.Name,"^NoOutput|^NoError")) lbi.IsChecked = true;
else if (lbi.IsChecked == true) lbi.IsChecked = false;
if (lbi.IsEnabled == false) lbi.IsEnabled = true;
}
} // foreach
// synchronize controls
if (mode == "Inverse")
{
if (selected == listParamSet.Items.Count)
{
Parameters.SelectedIndex = 0; // none
}
else if (selected == 0)
{
Parameters.SelectedIndex = 1; // all
}
else Parameters.SelectedIndex = Parameters.Items.Count - 1; // user
}
else if (mode == "GUI App") // uncheck leftovers
{
if (selected != 0)
{
CheckBox cb = (CheckBox)pWindow.FindName("ConfigFile");
cb.IsChecked = false;
}
}
listParamSet.UnselectAll();
groupSelection = false;
} // Parameter_Select
// Parameter checkbox preview handler
private void Resolve_Dependency(object sender, MouseButtonEventArgs e)
{
// NOTE/PROBLEM: too confusing logics; not complete yet
// CAUTION: make sure there is no looping
if (e.Source.GetType().Name != "CheckBox") return;
//Window pWindow = (Window)Find_ParentWindow();
//if (pWindow == null) return;
Window pWindow = Application.Current.MainWindow;
List<string> msg = new List<string>();
CheckBox master = (CheckBox)e.Source;
CheckBox dependent;
if (master.Name == "WinFormsDPIAware" && master.IsChecked == true)
{
dependent = pWindow.FindName("SupportOS") as CheckBox;
if (dependent.IsChecked == false) dependent.IsChecked = true;
}
else if (master.Name == "ConfigFile" && master.IsChecked != false)
{
dependent = (CheckBox)pWindow.FindName("WinFormsDPIAware");
if (dependent.IsChecked == true) e.Handled = true;
}
else if (master.Name == "ConfigFile" && master.IsChecked != false)
{
dependent = (CheckBox)pWindow.FindName("LongPaths");
if (dependent.IsChecked == true) e.Handled = true;
}
else if (master.Name == "MTA" && master.IsChecked == true)
{ // possible mutual exclusion
dependent = (CheckBox)pWindow.FindName("NoConsole");
if (dependent.IsChecked == true) dependent.IsChecked = false;
}
else if (master.Name == "NoConsole" && master.IsChecked != true)
{
dependent = (CheckBox)pWindow.FindName("MTA");
if (dependent.IsChecked == true) dependent.IsChecked = false;
dependent = (CheckBox)pWindow.FindName("ConHost");
if (dependent.IsChecked == true)
{
e.Handled = true;
msg.Add("'noConsole' cannot be used with 'conHost'");
}
}
// Incompatibilities, mutual exclusions
else if (master.Name == "ConHost" && master.IsChecked != true)
{
dependent = (CheckBox)pWindow.FindName("NoConsole");
if (dependent.IsChecked == true)
{
e.Handled = true;
msg.Add("'noConsole' cannot be used with 'conHost'");
}
}
else if (master.Name == "NoCompress" && master.IsChecked != true)
{ // mutual exclusion
dependent = (CheckBox)pWindow.FindName("Basic");
if (dependent.IsChecked == true) dependent.IsChecked = false;
}
else if (master.Name == "Basic" && master.IsChecked != true)
{ // mutual exclusion
dependent = (CheckBox)pWindow.FindName("NoCompress");
if (dependent.IsChecked == true)
{
e.Handled = true;
msg.Add("'Basic' cannot be used with 'NoCompress'\nDeactivate 'NoCompress' first");
}
}
// WHAT IS IT?????
/*else if (master.Name == " " && master.IsChecked != true)
{ // possible looping
dependent = (CheckBox)pWindow.FindName("LongPaths");
if (dependent.IsChecked == true)
{
e.Handled = true;
}
dependent = (CheckBox)pWindow.FindName("SupportOS");
if (dependent.IsChecked == true)
{
e.Handled = true;
}
dependent = (CheckBox)pWindow.FindName("RequireAdmin");
if (dependent.IsChecked == true)
{
e.Handled = true;
}
}*/
if (msg.Count > 0 && !groupSelection)
MessageBox.Show("Multiple conflicts found:\r\n" + string.Join("\r\n", msg), "Resolve dependency", MessageBoxButton.OK, MessageBoxImage.Error);
} // Resolve_Dependency
// Parameter checkbox handler
private void List_Check(object sender, RoutedEventArgs e)
{
if (disableListEvent) return;
// synchronize controls
List<string> selected = new List<string>();
foreach (CheckBox lbi in listParamSet.Items) {
if (lbi.IsChecked == true) selected.Add(lbi.Name);
}
if (selected.Count == 0) Parameters.SelectedIndex = 0; // none
else if (selected.Count == listParamSet.Items.Count) Parameters.SelectedIndex = 1; // all
else if (selected.Count == 3)
Parameters.SelectedIndex = Regex.IsMatch(string.Join(" ",selected), @"(?=.*NoConsole)(?=.*NoError)(?=.*NoOutput)",RegexOptions.IgnoreCase) ? 3 : Parameters.Items.Count - 1;
else Parameters.SelectedIndex = Parameters.Items.Count - 1; // user
} // List_Check
// Command button click
public void Button_Click(object sender, RoutedEventArgs e)
{
// event is handled afterwards
e.Handled = true;
// retrieve window parent object
Window pWindow = (Window)Find_ParentWindow(sender);
if (pWindow == null) return; // is this possible?
if (((Button)sender).Name == "AppClose")
{ // button "Close" -> close application
if (Test_ParamState() || MessageBox.Show("There are changed fields.\r\nAre you sure you want to exit?", "Close", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
pWindow.Close();
}
else if (((Button)sender).Name == "CmdRun") Start_CompiledApp();
else if (((Button)sender).Name == "AppHelp") Start_help(); // experimental
else if (((Button)sender).Name == "HelpClose") {}
//else if (((Button)sender).Name == "AddParam") {} // TODO; experimental
else
{ // button "Compile" -> call Ps2Exe
UserOptions uo = Get_Parameters();
if (Confirm_Parameters(ref uo)) Ps2Exe.Ps2Exe.Invoke_Ps2Exe(uo);
}
} // Button_Click
// Click on file picker button ("...")
private void FilePicker_Click(object sender, RoutedEventArgs e)
{
// retrieve window parent object
Window pWindow = (Window)Find_ParentWindow(null);
if (pWindow == null) return;
if (((Button)sender).Name != "TargetFilePicker")
{
// create OpenFileDialog control
Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog
{
Title = "Select File"
};
// set file extension filters
if (((Button)sender).Name == "SourceFilePicker")
{ // button to TextBox "SourceFile"
dialog.DefaultExt = ".ps1";
dialog.Filter = "PS1 Files (*.ps1)|*.ps1|All Files (*.*)|*.*";
if (SourceFile.Text != "" && System.IO.Directory.Exists(SourceFile.Text))
dialog.InitialDirectory = SourceFile.Text;
}
else if (((Button)sender).Name == "EmbedFilePicker") dialog.Filter = "All Files (*.*)|*.*";
else
{ // button to TextBox "IconFile"
dialog.DefaultExt = ".ico";
dialog.Filter = "Icon Files (*.ico)|*.ico|All Files (*.*)|*.*";
if (TargetFile.Text != "" && System.IO.Directory.Exists(TargetFile.Text))
dialog.InitialDirectory = TargetFile.Text;
}
// display file picker dialog
Nullable<bool> result = dialog.ShowDialog();
// file selected?
if (result.HasValue && result.Value)
{ // fill Texbox with file name
if (((Button)sender).Name == "SourceFilePicker")
{ // button to TextBox "SourceFile"
TextBox userSourceFile = (TextBox)pWindow.FindName("SourceFile");
userSourceFile.Text = dialog.FileName;
}
else if (((Button)sender).Name == "EmbedFilePicker")
{ // TODO
TextBox embedFile = (TextBox)pWindow.FindName("EmbedFiles");
string tmpd = System.IO.Path.GetTempPath() + System.IO.Path.GetFileName(dialog.FileName);
string fn = string.Format("\"{0}\"=\"{1}\"",tmpd,dialog.FileName);
if (embedFile.Text == "") embedFile.Text = fn;
else embedFile.Text = string.Join(";",embedFile.Text,fn);
}
else
{ // button to TextBox "IconFile"
TextBox userIconFile = (TextBox)pWindow.FindName("IconFile");
userIconFile.Text = dialog.FileName;
}
}
}
else
{ // use custom dialog for folder selection because there is no WPF folder dialog!!!
TextBox userTargetFile = (TextBox)pWindow.FindName("TargetFile");
// create OpenFolderDialog control
OpenFolderDialog.OpenFolderDialog dialog = new OpenFolderDialog.OpenFolderDialog();
if (userTargetFile.Text != "")
{ // set starting directory for folder picker
if (System.IO.Directory.Exists(userTargetFile.Text))
dialog.InitialFolder = userTargetFile.Text;
else
dialog.InitialFolder = System.IO.Path.GetDirectoryName(userTargetFile.Text);
}
else
{ // set starting directory to Documents
TextBox userSourceFile = (TextBox)pWindow.FindName("SourceFile");
if (userSourceFile.Text != "" && System.IO.File.Exists(userTargetFile.Text))
{
dialog.InitialFolder = System.IO.Path.GetDirectoryName(userSourceFile.Text);
}
else
dialog.InitialFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
// display folder picker dialog
System.Windows.Interop.WindowInteropHelper windowHwnd = new System.Windows.Interop.WindowInteropHelper(this);
Nullable<bool> result = dialog.ShowDialog(windowHwnd.Handle);
if (result.HasValue && result == true)
{ // get result only if a folder was selected
userTargetFile.Text = dialog.Folder;
}
}
} // FilePicker_Click
// "empty" drag handler
private void TextBox_PreviewDragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.All;
e.Handled = true;
}
// Drop handler: insert filename to textbox
private void TextBox_PreviewDrop(object sender, DragEventArgs e)
{
object userText = e.Data.GetData(DataFormats.FileDrop);
TextBox tb = sender as TextBox;
if (tb != null && userText != null)
{
//tb.Text = string.Format("{0}",((string[])userText)[0]);
tb.Text = ((string[])userText)[0];
}
} // FilePicker_Click
// Remove focus/selection/content from a control; experimental
private void Window_KeyDown(object sender, KeyEventArgs e)
{
Window pWindow = Application.Current.MainWindow;
if (e.Key == Key.Escape)
{
e.Handled = true;
ListBox lparam = (ListBox)pWindow.FindName("listParamSet");
if (lparam.IsMouseOver) lparam.UnselectAll();
if (e.Source.GetType().Name == "TextBox")
{
TextBox tb = e.Source as TextBox;
if (tb.IsMouseOver && !string.IsNullOrEmpty(tb.Text)) tb.Clear();
}
//FrameworkElement GUIControl = (FrameworkElement)sender; //Find_Children
//GUIControl.LogicalChildren
FocusManager.SetFocusedElement(this, this);
}
//else if (e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.S)
// Export_UserSettings();
} // Window_KeyDown
// Remove focus when clicking outside of a textbox
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
FocusManager.SetFocusedElement(this, this);
}
/*private void Textbox_clear(object sender, MouseButtonEventArgs e)
{
var focusedElement = FocusManager.GetFocusedElement(this);
if (focusedElement is TextBox tbox && !string.IsNullOrEmpty(tbox.Text)) tbox.Text = "";
}*/
#endregion EVENT HANDLERS
} // MainWindow
} // ps2exedotnet
namespace Ps2Exe
{
public class Ps2Exe
{
public static void Invoke_Ps2Exe(ps2exedotnet.UserOptions parameters)
{
if (null == parameters) return;
if (!Test_parameters(parameters)) return;
// Generate compiler options -- https://learn.microsoft.com/en-us/dotnet/api/system.codedom.compiler.compilerparameters?view=windowsdesktop-10.0
string[] alist = Add_assembly(parameters);
CompilerParameters compilerparam = new CompilerParameters(alist, parameters.outputfile)
{
GenerateInMemory = false,
GenerateExecutable = true
};
// Compiler command line parameters
string platform = parameters.platform;
string target = "exe";
if (parameters.noconsole || parameters.conhost) target = "winexe";
string manifestParam = null;
if (parameters.admin || parameters.dpi || parameters.supportos || parameters.longpaths) {
manifestParam = string.Format("/win32manifest:{0}.win32manifest", parameters.outputfile);
Export_manifest(parameters, "win32");
}
if (parameters.virt) {
platform = "x86";
manifestParam = "/nowin32manifest";
}
string iconFileParam = null;
if (parameters.iconfile != "") iconFileParam = string.Concat("/win32icon:",parameters.iconfile);
string optimizeParam = null;
if (!parameters.preparedebug) optimizeParam = "/optimize+";
compilerparam.CompilerOptions = string.Format("/platform:{0} /target:{1} {2} {3} {4}",platform,target,optimizeParam,iconFileParam,manifestParam).TrimEnd();
// Debug settings
compilerparam.IncludeDebugInformation = parameters.preparedebug;
if (parameters.preparedebug) compilerparam.TempFiles.KeepFiles = true;
// Create compiler
// generic dictionary type needed for CSharpCodeProvider
Dictionary<string,string> dict = Activator.CreateInstance<Dictionary<string,string>>();
//////Dictionary<string, string> dict = new Dictionary<string, string>();
dict["CompilerVersion"] = "v4.0";
CSharpCodeProvider csprov = new Microsoft.CSharp.CSharpCodeProvider(dict);
string csframe = Get_MainProgramSource(parameters, ref compilerparam);
if (csframe.Length < 5) return;
/*if (parameters.pshost) { // experimental
string fn1 = System.IO.Path.ChangeExtension(parameters.outputfile, "cs");
System.IO.File.WriteAllLines(fn, new[] { csframe }, Encoding.UTF8);
MessageBox.Show("PS host exported", "Compile", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}*/
CompilerResults cresult = csprov.CompileAssemblyFromSource(compilerparam, csframe);
if (cresult.Errors.Count > 0)
{
MessageBox.Show("Compile failed", "Compile", MessageBoxButton.OK, MessageBoxImage.Error);
if (System.IO.File.Exists(parameters.outputfile))
try {System.IO.File.Delete(parameters.outputfile);} catch {}
}
else
{
if (System.IO.File.Exists(parameters.outputfile)) {
MessageBox.Show("Compile is successful", "Compile", MessageBoxButton.OK, MessageBoxImage.Information);
if (parameters.configfile) Export_manifest(parameters, "exe3");
if (parameters.run)
{
if ((DateTime.Now - System.IO.File.GetLastWriteTime(parameters.outputfile)).TotalSeconds < 15) // just in case of compilation false positive
Process.Start(parameters.outputfile);
else
MessageBox.Show("The output file is likely old.\r\nRun compile again or click Run button", "Compile", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
else if (parameters.run) MessageBox.Show("Output file not found", "Run", MessageBoxButton.OK, MessageBoxImage.Error);
else MessageBox.Show("Output file not found", "Compile", MessageBoxButton.OK, MessageBoxImage.Error);
}
/*if (parameters.openfolder)
{
System.Diagnostics.Process.Start(@"c:\windows\explorer.exe", System.IO.Path.GetDirectoryName(parameters.outputfile));
//var psi = new ProcessStartInfo();
//psi.FileName = @"c:\windows\explorer.exe";
//psi.Arguments = folder;
//Process.Start(psi);
}*/
//try {System.IO.File.Delete(tempinputFile);} catch {}
if (parameters.preparedebug)
{
string fn = System.IO.Path.ChangeExtension(parameters.outputfile, "cs");
System.IO.File.WriteAllLines(fn, new[] { csframe }, Encoding.UTF8);
// NOTE: minified input script is exported in Get_sourcecontent
string dstSrc = parameters.raw ? Environment.CurrentDirectory : System.IO.Path.GetDirectoryName(parameters.outputfile);
IEnumerator tempfiles = cresult.TempFiles.GetEnumerator();
while (tempfiles.MoveNext())
{
string file = (string)tempfiles.Current;
if (Regex.IsMatch(file, @"\.cs$"))
{
System.IO.File.Copy(file, dstSrc);
System.IO.File.Delete(file);
}
}
}
if (parameters.admin || parameters.dpi || parameters.supportos || parameters.longpaths)
{
string fn = string.Concat(parameters.outputfile,".win32manifest");
if (System.IO.File.Exists(fn)) System.IO.File.Delete(fn);
}
} // Invoke_Ps2Exe
// partially duplicates Resolve_Dependency; fallback for the case of inability to resolve parameter conflicts
private static bool Test_parameters(ps2exedotnet.UserOptions options)
{
List<string> msg = new List<string>();
if (options.conhost && options.noconsole)
{
msg.Add("'noConsole' cannot be used with 'conHost'");
}
if (options.virt)
{
if (options.longpaths)
msg.Add("'longPaths' cannot be used with 'virtualize'");
if (options.supportos)
msg.Add("'supportOS' cannot be used with 'virtualize'");
if (options.admin)
msg.Add("'requireAdmin' cannot be used with 'virtualize'");
}
if (msg.Count > 0)
{
MessageBox.Show("Multiple conflicts found:\r\n" + string.Join("\r\n", msg), "Test Parameters", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
return true;
} // Test_parameters
private static string Compress_PSscriptblock(string scriptstring, bool basic=false)
{
if (scriptstring == "") return "";
//System.Collections.ObjectModel.
Collection<System.Management.Automation.PSParseError> psperrors = null;
Collection<PSToken> tokens = System.Management.Automation.PSParser.Tokenize(scriptstring, out psperrors); //.Where(t => t.Type != PSTokenType.Comment || Regex.IsMatch(t.Content, @"^#Requires",RegexOptions.IgnoreCase));
if (null == tokens || tokens.Count == 0) return scriptstring;
// https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pstoken.type?view=powershellsdk-7.4.0#system-management-automation-pstoken-type
// Parse options
int currentColumn = 1; // script line cursor
bool newLine = false; // sequential newlines semaphore
PSToken prevToken = null; // token cursor to look back
int tindex = 0; // token index to lookup ahead
int t1; // next token index
bool next;
Regex rxnewl = new Regex(@"^NewLine|^LineContin", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Regex rxhere = new Regex("^@['\"]", RegexOptions.Compiled);
Regex rxoper = new Regex(@"[,+=|/\$\-]", RegexOptions.Compiled);
Regex rxgroup = new Regex(@"Group[SE]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Regex rxtype = new Regex(@"GroupStart|NewLine|LineContin|Statement", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Regex funckey = new Regex("^funct", RegexOptions.Compiled | RegexOptions.IgnoreCase);
StringBuilder sb = new StringBuilder();
foreach (PSToken currentToken in tokens)
{
// Filter comments except #Requires instruction
if (currentToken.Type == PSTokenType.Comment && !Regex.IsMatch(currentToken.Content, @"^#Requires", RegexOptions.IgnoreCase)) {tindex++; continue;}
if (rxnewl.IsMatch(currentToken.Type.ToString())) {
currentColumn = 1;
// Handle newlines. Sequential newlines are ignored in order to save space
if (!newLine)
{
if (basic) sb.Append(Environment.NewLine);
else {
t1 = tindex + 1;
next = t1 < tokens.Count;
// TODO: 1) ignore newline on condition; 2) insert StatementSeparator (;)
if (prevToken != null && rxtype.IsMatch(prevToken.Type.ToString())) {}
else if (next && tokens[t1].Type == PSTokenType.GroupEnd) {} //13=GroupEnd
else if (next && funckey.IsMatch(tokens[t1].Content)) {}
else if (prevToken.Type == PSTokenType.StatementSeparator) {}
else if (prevToken.Content == ")" && next && tokens[t1].Content == "{") {}
//else if (next && tokens[t1].Type == PSTokenType.Variable && !rxgroup.IsMatch(prevToken.Type.ToString())) sb.Append(';');
//?else if (prevToken.Type == PSTokenType.GroupEnd && currentToken.Type != PSTokenType.Keyword) sb.Append(';');
else if (prevToken.Type == PSTokenType.Command) sb.Append(';');
else if (prevToken.Type == PSTokenType.CommandParameter) sb.Append(' ');
else sb.Append(Environment.NewLine);
}
}
newLine = true;
}
else {
newLine = false;
// Handle any indenting
if (currentColumn < currentToken.StartColumn)
{
// Handle spaces in between tokens on the same line
// TODO: ignore extra spaces on condition
if (currentColumn != 1)
{
if (basic) sb.Append(' ');
else {
if (currentToken.Type == PSTokenType.Operator && rxoper.IsMatch(currentToken.Content)) {} //11=Operator
else if (prevToken.Type == PSTokenType.Operator && rxoper.IsMatch(prevToken.Content)) {}
else if (rxgroup.IsMatch(currentToken.Type.ToString()) || prevToken.Type == PSTokenType.StatementSeparator) {} //16=StatementSeparator
else if (currentToken.Type == PSTokenType.Keyword && currentToken.Content != "in") {} //14=keyword
else sb.Append(' ');
}
}
}
string tokenBody = scriptstring.Substring(currentToken.Start,currentToken.Length);
bool herestring = currentToken.Type == PSTokenType.String && rxhere.IsMatch(tokenBody);
// Handle multi-line strings 5=String
if (!herestring && currentToken.Type == PSTokenType.String && currentToken.EndLine > currentToken.StartLine) {
sb.Append(tokenBody.Replace(Environment.NewLine,""));
}
else { // Write out a regular token
sb.Append(tokenBody);
}
// Update current position in the column
currentColumn = currentToken.EndColumn;
} // token type
prevToken = currentToken;
tindex++;
} // token iterator
return sb.ToString();
} // Compress_PSscriptblock
public static string Compress_text(string InputString)
{
if (string.IsNullOrEmpty(InputString)) return null;
string result;
using (var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(InputString)))
{
using (var compressedStream = new MemoryStream())
{
// Setting the leaveOpen parameter to true to ensure that compressedStream will not be closed when compressorStream is disposed
// This allows compressorStream to close and flush its buffers to compressedStream and guarantees that compressedStream.ToArray() can be called afterward
// Although MSDN documentation states that ToArray() can be called on a closed MemoryStream, we don't want to rely on that very odd behavior should it ever change
using (var compressorStream = new DeflateStream(compressedStream, CompressionLevel.Optimal, true))
{
uncompressedStream.CopyTo(compressorStream);
}
result = Convert.ToBase64String(compressedStream.ToArray());
} // compressedStream
} // uncompressedStream
return result;
} // Compress_text
public static string Expand_text(string InputString)
{
if (string.IsNullOrEmpty(InputString)) return null;
string result;
var compressedStream = new MemoryStream(Convert.FromBase64String(InputString));
using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
{
using (var decompressedStream = new MemoryStream())
{
decompressorStream.CopyTo(decompressedStream);
result = Encoding.UTF8.GetString(decompressedStream.ToArray());
}
}
return result;
} // Expand_text
private static string Create_embedFileSection(ps2exedotnet.UserOptions options, ref CompilerParameters cp)
{
if (options.embedfiles == "") return "";
StringBuilder sb = new StringBuilder();
int i = 0;
sb.Append("string tgtFile = string.Empty, tgtDir = string.Empty;" + Environment.NewLine);
// TODO: compress/expand embed files
List<string> errfile = new List<string>();
foreach (string el in options.embedfiles.Split(';'))
{
string[] files = el.Split('=');
string src = files[0].Trim(); // key
string tgt = files[1].Trim(); // value
if (src == "" || tgt == "") continue;
//cp.EmbeddedResources.Add(tgt);
string content = Compress_text(System.IO.File.ReadAllText(tgt));
if (string.IsNullOrEmpty(content)) {errfile.Add(tgt);continue;}
sb.Append(string.Format("tgtFile = Environment.ExpandEnvironmentVariables(@\"{0}\");{2}if (string.Compare(\".\\\", 0, tgtFile, 0, 2) == 0) {{ tgtFile = System.AppDomain.CurrentDomain.BaseDirectory + tgtFile.Substring(2); }}{2}try {{ tgtDir = System.IO.Path.GetDirectoryName(tgtFile);{2}if (tgtDir != string.Empty) {{ System.IO.Directory.CreateDirectory(tgtDir); }}{2}System.IO.File.WriteAllText(tgtFile, Expand_text(@\"{1}\"),Encoding.UTF8);{2}}}{2}catch {{ throw new System.IO.IOException(\"Error creating ''\" + tgtFile + \"''\r\n\"); }}{2}", src, content, Environment.NewLine));
// System.IO.File.WriteAllText(tgtFile, Expand_text(@\"{1}\"),Encoding.UTF8);
// using (System.IO.Stream tgtStream = new System.IO.FileStream(tgtFile, System.IO.FileMode.Create)) {{ executingAssembly.GetManifestResourceStream(\"{1}\").CopyTo(tgtStream); }} // System.IO.Path.GetFileName(tgt) => content
i++;
}
if (errfile.Count > 0) MessageBox.Show("Error reading file(s): " + string.Join(", ", errfile), "Compile", MessageBoxButton.OK, MessageBoxImage.Warning);
if (i > 0) return sb.ToString(); else return "";
} // Create_embedFileSection
private static string Get_sourcecontent(ps2exedotnet.UserOptions options)
{
string scriptstring = System.IO.File.ReadAllText(options.inputscript);
if (!options.nocompress)
{
scriptstring = Compress_PSscriptblock(scriptstring, options.basic);
if (options.preparedebug && scriptstring != "")
{
string fn = Regex.Replace(options.inputscript,@"\.ps1$","-min.ps1", RegexOptions.IgnoreCase);
if (fn != options.inputscript) System.IO.File.WriteAllLines(fn, new[] { scriptstring }, Encoding.UTF8);
}
}
string fl = scriptstring.Substring(0,scriptstring.IndexOf(Environment.NewLine));
if (Regex.IsMatch(fl,@"#Requires\s+-Version\s+[67]", RegexOptions.IgnoreCase))
MessageBox.Show(@"Input script contains ""#Requires -Version"" directive that may at least prevent correct working of the output executable.", "Compile", MessageBoxButton.OK, MessageBoxImage.Warning);
return Compress_text(scriptstring);
} // Get_sourcecontent
// NOTE: not sure if it's proper way
private static string[] Add_assembly(ps2exedotnet.UserOptions options)
{
// work around
List<string> asmlist = new List<string>() {"System.dll"};
string al = Find_assembly("System.Management.Automation.dll");
if (al != "") asmlist.Add(al);
al = Find_assembly("System.Core.dll","v4.0_4.0.0.0__b77a5c561934e089");
if (al != "") asmlist.Add(al);
if (options.noconsole) {
al = Find_assembly("System.Windows.Forms.dll","v4.0_4.0.0.0__b77a5c561934e089");
if (al != "") asmlist.Add(al);
al = Find_assembly("System.Drawing.dll","v4.0_4.0.0.0__b03f5f7f11d50a3a");
if (al != "") asmlist.Add(al);
} else {
al = Find_assembly("Microsoft.PowerShell.ConsoleHost.dll");
if (al != "") asmlist.Add(al);
}
// ISSUE: AppDomain is for .NET only
/*Assembly[] rawlist = AppDomain.CurrentDomain.GetAssemblies();
List<string> asmlist = new List<string>() {"System.dll"};
var asse = Array.Find(rawlist,e => e.ManifestModule.Name == "System.Management.Automation.dll");
if (asse != null) asmlist.Add(asse.Location);
AssemblyName an = new AssemblyName("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Assembly assembly = AppDomain.CurrentDomain.Load(an);
asse = Array.Find(rawlist,e => e.ManifestModule.Name == "System.Core.dll");
if (asse != null) asmlist.Add(asse.Location);
if (options.noconsole) {
an = new AssemblyName("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
assembly = AppDomain.CurrentDomain.Load(an);
an = new AssemblyName("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
assembly = AppDomain.CurrentDomain.Load(an);
rawlist = AppDomain.CurrentDomain.GetAssemblies();
asse = Array.Find(rawlist, e => e.ManifestModule.Name == "System.Windows.Forms.dll");
if (asse != null) asmlist.Add(asse.Location);
asse = Array.Find(rawlist, e => e.ManifestModule.Name == "System.Drawing.dll");
if (asse != null) asmlist.Add(asse.Location);
} else {
asse = Array.Find(rawlist,e => e.ManifestModule.Name == "Microsoft.PowerShell.ConsoleHost.dll");
if (asse != null) asmlist.Add(asse.Location);
}*/
return asmlist.ToArray();
} // add_assembly
// a dirty way to fetch assembly names; experimental
private static string Find_assembly(string name, string token=null)
{
string agac = @"C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL";
//if (string.Equals(System.IO.Path.GetExtension(name), ".dll", StringComparison.OrdinalIgnoreCase))
if (Regex.IsMatch(name, @"\.dll$", RegexOptions.IgnoreCase))
name = Regex.Replace(name, @"\.dll$", "", RegexOptions.IgnoreCase);
string aroot = string.Join(@"\", agac, name);
if (!System.IO.Directory.Exists(aroot)) return "";
string[] dl;
if (token == null) dl = System.IO.Directory.GetDirectories(aroot);
else dl = System.IO.Directory.GetDirectories(aroot,token);
if (dl == null) return "";
dl = System.IO.Directory.GetFiles(dl[0],@"*.dll");
if (dl == null || dl.Length == 0) return "";
return dl[0];
} // Find_assembly
private static void Export_manifest(ps2exedotnet.UserOptions options, string mtype)
{
string fn;
if (mtype == "win32")
{
List<string> win32manifest = new List<string>();
win32manifest.AddRange(new[] {"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>","<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"});
if (options.dpi || options.longpaths)
{
win32manifest.AddRange(new[] {"<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">","<windowsSettings>"});
if (options.dpi)
{
win32manifest.AddRange(new[] {"<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true</dpiAware>","<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2</dpiAwareness>"});
}
if (options.longpaths)
{
win32manifest.Add("<longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>");
}
}
if (options.admin)
{
win32manifest.AddRange(new[] {"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">","<security>","<requestedPrivileges xmlns=\"urn:schemas-microsoft-com:asm.v3\">","<requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"false\"/>","</requestedPrivileges>","</security>","</trustInfo>"});
}
if (options.supportos)
{
win32manifest.AddRange(new[] {"<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">","<application>","<supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>","<supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>","<supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>","<supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>","<supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>","</application>","</compatibility>"});
}
win32manifest.Add("</assembly>");
fn = string.Concat(options.outputfile,".win32manifest");
System.IO.File.WriteAllLines(fn,win32manifest,Encoding.UTF8);
return;
}
else if (mtype != "exe3") return;
List<string> configFileForEXE3 = new List<string>();
string x = "4.0";
if (options.winformsdpi) x = "4.7";
configFileForEXE3.AddRange(new[] {"<?xml version=\"1.0\" encoding=\"utf-8\" ?>","<configuration><startup><supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v"+x+"\" /></startup>"});
if (options.longpaths)
{
configFileForEXE3.Add("<runtime><AppContextSwitchOverrides value=\"Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false\" /></runtime>");
}
if (options.winformsdpi)
{
configFileForEXE3.Add("<System.Windows.Forms.ApplicationConfigurationSection><add key=\"DpiAwareness\" value=\"PerMonitorV2\" /></System.Windows.Forms.ApplicationConfigurationSection>");
}
configFileForEXE3.Add("</configuration>");
fn = string.Concat(options.outputfile,".config");
System.IO.File.WriteAllLines(fn,configFileForEXE3,Encoding.UTF8);
} // Export_manifest
private static string Get_MainProgramSource(ps2exedotnet.UserOptions parameters, ref CompilerParameters cp)
{
System.Windows.Resources.StreamResourceInfo res = Application.GetResourceStream(new Uri("csframe.txt", UriKind.Relative));
if (res == null || res.Stream == null)
{
MessageBox.Show("Resource 'csframe.txt' not found or empty", "Compile", MessageBoxButton.OK, MessageBoxImage.Error);
return "";
}
System.IO.StreamReader resreader = new System.IO.StreamReader(res.Stream, System.Text.Encoding.UTF8);
string csframe = Expand_text(resreader.ReadToEnd());
// template {{preprocessor}}
List<string> preprocessor = new List<string>();
if (parameters.noconsole) preprocessor.Add("#define noConsole");
if (parameters.winformsdpi) preprocessor.Add("#define winFormsDpiAware");
if (parameters.credgui) preprocessor.Add("#define credentialGUI");
if (parameters.novisualstyles) preprocessor.Add("#define noVisualStyles");
if (parameters.exitoncancel) preprocessor.Add("#define exitOnCancel");
if (parameters.nooutput) preprocessor.Add("#define noOutput");
if (parameters.noerror) preprocessor.Add("#define noError");
if (parameters.conhost) preprocessor.Add("#define conHost");
if (!parameters.mta) preprocessor.Add("#define STA");
if (parameters.unicode) preprocessor.Add("#define unicode");
if (parameters.title != "") preprocessor.Add("#define title");
// normalize metadata
parameters.title = parameters.title.Replace(@"\",@"\\");
parameters.product = parameters.product.Replace(@"\",@"\\");
parameters.copyright = parameters.copyright.Replace(@"\",@"\\");
parameters.trademark = parameters.trademark.Replace(@"\",@"\\");
parameters.description = parameters.description.Replace(@"\",@"\\");
parameters.company = parameters.company.Replace(@"\",@"\\");
// template {{metadata}}
List<string> metadata = new List<string>();
if (parameters.title != "") metadata.Add(string.Format(@"[assembly:AssemblyTitle(""{0}"")]",parameters.title));
if (parameters.product != "") metadata.Add(string.Format(@"[assembly:AssemblyProduct(""{0}"")]",parameters.product));
if (parameters.copyright != "") metadata.Add(string.Format(@"[assembly:AssemblyCopyright(""{0}"")]",parameters.copyright));
if (parameters.trademark != "") metadata.Add(string.Format(@"[assembly:AssemblyTrademark(""{0}"")]",parameters.trademark));
if (parameters.fileversion != "")
{
metadata.Add(string.Format(@"[assembly:AssemblyVersion(""{0}"")]",parameters.fileversion));
metadata.Add(string.Format(@"[assembly:AssemblyFileVersion(""{0}"")]",parameters.fileversion));
}
if (parameters.description != "" || parameters.company != "")
{
metadata.Add("// not displayed in details tab of properties dialog, but embedded to file");
if (parameters.description != "") metadata.Add(string.Format(@"[assembly:AssemblyDescription(""{0}"")]", parameters.description));
if (parameters.company != "") metadata.Add(string.Format(@"[assembly:AssemblyCompany(""{0}"")]", parameters.company));
}
// template {{culture}}
string culture = "";
if (parameters.locale != "") {
culture = string.Format("System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo({0});\r\nSystem.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo({0});",parameters.locale);
}
// template {{embedFileSection}}
string embedFileSection = Create_embedFileSection(parameters, ref cp);
// template {{sourceScript}}
/*experimental: file as resource; /
string sourceScript = System.IO.Path.GetTempFileName();
////parameters.tempInput = sourceScript;
string sc = Get_sourcecontent(parameters);
System.IO.File.WriteAllLines(sourceScript, new[] { sc }, Encoding.UTF8);
cp.EmbeddedResources.Add(sourceScript);*/
string sourceScript = Get_sourcecontent(parameters);
if (string.IsNullOrEmpty(sourceScript)) MessageBox.Show("The source script is empty", "Compile", MessageBoxButton.OK, MessageBoxImage.Warning);
// replace placeholders and assemble the final string without "changing" immutable string
// substitution placeholder is /*{{id}}*/
// NOTE: output string assembling depends on the amount and placeholders order
string[] slices = Regex.Split(csframe,@"/\*\{\{.+\}\}\*/");
return string.Concat(
slices[0],string.Join(Environment.NewLine, preprocessor),
slices[1],string.Join(Environment.NewLine, metadata),
slices[2],culture,
slices[3],embedFileSection,
slices[4],sourceScript,
slices[5]
);
} // Get_MainProgramSource
//public void Invoke_DomCompiler() {} // Invoke_DomCompiler()
//public void Invoke_DotnetCompiler() {} // Invoke_DotnetCompiler()
} // Ps2Exe class
} // Ps2Exe namespace
namespace OpenFolderDialog // to be replaced with modern one
{
internal class OpenFolderDialog : IDisposable
{
public string InitialFolder { get; set; }
public string DefaultFolder { get; set; }
public string Folder { get; private set; }
internal Nullable<bool> ShowDialog()
{
return ShowDialog(IntPtr.Zero);
}
internal Nullable<bool> ShowDialog(IntPtr ownerHandle)
{
var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (this.InitialFolder != null)
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.InitialFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (this.DefaultFolder != null)
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.DefaultFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (frm.Show(ownerHandle) == NativeMethods.S_OK)
{
NativeMethods.IShellItem shellItem;
if (frm.GetResult(out shellItem) == NativeMethods.S_OK)
{
IntPtr pszString;
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, out pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try {
this.Folder = Marshal.PtrToStringAuto(pszString);
return true;
}
finally {
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
return false;
}
public void Dispose() { } // just to have the possibility of the using statement
}
internal static class NativeMethods
{
public const uint FOS_PICKFOLDERS = 0x00000020;
public const uint FOS_FORCEFILESYSTEM = 0x00000040;
public const uint FOS_NOVALIDATE = 0x00000100;
public const uint FOS_NOTESTFILECREATE = 0x00010000;
public const uint FOS_DONTADDTORECENT = 0x02000000;
public const uint S_OK = 0x0000;
public const uint SIGDN_FILESYSPATH = 0x80058000;
[ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
internal class FileOpenDialogRCW { }
[ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()]
uint Show([In, Optional] IntPtr hwndOwner); // inherited from IModalWindow
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
}
} // end OpenFolderDialog

Ps2exe.NET is an educational project to go deep C#/WPF/VisualStudio.
Ps2exe.NET is a graphical dashboard to convert PowerShell scripts to standalone executables.

Key Features:

  • No setup, no external dependencies, pure C#/WPF
  • Source compressor & encoder
  • Automatic variables in your PS script: $ScriptRoot, $ScriptName, $RtMode
  • There is a PowerShell counterpart of the Ps2exe.NET — ps2exec.ps1

Main Window

image

Help Window

image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment