diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d3a2b38..1a308ab 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Version v2.0.0-alpha +## Version v2.0.4-alpha ### Breaking Changes @@ -11,6 +11,23 @@ * **Removed Aliases**: * `Get-Hash` - Use `ConvertTo-Hash` directly instead +### New Features + +* **Added `-Encoding` parameter** to `ConvertFrom-MemoryStreamToString` (Issue #21) +* **Added `-Encoding` parameter** to `ConvertFrom-MemoryStreamToSecureString` (Issue #21) +* **Added pipeline support** to `ConvertFrom-Base64ToByteArray` (Issue #16) +* **Added pipeline support** to `ConvertFrom-ByteArrayToMemoryStream` (Issue #16) + +### Changed + +* **Consolidated `-MemoryStream` parameter** into `-Stream` for `ConvertFrom-MemoryStreamToString` and `ConvertTo-String` (Issue #17) + * `-MemoryStream` is now an alias for `-Stream` for backward compatibility + +### Fixed + +* `ConvertFrom-MemoryStream` now correctly passes `-Encoding` parameter to `ConvertFrom-MemoryStreamToString` for consistent behavior +* `ConvertFrom-Base64ToString` and `ConvertTo-String` now handle binary data correctly (Issue #14) + ## Version v1.5.0 (2023-03-17) * **New Functions**: diff --git a/docs/functions/ConvertFrom-MemoryStreamToSecureString.md b/docs/functions/ConvertFrom-MemoryStreamToSecureString.md index df47d82..619a937 100644 --- a/docs/functions/ConvertFrom-MemoryStreamToSecureString.md +++ b/docs/functions/ConvertFrom-MemoryStreamToSecureString.md @@ -14,13 +14,13 @@ Converts a Memory Stream to a Secure String ### MemoryStream (Default) ``` -ConvertFrom-MemoryStreamToSecureString -MemoryStream [-ProgressAction ] +ConvertFrom-MemoryStreamToSecureString -MemoryStream [-Encoding ] [-ProgressAction ] [] ``` ### Stream ``` -ConvertFrom-MemoryStreamToSecureString -Stream [-ProgressAction ] +ConvertFrom-MemoryStreamToSecureString -Stream [-Encoding ] [-ProgressAction ] [] ``` @@ -72,6 +72,23 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` +### -Encoding +The encoding to use for conversion. +Defaults to UTF8. +Valid options are ASCII, BigEndianUnicode, Default, Unicode, UTF32, and UTF8. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: UTF8 +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -ProgressAction {{ Fill ProgressAction Description }} diff --git a/docs/functions/ConvertFrom-MemoryStreamToString.md b/docs/functions/ConvertFrom-MemoryStreamToString.md index f507297..864be4c 100644 --- a/docs/functions/ConvertFrom-MemoryStreamToString.md +++ b/docs/functions/ConvertFrom-MemoryStreamToString.md @@ -14,13 +14,14 @@ Converts MemoryStream to a string. ### MemoryStream ``` -ConvertFrom-MemoryStreamToString -MemoryStream [-ProgressAction ] +ConvertFrom-MemoryStreamToString -MemoryStream [-Encoding ] [-ProgressAction ] [] ``` ### Stream ``` -ConvertFrom-MemoryStreamToString -Stream [-ProgressAction ] [] +ConvertFrom-MemoryStreamToString -Stream [-Encoding ] [-ProgressAction ] + [] ``` ## DESCRIPTION @@ -126,6 +127,23 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` +### -Encoding +The encoding to use for conversion. +Defaults to UTF8. +Valid options are ASCII, BigEndianUnicode, Default, Unicode, UTF32, and UTF8. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: UTF8 +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -ProgressAction {{ Fill ProgressAction Description }} diff --git a/src/Convert/Public/ConvertFrom-MemoryStream.ps1 b/src/Convert/Public/ConvertFrom-MemoryStream.ps1 index 6cfb815..59482e5 100644 --- a/src/Convert/Public/ConvertFrom-MemoryStream.ps1 +++ b/src/Convert/Public/ConvertFrom-MemoryStream.ps1 @@ -176,7 +176,7 @@ function ConvertFrom-MemoryStream { process { foreach ($m in $MemoryStream) { try { - $string = ConvertFrom-MemoryStreamToString -MemoryStream $m -ErrorAction Stop + $string = ConvertFrom-MemoryStreamToString -MemoryStream $m -Encoding $Encoding -ErrorAction Stop if ($ToString) { $string diff --git a/src/Convert/Public/ConvertFrom-MemoryStreamToSecureString.ps1 b/src/Convert/Public/ConvertFrom-MemoryStreamToSecureString.ps1 index ce33768..83bf9be 100644 --- a/src/Convert/Public/ConvertFrom-MemoryStreamToSecureString.ps1 +++ b/src/Convert/Public/ConvertFrom-MemoryStreamToSecureString.ps1 @@ -11,6 +11,11 @@ .PARAMETER Stream A System.IO.Stream object for conversion. + .PARAMETER Encoding + The encoding to use for conversion. + Defaults to UTF8. + Valid options are ASCII, BigEndianUnicode, Default, Unicode, UTF32, and UTF8. + .EXAMPLE $string = 'My Super Secret Value' $bytes = [System.Text.Encoding]::UTF8.GetBytes($string) @@ -47,7 +52,11 @@ function ConvertFrom-MemoryStreamToSecureString { ParameterSetName = 'Stream')] [ValidateNotNullOrEmpty()] [System.IO.Stream[]] - $Stream + $Stream, + + [ValidateSet('ASCII', 'BigEndianUnicode', 'Default', 'Unicode', 'UTF32', 'UTF8')] + [String] + $Encoding = 'UTF8' ) begin { @@ -67,7 +76,8 @@ function ConvertFrom-MemoryStreamToSecureString { foreach ($object in $inputObject) { try { $secureString = [System.Security.SecureString]::new() - $reader = [System.IO.StreamReader]::new($object) + $enc = [System.Text.Encoding]::$Encoding + $reader = [System.IO.StreamReader]::new($object, $enc) while ($reader.Peek() -ge 0) { $secureString.AppendChar($reader.Read()) diff --git a/src/Convert/Public/ConvertFrom-MemoryStreamToString.ps1 b/src/Convert/Public/ConvertFrom-MemoryStreamToString.ps1 index f0937ee..26b74ea 100644 --- a/src/Convert/Public/ConvertFrom-MemoryStreamToString.ps1 +++ b/src/Convert/Public/ConvertFrom-MemoryStreamToString.ps1 @@ -8,6 +8,11 @@ .PARAMETER Stream A System.IO.Stream object for conversion. Accepts any stream type including MemoryStream, FileStream, etc. + .PARAMETER Encoding + The encoding to use for conversion. + Defaults to UTF8. + Valid options are ASCII, BigEndianUnicode, Default, Unicode, UTF32, and UTF8. + .EXAMPLE $string = 'A string' $stream = [System.IO.MemoryStream]::new() @@ -85,7 +90,11 @@ function ConvertFrom-MemoryStreamToString { [ValidateNotNullOrEmpty()] [Alias('MemoryStream')] [System.IO.Stream[]] - $Stream + $Stream, + + [ValidateSet('ASCII', 'BigEndianUnicode', 'Default', 'Unicode', 'UTF32', 'UTF8')] + [String] + $Encoding = 'UTF8' ) begin { @@ -98,7 +107,8 @@ function ConvertFrom-MemoryStreamToString { if ($object.CanSeek) { $object.Position = 0 } - $reader = [System.IO.StreamReader]::new($object) + $enc = [System.Text.Encoding]::$Encoding + $reader = [System.IO.StreamReader]::new($object, $enc) $reader.ReadToEnd() } catch { Write-Error -ErrorRecord $_ -ErrorAction $userErrorActionPreference diff --git a/src/Tests/Unit/ConvertFrom-MemoryStream.Tests.ps1 b/src/Tests/Unit/ConvertFrom-MemoryStream.Tests.ps1 index 46d6092..86ea812 100644 --- a/src/Tests/Unit/ConvertFrom-MemoryStream.Tests.ps1 +++ b/src/Tests/Unit/ConvertFrom-MemoryStream.Tests.ps1 @@ -39,7 +39,8 @@ Describe -Name $function -Fixture { $string = 'ThisIsMyString' $stream = [System.IO.MemoryStream]::new() - $writer = [System.IO.StreamWriter]::new($stream) + $enc = [System.Text.Encoding]::$Encoding + $writer = [System.IO.StreamWriter]::new($stream, $enc) $writer.Write($string) $writer.Flush() diff --git a/src/Tests/Unit/ConvertFrom-MemoryStreamToSecureString.Tests.ps1 b/src/Tests/Unit/ConvertFrom-MemoryStreamToSecureString.Tests.ps1 index b807a44..3b0ab5d 100644 --- a/src/Tests/Unit/ConvertFrom-MemoryStreamToSecureString.Tests.ps1 +++ b/src/Tests/Unit/ConvertFrom-MemoryStreamToSecureString.Tests.ps1 @@ -24,4 +24,63 @@ Describe $function { It 'Does not throw an exception when input is an empty System.IO.MemoryStream' { { ConvertFrom-MemoryStreamToSecureString -MemoryStream (New-Object System.IO.MemoryStream) } | Should -Not -Throw } + + Context 'Encoding' { + It 'Uses UTF8 encoding by default' { + $string = 'MySecretPassword' + $bytes = [System.Text.Encoding]::UTF8.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $secure = ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream + $credential = [PSCredential]::new('Dummy', $secure) + $credential.GetNetworkCredential().Password | Should -BeExactly $string + } + + It 'Converts ASCII encoded stream to SecureString' { + $string = 'MySecretPassword' + $bytes = [System.Text.Encoding]::ASCII.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $secure = ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream -Encoding ASCII + $credential = [PSCredential]::new('Dummy', $secure) + $credential.GetNetworkCredential().Password | Should -BeExactly $string + } + + It 'Converts Unicode encoded stream to SecureString' { + $string = 'MySecretPassword' + $bytes = [System.Text.Encoding]::Unicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $secure = ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream -Encoding Unicode + $credential = [PSCredential]::new('Dummy', $secure) + $credential.GetNetworkCredential().Password | Should -BeExactly $string + } + + It 'Converts BigEndianUnicode encoded stream to SecureString' { + $string = 'MySecretPassword' + $bytes = [System.Text.Encoding]::BigEndianUnicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $secure = ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream -Encoding BigEndianUnicode + $credential = [PSCredential]::new('Dummy', $secure) + $credential.GetNetworkCredential().Password | Should -BeExactly $string + } + + It 'Converts UTF32 encoded stream to SecureString' { + $string = 'MySecretPassword' + $bytes = [System.Text.Encoding]::UTF32.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $secure = ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream -Encoding UTF32 + $credential = [PSCredential]::new('Dummy', $secure) + $credential.GetNetworkCredential().Password | Should -BeExactly $string + } + + It 'Rejects invalid encoding name' { + $bytes = [System.Text.Encoding]::UTF8.GetBytes('test') + $stream = [System.IO.MemoryStream]::new($bytes) + + { ConvertFrom-MemoryStreamToSecureString -MemoryStream $stream -Encoding InvalidEncoding } | Should -Throw + } + } } diff --git a/src/Tests/Unit/ConvertFrom-MemoryStreamToString.Tests.ps1 b/src/Tests/Unit/ConvertFrom-MemoryStreamToString.Tests.ps1 index ba1151f..12b06b3 100644 --- a/src/Tests/Unit/ConvertFrom-MemoryStreamToString.Tests.ps1 +++ b/src/Tests/Unit/ConvertFrom-MemoryStreamToString.Tests.ps1 @@ -199,4 +199,104 @@ Describe -Name $function -Fixture { $assertion.Exception.InnerException.Message | Should -BeIn @('Cannot access a closed Stream.', 'Stream was not readable.') } } + + Context -Name 'Encoding' -Fixture { + It -Name 'Uses UTF8 encoding by default' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::UTF8.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Converts ASCII encoded stream' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::ASCII.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding ASCII + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Converts Unicode (UTF-16 LE) encoded stream' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::Unicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding Unicode + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Converts BigEndianUnicode (UTF-16 BE) encoded stream' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::BigEndianUnicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding BigEndianUnicode + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Converts UTF32 encoded stream' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::UTF32.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding UTF32 + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Converts UTF8 encoded stream explicitly' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::UTF8.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding UTF8 + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Supports -Encoding with pipeline input' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::Unicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = $stream | ConvertFrom-MemoryStreamToString -Encoding Unicode + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Handles special characters with Unicode encoding' -Test { + $string = 'Hello δΈ–η•Œ 🌍' + $bytes = [System.Text.Encoding]::Unicode.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + $assertion = ConvertFrom-MemoryStreamToString -Stream $stream -Encoding Unicode + + $assertion | Should -BeExactly $string + $stream.Dispose() + } + + It -Name 'Rejects invalid encoding name' -Test { + $string = 'Hello World' + $bytes = [System.Text.Encoding]::UTF8.GetBytes($string) + $stream = [System.IO.MemoryStream]::new($bytes) + + { ConvertFrom-MemoryStreamToString -Stream $stream -Encoding InvalidEncoding } | Should -Throw + + $stream.Dispose() + } + } }