From dc2eff497249708f37425a34126776c3149e9dfa Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Mon, 13 Nov 2023 23:07:50 -0600 Subject: [PATCH 01/32] Have manifest writer return the file path --- LANCommander.SDK/Helpers/ManifestHelper.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/LANCommander.SDK/Helpers/ManifestHelper.cs b/LANCommander.SDK/Helpers/ManifestHelper.cs index 4c09f16..9f87cef 100644 --- a/LANCommander.SDK/Helpers/ManifestHelper.cs +++ b/LANCommander.SDK/Helpers/ManifestHelper.cs @@ -30,7 +30,7 @@ namespace LANCommander.SDK.Helpers return manifest; } - public static void Write(GameManifest manifest, string installDirectory) + public static string Write(GameManifest manifest, string installDirectory) { var destination = GetPath(installDirectory); @@ -47,6 +47,8 @@ namespace LANCommander.SDK.Helpers Logger?.LogTrace("Writing manifest file"); File.WriteAllText(destination, yaml); + + return destination; } public static string GetPath(string installDirectory) From baa2b9b20692ffefdfc488f9510c6387677f370e Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Mon, 13 Nov 2023 23:09:06 -0600 Subject: [PATCH 02/32] Started adding PowerShell cmdlets useful for LANCommander scripting --- .../Cmdlets/Convert-AspectRatio.cs | 45 ++++++++++++ .../Cmdlets/ConvertTo-StringBytes.cs | 40 +++++++++++ .../Cmdlets/Edit-PatchBinary.cs | 30 ++++++++ .../Cmdlets/Get-GameManifest.cs | 19 +++++ .../Cmdlets/Get-PrimaryDisplay.cs | 18 +++++ .../Cmdlets/Write-GameManifest.cs | 24 +++++++ .../Cmdlets/Write-ReplaceContentInFile.cs | 31 ++++++++ .../LANCommander.PowerShell.csproj | 68 ++++++++++++++++++ .../LANCommander.PowerShell.psd1 | Bin 0 -> 8022 bytes .../Properties/AssemblyInfo.cs | 36 ++++++++++ LANCommander.PowerShell/packages.config | 4 ++ LANCommander.sln | 6 ++ 12 files changed, 321 insertions(+) create mode 100644 LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs create mode 100644 LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs create mode 100644 LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs create mode 100644 LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs create mode 100644 LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs create mode 100644 LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs create mode 100644 LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs create mode 100644 LANCommander.PowerShell/LANCommander.PowerShell.csproj create mode 100644 LANCommander.PowerShell/LANCommander.PowerShell.psd1 create mode 100644 LANCommander.PowerShell/Properties/AssemblyInfo.cs create mode 100644 LANCommander.PowerShell/packages.config diff --git a/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs b/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs new file mode 100644 index 0000000..5bb019d --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs @@ -0,0 +1,45 @@ +using System; +using System.Management.Automation; + +namespace LANCommander.PowerShell.Cmdlets +{ + public class DisplayResolution + { + public int Width { get; set; } + public int Height { get; set; } + } + + [Cmdlet(VerbsData.Convert, "AspectRatio")] + [OutputType(typeof(string))] + public class ConvertAspectRatioCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0)] + public int Width { get; set; } + + [Parameter(Mandatory = true, Position = 1)] + public int Height { get; set; } + + [Parameter(Mandatory = true, Position = 2)] + public double AspectRatio { get; set; } + + protected override void ProcessRecord() + { + var resolution = new DisplayResolution(); + + // Display is wider, pillar box + if ((Width / Height) < AspectRatio) + { + resolution.Width = (int)Math.Ceiling(Height * AspectRatio); + resolution.Height = Height; + } + // Letterbox + else + { + resolution.Width = Width; + resolution.Height = (int)Math.Ceiling(Width * (1 / AspectRatio)); + } + + WriteObject(resolution); + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs b/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs new file mode 100644 index 0000000..87b3c09 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs @@ -0,0 +1,40 @@ +using LANCommander.SDK; +using LANCommander.SDK.Helpers; +using System.Management.Automation; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsData.ConvertTo, "StringBytes")] + [OutputType(typeof(byte[]))] + public class ConvertToStringBytesCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public string Input { get; set; } + + [Parameter] + public bool Utf16 { get; set; } = false; + + [Parameter] + public bool BigEndian { get; set; } = false; + + [Parameter] + public int MaxLength { get; set; } = 0; + + protected override void ProcessRecord() + { + byte[] output; + + if (MaxLength > 0 && Input.Length > MaxLength) + Input = Input.Substring(0, MaxLength); + + if (Utf16 && BigEndian) + output = System.Text.Encoding.BigEndianUnicode.GetBytes(Input); + else if (Utf16) + output = System.Text.Encoding.Unicode.GetBytes(Input); + else + output = System.Text.Encoding.ASCII.GetBytes(Input); + + WriteObject(output); + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs b/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs new file mode 100644 index 0000000..0e73580 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.Management.Automation; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsData.Edit, "PatchBinary")] + [OutputType(typeof(string))] + public class EditPatchBinaryCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0)] + public long Offset { get; set; } + + [Parameter(Mandatory = true, Position = 1)] + public byte[] Data { get; set; } + + [Parameter(Mandatory = true, Position = 2)] + public string FilePath { get; set; } + + protected override void ProcessRecord() + { + using (var writer = File.OpenWrite(FilePath)) + { + writer.Seek(Offset, SeekOrigin.Begin); + + writer.Write(Data, 0, Data.Length); + } + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs b/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs new file mode 100644 index 0000000..b012bd5 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs @@ -0,0 +1,19 @@ +using LANCommander.SDK; +using LANCommander.SDK.Helpers; +using System.Management.Automation; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "GameManifest")] + [OutputType(typeof(GameManifest))] + public class GetGameManifestCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public string Path { get; set; } + + protected override void ProcessRecord() + { + WriteObject(ManifestHelper.Read(Path)); + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs b/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs new file mode 100644 index 0000000..0b53547 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs @@ -0,0 +1,18 @@ +using System.Linq; +using System.Management.Automation; +using System.Windows.Forms; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "PrimaryDisplay")] + [OutputType(typeof(string))] + public class GetPrimaryDisplayCmdlet : PSCmdlet + { + protected override void ProcessRecord() + { + var screens = Screen.AllScreens; + + WriteObject(screens.First(s => s.Primary)); + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs b/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs new file mode 100644 index 0000000..6d9ad0c --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs @@ -0,0 +1,24 @@ +using LANCommander.SDK; +using LANCommander.SDK.Helpers; +using System.Management.Automation; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsCommunications.Write, "GameManifest")] + [OutputType(typeof(string))] + public class WriteGameManifestCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public string Path { get; set; } + + [Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public GameManifest Manifest { get; set; } + + protected override void ProcessRecord() + { + var destination = ManifestHelper.Write(Manifest, Path); + + WriteObject(destination); + } + } +} diff --git a/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs b/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs new file mode 100644 index 0000000..32cda9c --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs @@ -0,0 +1,31 @@ +using System.IO; +using System.Management.Automation; +using System.Text.RegularExpressions; + +namespace LANCommander.PowerShell.Cmdlets +{ + + [Cmdlet(VerbsCommunications.Write, "ReplaceContentInFile")] + [OutputType(typeof(string))] + public class ReplaceContentInFileCmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0)] + public string Pattern { get; set; } + + [Parameter(Mandatory = true, Position = 1)] + public string Substitution { get; set; } + + [Parameter(Mandatory = true, Position = 2)] + public string FilePath { get; set; } + + protected override void ProcessRecord() + { + var contents = File.ReadAllText(FilePath); + var regex = new Regex(Pattern, RegexOptions.Multiline); + + var result = regex.Replace(contents, Substitution); + + WriteObject(result); + } + } +} diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.csproj b/LANCommander.PowerShell/LANCommander.PowerShell.csproj new file mode 100644 index 0000000..515ee5d --- /dev/null +++ b/LANCommander.PowerShell/LANCommander.PowerShell.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {807943BF-0C7D-4ED3-8393-CFEE64E3138C} + Library + Properties + LANCommander.PowerShell + LANCommander.PowerShell + v4.7.2 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + ..\packages\PowerShellStandard.Library.5.1.1\lib\net452\System.Management.Automation.dll + + + + + + + + + + + + + + + + + + + + + + + + + + {4c2a71fd-a30b-4d62-888a-4ef843d8e506} + LANCommander.SDK + + + + \ No newline at end of file diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.psd1 b/LANCommander.PowerShell/LANCommander.PowerShell.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..52b16e5c1381d6e249d47a7eb3b44108dc4b9778 GIT binary patch literal 8022 zcmd^^TTdKE5QY0WQvSopJb(8a|dH5_Wg(5r;Ql* zPx^X4jc>~1mcwpng%@E%Z-=v4UCo(>)v%{$7xDfe{Hp7T{+4I^`L0j(d=$sDwM$P3 zif|O(h3|CT69#sErt4I9CkxCSYc=Ms>F>Ti5B2}6@Iar3rP=KMB>WMdIFf_V(Jq59 ziF*z+ZJ6XodOM0(-f4$?L|^Yrb8YGCRI@vJl4QEjw=-#>i2nx~QPuHk#IvutV~xt~ z@x8`hSJ$i3X41LK`6_DrRCv%;q0hNwIf_pUJ?qb5Ox8AhWnA-X8Ok-;{=v-BzUzT@ zndlEqx}EpJLD&*TG-GH^XErKke40cJ4ulTf){QR$dp-#(;cjNlov^9r=hCxr>P$QH z9ZvtQD{RDy1MLq3LC}v+u#(#+$&MUP!^>dnnw$^Bsjlq&Fnle9>)~G9>ruR0*RyZq z-D8cgx9hrF)910qb@cg0(yfV^<`b@|me7I0ICqsjn30b*TvflxcQ9W?x1%Vr?er$< zp}XL|`5G^@)==}!8qGYd;+O~lUUw{s@pWR2c@67fmlS!LEd!eQl}r~a()3-e;W41N zB3>2JCjL^C5aFj&A%REJfR4IicP__fe4nC+dsea?n(0UObtI9!Z)+!*4+|$+d#u%s zjUEH@SdnvaNwb>vHOX^~&$Tw(9}2}#bCF~!sp_%*6i35_3ymQXS0j0$6-Kff>mnao z!m|ePZc!QPR<4gKxjcz+xt140j(1sB`*f(E&DKoF{wX`$rZkJ#Vli$p3Lio9*bL8J zRpqc14t2M!Hx@%K^mZCvUz<^@nsIm;yYVO(?wo|_2e4kFUj=Q7%sKG3+pGZRd^IX^CDAzPb zAmWe3>J??#-LN0yW6~6NAM)ORpRP@kMRd9+R#2T0(_tbtE%jw5atDqOqt7FE3e^=a zqCR`!OO5+EJW|%?t|c9Ib-#WC?KwZHNLr0J>SIaD32+)7Sj9|~xA;a~2j_=#wHHy_ zY9eRPvDiCSrGj5rY$qR~t5M{ON~$fQ^s;8(4(C!dF5^E{rWh;Emm@(F?+z8yCsB@incqg+Qe&Dwn8)Sp zyNH>^bdWr8F>mqxuY-9zdMG`-)z8+O=C-{wLEJ}xtO>Mrhb6@l3yYKs1FJ5Ji$8$2h}+c6`jo&ek?Z!f$R zM&hhl5T;VM<2}{LN=EW32L4&>N5<*wxt-^b^%zTKkN%Lw{C~ksrIb@_VWg-)+`qjH9%MGn(8%VUS8EE zw%W=xS#O68q2sIsiRyO%$^X>`oeyfq^q*^SQQg0aY~!rVPI+#sf4s1|Ry~U4@WosY z-;(vgK%ak81pi$xv|i~d?HB`cE!OM4TG?%?`q+@KTb(nGwYSyhH;aZIk2ht>POLVm z^Qq`<)kSgb#z;$qv|M8KN`CSSS2#)QsAIK0i)dMY+MDu|BP?f$v|D|QO7C+t<*MZ7 zNVa3_@2MXoyC8Et3Tmc7?4B+5cO^9^c5W#UP^Jrn?<3r4e27vy*?}FEZ`ftgOR>wI(z2#jQUdr^O{_z36)tO z{Yv2-MUK5`l#gE0-iJbU9Iet8TPHErS=DnEHB?_!xL%2fWMumdhqI5w@7%6v37_LE zlYDL&p1RjgN6?{`Z&KbzNODgdHt@gNji2t5jrBkXeN(W zOij|`rM|LX*#RF(>%5E};V0kel+tJT^=fRe*4W7}W=BHk=T%jd^s?jdo5oQ&HfzrM z8z1*^IH?2a;LMjSR)fR1fp>wvx%Y2IxieeyI{4^!sn#qbaY92hBI=~7zgi_X*|T{y z7`I%i6x^2Y^&ER{NoL}`?V9^#HKwpXpQhR6$eN-+^Ex1S7Bw-^?^2^!=^OWVE-}?} z8x(c3@f+sO%gtDRZRm%#^5}`QZNFLYWT5&wbsv5PX?+70DR(j!b3Rl_6L)@`MG$mC zw}CI)=`7!xaS(N#i9509upa7O*25M0tq$*S{Kn3zlpC^a`c=C;qpG9#m%l&$4TZ`X AjsO4v literal 0 HcmV?d00001 diff --git a/LANCommander.PowerShell/Properties/AssemblyInfo.cs b/LANCommander.PowerShell/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..87468b6 --- /dev/null +++ b/LANCommander.PowerShell/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("LANCommander.PowerShell")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LANCommander.PowerShell")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("807943bf-0c7d-4ed3-8393-cfee64e3138c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/LANCommander.PowerShell/packages.config b/LANCommander.PowerShell/packages.config new file mode 100644 index 0000000..411c02f --- /dev/null +++ b/LANCommander.PowerShell/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/LANCommander.sln b/LANCommander.sln index 529f8cc..5f6fef2 100644 --- a/LANCommander.sln +++ b/LANCommander.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.SDK", "LANComm EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.PCGamingWiki", "LANCommander.PCGamingWiki\LANCommander.PCGamingWiki.csproj", "{2436B817-4475-4E70-9BB2-E1E7866DB79F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.PowerShell", "LANCommander.PowerShell\LANCommander.PowerShell.csproj", "{807943BF-0C7D-4ED3-8393-CFEE64E3138C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {2436B817-4475-4E70-9BB2-E1E7866DB79F}.Debug|Any CPU.Build.0 = Debug|Any CPU {2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.Build.0 = Release|Any CPU + {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 29dcebb70f128e8c42a492865fb0e2057357a66f Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 15 Nov 2023 22:38:20 -0600 Subject: [PATCH 03/32] New PowerShell runtime with the ability to use variables --- LANCommander.SDK/Helpers/ScriptHelper.cs | 13 +- LANCommander.SDK/LANCommander.SDK.csproj | 1 + .../PowerShell/PowerShellArgument.cs | 20 +++ .../PowerShell/PowerShellFactory.cs | 14 ++ .../PowerShell/PowerShellScript.cs | 169 ++++++++++++++++++ .../PowerShell/PowerShellVariable.cs | 20 +++ 6 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 LANCommander.SDK/PowerShell/PowerShellArgument.cs create mode 100644 LANCommander.SDK/PowerShell/PowerShellFactory.cs create mode 100644 LANCommander.SDK/PowerShell/PowerShellScript.cs create mode 100644 LANCommander.SDK/PowerShell/PowerShellVariable.cs diff --git a/LANCommander.SDK/Helpers/ScriptHelper.cs b/LANCommander.SDK/Helpers/ScriptHelper.cs index 3232e57..dd27f7e 100644 --- a/LANCommander.SDK/Helpers/ScriptHelper.cs +++ b/LANCommander.SDK/Helpers/ScriptHelper.cs @@ -14,15 +14,24 @@ namespace LANCommander.SDK.Helpers public static readonly ILogger Logger; public static string SaveTempScript(Script script) + { + var tempPath = SaveTempScript(script.Contents); + + Logger?.LogTrace("Wrote script {Script} to {Destination}", script.Name, tempPath); + + return tempPath; + } + + public static string SaveTempScript(string contents) { var tempPath = Path.GetTempFileName(); // PowerShell will only run scripts with the .ps1 file extension File.Move(tempPath, tempPath + ".ps1"); - Logger?.LogTrace("Writing script {Script} to {Destination}", script.Name, tempPath); + tempPath = tempPath + ".ps1"; - File.WriteAllText(tempPath, script.Contents); + File.WriteAllText(tempPath, contents); return tempPath; } diff --git a/LANCommander.SDK/LANCommander.SDK.csproj b/LANCommander.SDK/LANCommander.SDK.csproj index e653767..2e097cf 100644 --- a/LANCommander.SDK/LANCommander.SDK.csproj +++ b/LANCommander.SDK/LANCommander.SDK.csproj @@ -6,6 +6,7 @@ + diff --git a/LANCommander.SDK/PowerShell/PowerShellArgument.cs b/LANCommander.SDK/PowerShell/PowerShellArgument.cs new file mode 100644 index 0000000..173e861 --- /dev/null +++ b/LANCommander.SDK/PowerShell/PowerShellArgument.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.PowerShell +{ + public class PowerShellArgument + { + public string Name { get; set; } + public object Value { get; set; } + public Type Type { get; set; } + + public PowerShellArgument(string name, object value, Type type) + { + Name = name; + Value = value; + Type = type; + } + } +} diff --git a/LANCommander.SDK/PowerShell/PowerShellFactory.cs b/LANCommander.SDK/PowerShell/PowerShellFactory.cs new file mode 100644 index 0000000..ace2d78 --- /dev/null +++ b/LANCommander.SDK/PowerShell/PowerShellFactory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.PowerShell +{ + public static class PowerShellFactory + { + public static PowerShellScript RunScript() + { + return new PowerShellScript(); + } + } +} diff --git a/LANCommander.SDK/PowerShell/PowerShellScript.cs b/LANCommander.SDK/PowerShell/PowerShellScript.cs new file mode 100644 index 0000000..6f300f9 --- /dev/null +++ b/LANCommander.SDK/PowerShell/PowerShellScript.cs @@ -0,0 +1,169 @@ +using LANCommander.SDK.Helpers; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace LANCommander.SDK.PowerShell +{ + public class PowerShellScript + { + private string Contents { get; set; } = ""; + private string WorkingDirectory { get; set; } = ""; + private bool AsAdmin { get; set; } = false; + private bool ShellExecute { get; set; } = false; + private bool IgnoreWow64 { get; set; } = false; + private ICollection Variables { get; set; } + private Dictionary Arguments { get; set; } + private Process Process { get; set; } + + public PowerShellScript() + { + Variables = new List(); + Arguments = new Dictionary(); + Process = new Process(); + + Process.StartInfo.FileName = "powershell.exe"; + Process.StartInfo.RedirectStandardOutput = false; + + AddArgument("ExecutionPolicy", "Unrestricted"); + } + + public PowerShellScript UseFile(string path) + { + Contents = File.ReadAllText(path); + + return this; + } + + public PowerShellScript UseInline(string contents) + { + Contents = contents; + + return this; + } + + public PowerShellScript UseWorkingDirectory(string path) + { + WorkingDirectory = path; + + return this; + } + + public PowerShellScript UseShellExecute() + { + ShellExecute = true; + + return this; + } + + public PowerShellScript AddVariable(string name, T value) + { + Variables.Add(new PowerShellVariable(name, value, typeof(T))); + + return this; + } + + public PowerShellScript AddArgument(string name, T value) + { + Arguments.Add(name, $"\"{value}\""); + + return this; + } + + public PowerShellScript AddArgument(string name, int value) + { + Arguments[name] = value.ToString(); + + return this; + } + + public PowerShellScript AddArgument(string name, long value) + { + Arguments[name] = value.ToString(); + + return this; + } + + public PowerShellScript RunAsAdmin() + { + AsAdmin = true; + + Process.StartInfo.Verb = "runas"; + Process.StartInfo.UseShellExecute = true; + + return this; + } + + public PowerShellScript IgnoreWow64Redirection() + { + IgnoreWow64 = true; + + return this; + } + + public int Execute() + { + var scriptBuilder = new StringBuilder(); + + var wow64Value = IntPtr.Zero; + + foreach (var variable in Variables) + { + scriptBuilder.AppendLine($"${variable.Name} = Convert-FromSerializedBase64 \"{Serialize(variable.Value)}\""); + } + + scriptBuilder.AppendLine(Contents); + + var path = ScriptHelper.SaveTempScript(scriptBuilder.ToString()); + + AddArgument("File", path); + + if (IgnoreWow64) + Wow64DisableWow64FsRedirection(ref wow64Value); + + Process.StartInfo.Arguments = String.Join(" ", Arguments.Select((name, value) => + { + return $"-{name} {value}"; + })); + + if (!String.IsNullOrEmpty(WorkingDirectory)) + Process.StartInfo.WorkingDirectory = WorkingDirectory; + + if (ShellExecute) + Process.StartInfo.UseShellExecute = true; + + if (AsAdmin) + { + Process.StartInfo.Verb = "runas"; + Process.StartInfo.UseShellExecute = true; + } + + Process.Start(); + Process.WaitForExit(); + + if (IgnoreWow64) + Wow64RevertWow64FsRedirection(ref wow64Value); + + if (File.Exists(path)) + File.Delete(path); + + return Process.ExitCode; + } + + 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))); + } + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool Wow64RevertWow64FsRedirection(ref IntPtr ptr); + } +} diff --git a/LANCommander.SDK/PowerShell/PowerShellVariable.cs b/LANCommander.SDK/PowerShell/PowerShellVariable.cs new file mode 100644 index 0000000..a7f78b8 --- /dev/null +++ b/LANCommander.SDK/PowerShell/PowerShellVariable.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.PowerShell +{ + public class PowerShellVariable + { + public string Name { get; set; } + public object Value { get; set; } + public Type Type { get; set; } + + public PowerShellVariable(string name, object value, Type type) + { + Name = name; + Value = value; + Type = type; + } + } +} From bf2c9ea45a66d927e407afc78eec906ee76c5812 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 15 Nov 2023 23:42:54 -0600 Subject: [PATCH 04/32] Move script path helpers to ScriptHelper. Execute post-install scripts in Playnite extension. --- .../InstallController.cs | 36 +++++++++++++++++++ LANCommander.SDK/GameManager.cs | 14 -------- LANCommander.SDK/Helpers/ScriptHelper.cs | 19 ++++++++++ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/LANCommander.Playnite.Extension/InstallController.cs b/LANCommander.Playnite.Extension/InstallController.cs index 7c7bb86..1be1388 100644 --- a/LANCommander.Playnite.Extension/InstallController.cs +++ b/LANCommander.Playnite.Extension/InstallController.cs @@ -1,6 +1,7 @@ using LANCommander.SDK; using LANCommander.SDK.Helpers; using LANCommander.SDK.Models; +using LANCommander.SDK.PowerShell; using Playnite.SDK; using Playnite.SDK.Models; using Playnite.SDK.Plugins; @@ -116,6 +117,9 @@ namespace LANCommander.PlaynitePlugin InstallDirectory = installDirectory, }; + RunInstallScript(installDirectory); + RunNameChangeScript(installDirectory); + InvokeOnInstalled(new GameInstalledEventArgs(installInfo)); } else if (result.Canceled) @@ -130,5 +134,37 @@ namespace LANCommander.PlaynitePlugin else if (result.Error != null) throw result.Error; } + + private int RunInstallScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + + return script.Execute(); + } + + private int RunNameChangeScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + script.AddVariable("OldPlayerAlias", ""); + script.AddVariable("NewPlayerAlias", Plugin.Settings.PlayerName); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + + return script.Execute(); + } } } diff --git a/LANCommander.SDK/GameManager.cs b/LANCommander.SDK/GameManager.cs index 056b563..dc2d733 100644 --- a/LANCommander.SDK/GameManager.cs +++ b/LANCommander.SDK/GameManager.cs @@ -91,20 +91,6 @@ namespace LANCommander.SDK ScriptHelper.SaveScript(game, ScriptType.NameChange); ScriptHelper.SaveScript(game, ScriptType.KeyChange); - try - { - PowerShellRuntime.RunScript(game, ScriptType.Install); - PowerShellRuntime.RunScript(game, ScriptType.NameChange, /* Plugin.Settings.PlayerName */ ""); - - var key = Client.GetAllocatedKey(game.Id); - - PowerShellRuntime.RunScript(game, ScriptType.KeyChange, $"\"{key}\""); - } - catch (Exception ex) - { - Logger?.LogError(ex, "Could not execute post-install scripts"); - } - return result.Directory; } diff --git a/LANCommander.SDK/Helpers/ScriptHelper.cs b/LANCommander.SDK/Helpers/ScriptHelper.cs index dd27f7e..352cb96 100644 --- a/LANCommander.SDK/Helpers/ScriptHelper.cs +++ b/LANCommander.SDK/Helpers/ScriptHelper.cs @@ -55,5 +55,24 @@ namespace LANCommander.SDK.Helpers File.WriteAllText(filename, script.Contents); } + + public static string GetScriptFilePath(Game game, ScriptType type) + { + return GetScriptFilePath(game.InstallDirectory, type); + } + + public static string GetScriptFilePath(string installDirectory, ScriptType type) + { + Dictionary filenames = new Dictionary() { + { ScriptType.Install, "_install.ps1" }, + { ScriptType.Uninstall, "_uninstall.ps1" }, + { ScriptType.NameChange, "_changename.ps1" }, + { ScriptType.KeyChange, "_changekey.ps1" } + }; + + var filename = filenames[type]; + + return Path.Combine(installDirectory, filename); + } } } From cb9f31a00afadc7e22cdf2795fafa4d1e004e514 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 15 Nov 2023 23:53:26 -0600 Subject: [PATCH 05/32] Use new PowerShell in redistributable installs --- LANCommander.SDK/RedistributableManager.cs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/LANCommander.SDK/RedistributableManager.cs b/LANCommander.SDK/RedistributableManager.cs index fcc87d8..699b5af 100644 --- a/LANCommander.SDK/RedistributableManager.cs +++ b/LANCommander.SDK/RedistributableManager.cs @@ -2,6 +2,7 @@ using LANCommander.SDK.Extensions; using LANCommander.SDK.Helpers; using LANCommander.SDK.Models; +using LANCommander.SDK.PowerShell; using Microsoft.Extensions.Logging; using SharpCompress.Common; using SharpCompress.Readers; @@ -57,7 +58,7 @@ namespace LANCommander.SDK var detectionScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.DetectInstall); detectionScriptTempFile = ScriptHelper.SaveTempScript(detectionScript); - var detectionResult = PowerShellRuntime.RunScript(detectionScriptTempFile, detectionScript.RequiresAdmin); + var detectionResult = RunScript(detectionScriptTempFile, redistributable); // Redistributable is not installed if (detectionResult == 0) @@ -70,12 +71,12 @@ namespace LANCommander.SDK { extractTempPath = extractionResult.Directory; - PowerShellRuntime.RunScript(installScriptTempFile, installScript.RequiresAdmin, null, extractTempPath); + RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath); } } else { - PowerShellRuntime.RunScript(installScriptTempFile, installScript.RequiresAdmin, null, extractTempPath); + RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath); } } } @@ -164,5 +165,20 @@ namespace LANCommander.SDK return extractionResult; } + + private int RunScript(string path, Redistributable redistributable, bool requiresAdmin = false, string workingDirectory = "") + { + var script = new PowerShellScript(); + + script.AddVariable("Redistributable", redistributable); + + script.UseWorkingDirectory(workingDirectory); + script.UseFile(path); + + if (requiresAdmin) + script.RunAsAdmin(); + + return script.Execute(); + } } } From 97f459eaff467e2fb32074343d922b9b1a7637a7 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 15 Nov 2023 23:58:55 -0600 Subject: [PATCH 06/32] Move uninstall script execution to Playnite addon --- .../UninstallController.cs | 30 ++++++++++++++++++- LANCommander.SDK/GameManager.cs | 1 - 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/LANCommander.Playnite.Extension/UninstallController.cs b/LANCommander.Playnite.Extension/UninstallController.cs index eb23735..350b37a 100644 --- a/LANCommander.Playnite.Extension/UninstallController.cs +++ b/LANCommander.Playnite.Extension/UninstallController.cs @@ -1,4 +1,6 @@ using LANCommander.SDK.Enums; +using LANCommander.SDK.Helpers; +using LANCommander.SDK.PowerShell; using Playnite.SDK; using Playnite.SDK.Models; using Playnite.SDK.Plugins; @@ -25,11 +27,37 @@ namespace LANCommander.PlaynitePlugin { var gameManager = new LANCommander.SDK.GameManager(Plugin.LANCommanderClient, Plugin.Settings.InstallDirectory); + try + { + var scriptPath = ScriptHelper.GetScriptFilePath(Game.InstallDirectory, SDK.Enums.ScriptType.Uninstall); + + if (!String.IsNullOrEmpty(scriptPath)) + { + var manifest = ManifestHelper.Read(Game.InstallDirectory); + var script = new PowerShellScript(); + + var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id); + + script.AddVariable("InstallDirectory", Game.InstallDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + + script.UseFile(scriptPath); + + script.Execute(); + } + } + catch (Exception ex) + { + Logger.Error(ex, "There was an error running the uninstall script"); + } + gameManager.Uninstall(Game.InstallDirectory); } catch (Exception ex) { - + Logger.Error(ex, "There was an error uninstalling the game"); } InvokeOnUninstalled(new GameUninstalledEventArgs()); diff --git a/LANCommander.SDK/GameManager.cs b/LANCommander.SDK/GameManager.cs index dc2d733..110c627 100644 --- a/LANCommander.SDK/GameManager.cs +++ b/LANCommander.SDK/GameManager.cs @@ -101,7 +101,6 @@ namespace LANCommander.SDK try { Logger?.LogTrace("Running uninstall script"); - PowerShellRuntime.RunScript(installDirectory, ScriptType.Uninstall); } catch (Exception ex) { From eb05364542385e28649aa5feaffdf6aeae21df15 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 15 Nov 2023 23:59:12 -0600 Subject: [PATCH 07/32] Fix reference to static method in ScriptHelper --- LANCommander.SDK/Helpers/ScriptHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LANCommander.SDK/Helpers/ScriptHelper.cs b/LANCommander.SDK/Helpers/ScriptHelper.cs index 352cb96..3fde3f8 100644 --- a/LANCommander.SDK/Helpers/ScriptHelper.cs +++ b/LANCommander.SDK/Helpers/ScriptHelper.cs @@ -46,7 +46,7 @@ namespace LANCommander.SDK.Helpers if (script.RequiresAdmin) script.Contents = "# Requires Admin" + "\r\n\r\n" + script.Contents; - var filename = PowerShellRuntime.GetScriptFilePath(game, type); + var filename = GetScriptFilePath(game, type); if (File.Exists(filename)) File.Delete(filename); From 16dc60b90a76bf340ec6e15d301f01c22832b759 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 00:40:27 -0600 Subject: [PATCH 08/32] Run key change script in InstallController --- .../InstallController.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/LANCommander.Playnite.Extension/InstallController.cs b/LANCommander.Playnite.Extension/InstallController.cs index 1be1388..bd27e7b 100644 --- a/LANCommander.Playnite.Extension/InstallController.cs +++ b/LANCommander.Playnite.Extension/InstallController.cs @@ -119,6 +119,7 @@ namespace LANCommander.PlaynitePlugin RunInstallScript(installDirectory); RunNameChangeScript(installDirectory); + RunKeyChangeScript(installDirectory); InvokeOnInstalled(new GameInstalledEventArgs(installInfo)); } @@ -166,5 +167,23 @@ namespace LANCommander.PlaynitePlugin return script.Execute(); } + + private int RunKeyChangeScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + script.AddVariable("AllocatedKey", key); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + + return script.Execute(); + } } } From 8d85aca0a781740f1283e2dbba09231f4ea10f49 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 00:46:20 -0600 Subject: [PATCH 09/32] Fix plugin menu items to use new script execution --- .../LANCommanderLibraryPlugin.cs | 84 ++++++++++++++++--- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs index e118e19..491de78 100644 --- a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs +++ b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs @@ -1,4 +1,6 @@ using LANCommander.PlaynitePlugin.Extensions; +using LANCommander.SDK.Helpers; +using LANCommander.SDK.PowerShell; using Playnite.SDK; using Playnite.SDK.Events; using Playnite.SDK.Models; @@ -220,9 +222,9 @@ namespace LANCommander.PlaynitePlugin if (args.Games.Count == 1 && args.Games.First().IsInstalled && !String.IsNullOrWhiteSpace(args.Games.First().InstallDirectory)) { - var nameChangeScriptPath = LANCommander.SDK.PowerShellRuntime.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.NameChange); - var keyChangeScriptPath = LANCommander.SDK.PowerShellRuntime.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.KeyChange); - var installScriptPath = LANCommander.SDK.PowerShellRuntime.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.Install); + var nameChangeScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.NameChange); + var keyChangeScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.KeyChange); + var installScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.Install); if (File.Exists(nameChangeScriptPath)) { @@ -241,7 +243,8 @@ namespace LANCommander.PlaynitePlugin { var game = nameChangeArgs.Games.First(); - LANCommander.SDK.PowerShellRuntime.RunScript(game.InstallDirectory, SDK.Enums.ScriptType.NameChange, $@"""{result.SelectedString}"" ""{oldName}"""); + RunNameChangeScript(game.InstallDirectory, oldName, result.SelectedString); + LANCommanderClient.ChangeAlias(result.SelectedString); } } @@ -267,7 +270,7 @@ namespace LANCommander.PlaynitePlugin if (String.IsNullOrEmpty(newKey)) PlayniteApi.Dialogs.ShowErrorMessage("There are no more keys available on the server.", "No Keys Available"); else - LANCommander.SDK.PowerShellRuntime.RunScript(keyChangeArgs.Games.First().InstallDirectory, SDK.Enums.ScriptType.KeyChange, $@"""{newKey}"""); + RunKeyChangeScript(keyChangeArgs.Games.First().InstallDirectory, newKey); } else { @@ -289,13 +292,9 @@ namespace LANCommander.PlaynitePlugin Guid gameId; if (Guid.TryParse(installArgs.Games.First().GameId, out gameId)) - { - LANCommander.SDK.PowerShellRuntime.RunScript(installArgs.Games.First().InstallDirectory, SDK.Enums.ScriptType.Install); - } + RunInstallScript(installArgs.Games.First().InstallDirectory); else - { PlayniteApi.Dialogs.ShowErrorMessage("This game could not be found on the server. Your game may be corrupted."); - } } }; } @@ -391,6 +390,8 @@ namespace LANCommander.PlaynitePlugin } else { + var oldName = Settings.PlayerName; + Settings.PlayerName = result.SelectedString; Logger.Trace($"New player name of \"{Settings.PlayerName}\" has been set!"); @@ -404,7 +405,17 @@ namespace LANCommander.PlaynitePlugin Logger.Trace($"Running name change scripts across {games.Count} installed game(s)"); - LANCommander.SDK.PowerShellRuntime.RunScripts(games.Select(g => g.InstallDirectory), SDK.Enums.ScriptType.NameChange, Settings.PlayerName); + foreach (var game in games) + { + var script = new PowerShellScript(); + + script.AddVariable("OldName", oldName); + script.AddVariable("NewName", Settings.PlayerName); + + script.UseFile(ScriptHelper.GetScriptFilePath(game.InstallDirectory, SDK.Enums.ScriptType.NameChange)); + + script.Execute(); + } } } else @@ -523,5 +534,56 @@ namespace LANCommander.PlaynitePlugin PlayniteApi.Database.Games.Update(game); } + + private int RunInstallScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + + return script.Execute(); + } + + private int RunNameChangeScript(string installDirectory, string oldPlayerAlias, string newPlayerAlias) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); + script.AddVariable("OldPlayerAlias", oldPlayerAlias); + script.AddVariable("NewPlayerAlias", newPlayerAlias); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + + return script.Execute(); + } + + private int RunKeyChangeScript(string installDirectory, string key = "") + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + if (String.IsNullOrEmpty(key)) + key = LANCommanderClient.GetAllocatedKey(manifest.Id); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); + script.AddVariable("AllocatedKey", key); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + + return script.Execute(); + } } } From 03828bea6059eacd4c7ee298a0d4447602bddda5 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 00:46:42 -0600 Subject: [PATCH 10/32] Remove unused code from uninstall --- LANCommander.SDK/GameManager.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/LANCommander.SDK/GameManager.cs b/LANCommander.SDK/GameManager.cs index 110c627..a9163cc 100644 --- a/LANCommander.SDK/GameManager.cs +++ b/LANCommander.SDK/GameManager.cs @@ -96,16 +96,6 @@ namespace LANCommander.SDK public void Uninstall(string installDirectory) { - var manifest = ManifestHelper.Read(installDirectory); - - try - { - Logger?.LogTrace("Running uninstall script"); - } - catch (Exception ex) - { - Logger?.LogError(ex, "Error running uninstall script"); - } Logger?.LogTrace("Attempting to delete the install directory"); From 35f6dadf9cfa821c47fcf841b643ebd1a0333213 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 00:47:01 -0600 Subject: [PATCH 11/32] Convert game save registry export commands to inline scripts --- LANCommander.SDK/GameSaveManager.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index a7ffc1b..caf53de 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -1,6 +1,7 @@ using LANCommander.SDK; using LANCommander.SDK.Helpers; using LANCommander.SDK.Models; +using LANCommander.SDK.PowerShell; using SharpCompress.Archives; using SharpCompress.Archives.Zip; using SharpCompress.Common; @@ -126,7 +127,14 @@ namespace LANCommander.SDK { var registryImportFileContents = File.ReadAllText(registryImportFilePath); - PowerShellRuntime.RunCommand($"regedit.exe /s \"{registryImportFilePath}\"", registryImportFileContents.Contains("HKEY_LOCAL_MACHINE")); + var script = new PowerShellScript(); + + script.UseInline($"regedit.exe /s \"{registryImportFilePath}\""); + + if (registryImportFileContents.Contains("HKEY_LOCAL_MACHINE")) + script.RunAsAdmin(); + + script.Execute(); } #endregion @@ -199,7 +207,11 @@ namespace LANCommander.SDK tempRegFiles.Add(tempRegFile); } - PowerShellRuntime.RunCommand(exportCommand.ToString()); + var script = new PowerShellScript(); + + script.UseInline(exportCommand.ToString()); + + script.Execute(); var exportFile = new StringBuilder(); From 86211a7500fbc0cc6f17d033d903b23b71d1c756 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 00:47:13 -0600 Subject: [PATCH 12/32] Remove unused PowerShell code --- .../PowerShell/PowerShellFactory.cs | 14 -- LANCommander.SDK/PowerShellRuntime.cs | 173 ------------------ 2 files changed, 187 deletions(-) delete mode 100644 LANCommander.SDK/PowerShell/PowerShellFactory.cs delete mode 100644 LANCommander.SDK/PowerShellRuntime.cs diff --git a/LANCommander.SDK/PowerShell/PowerShellFactory.cs b/LANCommander.SDK/PowerShell/PowerShellFactory.cs deleted file mode 100644 index ace2d78..0000000 --- a/LANCommander.SDK/PowerShell/PowerShellFactory.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LANCommander.SDK.PowerShell -{ - public static class PowerShellFactory - { - public static PowerShellScript RunScript() - { - return new PowerShellScript(); - } - } -} diff --git a/LANCommander.SDK/PowerShellRuntime.cs b/LANCommander.SDK/PowerShellRuntime.cs deleted file mode 100644 index 18d8f8c..0000000 --- a/LANCommander.SDK/PowerShellRuntime.cs +++ /dev/null @@ -1,173 +0,0 @@ -using LANCommander.SDK.Enums; -using LANCommander.SDK.Models; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace LANCommander.SDK -{ - public static class PowerShellRuntime - { - public static readonly ILogger Logger; - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool Wow64RevertWow64FsRedirection(ref IntPtr ptr); - - public static void RunCommand(string command, bool asAdmin = false) - { - Logger?.LogTrace($"Executing command `{command}` | Admin: {asAdmin}"); - - var tempScript = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".ps1"); - - Logger?.LogTrace($"Creating temp script at path {tempScript}"); - - File.WriteAllText(tempScript, command); - - RunScript(tempScript, asAdmin); - - File.Delete(tempScript); - } - - public static int RunScript(string path, bool asAdmin = false, string arguments = null, string workingDirectory = null) - { - Logger?.LogTrace($"Executing script at path {path} | Admin: {asAdmin} | Arguments: {arguments}"); - - var wow64Value = IntPtr.Zero; - - // Disable Wow64 redirection so we can hit areas of the registry absolutely - Wow64DisableWow64FsRedirection(ref wow64Value); - - var process = new Process(); - - process.StartInfo.FileName = "powershell.exe"; - process.StartInfo.Arguments = $@"-ExecutionPolicy Unrestricted -File ""{path}"""; - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = false; - - if (arguments != null) - process.StartInfo.Arguments += " " + arguments; - - if (workingDirectory != null) - process.StartInfo.WorkingDirectory = workingDirectory; - - if (asAdmin) - { - process.StartInfo.Verb = "runas"; - process.StartInfo.UseShellExecute = true; - } - - process.Start(); - process.WaitForExit(); - - Wow64RevertWow64FsRedirection(ref wow64Value); - - return process.ExitCode; - } - - public static void RunScript(Game game, ScriptType type, string arguments = null) - { - RunScript(game.InstallDirectory, type, arguments); - } - - public static void RunScript(string installDirectory, ScriptType type, string arguments = null) - { - var path = GetScriptFilePath(installDirectory, type); - - if (File.Exists(path)) - { - var contents = File.ReadAllText(path); - - if (contents.StartsWith("# Requires Admin")) - RunScript(path, true, arguments); - else - RunScript(path, false, arguments); - } - } - - public static void RunScriptsAsAdmin(IEnumerable paths, string arguments = null) - { - // Concatenate scripts - var sb = new StringBuilder(); - - Logger?.LogTrace("Concatenating scripts..."); - - foreach (var path in paths) - { - var contents = File.ReadAllText(path); - - sb.AppendLine(contents); - - Logger?.LogTrace($"Added {path}!"); - } - - Logger?.LogTrace("Done concatenating!"); - - if (sb.Length > 0) - { - var scriptPath = Path.GetTempFileName(); - - Logger?.LogTrace($"Creating temp script at path {scriptPath}"); - - File.WriteAllText(scriptPath, sb.ToString()); - - RunScript(scriptPath, true, arguments); - } - } - - public static void RunScripts(IEnumerable installDirectories, ScriptType type, string arguments = null) - { - List scripts = new List(); - List adminScripts = new List(); - - foreach (var installDirectory in installDirectories) - { - var path = GetScriptFilePath(installDirectory, type); - - if (!File.Exists(path)) - continue; - - var contents = File.ReadAllText(path); - - if (contents.StartsWith("# Requires Admin")) - adminScripts.Add(path); - else - scripts.Add(path); - } - - RunScriptsAsAdmin(adminScripts, arguments); - - foreach (var script in scripts) - { - RunScript(script, false, arguments); - } - } - - public static string GetScriptFilePath(Game game, ScriptType type) - { - return GetScriptFilePath(game.InstallDirectory, type); - } - - public static string GetScriptFilePath(string installDirectory, ScriptType type) - { - Dictionary filenames = new Dictionary() { - { ScriptType.Install, "_install.ps1" }, - { ScriptType.Uninstall, "_uninstall.ps1" }, - { ScriptType.NameChange, "_changename.ps1" }, - { ScriptType.KeyChange, "_changekey.ps1" } - }; - - var filename = filenames[type]; - - return Path.Combine(installDirectory, filename); - } - } -} From c71cf9fedd79366d7b2409476e201c6c114be5a9 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 01:01:17 -0600 Subject: [PATCH 13/32] Cmdlet for installing game --- .../Cmdlets/Install-Game.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 LANCommander.PowerShell/Cmdlets/Install-Game.cs diff --git a/LANCommander.PowerShell/Cmdlets/Install-Game.cs b/LANCommander.PowerShell/Cmdlets/Install-Game.cs new file mode 100644 index 0000000..a68037a --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Install-Game.cs @@ -0,0 +1,51 @@ +using LANCommander.SDK; +using System; +using System.Diagnostics; +using System.Linq; +using System.Management.Automation; +using System.Windows.Forms; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsLifecycle.Install, "PrimaryDisplay")] + [OutputType(typeof(string))] + public class InstallGameCmdlet : PSCmdlet + { + [Parameter(Mandatory = true)] + public Client Client { get; set; } + + [Parameter(Mandatory = true)] + public Guid Id { get; set; } + + [Parameter(Mandatory = false)] + public string InstallDirectory { get; set; } = "C:\\Games"; + + protected override void ProcessRecord() + { + var gameManager = new GameManager(Client, InstallDirectory); + var game = Client.GetGame(Id); + + var progress = new ProgressRecord(1, $"Installing {game.Title}", "Progress:"); + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + gameManager.OnArchiveExtractionProgress += (long position, long length) => + { + // Only update a max of every 500ms + if (stopwatch.ElapsedMilliseconds > 500) + { + progress.PercentComplete = (int)Math.Ceiling((position / (decimal)length) * 100); + + WriteProgress(progress); + + stopwatch.Restart(); + } + }; + + gameManager.Install(Id); + + stopwatch.Stop(); + } + } +} From 839e9b49351fd9d8ffc13e4420561fcd112c579e Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 01:44:21 -0600 Subject: [PATCH 14/32] Run scripts after cmdlet install --- .../Cmdlets/Install-Game.cs | 59 ++++++++++++++++++- .../LANCommander.PowerShell.csproj | 1 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/LANCommander.PowerShell/Cmdlets/Install-Game.cs b/LANCommander.PowerShell/Cmdlets/Install-Game.cs index a68037a..ffd4308 100644 --- a/LANCommander.PowerShell/Cmdlets/Install-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Install-Game.cs @@ -1,4 +1,6 @@ using LANCommander.SDK; +using LANCommander.SDK.Helpers; +using LANCommander.SDK.PowerShell; using System; using System.Diagnostics; using System.Linq; @@ -43,9 +45,64 @@ namespace LANCommander.PowerShell.Cmdlets } }; - gameManager.Install(Id); + var installDirectory = gameManager.Install(Id); stopwatch.Stop(); + + RunInstallScript(installDirectory); + RunNameChangeScript(installDirectory); + RunKeyChangeScript(installDirectory); + } + + private int RunInstallScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + + return script.Execute(); + } + + private int RunNameChangeScript(string installDirectory) + { + var user = Client.GetProfile(); + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); + script.AddVariable("OldPlayerAlias", ""); + script.AddVariable("NewPlayerAlias", user.UserName); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + + return script.Execute(); + } + + private int RunKeyChangeScript(string installDirectory) + { + var manifest = ManifestHelper.Read(installDirectory); + var script = new PowerShellScript(); + + var key = Client.GetAllocatedKey(manifest.Id); + + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); + script.AddVariable("AllocatedKey", key); + + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + + return script.Execute(); } } } diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.csproj b/LANCommander.PowerShell/LANCommander.PowerShell.csproj index 515ee5d..aaa8ee5 100644 --- a/LANCommander.PowerShell/LANCommander.PowerShell.csproj +++ b/LANCommander.PowerShell/LANCommander.PowerShell.csproj @@ -46,6 +46,7 @@ + From 26f03f61fc86123b7452eb8590849c0eaca47bd8 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 01:44:35 -0600 Subject: [PATCH 15/32] Add public base URL to LC client --- LANCommander.SDK/Client.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/LANCommander.SDK/Client.cs b/LANCommander.SDK/Client.cs index d7db648..4f8bdaa 100644 --- a/LANCommander.SDK/Client.cs +++ b/LANCommander.SDK/Client.cs @@ -18,18 +18,24 @@ namespace LANCommander.SDK private readonly ILogger Logger; private readonly RestClient ApiClient; - private AuthToken Token; + private AuthToken Token; + + public string BaseUrl; public Client(string baseUrl) { - if (!String.IsNullOrWhiteSpace(baseUrl)) - ApiClient = new RestClient(baseUrl); + BaseUrl = baseUrl; + + if (!String.IsNullOrWhiteSpace(BaseUrl)) + ApiClient = new RestClient(BaseUrl); } public Client(string baseUrl, ILogger logger) { - if (!String.IsNullOrWhiteSpace(baseUrl)) - ApiClient = new RestClient(baseUrl); + BaseUrl = baseUrl; + + if (!String.IsNullOrWhiteSpace(BaseUrl)) + ApiClient = new RestClient(BaseUrl); Logger = logger; } From 8bd422249e645c76b2b9ce14c5bf41cc7d9e69f8 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 12:04:26 -0600 Subject: [PATCH 16/32] Fix Install-Game cmdlet name --- LANCommander.PowerShell/Cmdlets/Install-Game.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LANCommander.PowerShell/Cmdlets/Install-Game.cs b/LANCommander.PowerShell/Cmdlets/Install-Game.cs index ffd4308..fe5ce74 100644 --- a/LANCommander.PowerShell/Cmdlets/Install-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Install-Game.cs @@ -9,7 +9,7 @@ using System.Windows.Forms; namespace LANCommander.PowerShell.Cmdlets { - [Cmdlet(VerbsLifecycle.Install, "PrimaryDisplay")] + [Cmdlet(VerbsLifecycle.Install, "Game")] [OutputType(typeof(string))] public class InstallGameCmdlet : PSCmdlet { From 49c4b10cf935843ffee0bfcf518d0a91460157a9 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 12:04:41 -0600 Subject: [PATCH 17/32] Don't get key when uninstalling --- LANCommander.Playnite.Extension/UninstallController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/LANCommander.Playnite.Extension/UninstallController.cs b/LANCommander.Playnite.Extension/UninstallController.cs index 350b37a..8185bc4 100644 --- a/LANCommander.Playnite.Extension/UninstallController.cs +++ b/LANCommander.Playnite.Extension/UninstallController.cs @@ -36,8 +36,6 @@ namespace LANCommander.PlaynitePlugin var manifest = ManifestHelper.Read(Game.InstallDirectory); var script = new PowerShellScript(); - var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id); - script.AddVariable("InstallDirectory", Game.InstallDirectory); script.AddVariable("GameManifest", manifest); script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); From f7fa7aa9f326faf71873c865003d83a59386d13a Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 12:04:55 -0600 Subject: [PATCH 18/32] Add cmdlet for uninstalling a game --- .../Cmdlets/Uninstall-Game.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs diff --git a/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs new file mode 100644 index 0000000..0d15815 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs @@ -0,0 +1,42 @@ +using LANCommander.SDK; +using LANCommander.SDK.Helpers; +using LANCommander.SDK.PowerShell; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Windows.Forms; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsLifecycle.Uninstall, "Game")] + [OutputType(typeof(string))] + public class UninstallGameCmdlet : PSCmdlet + { + [Parameter(Mandatory = false)] + public string InstallDirectory { get; set; } = "C:\\Games"; + + protected override void ProcessRecord() + { + var scriptPath = ScriptHelper.GetScriptFilePath(InstallDirectory, SDK.Enums.ScriptType.Uninstall); + + if (!String.IsNullOrEmpty(scriptPath) && File.Exists(scriptPath)) + { + var manifest = ManifestHelper.Read(InstallDirectory); + var script = new PowerShellScript(); + + script.AddVariable("InstallDirectory", InstallDirectory); + script.AddVariable("GameManifest", manifest); + + script.UseFile(scriptPath); + + script.Execute(); + } + + var gameManager = new GameManager(null, InstallDirectory); + + gameManager.Uninstall(InstallDirectory); + } + } +} From 986fb87db1251deb0e26ec62b036d6f21f039568 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 12:06:18 -0600 Subject: [PATCH 19/32] Make install directory mandatory when uninstalling --- LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs index 0d15815..5746de8 100644 --- a/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs @@ -14,8 +14,8 @@ namespace LANCommander.PowerShell.Cmdlets [OutputType(typeof(string))] public class UninstallGameCmdlet : PSCmdlet { - [Parameter(Mandatory = false)] - public string InstallDirectory { get; set; } = "C:\\Games"; + [Parameter(Mandatory = true)] + public string InstallDirectory { get; set; } protected override void ProcessRecord() { From a9f3b7a39d56bdde06801ffffa2285f52716431e Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 14:06:40 -0600 Subject: [PATCH 20/32] Only execute scripts if they exists on the disk --- .../InstallController.cs | 72 +++++++++++------- .../LANCommanderLibraryPlugin.cs | 73 ++++++++++++------- .../UninstallController.cs | 2 +- 3 files changed, 95 insertions(+), 52 deletions(-) diff --git a/LANCommander.Playnite.Extension/InstallController.cs b/LANCommander.Playnite.Extension/InstallController.cs index bd27e7b..c762c86 100644 --- a/LANCommander.Playnite.Extension/InstallController.cs +++ b/LANCommander.Playnite.Extension/InstallController.cs @@ -7,6 +7,7 @@ using Playnite.SDK.Models; using Playnite.SDK.Plugins; using System; using System.Diagnostics; +using System.IO; using System.Linq; namespace LANCommander.PlaynitePlugin @@ -139,51 +140,72 @@ namespace LANCommander.PlaynitePlugin private int RunInstallScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); - script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); - return script.Execute(); + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + + return script.Execute(); + } + + return 0; } private int RunNameChangeScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); - script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); - script.AddVariable("OldPlayerAlias", ""); - script.AddVariable("NewPlayerAlias", Plugin.Settings.PlayerName); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + script.AddVariable("OldPlayerAlias", ""); + script.AddVariable("NewPlayerAlias", Plugin.Settings.PlayerName); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } private int RunKeyChangeScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange); - var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); - script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); - script.AddVariable("AllocatedKey", key); + var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory); + script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress); + script.AddVariable("AllocatedKey", key); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } } } diff --git a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs index 491de78..21926a0 100644 --- a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs +++ b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs @@ -538,52 +538,73 @@ namespace LANCommander.PlaynitePlugin private int RunInstallScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); - script.AddVariable("ServerAddress", Settings.ServerAddress); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } private int RunNameChangeScript(string installDirectory, string oldPlayerAlias, string newPlayerAlias) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); - script.AddVariable("ServerAddress", Settings.ServerAddress); - script.AddVariable("OldPlayerAlias", oldPlayerAlias); - script.AddVariable("NewPlayerAlias", newPlayerAlias); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); + script.AddVariable("OldPlayerAlias", oldPlayerAlias); + script.AddVariable("NewPlayerAlias", newPlayerAlias); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } private int RunKeyChangeScript(string installDirectory, string key = "") { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange); - if (String.IsNullOrEmpty(key)) - key = LANCommanderClient.GetAllocatedKey(manifest.Id); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); - script.AddVariable("ServerAddress", Settings.ServerAddress); - script.AddVariable("AllocatedKey", key); + if (String.IsNullOrEmpty(key)) + key = LANCommanderClient.GetAllocatedKey(manifest.Id); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory); + script.AddVariable("ServerAddress", Settings.ServerAddress); + script.AddVariable("AllocatedKey", key); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } } } diff --git a/LANCommander.Playnite.Extension/UninstallController.cs b/LANCommander.Playnite.Extension/UninstallController.cs index 8185bc4..df9788f 100644 --- a/LANCommander.Playnite.Extension/UninstallController.cs +++ b/LANCommander.Playnite.Extension/UninstallController.cs @@ -31,7 +31,7 @@ namespace LANCommander.PlaynitePlugin { var scriptPath = ScriptHelper.GetScriptFilePath(Game.InstallDirectory, SDK.Enums.ScriptType.Uninstall); - if (!String.IsNullOrEmpty(scriptPath)) + if (!String.IsNullOrEmpty(scriptPath) && File.Exists(scriptPath)) { var manifest = ManifestHelper.Read(Game.InstallDirectory); var script = new PowerShellScript(); From 1b72d9002a07478bf288ee76fe5b35afb3f75af0 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 14:07:38 -0600 Subject: [PATCH 21/32] Switch PowerShell library to 4.6.2. Fix missing includes in project. --- LANCommander.PowerShell/LANCommander.PowerShell.csproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.csproj b/LANCommander.PowerShell/LANCommander.PowerShell.csproj index aaa8ee5..9f7d67d 100644 --- a/LANCommander.PowerShell/LANCommander.PowerShell.csproj +++ b/LANCommander.PowerShell/LANCommander.PowerShell.csproj @@ -9,9 +9,10 @@ Properties LANCommander.PowerShell LANCommander.PowerShell - v4.7.2 + v4.6.2 512 true + true @@ -46,6 +47,7 @@ + @@ -56,7 +58,9 @@ - + + PreserveNewest + From 2282d9b01396da00eb01989540867021356f86bb Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 14:08:35 -0600 Subject: [PATCH 22/32] Include PowerShell project in Playnite extension --- .../LANCommander.PlaynitePlugin.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/LANCommander.Playnite.Extension/LANCommander.PlaynitePlugin.csproj b/LANCommander.Playnite.Extension/LANCommander.PlaynitePlugin.csproj index 38dff6c..597df0b 100644 --- a/LANCommander.Playnite.Extension/LANCommander.PlaynitePlugin.csproj +++ b/LANCommander.Playnite.Extension/LANCommander.PlaynitePlugin.csproj @@ -12,6 +12,7 @@ v4.6.2 512 true + true true @@ -140,6 +141,10 @@ + + {807943bf-0c7d-4ed3-8393-cfee64e3138c} + LANCommander.PowerShell + {4c2a71fd-a30b-4d62-888a-4ef843d8e506} LANCommander.SDK From 196feedded04b43be93423851d61ef0784e2664d Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 14:34:00 -0600 Subject: [PATCH 23/32] Load PowerShell module on script execution. Add cmdlet to deserialize/decode variables. --- .../Cmdlets/ConvertFrom-SerializedBase64.cs | 24 +++++++++++++++++++ .../LANCommander.PowerShell.csproj | 1 + .../PowerShell/PowerShellScript.cs | 17 ++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs diff --git a/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs new file mode 100644 index 0000000..055aeee --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; +using System.Text; +using System.Threading.Tasks; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsData.ConvertFrom, "SerializedBase64")] + [OutputType(typeof(object))] + public class ConvertFromSerializedBase64Cmdlet : PSCmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public string Input { get; set; } + + protected override void ProcessRecord() + { + var xml = Encoding.UTF8.GetString(Convert.FromBase64String(Input)); + + WriteObject(PSSerializer.Deserialize(xml)); + } + } +} diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.csproj b/LANCommander.PowerShell/LANCommander.PowerShell.csproj index 9f7d67d..2357de7 100644 --- a/LANCommander.PowerShell/LANCommander.PowerShell.csproj +++ b/LANCommander.PowerShell/LANCommander.PowerShell.csproj @@ -46,6 +46,7 @@ + diff --git a/LANCommander.SDK/PowerShell/PowerShellScript.cs b/LANCommander.SDK/PowerShell/PowerShellScript.cs index 6f300f9..1d86f51 100644 --- a/LANCommander.SDK/PowerShell/PowerShellScript.cs +++ b/LANCommander.SDK/PowerShell/PowerShellScript.cs @@ -18,18 +18,21 @@ namespace LANCommander.SDK.PowerShell private bool IgnoreWow64 { get; set; } = false; private ICollection Variables { get; set; } private Dictionary Arguments { get; set; } + private List Modules { get; set; } private Process Process { get; set; } public PowerShellScript() { Variables = new List(); Arguments = new Dictionary(); + Modules = new List(); Process = new Process(); Process.StartInfo.FileName = "powershell.exe"; Process.StartInfo.RedirectStandardOutput = false; AddArgument("ExecutionPolicy", "Unrestricted"); + AddModule(Path.Combine(Environment.CurrentDirectory, "LANCommander.PowerShell.psd1")); } public PowerShellScript UseFile(string path) @@ -88,6 +91,13 @@ namespace LANCommander.SDK.PowerShell return this; } + public PowerShellScript AddModule(string path) + { + Modules.Add(path); + + return this; + } + public PowerShellScript RunAsAdmin() { AsAdmin = true; @@ -111,9 +121,14 @@ namespace LANCommander.SDK.PowerShell var wow64Value = IntPtr.Zero; + foreach (var module in Modules) + { + scriptBuilder.AppendLine($"Import-Module \"{module}\""); + } + foreach (var variable in Variables) { - scriptBuilder.AppendLine($"${variable.Name} = Convert-FromSerializedBase64 \"{Serialize(variable.Value)}\""); + scriptBuilder.AppendLine($"${variable.Name} = ConvertFrom-SerializedBase64 \"{Serialize(variable.Value)}\""); } scriptBuilder.AppendLine(Contents); From ed1b4973d3108c6e640419df9ace0ebdf7e31365 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 14:43:11 -0600 Subject: [PATCH 24/32] Fix cmdlet export specified by module manifest --- .../LANCommander.PowerShell.psd1 | Bin 8022 -> 8022 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.psd1 b/LANCommander.PowerShell/LANCommander.PowerShell.psd1 index 52b16e5c1381d6e249d47a7eb3b44108dc4b9778..7237c50e66600f386871344947ec57b24a69d06c 100644 GIT binary patch delta 16 Ycmca+cg=1?k;vp9B0`&6L@sdw07EthHvj+t delta 16 Xcmca+cg=1?k;r5oaiPsEBA2)TJL?8c From 8abc2fa15e0c608fe3c8ca568278bad256f712ff Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 15:20:50 -0600 Subject: [PATCH 25/32] Add cmdlet for encoding serialized objects for PS --- .../Cmdlets/ConvertFrom-SerializedBase64.cs | 2 +- .../Cmdlets/ConvertTo-SerializedBase64.cs | 24 +++++++++++++++++++ .../LANCommander.PowerShell.csproj | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs diff --git a/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs index 055aeee..d600b38 100644 --- a/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs +++ b/LANCommander.PowerShell/Cmdlets/ConvertFrom-SerializedBase64.cs @@ -9,7 +9,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsData.ConvertFrom, "SerializedBase64")] [OutputType(typeof(object))] - public class ConvertFromSerializedBase64Cmdlet : PSCmdlet + public class ConvertFromSerializedBase64Cmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Input { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs b/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs new file mode 100644 index 0000000..fe92654 --- /dev/null +++ b/LANCommander.PowerShell/Cmdlets/ConvertTo-SerializedBase64.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; +using System.Text; +using System.Threading.Tasks; + +namespace LANCommander.PowerShell.Cmdlets +{ + [Cmdlet(VerbsData.ConvertTo, "SerializedBase64")] + [OutputType(typeof(object))] + public class ConvertToSerializedBase64Cmdlet : Cmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public object Input { get; set; } + + protected override void ProcessRecord() + { + var output = Convert.ToBase64String(Encoding.UTF8.GetBytes(PSSerializer.Serialize(Input))); + + WriteObject(output); + } + } +} diff --git a/LANCommander.PowerShell/LANCommander.PowerShell.csproj b/LANCommander.PowerShell/LANCommander.PowerShell.csproj index 2357de7..b59a2f6 100644 --- a/LANCommander.PowerShell/LANCommander.PowerShell.csproj +++ b/LANCommander.PowerShell/LANCommander.PowerShell.csproj @@ -46,6 +46,7 @@ + From 982227cf1fd3618127feeaea135783da111365e6 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 15:21:50 -0600 Subject: [PATCH 26/32] Change to inherit from Cmdlet --- LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs | 2 +- LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs | 2 +- LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs | 2 +- LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs | 2 +- LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs | 2 +- LANCommander.PowerShell/Cmdlets/Install-Game.cs | 2 +- LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs | 2 +- LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs | 2 +- LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs b/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs index 5bb019d..a31949a 100644 --- a/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs +++ b/LANCommander.PowerShell/Cmdlets/Convert-AspectRatio.cs @@ -11,7 +11,7 @@ namespace LANCommander.PowerShell.Cmdlets [Cmdlet(VerbsData.Convert, "AspectRatio")] [OutputType(typeof(string))] - public class ConvertAspectRatioCmdlet : PSCmdlet + public class ConvertAspectRatioCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0)] public int Width { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs b/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs index 87b3c09..dced3b9 100644 --- a/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs +++ b/LANCommander.PowerShell/Cmdlets/ConvertTo-StringBytes.cs @@ -6,7 +6,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsData.ConvertTo, "StringBytes")] [OutputType(typeof(byte[]))] - public class ConvertToStringBytesCmdlet : PSCmdlet + public class ConvertToStringBytesCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Input { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs b/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs index 0e73580..95e2e46 100644 --- a/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs +++ b/LANCommander.PowerShell/Cmdlets/Edit-PatchBinary.cs @@ -6,7 +6,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsData.Edit, "PatchBinary")] [OutputType(typeof(string))] - public class EditPatchBinaryCmdlet : PSCmdlet + public class EditPatchBinaryCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0)] public long Offset { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs b/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs index b012bd5..d11ea2b 100644 --- a/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs +++ b/LANCommander.PowerShell/Cmdlets/Get-GameManifest.cs @@ -6,7 +6,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsCommon.Get, "GameManifest")] [OutputType(typeof(GameManifest))] - public class GetGameManifestCmdlet : PSCmdlet + public class GetGameManifestCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Path { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs b/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs index 0b53547..93c838e 100644 --- a/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs +++ b/LANCommander.PowerShell/Cmdlets/Get-PrimaryDisplay.cs @@ -6,7 +6,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsCommon.Get, "PrimaryDisplay")] [OutputType(typeof(string))] - public class GetPrimaryDisplayCmdlet : PSCmdlet + public class GetPrimaryDisplayCmdlet : Cmdlet { protected override void ProcessRecord() { diff --git a/LANCommander.PowerShell/Cmdlets/Install-Game.cs b/LANCommander.PowerShell/Cmdlets/Install-Game.cs index fe5ce74..84d8b5c 100644 --- a/LANCommander.PowerShell/Cmdlets/Install-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Install-Game.cs @@ -11,7 +11,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsLifecycle.Install, "Game")] [OutputType(typeof(string))] - public class InstallGameCmdlet : PSCmdlet + public class InstallGameCmdlet : Cmdlet { [Parameter(Mandatory = true)] public Client Client { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs index 5746de8..27b3dc4 100644 --- a/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Uninstall-Game.cs @@ -12,7 +12,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsLifecycle.Uninstall, "Game")] [OutputType(typeof(string))] - public class UninstallGameCmdlet : PSCmdlet + public class UninstallGameCmdlet : Cmdlet { [Parameter(Mandatory = true)] public string InstallDirectory { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs b/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs index 6d9ad0c..28ff74d 100644 --- a/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs +++ b/LANCommander.PowerShell/Cmdlets/Write-GameManifest.cs @@ -6,7 +6,7 @@ namespace LANCommander.PowerShell.Cmdlets { [Cmdlet(VerbsCommunications.Write, "GameManifest")] [OutputType(typeof(string))] - public class WriteGameManifestCmdlet : PSCmdlet + public class WriteGameManifestCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Path { get; set; } diff --git a/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs b/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs index 32cda9c..3a96f72 100644 --- a/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs +++ b/LANCommander.PowerShell/Cmdlets/Write-ReplaceContentInFile.cs @@ -7,7 +7,7 @@ namespace LANCommander.PowerShell.Cmdlets [Cmdlet(VerbsCommunications.Write, "ReplaceContentInFile")] [OutputType(typeof(string))] - public class ReplaceContentInFileCmdlet : PSCmdlet + public class ReplaceContentInFileCmdlet : Cmdlet { [Parameter(Mandatory = true, Position = 0)] public string Pattern { get; set; } From e723a5345be26b313b66710d22d3b0df60306742 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 15:22:20 -0600 Subject: [PATCH 27/32] Scaffold tests for cmdlets --- LANCommander.PowerShell.Tests/Cmdlets.cs | 36 +++++++++ .../LANCommander.PowerShell.Tests.csproj | 75 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 20 +++++ LANCommander.PowerShell.Tests/packages.config | 5 ++ LANCommander.sln | 6 ++ 5 files changed, 142 insertions(+) create mode 100644 LANCommander.PowerShell.Tests/Cmdlets.cs create mode 100644 LANCommander.PowerShell.Tests/LANCommander.PowerShell.Tests.csproj create mode 100644 LANCommander.PowerShell.Tests/Properties/AssemblyInfo.cs create mode 100644 LANCommander.PowerShell.Tests/packages.config diff --git a/LANCommander.PowerShell.Tests/Cmdlets.cs b/LANCommander.PowerShell.Tests/Cmdlets.cs new file mode 100644 index 0000000..062dc71 --- /dev/null +++ b/LANCommander.PowerShell.Tests/Cmdlets.cs @@ -0,0 +1,36 @@ +using LANCommander.PowerShell.Cmdlets; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Linq; + +namespace LANCommander.PowerShell.Tests +{ + [TestClass] + public class CmdletTests + { + [TestMethod] + public void ConvertToSerializedBase64ShouldBeDeserializable() + { + var testPhrase = "Hello world! This should be deserializable back to its original form."; + + var encodingCmdlet = new ConvertToSerializedBase64Cmdlet() + { + Input = testPhrase + }; + + var encodingResults = encodingCmdlet.Invoke().OfType().ToList(); + + Assert.AreEqual(1, encodingResults.Count); + + var decodingCmdlet = new ConvertFromSerializedBase64Cmdlet() + { + Input = encodingResults.First() + }; + + var decodingResults = decodingCmdlet.Invoke().OfType().ToList(); + + Assert.AreEqual(1, encodingResults.Count); + Assert.AreEqual(testPhrase, decodingResults.First()); + } + } +} diff --git a/LANCommander.PowerShell.Tests/LANCommander.PowerShell.Tests.csproj b/LANCommander.PowerShell.Tests/LANCommander.PowerShell.Tests.csproj new file mode 100644 index 0000000..af5df94 --- /dev/null +++ b/LANCommander.PowerShell.Tests/LANCommander.PowerShell.Tests.csproj @@ -0,0 +1,75 @@ + + + + + + Debug + AnyCPU + {D7069A13-F0AA-4CBF-9013-4276F130A6DD} + Library + Properties + LANCommander.PowerShell.Tests + LANCommander.PowerShell.Tests + v4.6.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + + + + + + + + + + + + + {807943bf-0c7d-4ed3-8393-cfee64e3138c} + LANCommander.PowerShell + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/LANCommander.PowerShell.Tests/Properties/AssemblyInfo.cs b/LANCommander.PowerShell.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..82c8b70 --- /dev/null +++ b/LANCommander.PowerShell.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("LANCommander.PowerShell.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LANCommander.PowerShell.Tests")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("d7069a13-f0aa-4cbf-9013-4276f130a6dd")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/LANCommander.PowerShell.Tests/packages.config b/LANCommander.PowerShell.Tests/packages.config new file mode 100644 index 0000000..e47cc4d --- /dev/null +++ b/LANCommander.PowerShell.Tests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LANCommander.sln b/LANCommander.sln index 5f6fef2..f77170c 100644 --- a/LANCommander.sln +++ b/LANCommander.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.PCGamingWiki", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.PowerShell", "LANCommander.PowerShell\LANCommander.PowerShell.csproj", "{807943BF-0C7D-4ED3-8393-CFEE64E3138C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.PowerShell.Tests", "LANCommander.PowerShell.Tests\LANCommander.PowerShell.Tests.csproj", "{D7069A13-F0AA-4CBF-9013-4276F130A6DD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Debug|Any CPU.Build.0 = Debug|Any CPU {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.ActiveCfg = Release|Any CPU {807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.Build.0 = Release|Any CPU + {D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 7649e63195b675e0849a3b64642eea5c6ac61c92 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 15:36:45 -0600 Subject: [PATCH 28/32] Add test for Convert-AspectRatio --- LANCommander.PowerShell.Tests/Cmdlets.cs | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/LANCommander.PowerShell.Tests/Cmdlets.cs b/LANCommander.PowerShell.Tests/Cmdlets.cs index 062dc71..b56e654 100644 --- a/LANCommander.PowerShell.Tests/Cmdlets.cs +++ b/LANCommander.PowerShell.Tests/Cmdlets.cs @@ -32,5 +32,33 @@ namespace LANCommander.PowerShell.Tests Assert.AreEqual(1, encodingResults.Count); Assert.AreEqual(testPhrase, decodingResults.First()); } + + [TestMethod] + [DataRow(640, 480, 640, 360, 16, 9)] + [DataRow(1024, 768, 1024, 576, 16, 9)] + [DataRow(1600, 1200, 1600, 900, 16, 9)] + [DataRow(1920, 1080, 1440, 1080, 4, 3)] + [DataRow(1366, 1024, 1024, 768, 4, 3)] + [DataRow(854, 480, 640, 480, 4, 3)] + public void ConvertAspectRatioShouldReturnCorrectBounds(int x1, int y1, int x2, int y2, int ratioX, int ratioY) + { + var aspectRatio = (double)ratioX / (double)ratioY; + + var cmdlet = new ConvertAspectRatioCmdlet() + { + AspectRatio = aspectRatio, + Width = x1, + Height = y1 + }; + + var output = cmdlet.Invoke().OfType().ToList(); + + Assert.AreEqual(1, output.Count); + + var bounds = output.First(); + + Assert.AreEqual(x2, bounds.Width); + Assert.AreEqual(y2, bounds.Height); + } } } From 2cb7013120a9fd0e1f6d6a0e0e1caaae21860f7e Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 16 Nov 2023 15:42:34 -0600 Subject: [PATCH 29/32] Write final install directory as output for Install-Game. Only process scripts that exist --- .../Cmdlets/Install-Game.cs | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/LANCommander.PowerShell/Cmdlets/Install-Game.cs b/LANCommander.PowerShell/Cmdlets/Install-Game.cs index 84d8b5c..c24b5ed 100644 --- a/LANCommander.PowerShell/Cmdlets/Install-Game.cs +++ b/LANCommander.PowerShell/Cmdlets/Install-Game.cs @@ -3,6 +3,7 @@ using LANCommander.SDK.Helpers; using LANCommander.SDK.PowerShell; using System; using System.Diagnostics; +using System.IO; using System.Linq; using System.Management.Automation; using System.Windows.Forms; @@ -52,57 +53,80 @@ namespace LANCommander.PowerShell.Cmdlets RunInstallScript(installDirectory); RunNameChangeScript(installDirectory); RunKeyChangeScript(installDirectory); + + WriteObject(installDirectory); } private int RunInstallScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", InstallDirectory); - script.AddVariable("ServerAddress", Client.BaseUrl); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); - return script.Execute(); + script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install)); + + return script.Execute(); + } + + return 0; } private int RunNameChangeScript(string installDirectory) { var user = Client.GetProfile(); var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange); + + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", InstallDirectory); - script.AddVariable("ServerAddress", Client.BaseUrl); - script.AddVariable("OldPlayerAlias", ""); - script.AddVariable("NewPlayerAlias", user.UserName); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); + script.AddVariable("OldPlayerAlias", ""); + script.AddVariable("NewPlayerAlias", user.UserName); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange)); + script.UseFile(path); - return script.Execute(); + return script.Execute(); + } + + return 0; } private int RunKeyChangeScript(string installDirectory) { var manifest = ManifestHelper.Read(installDirectory); - var script = new PowerShellScript(); + var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange); - var key = Client.GetAllocatedKey(manifest.Id); + if (File.Exists(path)) + { + var script = new PowerShellScript(); - script.AddVariable("InstallDirectory", installDirectory); - script.AddVariable("GameManifest", manifest); - script.AddVariable("DefaultInstallDirectory", InstallDirectory); - script.AddVariable("ServerAddress", Client.BaseUrl); - script.AddVariable("AllocatedKey", key); + var key = Client.GetAllocatedKey(manifest.Id); - script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange)); + script.AddVariable("InstallDirectory", installDirectory); + script.AddVariable("GameManifest", manifest); + script.AddVariable("DefaultInstallDirectory", InstallDirectory); + script.AddVariable("ServerAddress", Client.BaseUrl); + script.AddVariable("AllocatedKey", key); - return script.Execute(); + script.UseFile(path); + + return script.Execute(); + } + + return 0; } } } From aed9935b16a1b35c1c48549b04ef9aefeea4e5a3 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Fri, 17 Nov 2023 00:46:05 -0600 Subject: [PATCH 30/32] Updated default snippets --- .../Snippets/Examples/Copy Directory.ps1 | 2 +- .../Snippets/Examples/Create Directory.ps1 | 2 +- .../Snippets/Examples/Patch Binary.ps1 | 2 +- .../Snippets/Examples/Remove Directory.ps1 | 2 +- .../Snippets/Examples/Rename File.ps1 | 2 +- .../Examples/Replace Content In File.ps1 | 2 -- .../Examples/Separate ASCII Bytes.ps1 | 2 -- .../Examples/Set Compatibility Mode.ps1 | 2 +- .../Examples/String to ASCII Bytes.ps1 | 2 -- .../Snippets/Examples/Trim String.ps1 | 4 +-- .../Snippets/Examples/Write to File.ps1 | 2 +- .../Functions/Convert-AspectRatio.ps1 | 2 ++ .../Functions/ConvertTo-StringBytes.ps1 | 2 ++ .../Snippets/Functions/Edit-PatchBinary.ps1 | 1 + .../Snippets/Functions/Get-43Resolution.ps1 | 14 --------- .../Snippets/Functions/Get-AsciiBytes.ps1 | 30 ------------------- .../Snippets/Functions/Get-GameManifest.ps1 | 1 + .../Snippets/Functions/Get-PrimaryDisplay.ps1 | 2 ++ .../Snippets/Functions/Patch-Binary.ps1 | 11 ------- .../Functions/Separate-AsciiBytes.ps1 | 12 -------- .../Functions/Write-ReplaceContentInFile.ps1 | 7 ++--- .../Snippets/Variables/Allocated Key.ps1 | 1 + .../Variables/Default Install Directory.ps1 | 1 + LANCommander/Snippets/Variables/Display.ps1 | 3 -- .../Variables/Game Install Directory.ps1 | 1 + .../Snippets/Variables/Game Manifest.ps1 | 1 + .../Snippets/Variables/InstallDir.ps1 | 1 - .../{NewName.ps1 => New Player Alias.ps1} | 0 .../{OldName.ps1 => Old Player Alias.ps1} | 0 .../Snippets/Variables/Server Address.ps1 | 1 + 30 files changed, 24 insertions(+), 91 deletions(-) delete mode 100644 LANCommander/Snippets/Examples/Replace Content In File.ps1 delete mode 100644 LANCommander/Snippets/Examples/Separate ASCII Bytes.ps1 delete mode 100644 LANCommander/Snippets/Examples/String to ASCII Bytes.ps1 create mode 100644 LANCommander/Snippets/Functions/Convert-AspectRatio.ps1 create mode 100644 LANCommander/Snippets/Functions/ConvertTo-StringBytes.ps1 create mode 100644 LANCommander/Snippets/Functions/Edit-PatchBinary.ps1 delete mode 100644 LANCommander/Snippets/Functions/Get-43Resolution.ps1 delete mode 100644 LANCommander/Snippets/Functions/Get-AsciiBytes.ps1 create mode 100644 LANCommander/Snippets/Functions/Get-GameManifest.ps1 create mode 100644 LANCommander/Snippets/Functions/Get-PrimaryDisplay.ps1 delete mode 100644 LANCommander/Snippets/Functions/Patch-Binary.ps1 delete mode 100644 LANCommander/Snippets/Functions/Separate-AsciiBytes.ps1 create mode 100644 LANCommander/Snippets/Variables/Allocated Key.ps1 create mode 100644 LANCommander/Snippets/Variables/Default Install Directory.ps1 delete mode 100644 LANCommander/Snippets/Variables/Display.ps1 create mode 100644 LANCommander/Snippets/Variables/Game Install Directory.ps1 create mode 100644 LANCommander/Snippets/Variables/Game Manifest.ps1 delete mode 100644 LANCommander/Snippets/Variables/InstallDir.ps1 rename LANCommander/Snippets/Variables/{NewName.ps1 => New Player Alias.ps1} (100%) rename LANCommander/Snippets/Variables/{OldName.ps1 => Old Player Alias.ps1} (100%) create mode 100644 LANCommander/Snippets/Variables/Server Address.ps1 diff --git a/LANCommander/Snippets/Examples/Copy Directory.ps1 b/LANCommander/Snippets/Examples/Copy Directory.ps1 index 26c82d5..02c366f 100644 --- a/LANCommander/Snippets/Examples/Copy Directory.ps1 +++ b/LANCommander/Snippets/Examples/Copy Directory.ps1 @@ -1 +1 @@ -Copy-Item -Path "$InstallDir\" -Destination "$InstallDir\" -Recurse \ No newline at end of file +Copy-Item -Path "$InstallDirectory\" -Destination "$InstallDirectory\" -Recurse \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Create Directory.ps1 b/LANCommander/Snippets/Examples/Create Directory.ps1 index b5d5d4c..b65e50d 100644 --- a/LANCommander/Snippets/Examples/Create Directory.ps1 +++ b/LANCommander/Snippets/Examples/Create Directory.ps1 @@ -1 +1 @@ -New-Item -ItemType Directory -Force -Path "$InstallDir\" \ No newline at end of file +New-Item -ItemType Directory -Force -Path "$InstallDirectory\" \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Patch Binary.ps1 b/LANCommander/Snippets/Examples/Patch Binary.ps1 index 5019bf2..b3568ad 100644 --- a/LANCommander/Snippets/Examples/Patch Binary.ps1 +++ b/LANCommander/Snippets/Examples/Patch Binary.ps1 @@ -1,2 +1,2 @@ # Writes byte[] to a file at an offset -Patch-Binary -FilePath "$InstallDir\" -Offset 0x00 -Data $bytes \ No newline at end of file +Patch-Binary -FilePath "$InstallDirectory\" -Offset 0x00 -Data $bytes \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Remove Directory.ps1 b/LANCommander/Snippets/Examples/Remove Directory.ps1 index 5df8909..8425c7b 100644 --- a/LANCommander/Snippets/Examples/Remove Directory.ps1 +++ b/LANCommander/Snippets/Examples/Remove Directory.ps1 @@ -1 +1 @@ -Remove-Item "$InstallDir\" -Recurse -ErrorAction Ignore \ No newline at end of file +Remove-Item "$InstallDirectory\" -Recurse -ErrorAction Ignore \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Rename File.ps1 b/LANCommander/Snippets/Examples/Rename File.ps1 index b315277..9042ba1 100644 --- a/LANCommander/Snippets/Examples/Rename File.ps1 +++ b/LANCommander/Snippets/Examples/Rename File.ps1 @@ -1 +1 @@ -Rename-Item -Path "$InstallDir\" -NewName "$InstallDir\" \ No newline at end of file +Rename-Item -Path "$InstallDirectory\" -NewName "$InstallDirectory\" \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Replace Content In File.ps1 b/LANCommander/Snippets/Examples/Replace Content In File.ps1 deleted file mode 100644 index c28c8bf..0000000 --- a/LANCommander/Snippets/Examples/Replace Content In File.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -# Use regex to replace text within a file. Quotes are escaped by double quoting ("") -Write-ReplaceContentInFile -Regex '^game.setPlayerName "(.+)"' -Replacement "game.setPlayerName ""$NewName""" -FilePath "$InstallDir\" \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Separate ASCII Bytes.ps1 b/LANCommander/Snippets/Examples/Separate ASCII Bytes.ps1 deleted file mode 100644 index 2ea805a..0000000 --- a/LANCommander/Snippets/Examples/Separate ASCII Bytes.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -# Takes an input byte[] and separates it with 0x00 between each character -$bytes = Separate-AsciiBytes -Data $bytes \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Set Compatibility Mode.ps1 b/LANCommander/Snippets/Examples/Set Compatibility Mode.ps1 index b9e130d..0ebf256 100644 --- a/LANCommander/Snippets/Examples/Set Compatibility Mode.ps1 +++ b/LANCommander/Snippets/Examples/Set Compatibility Mode.ps1 @@ -9,4 +9,4 @@ # WIN7RTM # WIN8RTM # See: https://ss64.com/nt/syntax-compatibility.html -New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" -Name "$InstallDir\" -Value "~ WINXPSP2 HIGHDPIAWARE" -Force \ No newline at end of file +New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" -Name "$InstallDirectory\" -Value "~ WINXPSP2 HIGHDPIAWARE" -Force \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/String to ASCII Bytes.ps1 b/LANCommander/Snippets/Examples/String to ASCII Bytes.ps1 deleted file mode 100644 index d40c156..0000000 --- a/LANCommander/Snippets/Examples/String to ASCII Bytes.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -# Convert an input string to ASCII-encoded byte[]. Shorter strings will pad out to 12 bytes, longer strings will be trimmed. -$bytes = Get-AsciiBytes -InputString "Hello world!" -MaxLength 12 \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Trim String.ps1 b/LANCommander/Snippets/Examples/Trim String.ps1 index b4d7b94..2a72e13 100644 --- a/LANCommander/Snippets/Examples/Trim String.ps1 +++ b/LANCommander/Snippets/Examples/Trim String.ps1 @@ -1,4 +1,4 @@ # Trim a string down to a specified amount of characters -if ($NewName.Length -gt 10) { - $NewName = $NewName.Substring(0, 10); +if ($NewPlayerAlias.Length -gt 10) { + $NewPlayerAlias = $NewPlayerAlias.Substring(0, 10); } \ No newline at end of file diff --git a/LANCommander/Snippets/Examples/Write to File.ps1 b/LANCommander/Snippets/Examples/Write to File.ps1 index e2e2bbf..8dbb621 100644 --- a/LANCommander/Snippets/Examples/Write to File.ps1 +++ b/LANCommander/Snippets/Examples/Write to File.ps1 @@ -1,2 +1,2 @@ # Write contents of a string to a file -Set-Content "$InstallDir\" "Hello world!" \ No newline at end of file +Set-Content "$InstallDirectory\" "Hello world!" \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Convert-AspectRatio.ps1 b/LANCommander/Snippets/Functions/Convert-AspectRatio.ps1 new file mode 100644 index 0000000..5faeb50 --- /dev/null +++ b/LANCommander/Snippets/Functions/Convert-AspectRatio.ps1 @@ -0,0 +1,2 @@ +# Bounds accessible via $Resolution.Height, $Resolution.Width +$Resolution = Convert-AspectRatio -Width 1280 -Height 800 -AspectRatio (4 / 3) \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/ConvertTo-StringBytes.ps1 b/LANCommander/Snippets/Functions/ConvertTo-StringBytes.ps1 new file mode 100644 index 0000000..18e775b --- /dev/null +++ b/LANCommander/Snippets/Functions/ConvertTo-StringBytes.ps1 @@ -0,0 +1,2 @@ +# Converts a string to a UTF16-encoded byte array. This looks like ASCII characters separated by 0x00 in most cases. +$bytes = ConvertTo-StringBytes -Input "Hello World!" -Utf16 1 -MaxLength 12 \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Edit-PatchBinary.ps1 b/LANCommander/Snippets/Functions/Edit-PatchBinary.ps1 new file mode 100644 index 0000000..e35312d --- /dev/null +++ b/LANCommander/Snippets/Functions/Edit-PatchBinary.ps1 @@ -0,0 +1 @@ +Edit-PatchBinary -FilePath "$InstallDirectory\" -Offset 0x00 -Data $bytes \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Get-43Resolution.ps1 b/LANCommander/Snippets/Functions/Get-43Resolution.ps1 deleted file mode 100644 index 7c45514..0000000 --- a/LANCommander/Snippets/Functions/Get-43Resolution.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -function Get-43Resolution([int]$Width, [int]$Height) { - $ratio = 4 / 3 - - if (($Width -gt $Height) -or ($Width -eq $Height)) { - return @{ Width = [math]::Round($ratio * $Height); Height = $Height } - } - - if ($Width -lt $Height) { - return @{ Width = $Width; Height = [math]::Round($Width / $ratio) } - } -} - -# Accessible via $Resolution.Height, $Resolution.Width -$Resolution = Get-43Resolution -Width 1280 -Height 800 \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Get-AsciiBytes.ps1 b/LANCommander/Snippets/Functions/Get-AsciiBytes.ps1 deleted file mode 100644 index 9696eb2..0000000 --- a/LANCommander/Snippets/Functions/Get-AsciiBytes.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -function Get-AsciiBytes([string]$InputString, [int]$MaxLength) -{ - if ($InputString.Length -gt $MaxLength) - { - $InputString = $InputString.Substring(0, $MaxLength) - } - - $bytes = [System.Text.Encoding]::ASCII.GetBytes($InputString) - $array = @() - $count = 0 - - $extraPadding = $MaxLength - $bytes.Length - - foreach ($byte in $bytes) - { - if ($count -lt $MaxLength) - { - $array += $byte - $count++ - } - } - - # Pad the end with 0x00 to meet our max length - for ($i = $count; $i -lt $MaxLength; $i++) - { - $array += 0x00 - } - - return $array -} \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Get-GameManifest.ps1 b/LANCommander/Snippets/Functions/Get-GameManifest.ps1 new file mode 100644 index 0000000..5fa659b --- /dev/null +++ b/LANCommander/Snippets/Functions/Get-GameManifest.ps1 @@ -0,0 +1 @@ +$manifest = Get-GameManifest "C:\\Games\\" \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Get-PrimaryDisplay.ps1 b/LANCommander/Snippets/Functions/Get-PrimaryDisplay.ps1 new file mode 100644 index 0000000..db37f87 --- /dev/null +++ b/LANCommander/Snippets/Functions/Get-PrimaryDisplay.ps1 @@ -0,0 +1,2 @@ +# Bounds are accessible by $Resolution.Width and $Resolution.Height +$Resolution = Get-PrimaryDisplay \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Patch-Binary.ps1 b/LANCommander/Snippets/Functions/Patch-Binary.ps1 deleted file mode 100644 index 80be124..0000000 --- a/LANCommander/Snippets/Functions/Patch-Binary.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -function Patch-Binary([byte[]]$Data, [int]$Offset, [string]$FilePath) -{ - $bytes = [System.IO.File]::ReadAllBytes($FilePath) - - for ($i = 0; $i -lt $Data.Length; $i++) - { - $bytes[$Offset + $i] = $Data[$i] - } - - [System.IO.File]::WriteAllBytes($FilePath, $bytes) -} \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Separate-AsciiBytes.ps1 b/LANCommander/Snippets/Functions/Separate-AsciiBytes.ps1 deleted file mode 100644 index d8c86f1..0000000 --- a/LANCommander/Snippets/Functions/Separate-AsciiBytes.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -function Separate-AsciiBytes([byte[]]$Data) -{ - $array = @() - - foreach ($byte in $Data) - { - $array += $byte - $array += 0x00 - } - - return $array -} \ No newline at end of file diff --git a/LANCommander/Snippets/Functions/Write-ReplaceContentInFile.ps1 b/LANCommander/Snippets/Functions/Write-ReplaceContentInFile.ps1 index b50e3b3..c28c8bf 100644 --- a/LANCommander/Snippets/Functions/Write-ReplaceContentInFile.ps1 +++ b/LANCommander/Snippets/Functions/Write-ReplaceContentInFile.ps1 @@ -1,5 +1,2 @@ -function Write-ReplaceContentInFile([string]$Regex, [string]$Replacement, [string]$FilePath) -{ - $content = (Get-Content $FilePath) -replace $Regex, $Replacement - [IO.File]::WriteAllLines($FilePath, $content) -} \ No newline at end of file +# Use regex to replace text within a file. Quotes are escaped by double quoting ("") +Write-ReplaceContentInFile -Regex '^game.setPlayerName "(.+)"' -Replacement "game.setPlayerName ""$NewName""" -FilePath "$InstallDir\" \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/Allocated Key.ps1 b/LANCommander/Snippets/Variables/Allocated Key.ps1 new file mode 100644 index 0000000..0fb4572 --- /dev/null +++ b/LANCommander/Snippets/Variables/Allocated Key.ps1 @@ -0,0 +1 @@ +$AllocatedKey \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/Default Install Directory.ps1 b/LANCommander/Snippets/Variables/Default Install Directory.ps1 new file mode 100644 index 0000000..3f6de2c --- /dev/null +++ b/LANCommander/Snippets/Variables/Default Install Directory.ps1 @@ -0,0 +1 @@ +$DefaultInstallDirectory \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/Display.ps1 b/LANCommander/Snippets/Variables/Display.ps1 deleted file mode 100644 index eca1e0e..0000000 --- a/LANCommander/Snippets/Variables/Display.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -# Accessible via $Display.Width and $Display.Height -Add-Type -AssemblyName System.Windows.Forms -$Display = ([System.Windows.Forms.Screen]::AllScreens | Where-Object Primary).Bounds \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/Game Install Directory.ps1 b/LANCommander/Snippets/Variables/Game Install Directory.ps1 new file mode 100644 index 0000000..ac9ce15 --- /dev/null +++ b/LANCommander/Snippets/Variables/Game Install Directory.ps1 @@ -0,0 +1 @@ +$OldPlayerAlias \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/Game Manifest.ps1 b/LANCommander/Snippets/Variables/Game Manifest.ps1 new file mode 100644 index 0000000..d839b38 --- /dev/null +++ b/LANCommander/Snippets/Variables/Game Manifest.ps1 @@ -0,0 +1 @@ +$GameManifest \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/InstallDir.ps1 b/LANCommander/Snippets/Variables/InstallDir.ps1 deleted file mode 100644 index 262b772..0000000 --- a/LANCommander/Snippets/Variables/InstallDir.ps1 +++ /dev/null @@ -1 +0,0 @@ -$InstallDir = $PSScriptRoot \ No newline at end of file diff --git a/LANCommander/Snippets/Variables/NewName.ps1 b/LANCommander/Snippets/Variables/New Player Alias.ps1 similarity index 100% rename from LANCommander/Snippets/Variables/NewName.ps1 rename to LANCommander/Snippets/Variables/New Player Alias.ps1 diff --git a/LANCommander/Snippets/Variables/OldName.ps1 b/LANCommander/Snippets/Variables/Old Player Alias.ps1 similarity index 100% rename from LANCommander/Snippets/Variables/OldName.ps1 rename to LANCommander/Snippets/Variables/Old Player Alias.ps1 diff --git a/LANCommander/Snippets/Variables/Server Address.ps1 b/LANCommander/Snippets/Variables/Server Address.ps1 new file mode 100644 index 0000000..e244bae --- /dev/null +++ b/LANCommander/Snippets/Variables/Server Address.ps1 @@ -0,0 +1 @@ +$ServerAddress \ No newline at end of file From 35fbdd008a1bc27ece1883aa6df267f13108f7b5 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Fri, 17 Nov 2023 00:54:38 -0600 Subject: [PATCH 31/32] Add migration to delete old snippets --- ...64657_DeleteDeprecatedSnippets.Designer.cs | 1691 +++++++++++++++++ ...20231117064657_DeleteDeprecatedSnippets.cs | 43 + 2 files changed, 1734 insertions(+) create mode 100644 LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs create mode 100644 LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs diff --git a/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs new file mode 100644 index 0000000..f143973 --- /dev/null +++ b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs @@ -0,0 +1,1691 @@ +// +using System; +using LANCommander.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace LANCommander.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20231117064657_DeleteDeprecatedSnippets")] + partial class DeleteDeprecatedSnippets + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("CategoryGame", b => + { + b.Property("CategoriesId") + .HasColumnType("TEXT"); + + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.HasKey("CategoriesId", "GamesId"); + + b.HasIndex("GamesId"); + + b.ToTable("CategoryGame"); + }); + + modelBuilder.Entity("GameDeveloper", b => + { + b.Property("DeveloperId") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.HasKey("DeveloperId", "GameId"); + + b.HasIndex("GameId"); + + b.ToTable("GameDeveloper"); + }); + + modelBuilder.Entity("GameGenre", b => + { + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.Property("GenresId") + .HasColumnType("TEXT"); + + b.HasKey("GamesId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("GameGenre"); + }); + + modelBuilder.Entity("GamePublisher", b => + { + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("PublisherId") + .HasColumnType("TEXT"); + + b.HasKey("GameId", "PublisherId"); + + b.HasIndex("PublisherId"); + + b.ToTable("GamePublisher"); + }); + + modelBuilder.Entity("GameRedistributable", b => + { + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.HasKey("GameId", "RedistributableId"); + + b.HasIndex("RedistributableId"); + + b.ToTable("GameRedistributable"); + }); + + modelBuilder.Entity("GameTag", b => + { + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.Property("TagsId") + .HasColumnType("TEXT"); + + b.HasKey("GamesId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("GameTag"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Action", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Arguments") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PrimaryAction") + .HasColumnType("INTEGER"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("WorkingDirectory") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Actions"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Archive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Changelog") + .HasColumnType("TEXT"); + + b.Property("CompressedSize") + .HasColumnType("INTEGER"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("LastVersionId") + .HasColumnType("TEXT"); + + b.Property("ObjectKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.Property("UncompressedSize") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("Version") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("LastVersionId"); + + b.HasIndex("RedistributableId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Archive"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ParentId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Company", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DirectoryName") + .HasColumnType("TEXT"); + + b.Property("IGDBId") + .HasColumnType("INTEGER"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("ReleasedOn") + .HasColumnType("TEXT"); + + b.Property("Singleplayer") + .HasColumnType("INTEGER"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("ValidKeyRegex") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.GameSave", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.HasIndex("UserId"); + + b.ToTable("GameSaves"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Genres"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Key", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AllocationMethod") + .HasColumnType("INTEGER"); + + b.Property("ClaimedByComputerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("ClaimedByIpv4Address") + .HasMaxLength(15) + .HasColumnType("TEXT"); + + b.Property("ClaimedByMacAddress") + .HasMaxLength(17) + .HasColumnType("TEXT"); + + b.Property("ClaimedByUserId") + .HasColumnType("TEXT"); + + b.Property("ClaimedOn") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClaimedByUserId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Keys"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Media", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("FileId") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SourceUrl") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("GameId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MaxPlayers") + .HasColumnType("INTEGER"); + + b.Property("MinPlayers") + .HasColumnType("INTEGER"); + + b.Property("NetworkProtocol") + .HasColumnType("INTEGER"); + + b.Property("Spectators") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("MultiplayerModes"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Redistributables"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("LANCommander.Data.Models.SavePath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("SavePaths"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Script", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Contents") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.Property("RequiresAdmin") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("RedistributableId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Scripts"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Arguments") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Autostart") + .HasColumnType("INTEGER"); + + b.Property("AutostartDelay") + .HasColumnType("INTEGER"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OnStartScriptPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OnStopScriptPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("UseShellExecute") + .HasColumnType("INTEGER"); + + b.Property("WorkingDirectory") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Servers"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerConsole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerId1") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerId1"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ServerConsoles"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("LocalPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.Property("ServerId1") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerId1"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ServerHttpPath"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("Alias") + .HasColumnType("TEXT"); + + b.Property("Approved") + .HasColumnType("INTEGER"); + + b.Property("ApprovedOn") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RefreshToken") + .HasColumnType("TEXT"); + + b.Property("RefreshTokenExpiration") + .HasColumnType("TEXT"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("CategoryGame", b => + { + b.HasOne("LANCommander.Data.Models.Category", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameDeveloper", b => + { + b.HasOne("LANCommander.Data.Models.Company", null) + .WithMany() + .HasForeignKey("DeveloperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameGenre", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GamePublisher", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Company", null) + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameRedistributable", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Redistributable", null) + .WithMany() + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameTag", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Action", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Actions") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Archive", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Archives") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.Archive", "LastVersion") + .WithMany() + .HasForeignKey("LastVersionId"); + + b.HasOne("LANCommander.Data.Models.Redistributable", "Redistributable") + .WithMany("Archives") + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("LastVersion"); + + b.Navigation("Redistributable"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Category", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Parent"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Company", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.GameSave", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("GameSaves") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.HasOne("LANCommander.Data.Models.User", "User") + .WithMany("GameSaves") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Genre", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Key", b => + { + b.HasOne("LANCommander.Data.Models.User", "ClaimedByUser") + .WithMany() + .HasForeignKey("ClaimedByUserId"); + + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Keys") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ClaimedByUser"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Media", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Media") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("MultiplayerModes") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.SavePath", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("SavePaths") + .HasForeignKey("GameId"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Script", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Scripts") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.Redistributable", "Redistributable") + .WithMany("Scripts") + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("Redistributable"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Servers") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerConsole", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Server", null) + .WithMany("ServerConsoles") + .HasForeignKey("ServerId1"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Server"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Server", null) + .WithMany("HttpPaths") + .HasForeignKey("ServerId1"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Server"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Tag", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("LANCommander.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("LANCommander.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.Navigation("Actions"); + + b.Navigation("Archives"); + + b.Navigation("GameSaves"); + + b.Navigation("Keys"); + + b.Navigation("Media"); + + b.Navigation("MultiplayerModes"); + + b.Navigation("SavePaths"); + + b.Navigation("Scripts"); + + b.Navigation("Servers"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.Navigation("Archives"); + + b.Navigation("Scripts"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.Navigation("HttpPaths"); + + b.Navigation("ServerConsoles"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.User", b => + { + b.Navigation("GameSaves"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs new file mode 100644 index 0000000..cc3554c --- /dev/null +++ b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LANCommander.Migrations +{ + /// + public partial class DeleteDeprecatedSnippets : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + string[] snippetsToRemove = new string[] + { + "Examples\\Replace Content In File.ps1", + "Examples\\Separate ASCII Bytes.ps1", + "Examples\\String to ASCII Bytes.ps1", + "Functions\\Get-43Resolution.ps1", + "Functions\\Get-AsciiBytes.ps1", + "Functions\\Patch-Binary.ps1", + "Functions\\Separate-AsciiBytes.ps1", + "Variables\\Display.ps1", + "Variables\\InstallDir.ps1", + "Variables\\NewName.ps1", + "Variables\\OldName.ps1", + }; + + foreach (var snippet in snippetsToRemove) + { + var path = Path.Combine("Snippets", snippet); + + if (File.Exists(path)) + File.Delete(path); + } + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} From 14600f5d709f5cafbb5bb4130e828179d057d0db Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Fri, 17 Nov 2023 01:16:45 -0600 Subject: [PATCH 32/32] Alter migration to try to automatically convert scripts to new variables where arguments may be missing --- .../Migrations/20231117064657_DeleteDeprecatedSnippets.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs index cc3554c..fd076f9 100644 --- a/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs +++ b/LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.cs @@ -32,6 +32,14 @@ namespace LANCommander.Migrations if (File.Exists(path)) File.Delete(path); } + + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$NewName = $args[0]' || char(13) || char(10), '')"); + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$OldName = \"\"' || char(13) || char(10) || 'if ($args[1]) {' || char(13) || char(10) || char(9) || '$OldName = $args[1]' || char(13) || char(10) || '}' || char(13) || char(10), '')"); + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$InstallDir = $PSScriptRoot' || char(13) || char(10), '')"); + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$InstallDir', '$InstallDirectory')"); + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$NewName', '$NewPlayerAlias')"); + migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$OldName', '$OldPlayerAlias')"); + } ///