Functions/GenXdev.Helpers/ConvertTo-HashTable.cs
|
using System.Collections; using System.Management.Automation; namespace GenXdev.Helpers { [System.ComponentModel.Description(@" .SYNOPSIS Converts a PSCustomObject to a HashTable recursively. .DESCRIPTION * This function converts a PSCustomObject and all its nested PSCustomObject properties into HashTables. * It handles arrays and other collection types by processing each element recursively. .LICENSE Copyright (C) 2026 René Vaessen / GenXdev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. .EXAMPLE ```powershell $object = [PSCustomObject]@{ Name = ""John"" Age = 30 Details = [PSCustomObject]@{ City = ""New York"" } } $hashTable = ConvertTo-HashTable -InputObject $object ``` Convert a PSCustomObject to a HashTable with nested properties. ")] [Cmdlet(VerbsData.ConvertTo, "HashTable")] [OutputType(typeof(Hashtable), typeof(System.Collections.IEnumerable), typeof(System.ValueType), typeof(string))] public class ConvertToHashTableCommand : PSGenXdevCmdlet { /// <summary> /// The PSCustomObject to convert into a HashTable /// </summary> [Parameter( Mandatory = true, Position = 0, ValueFromPipeline = true, HelpMessage = "The PSCustomObject to convert into a HashTable" )] [ValidateNotNull] public object InputObject { get; set; } /// <summary> /// Begin processing - initialization logic /// </summary> protected override void BeginProcessing() { //WriteVerbose("Starting PSCustomObject to HashTable conversion"); } /// <summary> /// Process record - main cmdlet logic /// </summary> protected override void ProcessRecord() { WriteObject(ConvertToHashTable(InputObject)); } /// <summary> /// End processing - cleanup logic /// </summary> protected override void EndProcessing() { //WriteVerbose("Completed HashTable conversion"); } private object ConvertToHashTable(object input) { if (input == null) { return null; } // handle simple value types directly if (input is System.ValueType || input is string) { return input; } // handle Hashtable if (input is System.Collections.Hashtable || (input is PSObject pso && pso.BaseObject is Hashtable)) { // return empty hashtable if input is null if (input is PSObject psObject) { input = psObject.BaseObject; } Hashtable hashTable = (Hashtable)input; System.Collections.Hashtable newTable = (System.Collections.Hashtable ) hashTable.Clone(); foreach (var key in hashTable.Keys) { newTable[key] = ConvertToHashTable(newTable[key]); } return newTable; } // handle PSCustomObject var psObj = input as PSObject; if (psObj != null) { // PSObject wrapping null (e.g. from ConvertFrom-Json parsing // JSON null) should stay null, not become an empty hashtable if (psObj.BaseObject == null) { return null; } var resultTable = new Dictionary<string, object>(); // process each property of the current object foreach (var property in psObj.Properties) { var value = property.Value; // PSObject wrapping null (from JSON null values) → keep // as null rather than recursively converting to empty {} if (value is PSObject psoVal && psoVal.BaseObject == null) { value = null; } // handle nested PSCustomObject properties else if (value is PSObject) { value = ConvertToHashTable(value); } // handle collection properties else if (value is System.Collections.IEnumerable && !(value is string)) { var list = new List<object>(); foreach (var element in (System.Collections.IEnumerable)value) { if (element is PSObject) { list.Add(ConvertToHashTable(element)); } else { list.Add(element); } } value = list.ToArray(); } // handle simple value properties else { // value remains as is } resultTable[property.Name] = value; } // create final hashtable with sorted keys var finalResultTable = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (var key in resultTable.Keys.OrderBy(k => k, StringComparer.Ordinal)) { finalResultTable[key] = resultTable[key]; } return finalResultTable; } // handle collection types else if (input is System.Collections.IEnumerable && !(input is string)) { var list = new List<object>(); foreach (var element in (System.Collections.IEnumerable)input) { list.Add(ConvertToHashTable(element)); } return list.ToArray(); } // handle other types else { return input; } } } } |