diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs
index 7cab758287e..595161f7e46 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs
@@ -2,12 +2,14 @@
// Licensed under the MIT License.
using System;
+using System.Collections.Generic;
using System.IO;
-using System.Text;
-using System.Security;
using System.Management.Automation;
-using System.Collections.Generic;
using System.Management.Automation.Internal;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
// Once Serialization is available on CoreCLR: using System.Runtime.Serialization.Formatters.Binary;
namespace Microsoft.PowerShell.Commands
@@ -18,38 +20,55 @@ namespace Microsoft.PowerShell.Commands
[Cmdlet(VerbsCommon.Format, "Hex", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526919")]
[OutputType(typeof(Microsoft.PowerShell.Commands.ByteCollection))]
[Alias("fhx")]
- public sealed class FormatHex : PSCmdlet
+ public sealed class FormatHexCommand : PSCmdlet
{
private const int BUFFERSIZE = 16;
+ ///
+ /// For cases where a homogenous collection of bytes or other items are directly piped in, we collect all the
+ /// bytes in a List<byte> and then output the formatted result all at once in EndProcessing().
+ ///
+ private List _inputBytes;
+
+ ///
+ /// If the input is determined to be heterogenous piped input or each input object turns out to be a complete
+ /// array of items, we output each item as we receive it to avoid squashing output together in strange ways.
+ ///
+ private bool _isHeterogenousPipedInput = false;
+
+ ///
+ /// Keep track of prior input types to determine if we're given a heterogenous collection.
+ ///
+ private Type _lastInputType;
+
#region Parameters
///
- /// Path of file(s) to process.
+ /// Gets or sets the path of file(s) to process.
///
[Parameter(Mandatory = true, Position = 0, ParameterSetName = "Path")]
- [ValidateNotNullOrEmpty()]
+ [ValidateNotNullOrEmpty]
public string[] Path { get; set; }
///
- /// Literal path of file to process.
+ /// Gets or sets the literal path of file to process.
///
- [Parameter(Mandatory = true, ParameterSetName = "LiteralPath")]
- [ValidateNotNullOrEmpty()]
- [Alias("PSPath", "LP")]
+ [Parameter(Mandatory = true, ParameterSetName = "LiteralPath", ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNullOrEmpty]
+ [Alias("PSPath", "LP", "FullName")]
public string[] LiteralPath { get; set; }
///
- /// Object to process.
+ /// Gets or sets the pipeline object to process.
///
[Parameter(Mandatory = true, ParameterSetName = "ByInputObject", ValueFromPipeline = true)]
public PSObject InputObject { get; set; }
///
- /// Type of character encoding for InputObject.
+ /// Gets or sets the type of character encoding for InputObject.
///
[Parameter(ParameterSetName = "ByInputObject")]
- [ArgumentToEncodingTransformationAttribute()]
+ [ArgumentToEncodingTransformationAttribute]
[ArgumentEncodingCompletionsAttribute]
[ValidateNotNullOrEmpty]
public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding();
@@ -59,17 +78,17 @@ public sealed class FormatHex : PSCmdlet
///
[Parameter]
[ValidateRange(ValidateRangeKind.Positive)]
- public Int64 Count { get; set; } = Int64.MaxValue;
+ public long Count { get; set; } = long.MaxValue;
///
/// Gets or sets offset of bytes to start reading the input stream from.
///
[Parameter]
[ValidateRange(ValidateRangeKind.NonNegative)]
- public Int64 Offset { get; set; }
+ public long Offset { get; set; }
///
- /// This parameter is no-op.
+ /// Gets or sets whether the file input should be swallowed as is. This parameter is no-op, deprecated.
///
[Parameter(ParameterSetName = "ByInputObject", DontShow = true)]
[Obsolete("Raw parameter is deprecated.", true)]
@@ -97,6 +116,26 @@ protected override void ProcessRecord()
}
}
+ ///
+ /// Implements the EndProcessing method for the FormatHex command.
+ ///
+ protected override void EndProcessing()
+ {
+ if (_inputBytes != null)
+ {
+ int offset = Math.Min(_inputBytes.Count, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
+ int count = Math.Min(_inputBytes.Count - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue);
+ if (offset != 0 || count != _inputBytes.Count)
+ {
+ WriteHexadecimal(_inputBytes.GetRange(offset, count).ToArray(), null, 0);
+ }
+ else
+ {
+ WriteHexadecimal(_inputBytes.ToArray(), null, 0);
+ }
+ }
+ }
+
#endregion
#region Paths
@@ -106,9 +145,9 @@ protected override void ProcessRecord()
/// If path is a literal path it is added to the array to process; we cannot validate them until we
/// try to process file contents.
///
- ///
- ///
- ///
+ /// The file path to resolve.
+ /// Indicates whether the path is to be resolved as literal or may have wildcards.
+ /// Returns a list of resolved paths.
private List ResolvePaths(string[] path, bool literalPath)
{
List pathsToProcess = new List();
@@ -144,10 +183,11 @@ private List ResolvePaths(string[] path, bool literalPath)
{
// Write a non-terminating error message indicating that path specified is not supported.
string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexOnlySupportsFileSystemPaths, currentPath);
- ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage),
- "FormatHexOnlySupportsFileSystemPaths",
- ErrorCategory.InvalidArgument,
- currentPath);
+ ErrorRecord errorRecord = new ErrorRecord(
+ new ArgumentException(errorMessage),
+ "FormatHexOnlySupportsFileSystemPaths",
+ ErrorCategory.InvalidArgument,
+ currentPath);
WriteError(errorRecord);
continue;
}
@@ -161,7 +201,7 @@ private List ResolvePaths(string[] path, bool literalPath)
///
/// Pass each valid path on to process its contents.
///
- ///
+ /// The paths to process.
private void ProcessPath(List pathsToProcess)
{
foreach (string path in pathsToProcess)
@@ -174,7 +214,7 @@ private void ProcessPath(List pathsToProcess)
/// Creates a binary reader that reads the file content into a buffer (byte[]) 16 bytes at a time, and
/// passes a copy of that array on to the WriteHexidecimal method to output.
///
- ///
+ /// The file path to retrieve content from for processing.
private void ProcessFileContent(string path)
{
Span buffer = stackalloc byte[BUFFERSIZE];
@@ -183,9 +223,9 @@ private void ProcessFileContent(string path)
{
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
- Int64 offset = Offset;
- Int32 bytesRead = 0;
- Int64 count = 0;
+ long offset = Offset;
+ int bytesRead = 0;
+ long count = 0;
reader.BaseStream.Position = Offset;
@@ -195,20 +235,20 @@ private void ProcessFileContent(string path)
if (count > Count)
{
bytesRead -= (int)(count - Count);
- WriteHexidecimal(buffer.Slice(0, bytesRead), path, offset);
+ WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset);
break;
}
- WriteHexidecimal(buffer.Slice(0, bytesRead), path, offset);
+ WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset);
offset += bytesRead;
}
}
}
- catch (IOException ioException)
+ catch (IOException fileException)
{
// IOException takes care of FileNotFoundException, DirectoryNotFoundException, and PathTooLongException
- WriteError(new ErrorRecord(ioException, "FormatHexIOError", ErrorCategory.WriteError, path));
+ WriteError(new ErrorRecord(fileException, "FormatHexIOError", ErrorCategory.WriteError, path));
}
catch (ArgumentException argException)
{
@@ -232,84 +272,188 @@ private void ProcessFileContent(string path)
/// Creates a byte array from the object passed to the cmdlet (based on type) and passes
/// that array on to the WriteHexidecimal method to output.
///
- ///
+ /// The pipeline input object being processed.
private void ProcessObjectContent(PSObject inputObject)
{
- object obj = inputObject.BaseObject;
- byte[] inputBytes = null;
+ dynamic baseObject = inputObject.BaseObject;
+ Type baseType = baseObject.GetType();
+ int elements = 1;
+ bool isArray = false;
+ bool isBool = false;
+ bool isEnum = false;
+
+ byte[] processResult = null;
+ if (baseType.IsArray)
+ {
+ baseType = baseType.GetElementType();
+ elements = (int)baseObject.Length;
+ isArray = true;
+ _isHeterogenousPipedInput = true;
+ }
- switch (obj)
+ if (baseType == typeof(FileInfo))
{
- case System.IO.FileSystemInfo fsi:
- string[] path = { fsi.FullName };
- List pathsToProcess = ResolvePaths(path, true);
- ProcessPath(pathsToProcess);
- return;
- case string str:
- inputBytes = Encoding.GetBytes(str);
- break;
- case byte b:
- inputBytes = new byte[] { b };
- break;
- case byte[] byteArray:
- inputBytes = byteArray;
- break;
- case Int32 iInt32:
- inputBytes = BitConverter.GetBytes(iInt32);
- break;
- case Int32[] i32s:
- int i32 = 0;
- inputBytes = new byte[sizeof(Int32) * i32s.Length];
- Span inputStreamArray32 = inputBytes;
-
- foreach (Int32 value in i32s)
+ List paths = new List();
+ if (!isArray)
+ {
+ paths.Add(baseObject.FullName);
+ }
+ else
+ {
+ foreach (FileInfo file in baseObject)
{
- BitConverter.TryWriteBytes(inputStreamArray32.Slice(i32), value);
- i32 += sizeof(Int32);
+ paths.Add(file.FullName);
}
+ }
- break;
- case Int64 iInt64:
- inputBytes = BitConverter.GetBytes(iInt64);
- break;
- case Int64[] inputInt64s:
- int i64 = 0;
- inputBytes = new byte[sizeof(Int64) * inputInt64s.Length];
- Span inputStreamArray64 = inputBytes;
+ List pathsToProcess = new List(ResolvePaths(paths.ToArray(), true));
+ ProcessPath(pathsToProcess);
+ return;
+ }
- foreach (Int64 value in inputInt64s)
+ if (baseType == typeof(string))
+ {
+ _isHeterogenousPipedInput = true;
+
+ if (!isArray)
+ {
+ baseObject = new string[] { baseObject };
+ }
+
+ foreach (string str in (Array)baseObject)
+ {
+ processResult = Encoding.GetBytes(str);
+ int offset = Math.Min(processResult.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
+ int count = Math.Min(processResult.Length - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue);
+ if (offset != 0 || count != processResult.Length)
{
- BitConverter.TryWriteBytes(inputStreamArray64.Slice(i64), value);
- i64 += sizeof(Int64);
+ WriteHexadecimal(processResult.AsSpan().Slice(offset, count), null, 0);
}
+ else
+ {
+ WriteHexadecimal(processResult, null, 0);
+ }
+ }
- break;
+ return;
+ }
- // If the object type is not supported, throw an error. Once Serialization is
- // available on CoreCLR, other types will be supported.
- default:
+ if (baseType.IsEnum)
+ {
+ baseType = baseType.GetEnumUnderlyingType();
+ isEnum = true;
+ }
+
+ if (!_isHeterogenousPipedInput)
+ {
+ if (_lastInputType != null && baseType != _lastInputType)
{
- string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, obj.GetType());
- ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage),
- "FormatHexTypeNotSupported",
- ErrorCategory.InvalidArgument,
- obj.GetType());
- WriteError(errorRecord);
- break;
+ _isHeterogenousPipedInput = true;
+ }
+ else
+ {
+ _lastInputType = baseType;
}
}
- if (inputBytes != null)
+ if (baseType.IsPrimitive && elements > 0)
+ {
+ if (baseType == typeof(bool))
+ {
+ isBool = true;
+ }
+
+ var elementSize = Marshal.SizeOf(baseType);
+ processResult = new byte[elementSize * elements];
+ if (!isArray)
+ {
+ baseObject = new object[1] { baseObject };
+ }
+
+ int index = 0;
+ foreach (dynamic item in (Array)baseObject)
+ {
+ if (elementSize == 1)
+ {
+ processResult[index] = (byte)item;
+ }
+ else
+ {
+ // bool is 4 bytes, apparently -- @lzybkr
+ dynamic byteConverterInput;
+ if (isEnum)
+ {
+ byteConverterInput = Convert.ChangeType(item, baseType);
+ }
+ else if (isBool)
+ {
+ byteConverterInput = Convert.ToInt32(item);
+ }
+ else
+ {
+ byteConverterInput = item;
+ }
+
+ byte[] bytes = BitConverter.GetBytes(byteConverterInput);
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ processResult[i + index] = bytes[i];
+ }
+ }
+
+ index += elementSize;
+ }
+ }
+ else
+ {
+ // Type is neither any kind of primitive, enum, string, nor file, so we write an error
+ string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, baseObject.GetType());
+ ErrorRecord errorRecord = new ErrorRecord(
+ new ArgumentException(errorMessage),
+ "FormatHexTypeNotSupported",
+ ErrorCategory.InvalidArgument,
+ baseObject.GetType());
+ WriteError(errorRecord);
+ return;
+ }
+
+ if (_isHeterogenousPipedInput)
+ {
+ if (_inputBytes != null)
+ {
+ // If we've been collecting individual bytes now, and some other input has been detected,
+ // we revert to heterogenous behaviour
+ foreach (byte b in _inputBytes)
+ {
+ WriteHexadecimal(new byte[] { b }, null, 0);
+ }
+
+ _inputBytes = null;
+ }
+
+ if (processResult != null)
+ {
+ int offset = Math.Min(processResult.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
+ int count = Math.Min(processResult.Length - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue);
+ if (offset != 0 || count != processResult.Length)
+ {
+ WriteHexadecimal(processResult.AsSpan().Slice(offset, count), null, 0);
+ }
+ else
+ {
+ WriteHexadecimal(processResult, null, 0);
+ }
+ }
+ }
+ else
{
- int offset = Math.Min(inputBytes.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
- int count = Math.Min(inputBytes.Length - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue);
- if (offset != 0 || count != inputBytes.Length)
+ if (_inputBytes == null)
{
- WriteHexidecimal(inputBytes.AsSpan().Slice(offset, count), null, 0);
+ _inputBytes = new List(processResult);
}
else
{
- WriteHexidecimal(inputBytes, null, 0);
+ _inputBytes.AddRange(processResult);
}
}
}
@@ -324,15 +468,15 @@ private void ProcessObjectContent(PSObject inputObject)
/// Bytes for the hexadecimial representaion.
/// File path.
/// Offset in the file.
- private void WriteHexidecimal(Span inputBytes, string path, Int64 offset)
+ private void WriteHexadecimal(Span inputBytes, string path, long offset)
{
- ByteCollection byteCollectionObject = new ByteCollection((UInt64)offset, inputBytes.ToArray(), path);
+ ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes.ToArray(), path);
WriteObject(byteCollectionObject);
}
- private void WriteHexidecimal(byte[] inputBytes, string path, Int64 offset)
+ private void WriteHexadecimal(byte[] inputBytes, string path, long offset)
{
- ByteCollection byteCollectionObject = new ByteCollection((UInt64)offset, inputBytes, path);
+ ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes, path);
WriteObject(byteCollectionObject);
}
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/FormatHex.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/FormatHex.Tests.ps1
index 9dd90a125cf..12c6cc1c910 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/FormatHex.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/FormatHex.Tests.ps1
@@ -34,8 +34,7 @@ Describe "FormatHex" -tags "CI" {
$thumbprint = $null
$certProviderAvailable = $false
- if ($certificateProvider.Count -gt 0)
- {
+ if ($certificateProvider.Count -gt 0) {
$thumbprint = $certificateProvider[0].Thumbprint
$certProviderAvailable = $true
}
@@ -44,64 +43,90 @@ Describe "FormatHex" -tags "CI" {
}
Context "InputObject Paramater" {
+ BeforeAll {
+ enum TestEnum {
+ TestOne = 1; TestTwo = 2; TestThree = 3; TestFour = 4
+ }
+ Add-Type -TypeDefinition @'
+public enum TestSByteEnum : sbyte {
+ One = -1,
+ Two = -2,
+ Three = -3,
+ Four = -4
+}
+'@
+ }
+
$testCases = @(
@{
- Name = "Can process byte type 'fhx -InputObject [byte]5'"
- InputObject = [byte]5
- Count = 1
+ Name = "Can process byte type 'fhx -InputObject [byte]5'"
+ InputObject = [byte]5
+ Count = 1
ExpectedResult = "00000000 05"
}
@{
- Name = "Can process byte[] type 'fhx -InputObject [byte[]](1,2,3,4,5)'"
- InputObject = [byte[]](1,2,3,4,5)
- Count = 1
+ Name = "Can process byte[] type 'fhx -InputObject [byte[]](1,2,3,4,5)'"
+ InputObject = [byte[]](1, 2, 3, 4, 5)
+ Count = 1
ExpectedResult = "00000000 01 02 03 04 05 ....."
}
@{
- Name = "Can process int type 'fhx -InputObject 7'"
- InputObject = 7
- Count = 1
+ Name = "Can process int type 'fhx -InputObject 7'"
+ InputObject = 7
+ Count = 1
ExpectedResult = "00000000 07 00 00 00 ...."
}
@{
- Name = "Can process int[] type 'fhx -InputObject [int[]](5,6,7,8)'"
- InputObject = [int[]](5,6,7,8)
- Count = 1
+ Name = "Can process int[] type 'fhx -InputObject [int[]](5,6,7,8)'"
+ InputObject = [int[]](5, 6, 7, 8)
+ Count = 1
ExpectedResult = "00000000 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 ................"
}
@{
- Name = "Can process int32 type 'fhx -InputObject [int32]2032'"
- InputObject = [int32]2032
- Count = 1
+ Name = "Can process int32 type 'fhx -InputObject [int32]2032'"
+ InputObject = [int32]2032
+ Count = 1
ExpectedResult = "00000000 F0 07 00 00 ð..."
}
@{
- Name = "Can process int32[] type 'fhx -InputObject [int32[]](2032, 2033, 2034)'"
- InputObject = [int32[]](2032, 2033, 2034)
- Count = 1
+ Name = "Can process int32[] type 'fhx -InputObject [int32[]](2032, 2033, 2034)'"
+ InputObject = [int32[]](2032, 2033, 2034)
+ Count = 1
ExpectedResult = "00000000000000000000 F0 07 00 00 F1 07 00 00 F2 07 00 00 ð...ñ...ò..."
}
@{
- Name = "Can process Int64 type 'fhx -InputObject [Int64]9223372036854775807'"
- InputObject = [Int64]9223372036854775807
- Count = 1
+ Name = "Can process Int64 type 'fhx -InputObject [Int64]9223372036854775807'"
+ InputObject = [Int64]9223372036854775807
+ Count = 1
ExpectedResult = "00000000000000000000 FF FF FF FF FF FF FF 7F ......."
}
@{
- Name = "Can process Int64[] type 'fhx -InputObject [Int64[]](9223372036852,9223372036853)'"
- InputObject = [Int64[]](9223372036852,9223372036853)
- Count = 1
+ Name = "Can process Int64[] type 'fhx -InputObject [Int64[]](9223372036852,9223372036853)'"
+ InputObject = [Int64[]](9223372036852, 9223372036853)
+ Count = 1
ExpectedResult = "00000000000000000000 F4 5A D0 7B 63 08 00 00 F5 5A D0 7B 63 08 00 00 ôZÐ{c...õZÐ{c..."
}
@{
- Name = "Can process string type 'fhx -InputObject hello world'"
- InputObject = "hello world"
- Count = 1
+ Name = "Can process string type 'fhx -InputObject hello world'"
+ InputObject = "hello world"
+ Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
+ @{
+ Name = "Can process PS-native enum array '[TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour') | fhx'"
+ InputObject = [TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour')
+ Count = 1
+ ExpectedResult = "00000000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................"
+ }
+ @{
+ Name = "Can process C#-native sbyte enum array '[TestSByteEnum[]]('One', 'Two', 'Three', 'Four') | fhx'"
+ InputObject = [TestSByteEnum[]]('One', 'Two', 'Three', 'Four')
+ Count = 1
+ ExpectedResult = "00000000000000000000 FF FE FD FC .þýü"
+ }
)
- It "" -TestCase $testCases{
+ It "" -TestCase $testCases {
param ($Name, $InputObject, $Count, $ExpectedResult)
@@ -114,65 +139,94 @@ Describe "FormatHex" -tags "CI" {
}
Context "InputObject From Pipeline" {
+ BeforeAll {
+ enum TestEnum {
+ TestOne = 1; TestTwo = 2; TestThree = 3; TestFour = 4
+ }
+ Add-Type -TypeDefinition @'
+public enum TestSByteEnum : sbyte {
+ One = -1,
+ Two = -2,
+ Three = -3,
+ Four = -4
+}
+'@
+ }
+
$testCases = @(
@{
- Name = "Can process byte type '[byte]5 | fhx'"
- InputObject = [byte]5
- Count = 1
+ Name = "Can process byte type '[byte]5 | fhx'"
+ InputObject = [byte]5
+ Count = 1
ExpectedResult = "00000000000000000000 05"
}
@{
- Name = "Can process byte[] type '[byte[]](1,2) | fhx'"
- InputObject = [byte[]](1,2)
- Count = 2
- ExpectedResult = "00000000000000000000 01 ."
- ExpectedSecondResult = "00000000000000000000 02 ."
+ Name = "Can process byte[] type '[byte[]](1,2) | fhx'"
+ InputObject = [byte[]](1, 2)
+ Count = 1
+ ExpectedResult = "00000000000000000000 01 02 .."
}
@{
- Name = "Can process int type '7 | fhx'"
- InputObject = 7
- Count = 1
+ Name = "Can process int type '7 | fhx'"
+ InputObject = 7
+ Count = 1
ExpectedResult = "00000000000000000000 07 00 00 00 ...."
}
@{
- Name = "Can process int[] type '[int[]](5,6) | fhx'"
- InputObject = [int[]](5,6)
- Count = 2
- ExpectedResult = "00000000000000000000 05 00 00 00 ...."
- ExpectedSecondResult = "00000000000000000000 06 00 00 00 ...."
+ Name = "Can process int[] type '[int[]](5,6) | fhx'"
+ InputObject = [int[]](5, 6)
+ Count = 1
+ ExpectedResult = "00000000000000000000 05 00 00 00 06 00 00 00 ........"
}
@{
- Name = "Can process int32 type '[int32]2032 | fhx'"
- InputObject = [int32]2032
- Count = 1
+ Name = "Can process int32 type '[int32]2032 | fhx'"
+ InputObject = [int32]2032
+ Count = 1
ExpectedResult = "00000000000000000000 F0 07 00 00 ð..."
}
@{
- Name = "Can process int32[] type '[int32[]](2032, 2033) | fhx'"
- InputObject = [int32[]](2032, 2033)
- Count = 2
- ExpectedResult = "00000000000000000000 F0 07 00 00 ð..."
- ExpectedSecondResult = "00000000000000000000 F1 07 00 00 ñ..."
+ Name = "Can process int32[] type '[int32[]](2032, 2033) | fhx'"
+ InputObject = [int32[]](2032, 2033)
+ Count = 1
+ ExpectedResult = "00000000000000000000 F0 07 00 00 F1 07 00 00 ð...ñ..."
}
@{
- Name = "Can process Int64 type '[Int64]9223372036854775807 | fhx'"
- InputObject = [Int64]9223372036854775807
- Count = 1
+ Name = "Can process Int64 type '[Int64]9223372036854775807 | fhx'"
+ InputObject = [Int64]9223372036854775807
+ Count = 1
ExpectedResult = "00000000000000000000 FF FF FF FF FF FF FF 7F ......."
}
@{
- Name = "Can process Int64[] type '[Int64[]](9223372036852,9223372036853) | fhx'"
- InputObject = [Int64[]](9223372036852,9223372036853)
- Count = 2
- ExpectedResult = "00000000000000000000 F4 5A D0 7B 63 08 00 00 ôZÐ{c..."
- ExpectedSecondResult = "00000000000000000000 F5 5A D0 7B 63 08 00 00 õZÐ{c..."
+ Name = "Can process Int64[] type '[Int64[]](9223372036852,9223372036853) | fhx'"
+ InputObject = [Int64[]](9223372036852, 9223372036853)
+ Count = 1
+ ExpectedResult = "00000000000000000000 F4 5A D0 7B 63 08 00 00 F5 5A D0 7B 63 08 00 00 ôZÐ{c...õZÐ{c..."
}
@{
- Name = "Can process string type 'hello world | fhx'"
- InputObject = "hello world"
- Count = 1
+ Name = "Can process string type 'hello world | fhx'"
+ InputObject = "hello world"
+ Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
+ @{
+ Name = "Can process jagged array type '[sbyte[]](-15, 18, 21, -5), [byte[]](1, 2, 3, 4, 5, 6) | fhx'"
+ InputObject = [sbyte[]](-15, 18, 21, -5), [byte[]](1, 2, 3, 4, 5, 6)
+ Count = 2
+ ExpectedResult = "00000000000000000000 F1 12 15 FB ñ..û"
+ ExpectedSecondResult = "00000000000000000000 01 02 03 04 05 06 ......"
+ }
+ @{
+ Name = "Can process PS-native enum array '[TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour') | fhx'"
+ InputObject = [TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour')
+ Count = 1
+ ExpectedResult = "00000000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................"
+ }
+ @{
+ Name = "Can process C#-native sbyte enum array '[TestSByteEnum[]]('One', 'Two', 'Three', 'Four') | fhx'"
+ InputObject = [TestSByteEnum[]]('One', 'Two', 'Three', 'Four')
+ Count = 1
+ ExpectedResult = "00000000000000000000 FF FE FD FC .þýü"
+ }
)
It "" -Testcase $testCases {
@@ -181,12 +235,11 @@ Describe "FormatHex" -tags "CI" {
$result = $InputObject | Format-Hex
- $result.count | Should -Be $Count
+ $result.Count | Should -Be $Count
$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result[0].ToString() | Should -MatchExactly $ExpectedResult
- if ($result.count -gt 1)
- {
+ if ($result.count -gt 1) {
$result[1].ToString() | Should -MatchExactly $ExpectedSecondResult
}
}
@@ -198,39 +251,39 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
- Name = "Can process file content from given file path 'fhx -Path `$inputFile1'"
- PathCase = $true
- Path = $inputFile1
- Count = 1
+ Name = "Can process file content from given file path 'fhx -Path `$inputFile1'"
+ PathCase = $true
+ Path = $inputFile1
+ Count = 1
ExpectedResult = $inputText1
}
@{
- Name = "Can process file content from all files in array of file paths 'fhx -Path `$inputFile1, `$inputFile2'"
- PathCase = $true
- Path = @($inputFile1, $inputFile2)
- Count = 2
- ExpectedResult = $inputText1
+ Name = "Can process file content from all files in array of file paths 'fhx -Path `$inputFile1, `$inputFile2'"
+ PathCase = $true
+ Path = @($inputFile1, $inputFile2)
+ Count = 2
+ ExpectedResult = $inputText1
ExpectedSecondResult = $inputText2
}
@{
- Name = "Can process file content from all files when resolved to multiple paths 'fhx -Path '`$testDirectory\SourceFile-*''"
- PathCase = $true
- Path = "$testDirectory\SourceFile-*"
- Count = 2
- ExpectedResult = $inputText1
+ Name = "Can process file content from all files when resolved to multiple paths 'fhx -Path '`$testDirectory\SourceFile-*''"
+ PathCase = $true
+ Path = "$testDirectory\SourceFile-*"
+ Count = 2
+ ExpectedResult = $inputText1
ExpectedSecondResult = $inputText2
}
@{
- Name = "Can process file content from given file path 'fhx -LiteralPath `$inputFile3'"
- Path = $inputFile3
- Count = 1
+ Name = "Can process file content from given file path 'fhx -LiteralPath `$inputFile3'"
+ Path = $inputFile3
+ Count = 1
ExpectedResult = $inputText3
}
@{
- Name = "Can process file content from all files in array of file paths 'fhx -LiteralPath `$inputFile1, `$inputFile3'"
- Path = @($inputFile1, $inputFile3)
- Count = 2
- ExpectedResult = $inputText1
+ Name = "Can process file content from all files in array of file paths 'fhx -LiteralPath `$inputFile1, `$inputFile3'"
+ Path = @($inputFile1, $inputFile3)
+ Count = 2
+ ExpectedResult = $inputText1
ExpectedSecondResult = $inputText3
}
)
@@ -239,61 +292,75 @@ Describe "FormatHex" -tags "CI" {
param ($Name, $PathCase, $Path, $ExpectedResult, $ExpectedSecondResult)
- if ($PathCase)
- {
- $result = Format-Hex -Path $Path
+ if ($PathCase) {
+ $result = Format-Hex -Path $Path
}
- else # LiteralPath
- {
+ else {
+ # LiteralPath
$result = Format-Hex -LiteralPath $Path
}
$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result[0].ToString() | Should -MatchExactly $ExpectedResult
- if ($result.count -gt 1)
- {
+ if ($result.count -gt 1) {
$result[1].ToString() | Should -MatchExactly $ExpectedSecondResult
}
}
+
+ It 'properly accepts -LiteralPath input from a FileInfo object' {
+ $FilePath = 'TestDrive:\FHX-LitPathTest.txt'
+ "Hello World!" | Set-Content -Path $FilePath
+ $FileObject = Get-Item -Path $FilePath
+
+ $result = $FileObject | Format-Hex
+ if ($IsWindows) {
+ $ExpectedResult = "00000000000000000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 0D 0A Hello World!.."
+ }
+ else {
+ $ExpectedResult = "00000000000000000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 0A Hello World!."
+ }
+
+ $result[0].ToString() | Should -MatchExactly $ExpectedResult
+ }
}
Context "Encoding Parameter" {
$testCases = @(
@{
- Name = "Can process ASCII encoding 'fhx -InputObject 'hello' -Encoding ASCII'"
- Encoding = "ASCII"
- Count = 1
+ Name = "Can process ASCII encoding 'fhx -InputObject 'hello' -Encoding ASCII'"
+ Encoding = "ASCII"
+ Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
}
@{
- Name = "Can process BigEndianUnicode encoding 'fhx -InputObject 'hello' -Encoding BigEndianUnicode'"
- Encoding = "BigEndianUnicode"
- Count = 1
+ Name = "Can process BigEndianUnicode encoding 'fhx -InputObject 'hello' -Encoding BigEndianUnicode'"
+ Encoding = "BigEndianUnicode"
+ Count = 1
ExpectedResult = "00000000000000000000 00 68 00 65 00 6C 00 6C 00 6F .h.e.l.l.o"
}
@{
- Name = "Can process Unicode encoding 'fhx -InputObject 'hello' -Encoding Unicode'"
- Encoding = "Unicode"
- Count = 1
+ Name = "Can process Unicode encoding 'fhx -InputObject 'hello' -Encoding Unicode'"
+ Encoding = "Unicode"
+ Count = 1
ExpectedResult = "00000000000000000000 68 00 65 00 6C 00 6C 00 6F 00 h.e.l.l.o."
}
@{
- Name = "Can process UTF7 encoding 'fhx -InputObject 'hello' -Encoding UTF7'"
- Encoding = "UTF7"
- Count = 1
+ Name = "Can process UTF7 encoding 'fhx -InputObject 'hello' -Encoding UTF7'"
+ Encoding = "UTF7"
+ Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
}
- @{
- Name = "Can process UTF8 encoding 'fhx -InputObject 'hello' -Encoding UTF8'"
- Encoding = "UTF8"
- Count = 1
+ @{
+ Name = "Can process UTF8 encoding 'fhx -InputObject 'hello' -Encoding UTF8'"
+ Encoding = "UTF8"
+ Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
}
- @{
- Name = "Can process UTF32 encoding 'fhx -InputObject 'hello' -Encoding UTF32'"
- Encoding = "UTF32"
- Count = 1
+ @{
+ Name = "Can process UTF32 encoding 'fhx -InputObject 'hello' -Encoding UTF32'"
+ Encoding = "UTF32"
+ Count = 1
ExpectedResult = "00000000000000000000 68 00 00 00 65 00 00 00 6C 00 00 00 6C 00 00 00 h...e...l...l...$($newline)00000000000000000010 6F 00 00 00 o..."
}
)
@@ -316,16 +383,16 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
- Name = "Does not support non-FileSystem Provider paths 'fhx -Path 'Cert:\CurrentUser\My\`$thumbprint' -ErrorAction Stop'"
- PathParameterErrorCase = $true
- Path = "Cert:\CurrentUser\My\$thumbprint"
+ Name = "Does not support non-FileSystem Provider paths 'fhx -Path 'Cert:\CurrentUser\My\`$thumbprint' -ErrorAction Stop'"
+ PathParameterErrorCase = $true
+ Path = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
@{
- Name = "Type Not Supported 'fhx -InputObject @{'hash' = 'table'} -ErrorAction Stop'"
- InputObjectErrorCase = $true
- Path = $inputFile1
- InputObject = @{ "hash" = "table" }
+ Name = "Type Not Supported 'fhx -InputObject @{'hash' = 'table'} -ErrorAction Stop'"
+ InputObjectErrorCase = $true
+ Path = $inputFile1
+ InputObject = @{ "hash" = "table" }
ExpectedFullyQualifiedErrorId = "FormatHexTypeNotSupported,Microsoft.PowerShell.Commands.FormatHex"
}
)
@@ -335,12 +402,10 @@ Describe "FormatHex" -tags "CI" {
param ($Name, $PathParameterErrorCase, $Path, $InputObject, $InputObjectErrorCase, $ExpectedFullyQualifiedErrorId)
{
- if ($PathParameterErrorCase)
- {
+ if ($PathParameterErrorCase) {
$result = Format-Hex -Path $Path -ErrorAction Stop
}
- if ($InputObjectErrorCase)
- {
+ if ($InputObjectErrorCase) {
$result = Format-Hex -InputObject $InputObject -ErrorAction Stop
}
} | Should -Throw -ErrorId $ExpectedFullyQualifiedErrorId
@@ -351,20 +416,20 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
- Name = "If given invalid path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
- PathCase = $true
- InvalidPath = "$($inputFile1.DirectoryName)\fakefile8888845345345348709.txt"
+ Name = "If given invalid path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
+ PathCase = $true
+ InvalidPath = "$($inputFile1.DirectoryName)\fakefile8888845345345348709.txt"
ExpectedFullyQualifiedErrorId = "FileNotFound,Microsoft.PowerShell.Commands.FormatHex"
}
@{
- Name = "If given a non FileSystem path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
- PathCase = $true
- InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
+ Name = "If given a non FileSystem path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
+ PathCase = $true
+ InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
@{
- Name = "If given a non FileSystem path in array (with LiteralPath), continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
- InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
+ Name = "If given a non FileSystem path in array (with LiteralPath), continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
+ InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
)
@@ -376,12 +441,11 @@ Describe "FormatHex" -tags "CI" {
$output = $null
$errorThrown = $null
- if ($PathCase)
- {
+ if ($PathCase) {
$output = Format-Hex -Path $InvalidPath, $inputFile1 -ErrorVariable errorThrown -ErrorAction SilentlyContinue
}
- else # LiteralPath
- {
+ else {
+ # LiteralPath
$output = Format-Hex -LiteralPath $InvalidPath, $inputFile1 -ErrorVariable errorThrown -ErrorAction SilentlyContinue
}
@@ -396,10 +460,10 @@ Describe "FormatHex" -tags "CI" {
It "Path is default Parameter Set 'fhx `$inputFile1'" {
- $result = Format-Hex $inputFile1
+ $result = Format-Hex $inputFile1
$result | Should -Not -BeNullOrEmpty
- ,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
+ , $result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$actualResult = $result.ToString()
$actualResult | Should -MatchExactly $inputText1
}
@@ -409,7 +473,7 @@ Describe "FormatHex" -tags "CI" {
$result = Get-ChildItem $inputFile1 | Format-Hex
$result | Should -Not -BeNullOrEmpty
- ,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
+ , $result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$actualResult = $result.ToString()
$actualResult | Should -MatchExactly $inputText1
}
@@ -419,7 +483,7 @@ Describe "FormatHex" -tags "CI" {
$result = "a" * 30 | Format-Hex
$result | Should -Not -BeNullOrEmpty
- ,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
+ , $result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result.ToString() | Should -MatchExactly "00000000000000000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa$($newline)00000000000000000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaa "
}