From 6fec91e73eb448b1d4e176cc3a57d3790c4aea59 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Tue, 11 Jun 2024 21:43:12 -0500 Subject: [PATCH] Fix PowerShell scripts, add script debug mode PowerShell scripts now execute correctly with the client. The built in PowerShell API's serializer will always return null on .NET 8 for some reason. The serializer/deserializer was switched to YAML, mostly due to convenience of already having a package for it. Added a new settings for enabling script debugging mode. This ensures that when a script is executed, the PowerShell terminal window is not closed. This allows power users to get the same environment that the script executes in. It also allows for some scroll back to see what potentially went wrong in their script. --- .../LANCommander.Client.csproj | 4 +++ LANCommander.Client/Models/Settings.cs | 11 +++++++- .../Services/DownloadService.cs | 9 +++++++ .../Cmdlets/ConvertFrom-SerializedBase64.cs | 11 ++++++-- .../Cmdlets/ConvertTo-SerializedBase64.cs | 8 +++++- .../PowerShell/PowerShellScript.cs | 25 +++++++++++++++++-- LANCommander.sln | 3 +++ 7 files changed, 65 insertions(+), 6 deletions(-) diff --git a/LANCommander.Client/LANCommander.Client.csproj b/LANCommander.Client/LANCommander.Client.csproj index 6055ef27..95081727 100644 --- a/LANCommander.Client/LANCommander.Client.csproj +++ b/LANCommander.Client/LANCommander.Client.csproj @@ -3298,4 +3298,8 @@ + + + + diff --git a/LANCommander.Client/Models/Settings.cs b/LANCommander.Client/Models/Settings.cs index d2323ca4..84652d59 100644 --- a/LANCommander.Client/Models/Settings.cs +++ b/LANCommander.Client/Models/Settings.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,6 +14,7 @@ namespace LANCommander.Client.Models public GameSettings Games { get; set; } = new GameSettings(); public MediaSettings Media { get; set; } = new MediaSettings(); public ProfileSettings Profile { get; set; } = new ProfileSettings(); + public DebugSettings Debug { get; set; } = new DebugSettings(); } public class DatabaseSettings @@ -43,4 +45,11 @@ namespace LANCommander.Client.Models public string Alias { get; set; } public string Avatar { get; set; } } + + public class DebugSettings + { + public bool EnableScriptDebugging { get; set; } = false; + public LogLevel LoggingLevel { get; set; } = LogLevel.Warning; + public string LoggingPath { get; set; } = "Logs"; + } } diff --git a/LANCommander.Client/Services/DownloadService.cs b/LANCommander.Client/Services/DownloadService.cs index 311a1cdd..9748f4c4 100644 --- a/LANCommander.Client/Services/DownloadService.cs +++ b/LANCommander.Client/Services/DownloadService.cs @@ -309,6 +309,9 @@ namespace LANCommander.Client.Services script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, game.Id, SDK.Enums.ScriptType.Install)); + if (Settings.Debug.EnableScriptDebugging) + script.EnableDebug(); + return script.Execute(); } @@ -341,6 +344,9 @@ namespace LANCommander.Client.Services SDK.GameService.UpdatePlayerAlias(installDirectory, game.Id, newName); + if (Settings.Debug.EnableScriptDebugging) + script.EnableDebug(); + return script.Execute(); } @@ -371,6 +377,9 @@ namespace LANCommander.Client.Services SDK.GameService.UpdateCurrentKey(installDirectory, game.Id, key); + if (Settings.Debug.EnableScriptDebugging) + script.EnableDebug(); + return script.Execute(); } diff --git a/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs index d600b385..0df64657 100644 --- a/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs +++ b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Management.Automation; using System.Text; using System.Threading.Tasks; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; namespace LANCommander.PowerShell.Cmdlets { @@ -16,9 +18,14 @@ namespace LANCommander.PowerShell.Cmdlets protected override void ProcessRecord() { - var xml = Encoding.UTF8.GetString(Convert.FromBase64String(Input)); + var yaml = Encoding.UTF8.GetString(Convert.FromBase64String(Input)); - WriteObject(PSSerializer.Deserialize(xml)); + var deserializer = new DeserializerBuilder() + .IgnoreUnmatchedProperties() + .WithNamingConvention(new PascalCaseNamingConvention()) + .Build(); + + WriteObject(deserializer.Deserialize(yaml)); } } } diff --git a/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs b/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs index fe92654a..50de9fe1 100644 --- a/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs +++ b/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Management.Automation; using System.Text; using System.Threading.Tasks; +using YamlDotNet.Serialization.NamingConventions; +using YamlDotNet.Serialization; namespace LANCommander.PowerShell.Cmdlets { @@ -16,7 +18,11 @@ namespace LANCommander.PowerShell.Cmdlets protected override void ProcessRecord() { - var output = Convert.ToBase64String(Encoding.UTF8.GetBytes(PSSerializer.Serialize(Input))); + var serializer = new SerializerBuilder() + .WithNamingConvention(new PascalCaseNamingConvention()) + .Build(); + + var output = Convert.ToBase64String(Encoding.UTF8.GetBytes(serializer.Serialize(Input))); WriteObject(output); } diff --git a/LANCommander.SDK/PowerShell/PowerShellScript.cs b/LANCommander.SDK/PowerShell/PowerShellScript.cs index 13bee986..884ee0aa 100644 --- a/LANCommander.SDK/PowerShell/PowerShellScript.cs +++ b/LANCommander.SDK/PowerShell/PowerShellScript.cs @@ -7,6 +7,8 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; namespace LANCommander.SDK.PowerShell { @@ -17,6 +19,7 @@ namespace LANCommander.SDK.PowerShell private bool AsAdmin { get; set; } = false; private bool ShellExecute { get; set; } = false; private bool IgnoreWow64 { get; set; } = false; + private bool Debug { get; set; } = false; private ICollection Variables { get; set; } private Dictionary Arguments { get; set; } private List Modules { get; set; } @@ -122,6 +125,13 @@ namespace LANCommander.SDK.PowerShell return this; } + public PowerShellScript EnableDebug() + { + Debug = true; + + return this; + } + public int Execute() { var scriptBuilder = new StringBuilder(); @@ -143,6 +153,13 @@ namespace LANCommander.SDK.PowerShell scriptBuilder.AppendLine(Contents); + if (Debug) + { + scriptBuilder.AppendLine("Read-Host"); + + Process.StartInfo.Arguments += " -NoExit"; + } + var path = ScriptHelper.SaveTempScript(scriptBuilder.ToString()); AddArgument("File", path); @@ -181,8 +198,12 @@ namespace LANCommander.SDK.PowerShell public static string Serialize(T input) { - // Use the PowerShell serializer to generate XML for our input. Then convert to base64 so we can put it on one line. - return Convert.ToBase64String(Encoding.UTF8.GetBytes(System.Management.Automation.PSSerializer.Serialize(input))); + var serializer = new SerializerBuilder() + .WithNamingConvention(new PascalCaseNamingConvention()) + .Build(); + + // Use the YamlDotNet serializer to generate a string for our input. Then convert to base64 so we can put it on one line. + return Convert.ToBase64String(Encoding.UTF8.GetBytes(serializer.Serialize(input))); } [DllImport("kernel32.dll", SetLastError = true)] diff --git a/LANCommander.sln b/LANCommander.sln index 544311af..093583bf 100644 --- a/LANCommander.sln +++ b/LANCommander.sln @@ -22,6 +22,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.Client.Data", "LANCommander.Client.Data\LANCommander.Client.Data.csproj", "{02FBFF81-6550-4E11-A78C-E965E593B3CC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.Client", "LANCommander.Client\LANCommander.Client.csproj", "{28D73284-B55A-4468-B96D-394C39BA162D}" + ProjectSection(ProjectDependencies) = postProject + {807943BF-0C7D-4ED3-8393-CFEE64E3138C} = {807943BF-0C7D-4ED3-8393-CFEE64E3138C} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Photino.Blazor.CustomWindow", "..\Photino.Blazor.CustomWindow\Photino.Blazor.CustomWindow\Photino.Blazor.CustomWindow.csproj", "{507C8A0B-636B-4EC9-B47A-DD65C8829301}" EndProject