﻿# encoding: utf-8
# api: powershell
# title: 
# description: My old bytes module with some extra functions from SANS all wrapped up into a single module.
# version: 0.1
# type: class
# license: CC0
# function: Shift-Left
# x-poshcode-id: 1729
# x-archived: 2016-03-10T10:09:48
#
#
#requires -version 2.0
Add-Type @"
public class Shift {
   public static int   Right(int x,   int count) { return x >> count; }
   public static uint  Right(uint x,  int count) { return x >> count; }
   public static long  Right(long x,  int count) { return x >> count; }
   public static ulong Right(ulong x, int count) { return x >> count; }
   public static int    Left(int x,   int count) { return x << count; }
   public static uint   Left(uint x,  int count) { return x << count; }
   public static long   Left(long x,  int count) { return x << count; }
   public static ulong  Left(ulong x, int count) { return x << count; }
}                    
"@



#.Example 
#  Shift-Left 16 1        ## returns 32
#.Example 
#  8,16 |Shift-Left       ## returns 16,32
function Shift-Left {
PARAM( $x=1, $y )
BEGIN {
   if($y) {
      [Shift]::Left( $x, $y )
   }
}
PROCESS {
   if($_){
      [Shift]::Left($_, $x)
   }
}
}


#.Example 
#  Shift-Right 8 1        ## returns 4
#.Example 
#  2,4,8 |Shift-Right 2   ## returns 0,1,2
function Shift-Right {
PARAM( $x=1, $y )
BEGIN {
   if($y) {
      [Shift]::Right( $x, $y )
   }
}
PROCESS {
   if($_){
      [Shift]::Right($_, $x)
   }
}
}function Write-FileByte {
################################################################
#.Synopsis
#Â  Overwrites or creates a file with an array of raw bytes.
#.Parameter ByteArray
#Â  System.Byte[] array of bytes to put into the file.Â  If you
#Â  pipe this array in, you must pipe the [Ref] to the array.
#.Parameter Path
#Â  Path to the file as a string or as System.IO.FileInfo object.
#Â  Path as a string can be relative, absolute, or a simple file
#Â  name if the file is in the present working directory.
#.Example
#Â  write-filebyte -bytearray $bytes -path outfile.bin
#.Example
#Â  [Ref] $bytes | write-filebyte -path c:\temp\outfile.bin
################################################################
[CmdletBinding()] Param (
 [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Byte[]] $ByteArray,
 [Parameter(Mandatory = $True)] $Path
)

if ($Path -is [System.IO.FileInfo])
 { $Path = $Path.FullName }
elseif ($Path -notlike "*\*") #Simple file name.
 { $Path = "$pwd" + "\" + "$Path" }
elseif ($Path -like ".\*")Â  #pwd of script
 { $Path = $Path -replace "^\.",$pwd.Path }
elseif ($Path -like "..\*") #parent directory of pwd of script
 { $Path = $Path -replace "^\.\.",$(get-item $pwd).Parent.FullName }
else
 { throw "Cannot resolve path!" }
[System.IO.File]::WriteAllBytes($Path, $ByteArray)
}
function Convert-HexStringToByteArray {
################################################################
#.Synopsis
#Â  Convert a string of hex data into a System.Byte[] array. An
#Â  array is always returned, even if it contains only one byte.
#.Parameter String
#Â  A string containing hex data in any of a variety of formats,
#Â  including strings like the following, with or without extra
#Â  tabs, spaces, quotes or other non-hex characters:
#Â Â Â Â  0x41,0x42,0x43,0x44
#Â Â Â Â  \x41\x42\x43\x44
#Â Â Â Â  41-42-43-44
#Â Â Â Â  41424344
#Â  The string can be piped into the function too.
################################################################
[CmdletBinding()]
Param ( [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [String] $String )

#Clean out whitespaces and any other non-hex crud.
$String = $String.ToLower() -replace '[^a-f0-9\\\,x\-\:]',''

#Try to put into canonical colon-delimited format.
$String = $String -replace '0x|\\x|\-|,',':'

#Remove beginning and ending colons, and other detritus.
$String = $String -replace '^:+|:+$|x|\\',''

#Maybe there's nothing left over to convert...
if ($String.Length -eq 0) { ,@() ; return } 

#Split string with or without colon delimiters.
if ($String.Length -eq 1)
{ ,@([System.Convert]::ToByte($String,16)) }
elseif (($String.Length % 2 -eq 0) -and ($String.IndexOf(":") -eq -1))
{ ,@($String -split '([a-f0-9]{2})' | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}}) }
elseif ($String.IndexOf(":") -ne -1)
{ ,@($String -split ':+' | foreach-object {[System.Convert]::ToByte($_,16)}) }
else
{ ,@() }
#The strange ",@(...)" syntax is needed to force the output into an
#array even if there is only one element in the output (or none).
}
function Convert-ByteArrayToHexString {
################################################################
#.Synopsis
#Â  Returns a hex representation of a System.Byte[] array as
#Â  one or more strings.Â  Hex format can be changed.
#.Parameter ByteArray
#Â  System.Byte[] array of bytes to put into the file.Â  If you
#Â  pipe this array in, you must pipe the [Ref] to the array.
#Â  Also accepts a single Byte object instead of Byte[].
#.Parameter Width
#Â  Number of hex characters per line of output.
#.Parameter Delimiter
#Â  How each pair of hex characters (each byte of input) will be
#Â  delimited from the next pair in the output.Â  The default
#Â  looks like "0x41,0xFF,0xB9" but you could specify "\x" if
#Â  you want the output like "\x41\xFF\xB9" instead.Â  You do
#Â  not have to worry about an extra comma, semicolon, colon
#Â  or tab appearing before each line of output.Â  The default
#Â  value is ",0x".
#.Parameter Prepend
#Â  An optional string you can prepend to each line of hex
#Â  output, perhaps like '$x += ' to paste into another
#Â  script, hence the single quotes.
#.Parameter AddQuotes
#Â  An switch which will enclose each line in double-quotes.
#.Example
#Â  [Byte[]] $x = 0x41,0x42,0x43,0x44
#Â  Convert-ByteArrayToHexString $x
#
#Â  0x41,0x42,0x43,0x44
#.Example
#Â  [Byte[]] $x = 0x41,0x42,0x43,0x44
#Â  Convert-ByteArrayToHexString $x -width 2 -delimiter "\x" -addquotes
#
#Â  "\x41\x42"
#Â  "\x43\x44"
################################################################
[CmdletBinding()] Param (
 [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Byte[]] $ByteArray,
 [Parameter()] [Int] $Width = 10,
 [Parameter()] [String] $Delimiter = ",0x",
 [Parameter()] [String] $Prepend = "",
 [Parameter()] [Switch] $AddQuotes
)

if ($Width -lt 1) { $Width = 1 }
if ($ByteArray.Length -eq 0) { Return }
$FirstDelimiter = $Delimiter -Replace "^[\,\;\:\t]",""
$From = 0
$To = $Width - 1
Do
{
 $String = [System.BitConverter]::ToString($ByteArray[$From..$To])
 $String = $FirstDelimiter + ($String -replace "\-",$Delimiter)
 if ($AddQuotes) { $String = '"' + $String + '"' }
 if ($Prepend -ne "") { $String = $Prepend + $String }
 $String
 $From += $Width
 $To += $Width
} While ($From -lt $ByteArray.Length)
}
function Convert-ByteArrayToString {
################################################################
#.Synopsis
#Â  Returns the string representation of a System.Byte[] array.
#Â  ASCII string is the default, but Unicode, UTF7, UTF8 and
#Â  UTF32 are available too.
#.Parameter ByteArray
#Â  System.Byte[] array of bytes to put into the file.Â  If you
#Â  pipe this array in, you must pipe the [Ref] to the array.
#Â  Also accepts a single Byte object instead of Byte[].
#.Parameter Encoding
#Â  Encoding of the string: ASCII, Unicode, UTF7, UTF8 or UTF32.
#Â  ASCII is the default.
################################################################
[CmdletBinding()] Param (
 [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Byte[]] $ByteArray,
 [Parameter()] [String] $Encoding = "ASCII"
)

switch ( $Encoding.ToUpper() )
{
 "ASCII"Â Â  { $EncodingType = "System.Text.ASCIIEncoding" }
 "UNICODE" { $EncodingType = "System.Text.UnicodeEncoding" }
 "UTF7"Â Â Â  { $EncodingType = "System.Text.UTF7Encoding" }
 "UTF8"Â Â Â  { $EncodingType = "System.Text.UTF8Encoding" }
 "UTF32"Â Â  { $EncodingType = "System.Text.UTF32Encoding" }
 DefaultÂ Â  { $EncodingType = "System.Text.ASCIIEncoding" }
}
$Encode = new-object $EncodingType
$Encode.GetString($ByteArray)
}
function Get-FileHex {
################################################################
#.Synopsis
#Â  Display the hex dump of a file.
#.Parameter Path
#Â  Path to file as a string or as a System.IO.FileInfo object;
#Â  object can be piped into the function, string cannot.
#.Parameter Width
#Â  Number of hex bytes shown per line (default = 16).
#.Parameter Count
#Â  Number of bytes in the file to process (default = all).
#.Parameter NoOffset
#Â  Switch to suppress offset line numbers in output.
#.Parameter NoText
#Â  Switch to suppress ASCII translation of bytes in output.
################################################################
[CmdletBinding()] Param (
 [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
 [Alias("FullName","FilePath")] $Path,
 [Parameter()] [Int] $Width = 16,
 [Parameter()] [Int] $Count = -1,
 [Parameter()] [Switch] $NoOffset,
 [Parameter()] [Switch] $NoText
)

$linecounter = 0Â Â Â Â Â Â Â  # Offset from beginning of file in hex.
$placeholder = "."Â Â Â Â Â  # What to print when byte is not a letter or digit.

get-content $path -encoding byte -readcount $width -totalcount $count |
foreach-object {
 $paddedhex = $asciitext = $null
 $bytes = $_Â Â Â Â Â Â Â  # Array of [Byte] objects that is $width items in length.

 foreach ($byte in $bytes) {
 $byteinhex = [String]::Format("{0:X}", $byte)Â Â Â Â  # Convert byte to hex, e.g., "F".
 $paddedhex += $byteinhex.PadLeft(2,"0") + " "Â Â Â Â  # Pad with zero to force 2-digit length, e.g., "0F ".
 } 

 # Total bytes in file unlikely to be evenly divisible by $width, so fix last line.
 # Hex output width is '$width * 3' because of the extra spaces added around hex characters.
 if ($paddedhex.length -lt $width * 3)
 { $paddedhex = $paddedhex.PadRight($width * 3," ") }

 foreach ($byte in $bytes) {
 if ( [Char]::IsLetterOrDigit($byte) -or
 [Char]::IsPunctuation($byte) -or
 [Char]::IsSymbol($byte) )
 { $asciitext += [Char] $byte }
 else
 { $asciitext += $placeholder }
 }

 $offsettext = [String]::Format("{0:X}", $linecounter) # Linecounter in hex too.
 $offsettext = $offsettext.PadLeft(8,"0") + "h:"Â Â Â Â Â Â  # Pad linecounter with left zeros.
 $linecounter += $widthÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â  # Increment linecounter, each line representing $width bytes.

 if (-not $NoOffset) { $paddedhex = "$offsettext $paddedhex" }
 if (-not $NoText) { $paddedhex = $paddedhex + $asciitext }
 $paddedhex
}
}
function Toggle-Endian {
################################################################
#.Synopsis
#Â  Swaps the ordering of bytes in an array where each swappable
#Â  unit can be one or more bytes, and, if more than one, the
#Â  ordering of the bytes within that unit is NOT swapped. Can
#Â  be used to toggle between little- and big-endian formats.
#Â  Cannot be used to swap nibbles or bits within a single byte.
#.Parameter ByteArray
#Â  System.Byte[] array of bytes to be rearranged.Â  If you
#Â  pipe this array in, you must pipe the [Ref] to the array, but
#Â  a new array will be returned (originally array untouched).
#.Parameter SubWidthInBytes
#Â  Defaults to 1 byte.Â  Defines the number of bytes in each unit
#Â  (or atomic element) which is swapped, but no swapping occurs
#Â  within that unit.Â  The number of bytes in the ByteArray must
#Â  be evenly divisible by SubWidthInBytes.
#.Example
#Â  $bytearray = toggle-endian $bytearray
#.Example
#Â  [Ref] $bytearray | toggle-endian -SubWidthInBytes 2
################################################################
[CmdletBinding()] Param (
 [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Byte[]] $ByteArray,
 [Parameter()] [Int] $SubWidthInBytes = 1
)

if ($ByteArray.count -eq 1 -or $ByteArray.count -eq 0) { $ByteArray ; return } 

if ($SubWidthInBytes -eq 1) { [System.Array]::Reverse($ByteArray); $ByteArray ; return } 

if ($ByteArray.count % $SubWidthInBytes -ne 0)
{ throw "ByteArray size must be an even multiple of SubWidthInBytes!" ; return } Â 

$newarray = new-object System.Byte[] $ByteArray.count 

# $i tracks ByteArray from head, $j tracks NewArray from end.
for ($($i = 0; $j = $newarray.count - 1) ;
 $i -lt $ByteArray.count ;
 $($i += $SubWidthInBytes; $j -= $SubWidthInBytes))
{
 for ($k = 0 ; $k -lt $SubWidthInBytes ; $k++)
 { $newarray[$j - ($SubWidthInBytes - 1) + $k] = $ByteArray[$i + $k] }
}
$newarray
}
function PushToTcpPort
{
 param ([Byte[]] $bytearray, [String] $ipaddress, [Int32] $port)
 $tcpclient = new-object System.Net.Sockets.TcpClient($ipaddress, $port) -ErrorAction "SilentlyContinue"
 trap { "Failed to connect to $ipaddress`:$port" ; return }
 $networkstream = $tcpclient.getstream()
 #write(payload,starting offset,number of bytes to send)
 $networkstream.write($bytearray,0,$bytearray.length)
 $networkstream.close(1) #Wait 1 second before closing TCP session.
 $tcpclient.close()
}
