diff --git a/PSModuleDevelopment/PSModuleDevelopment.psd1 b/PSModuleDevelopment/PSModuleDevelopment.psd1 index 1e440c0..083f7e4 100644 --- a/PSModuleDevelopment/PSModuleDevelopment.psd1 +++ b/PSModuleDevelopment/PSModuleDevelopment.psd1 @@ -5,7 +5,7 @@ # Version number of this module. - ModuleVersion = '2.2.12.171' + ModuleVersion = '2.2.12.172' # ID used to uniquely identify this module GUID = '37dd5fce-e7b5-4d57-ac37-832055ce49d6' @@ -29,7 +29,7 @@ # this module RequiredModules = @( @{ ModuleName = 'PSFramework'; ModuleVersion = '1.12.346' } - @{ ModuleName = 'string'; ModuleVersion = '1.1.3' } + @{ ModuleName = 'string'; ModuleVersion = '1.1.5' } ) # Assemblies that must be loaded prior to importing this module diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.dll b/PSModuleDevelopment/bin/PSModuleDevelopment.dll index 7b367b5..85c4f32 100644 Binary files a/PSModuleDevelopment/bin/PSModuleDevelopment.dll and b/PSModuleDevelopment/bin/PSModuleDevelopment.dll differ diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.pdb b/PSModuleDevelopment/bin/PSModuleDevelopment.pdb index 405490d..fd83f8b 100644 Binary files a/PSModuleDevelopment/bin/PSModuleDevelopment.pdb and b/PSModuleDevelopment/bin/PSModuleDevelopment.pdb differ diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.xml b/PSModuleDevelopment/bin/PSModuleDevelopment.xml index dd9f075..dca5b42 100644 --- a/PSModuleDevelopment/bin/PSModuleDevelopment.xml +++ b/PSModuleDevelopment/bin/PSModuleDevelopment.xml @@ -574,6 +574,13 @@ Static helpers for the template system + + + Convert a deserialized template item into a fully valid object of its type. + + The PSObject to transform back into what it was meant to be + The resultant TemplateItemBase + Class containing meta information about a template @@ -695,6 +702,18 @@ List of script value insertion parameters for the plaintext file + + + Creates an empty TemplateItemFile + + + + + Creates a filled-out TemplateItemFile. + Usually called when deserializing a template. + + The deserialized instance of this template item file. + Describes a folder that is part of a template @@ -860,7 +879,16 @@ The name of the property that has the value The value - + + + Get the Values! + Always as an arraylist, empty if null + + The object to extend + >The name of the property that has the values + The values + + Get a hashtable value! diff --git a/PSModuleDevelopment/changelog.md b/PSModuleDevelopment/changelog.md index 57a505d..0c53e6d 100644 --- a/PSModuleDevelopment/changelog.md +++ b/PSModuleDevelopment/changelog.md @@ -1,5 +1,9 @@ # Changelog +## 2.2.12.172 (2024-10-06) + ++ Fix: Invoke-PSMDTemplate - On WinPS, script-logic on templates is not executed + ## 2.2.12.171 (2024-10-04) + Upd: Raised PSFramework dependency due to critical security update diff --git a/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1 b/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1 index 00df036..96a0d77 100644 --- a/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1 +++ b/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1 @@ -91,12 +91,12 @@ #region Scan folders if (Test-PSFParameterBinding -ParameterName "Path") { - $templateInfos = Get-ChildItem -Path $Path -Filter "$($TemplateName)-*.Info.xml" | Where-Object { ($_.Name -replace "-\d+(\.\d+){0,3}.Info.xml$") -like $TemplateName } + $templateInfos = Get-ChildItem -Path $Path -Filter "$($TemplateName)-*-Info.xml" | Where-Object { ($_.Name -replace "-\d+(\.\d+){0,3}-Info.xml$") -like $TemplateName } foreach ($info in $templateInfos) { $data = Import-PSFClixml $info.FullName - $data.Path = $info.FullName -replace '\.Info\.xml$','.xml' + $data.Path = $info.FullName -replace '-Info\.xml$','.xml' $prospects += $data } } diff --git a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 index 639a7cd..fbb82cc 100644 --- a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 +++ b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 @@ -317,7 +317,9 @@ [OutputType([PSModuleDevelopment.Template.TemplateResult])] [CmdletBinding()] param ( - [PSModuleDevelopment.Template.TemplateItemBase] + # Fixing that in the next PSFramework release: https://github.com/PowershellFrameworkCollective/psframework/issues/646 + #[PSFramework.Utility.ScriptTransformation('PSModuleDevelopment.TemplateItem', [PSModuleDevelopment.Template.TemplateItemBase])] + #[PSModuleDevelopment.Template.TemplateItemBase] $Item, [string] diff --git a/PSModuleDevelopment/internal/scripts/initialize.ps1 b/PSModuleDevelopment/internal/scripts/initialize.ps1 index 865cf43..08f0b27 100644 --- a/PSModuleDevelopment/internal/scripts/initialize.ps1 +++ b/PSModuleDevelopment/internal/scripts/initialize.ps1 @@ -10,4 +10,10 @@ if (-not (Test-Path (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Debug.Con #endregion Ensure Config path exists # Pass on the host UI to the library -[PSModuleDevelopment.Utility.UtilityHost]::RawUI = $host.UI.RawUI \ No newline at end of file +[PSModuleDevelopment.Utility.UtilityHost]::RawUI = $host.UI.RawUI + +# Register Type-Conversion to fix template issues in serialization edge-casaes +Register-PSFArgumentTransformationScriptblock -Name 'PSModuleDevelopment.TemplateItem' -Scriptblock { + if ($_ -is [PSModuleDevelopment.Template.TemplateItemBase]) { return $_ } + [PSModuleDevelopment.Template.TemplateHost]::GetTemplateItem($_) +} \ No newline at end of file diff --git a/PSModuleDevelopment/tests/functions/Templates.Tests.ps1 b/PSModuleDevelopment/tests/functions/Templates.Tests.ps1 new file mode 100644 index 0000000..3e38b57 --- /dev/null +++ b/PSModuleDevelopment/tests/functions/Templates.Tests.ps1 @@ -0,0 +1,40 @@ +Describe "Verifying templating component" { + BeforeAll { + $outPath = (Get-Item -Path 'TestDrive:\').FullName + $resourcePath = Resolve-PSFPath -Path "$PSScriptRoot\..\resources" + $templateName = 'TestTemplate-{0}' -f (Get-Random) + } + + It "Should Record the template correctly" { + { New-PSMDTemplate -TemplateName $templateName -FilePath "$resourcePath\þnameþ.txt" -OutPath $outPath -EnableException -ErrorAction Stop } | Should -Not -Throw + $templateInfo = Get-PSMDTemplate -TemplateName $templateName -Path $outPath + $templateRaw = Import-PSFClixml -Path $templateInfo.Path + try { $template = [PSModuleDevelopment.Template.Template]$templateRaw } + catch { + Write-Warning "Conversion to template Failed!" + Write-Warning "=======================================================================" + $_ | Format-List -Force | Out-Host + Write-Warning "=======================================================================" + $_.Exception | Format-List -Force | Out-Host + Write-Warning "=======================================================================" + throw + } + $template.Name | Should -Be $templateName + $template.Parameters.Count | Should -Be 1 + $template.Scripts.Count | Should -Be 1 + $template.Scripts.Values.ScriptBlock | Should -BeOfType ([scriptblock]) + } + + It "Should Invoke the template correctly" { + { Invoke-PSMDTemplate -TemplateName $templateName -Path $outPath -OutPath $outPath -Name Test -EnableException } | Should -Not -Throw + $content = Get-Content -Path "TestDrive:\Test.txt" -ErrorAction Stop + $values = $content | ConvertFrom-StringData -ErrorAction Stop + $values.Name | Should -Be Test + $values.Value | Should -Be '123' + } + + It "Should Remove the template correctly" { + { Remove-PSMDTemplate -TemplateName $templateName -EnableException -Confirm:$false } | Should -Not -Throw + Get-PSMDTemplate -TemplateName $templateName | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git "a/PSModuleDevelopment/tests/resources/\303\276name\303\276.txt" "b/PSModuleDevelopment/tests/resources/\303\276name\303\276.txt" new file mode 100644 index 0000000..faaf9b3 --- /dev/null +++ "b/PSModuleDevelopment/tests/resources/\303\276name\303\276.txt" @@ -0,0 +1,2 @@ +Name = þnameþ +Value = þ{ "123" }þ \ No newline at end of file diff --git a/PSModuleDevelopment/xml/PSModuleDevelopment.Types.ps1xml b/PSModuleDevelopment/xml/PSModuleDevelopment.Types.ps1xml index fc2ef4a..01ae5a4 100644 --- a/PSModuleDevelopment/xml/PSModuleDevelopment.Types.ps1xml +++ b/PSModuleDevelopment/xml/PSModuleDevelopment.Types.ps1xml @@ -1,7 +1,7 @@  - + diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs index 494c2eb..def8553 100644 --- a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs +++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs @@ -122,14 +122,14 @@ public Template(PSObject Item) Description = Item.GetValue("Description"); Author = Item.GetValue("Author"); CreatedOn = Item.GetValue("CreatedOn"); - foreach (object item in Item.GetValue("Tags")) + foreach (object item in Item.GetValues("Tags")) Tags.Add((string)item); - foreach (object item in Item.GetValue("Parameters")) + foreach (object item in Item.GetValues("Parameters")) Parameters.Add((string)item); - foreach (KeyValuePair entry in Item.GetDictionary("Scripts")) + foreach (KeyValuePair entry in Item.GetParameterScriptDictionary("Scripts")) Scripts[entry.Key] =entry.Value; // Parameters2 not used - foreach (object item in Item.GetValue("Children")) + foreach (object item in Item.GetValues("Children")) Children.Add(TemplateHost.GetTemplateItem(item)); Generation = Item.GetValue("Generation"); diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateHost.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateHost.cs index 3ed53af..21b6173 100644 --- a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateHost.cs +++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateHost.cs @@ -12,25 +12,33 @@ namespace PSModuleDevelopment.Template /// /// Static helpers for the template system /// - internal static class TemplateHost + public static class TemplateHost { - internal static TemplateItemBase GetTemplateItem(object Item) + /// + /// Convert a deserialized template item into a fully valid object of its type. + /// + /// The PSObject to transform back into what it was meant to be + /// The resultant TemplateItemBase + public static TemplateItemBase GetTemplateItem(object Item) { if (Item.GetType() == typeof(TemplateItemFile)) return (TemplateItemFile)Item; - TemplateItemFolder result = new TemplateItemFolder(); ; PSObject PSItem = PSObject.AsPSObject(Item); + if (PSItem.TypeNames.Contains("Deserialized.PSModuleDevelopment.Template.TemplateItemFile")) + return new TemplateItemFile(PSItem); - foreach (object child in PSItem.GetValue("Children")) + TemplateItemFolder result = new TemplateItemFolder(); + + foreach (object child in PSItem.GetValues("Children")) result.Children.Add(GetTemplateItem(child)); result.Name = PSItem.GetValue("Name"); result.RelativePath = PSItem.GetValue("RelativePath"); result.Identifier = PSItem.GetValue("Identifier"); - foreach (string entry in PSItem.GetValue("FileSystemParameterFlat")) + foreach (string entry in PSItem.GetValues("FileSystemParameterFlat")) result.FileSystemParameterFlat.Add(entry); - foreach (string entry in PSItem.GetValue("FileSystemParameterScript")) + foreach (string entry in PSItem.GetValues("FileSystemParameterScript")) result.FileSystemParameterScript.Add(entry); return result; diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateItemFile.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateItemFile.cs index e936a5b..f1a8e75 100644 --- a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateItemFile.cs +++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateItemFile.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Management.Automation; using System.Text; using System.Threading.Tasks; +using PSModuleDevelopment.Utility; namespace PSModuleDevelopment.Template { @@ -31,5 +33,37 @@ public class TemplateItemFile : TemplateItemBase /// List of script value insertion parameters for the plaintext file /// public List ContentParameterScript = new List(); + + /// + /// Creates an empty TemplateItemFile + /// + public TemplateItemFile() + { + + } + + /// + /// Creates a filled-out TemplateItemFile. + /// Usually called when deserializing a template. + /// + /// The deserialized instance of this template item file. + public TemplateItemFile(PSObject PSItem) + { + Name = PSItem.GetValue("Name"); + RelativePath = PSItem.GetValue("RelativePath"); + Identifier = PSItem.GetValue("Identifier"); + foreach (string entry in PSItem.GetValues("FileSystemParameterFlat")) + FileSystemParameterFlat.Add(entry); + foreach (string entry in PSItem.GetValues("FileSystemParameterScript")) + FileSystemParameterScript.Add(entry); + + foreach (string entry in PSItem.GetValues("ContentParameterFlat")) + ContentParameterFlat.Add(entry); + foreach (string entry in PSItem.GetValues("ContentParameterScript")) + ContentParameterScript.Add(entry); + + Value = PSItem.GetValue("Value"); + PlainText = PSItem.GetValue("PlainText"); + } } } diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Utility/PSObjectExtension.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Utility/PSObjectExtension.cs index 8fb3235..00c5098 100644 --- a/library/PSModuleDevelopment/PSModuleDevelopment/Utility/PSObjectExtension.cs +++ b/library/PSModuleDevelopment/PSModuleDevelopment/Utility/PSObjectExtension.cs @@ -1,4 +1,5 @@ -using System; +using PSModuleDevelopment.Template; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -26,6 +27,23 @@ public static T GetValue(this PSObject PSObject, string Name) return (T)value.BaseObject; } + /// + /// Get the Values! + /// Always as an arraylist, empty if null + /// + /// The object to extend + /// >The name of the property that has the values + /// The values + public static ArrayList GetValues(this PSObject PSObject, string Name) + { + if (null == PSObject || null == PSObject.Properties || null == PSObject.Properties[Name] || null == PSObject.Properties[Name]?.Value) + return new ArrayList(); + PSObject value = PSObject.AsPSObject(PSObject.Properties[Name].Value); + if (null == value.BaseObject) + return new ArrayList(); + return (ArrayList)value.BaseObject; + } + /// /// Get a hashtable value! /// @@ -33,12 +51,12 @@ public static T GetValue(this PSObject PSObject, string Name) /// The object to extend /// The name of the property that has the hashtable /// The hashtable! - public static Dictionary GetDictionary(this PSObject PSObject, string Name) + public static Dictionary GetParameterScriptDictionary(this PSObject PSObject, string Name) { Hashtable temp = PSObject.GetValue(Name); - Dictionary result = new Dictionary(); + Dictionary result = new Dictionary(); foreach (DictionaryEntry pair in temp) - result[(string)pair.Key] = (T)pair.Value; + result[(string)pair.Key] = new ParameterScript((PSObject)pair.Value); return result; }