Skip to content

Commit d322bf3

Browse files
🚀 [Feature]: Add functions Import-Hashtable and Export-Hashtable (#7)
## Description This pull request introduces two new functions and updates to existing functions for handling hashtables in PowerShell scripts. ### New Functions * `Export-Hashtable`: A new function to export a hashtable to a specified file in PSD1, PS1, or JSON format. * `Import-Hashtable`: A new function to import a hashtable from a specified file, supporting PSD1, PS1, and JSON formats. ### Tests * Added tests for the new `Export-Hashtable` and `Import-Hashtable` functions to verify their functionality with different file formats. ## Type of change <!-- Use the check-boxes [x] on the options that are relevant. --> - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [x] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist <!-- Use the check-boxes [x] on the options that are relevant. --> - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas
1 parent 6a5b426 commit d322bf3

6 files changed

Lines changed: 311 additions & 22 deletions

File tree

src/functions/public/ConvertTo-HashTable.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
converting complex nested structures recursively.
5050
5151
.LINK
52-
https://psmodule.io/ConvertTo/Functions/ConvertTo-Hashtable
52+
https://psmodule.io/Hashtable/Functions/ConvertTo-Hashtable
5353
#>
5454
[OutputType([hashtable])]
5555
[CmdletBinding()]
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
filter Export-Hashtable {
2+
<#
3+
.SYNOPSIS
4+
Exports a hashtable to a specified file in PSD1, PS1, or JSON format.
5+
6+
.DESCRIPTION
7+
This function takes a hashtable and exports it to a file in one of the supported formats: PSD1, PS1, or JSON.
8+
The format is determined based on the file extension provided in the Path parameter. If the extension is not
9+
recognized, the function throws an error. This function supports pipeline input.
10+
11+
.EXAMPLE
12+
$myHashtable = @{ Key = 'Value'; Number = 42 }
13+
$myHashtable | Export-Hashtable -Path 'C:\config.psd1'
14+
15+
Exports the hashtable to a PSD1 file.
16+
17+
.EXAMPLE
18+
$myHashtable = @{ Key = 'Value'; Number = 42 }
19+
Export-Hashtable -Hashtable $myHashtable -Path 'C:\script.ps1'
20+
21+
Exports the hashtable as a PowerShell script that returns the hashtable when executed.
22+
23+
.EXAMPLE
24+
$myHashtable = @{ Key = 'Value'; Number = 42 }
25+
Export-Hashtable -Hashtable $myHashtable -Path 'C:\data.json'
26+
27+
Exports the hashtable as a JSON file.
28+
29+
.OUTPUTS
30+
void
31+
32+
.NOTES
33+
This function does not return an output. It writes the exported data to a file.
34+
35+
.LINK
36+
https://psmodule.io/Export/Functions/Export-Hashtable/
37+
#>
38+
[OutputType([void])]
39+
[CmdletBinding()]
40+
param(
41+
# The hashtable to export.
42+
[Parameter(
43+
Mandatory,
44+
ValueFromPipeline,
45+
ValueFromPipelineByPropertyName
46+
)]
47+
[hashtable] $Hashtable,
48+
49+
# The file path where the hashtable will be exported.
50+
[Parameter(Mandatory)]
51+
[string] $Path
52+
)
53+
54+
# Determine file extension and select export format.
55+
$extension = [System.IO.Path]::GetExtension($Path).ToLower()
56+
57+
switch ($extension) {
58+
'.psd1' {
59+
try {
60+
# Use Format-Hashtable to generate a PSD1-like output.
61+
$formattedHashtable = Format-Hashtable -Hashtable $Hashtable
62+
Set-Content -Path $Path -Value $formattedHashtable -Force
63+
} catch {
64+
throw "Failed to export hashtable to PSD1 file '$Path'. Error details: $_"
65+
}
66+
}
67+
'.ps1' {
68+
try {
69+
# Format the hashtable and wrap it in a function so that when the script is run it returns the hashtable.
70+
$formattedHashtable = Format-Hashtable -Hashtable $Hashtable
71+
Set-Content -Path $Path -Value $formattedHashtable -Force
72+
} catch {
73+
throw "Failed to export hashtable to PS1 file '$Path'. Error details: $_"
74+
}
75+
}
76+
'.json' {
77+
try {
78+
# Convert the hashtable to JSON. You might adjust the Depth parameter as needed.
79+
$jsonContent = $Hashtable | ConvertTo-Json -Depth 10
80+
Set-Content -Path $Path -Value $jsonContent -Force
81+
} catch {
82+
throw "Failed to export hashtable to JSON file '$Path'. Error details: $_"
83+
}
84+
}
85+
default {
86+
throw "Unsupported file extension '$extension'. Only .psd1, .ps1, and .json files are supported."
87+
}
88+
}
89+
}

src/functions/public/Format-Hashtable.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
Useful for serialization and exporting hashtables to files.
4848
4949
.LINK
50-
https://psmodule.io/Format/Functions/Format-Hashtable
50+
https://psmodule.io/Hashtable/Functions/Format-Hashtable
5151
#>
5252
[OutputType([string])]
5353
[CmdletBinding()]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
filter Import-Hashtable {
2+
<#
3+
.SYNOPSIS
4+
Imports a hashtable from a specified file.
5+
6+
.DESCRIPTION
7+
This function reads a file and imports its contents as a hashtable. It supports `.psd1`, `.ps1`, and `.json` files.
8+
- `.psd1` files are imported using `Import-PowerShellDataFile`. This process is safe and does not execute any code.
9+
- `.ps1` scripts are executed, and their output must be a hashtable. If the script does not return a hashtable, an error is thrown.
10+
- `.json` files are read and converted to a hashtable using `ConvertFrom-Json -AsHashtable`.
11+
This process is safe and does not execute any code.
12+
13+
If the specified file does not exist or has an unsupported format, an error is thrown.
14+
15+
.EXAMPLE
16+
Import-Hashtable -Path 'C:\config.psd1'
17+
18+
Output:
19+
```powershell
20+
Name Value
21+
---- -----
22+
Setting1 Enabled
23+
Setting2 42
24+
```
25+
26+
Imports a hashtable from a `.psd1` file.
27+
28+
.EXAMPLE
29+
Import-Hashtable -Path 'C:\script.ps1'
30+
31+
Output:
32+
```powershell
33+
Name Value
34+
---- -----
35+
Key1 Value1
36+
Key2 Value2
37+
```
38+
39+
Executes the script and imports the hashtable returned by the `.ps1` file.
40+
41+
.EXAMPLE
42+
Import-Hashtable -Path 'C:\data.json'
43+
44+
Output:
45+
```powershell
46+
Name Value
47+
---- -----
48+
username johndoe
49+
roles {Admin, User}
50+
```
51+
52+
Reads a JSON file and converts its content into a hashtable.
53+
54+
.OUTPUTS
55+
hashtable
56+
57+
.NOTES
58+
A hashtable containing the data from the imported file.
59+
The hashtable structure depends on the contents of the imported file.
60+
61+
.LINK
62+
https://psmodule.io/Hashtable/Functions/Import-Hashtable
63+
#>
64+
[CmdletBinding()]
65+
param(
66+
# Path to the file containing the hashtable.
67+
[Parameter(
68+
Mandatory,
69+
ValueFromPipeline,
70+
ValueFromPipelineByPropertyName
71+
)]
72+
[string] $Path
73+
)
74+
75+
if (-not (Test-Path -Path $Path)) {
76+
throw "File '$Path' does not exist."
77+
}
78+
79+
$extension = [System.IO.Path]::GetExtension($Path).ToLower()
80+
81+
switch ($extension) {
82+
'.psd1' {
83+
try {
84+
$hashtable = Import-PowerShellDataFile -Path $Path
85+
} catch {
86+
throw "Failed to import hashtable from PSD1 file '$Path'. Error details: $_"
87+
}
88+
}
89+
'.ps1' {
90+
try {
91+
$hashtable = & $Path
92+
if (-not ($hashtable -is [hashtable])) {
93+
throw 'The PS1 script did not return a hashtable. Verify its content.'
94+
}
95+
} catch {
96+
throw "Failed to import hashtable from PS1 file '$Path'. Error details: $_"
97+
}
98+
}
99+
'.json' {
100+
try {
101+
# Read the entire JSON file and convert it to a hashtable.
102+
$jsonContent = Get-Content -Path $Path -Raw
103+
$hashtable = $jsonContent | ConvertFrom-Json -AsHashtable
104+
} catch {
105+
throw "Failed to import hashtable from JSON file '$Path'. Error details: $_"
106+
}
107+
}
108+
default {
109+
throw "Unsupported file extension '$extension'. Only .psd1, .ps1, and .json files are supported."
110+
}
111+
}
112+
113+
return $hashtable
114+
}

src/functions/public/Remove-HashtableEntry.ps1

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,54 @@
11
filter Remove-HashtableEntry {
22
<#
33
.SYNOPSIS
4-
Removes specific entries from a hashtable based on value, type, or name.
4+
Removes specific entries from a hashtable based on given criteria.
55
66
.DESCRIPTION
7-
This version applies keep filters with the highest precedence. If a key
8-
qualifies based on the provided Keep parameters (KeepTypes and/or KeepKeys),
9-
it is preserved no matter what removal conditions might say.
7+
This function filters out entries from a hashtable based on different conditions. You can remove keys with
8+
null or empty values, keys of a specific type, or keys matching certain names. It also allows keeping entries
9+
based on the opposite criteria. If the `-All` parameter is used, all entries in the hashtable will be removed.
1010
11-
If no keep filters are provided, the function applies removal conditions:
12-
- NullOrEmptyValues: Remove keys with null or empty values.
13-
- RemoveTypes: Remove keys whose values are of the specified type(s).
14-
- RemoveKeys: Remove keys with the specified name(s).
11+
.EXAMPLE
12+
$myHashtable = @{ Name = 'John'; Age = 30; Country = $null }
13+
$myHashtable | Remove-HashtableEntry -NullOrEmptyValues
1514
16-
When Keep filters are provided, only keys that match ALL specified keep criteria
17-
will be preserved; keys that do not match are removed regardless of removal settings.
15+
Output:
16+
```powershell
17+
@{ Name = 'John'; Age = 30 }
18+
```
1819
19-
At the end, the original hashtable is cleared and repopulated with the filtered results.
20+
Removes entries with null or empty values from the hashtable.
2021
2122
.EXAMPLE
22-
$ht = @{
23-
KeepThis = 'Value1'
24-
RemoveThis = 'Delete'
25-
Other = 42
26-
}
27-
$ht | Remove-HashtableEntry -KeepKeys 'KeepThis' -RemoveKeys 'RemoveThis'
23+
$myHashtable = @{ Name = 'John'; Age = 30; Active = $true }
24+
$myHashtable | Remove-HashtableEntry -Types 'Boolean'
25+
26+
Output:
27+
```powershell
28+
@{ Name = 'John'; Age = 30 }
29+
```
30+
31+
Removes entries where the value type is Boolean.
2832
29-
This will keep only the key "KeepThis", regardless of other removal flags.
33+
.EXAMPLE
34+
$myHashtable = @{ Name = 'John'; Age = 30; Country = 'USA' }
35+
$myHashtable | Remove-HashtableEntry -Keys 'Age'
36+
37+
Output:
38+
```powershell
39+
@{ Name = 'John'; Country = 'USA' }
40+
```
41+
42+
Removes the key 'Age' from the hashtable.
3043
3144
.OUTPUTS
32-
hashtable
45+
void
3346
3447
.NOTES
35-
The function modifies the input hashtable in place.
48+
The function modifies the input hashtable but does not return output.
49+
50+
.LINK
51+
https://psmodule.io/Hashtable/Functions/Remove-HashtableEntry/
3652
#>
3753
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
3854
'PSUseShouldProcessForStateChangingFunctions', '',

tests/Hashtable.Tests.ps1

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,4 +529,74 @@
529529
}
530530
}
531531
}
532+
533+
Describe 'Export/Import-Hashtable' {
534+
$testData = @(
535+
@{ Path = "$HOME/config.psd1"; Extension = '.psd1' }
536+
@{ Path = "$HOME/config.ps1"; Extension = '.ps1' }
537+
@{ Path = "$HOME/config.json"; Extension = '.json' }
538+
)
539+
540+
It 'Exports a hashtable to a <Extension> file at <Path>' -ForEach $testData {
541+
$hashtable = [ordered]@{
542+
StringKey = "Hello 'PowerShell'!"
543+
NumberKey = 42
544+
BooleanKey = $true
545+
NullKey = $null
546+
ArrayKey = @(
547+
'FirstItem'
548+
123
549+
$false
550+
@('NestedArray1', 'NestedArray2')
551+
[ordered]@{
552+
NestedHashtableKey1 = 'NestedValue1'
553+
NestedHashtableKey2 = @(
554+
@{ DeepNestedKey = 'DeepValue' }
555+
999
556+
)
557+
}
558+
)
559+
NestedHashtable = [ordered]@{
560+
SubKey1 = 'SubValue1'
561+
SubKey2 = @(
562+
'ArrayInsideHashtable1'
563+
'ArrayInsideHashtable2'
564+
''
565+
@{
566+
EvenDeeper = "Yes, it's deep!"
567+
}
568+
)
569+
}
570+
}
571+
572+
Export-Hashtable -Hashtable $hashtable -Path $Path
573+
Write-Verbose (Get-Content -Path $Path | Out-String) -Verbose
574+
$result = Test-Path -Path $path
575+
$result | Should -Be $true
576+
}
577+
It 'Imports a <Extension> file at <Path> to a hashtable' -ForEach $testData {
578+
$hashtable = Import-Hashtable -Path $Path
579+
580+
Write-Verbose ($hashtable | Format-Hashtable | Out-String) -Verbose
581+
582+
$hashtable | Should -BeOfType [hashtable]
583+
$hashtable.StringKey | Should -Be "Hello 'PowerShell'!"
584+
$hashtable.NumberKey | Should -Be 42
585+
$hashtable.BooleanKey | Should -Be $true
586+
$hashtable.NullKey | Should -Be $null
587+
$hashtable.ArrayKey[0] | Should -Be 'FirstItem'
588+
$hashtable.ArrayKey[1] | Should -Be 123
589+
$hashtable.ArrayKey[2] | Should -Be $false
590+
$hashtable.ArrayKey[3] | Should -Be 'NestedArray1'
591+
$hashtable.ArrayKey[4] | Should -Be 'NestedArray2'
592+
$hashtable.ArrayKey[5].NestedHashtableKey1 | Should -Be 'NestedValue1'
593+
$hashtable.ArrayKey[5].NestedHashtableKey2[0].DeepNestedKey | Should -Be 'DeepValue'
594+
$hashtable.ArrayKey[5].NestedHashtableKey2[1] | Should -Be 999
595+
$hashtable.NestedHashtable.SubKey1 | Should -Be 'SubValue1'
596+
$hashtable.NestedHashtable.SubKey2[0] | Should -Be 'ArrayInsideHashtable1'
597+
$hashtable.NestedHashtable.SubKey2[1] | Should -Be 'ArrayInsideHashtable2'
598+
$hashtable.NestedHashtable.SubKey2[2] | Should -Be ''
599+
$hashtable.NestedHashtable.SubKey2[3].EvenDeeper | Should -Be "Yes, it's deep!"
600+
}
601+
}
532602
}

0 commit comments

Comments
 (0)