Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Friday Fun What a CHAR!

Posted on September 23, 2011September 13, 2013

Last week I posted a PowerShell snippet on Twitter. My original post piped an array of integers as [CHAR] type using an OFS. Don't worry about that. As many people reminded me, it is much easier to use the -Join operator.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!
-join [char[]](116,103,105,102)

I'll let you try that on your own. The [CHAR] type is used to represent a character as an integer value, like this:

PS C:\> [char]120
x

For this week's Friday Fun I thought it would be nice to translate a string of text into corresponding character values. It looks like a secret code! Or we could use the translation in a join scriptblock. So I put together a little script I call Translate-ToChar.ps1. The script takes a string of text and writes an array of [CHAR] objects.

Param(
[Parameter(Position=0)]
[ValidateNotNullOrEmpty()]
[string]$Text="PowerShell Rocks!",
[switch]$Scriptblock
)

#create CHAR mapping hash table
$map=@{}
33..125 | foreach { $map.Add([string]$_,[char]$_)}

#create an empty array to hold the CHAR values
$values=@()
$text.ToCharArray() | foreach {
#because $_ will change, save the current piped in character as a variable
$ltr=$_
[int]$i=($map.getEnumerator() | where {$_.value -ceq $ltr }).Name
#add the value to the array
$values+=$i
}

if ($ScriptBlock) {
#write a scriptblock to the pipeline
#create the command
$ofs=","
#create a variable so we variable expansion of $values
$t="-join [char[]]($values)"

#put it back together as a script block and write to the pipeline
[scriptblock]::Create($t)
}
else {
#write value array
$values
}

The script begins by defining a map hash table for what I think are all characters you are likely to find on a US keyboard. These should be character values 33 through 125 which I get using the range (..) operator.

$map=@{}
33..125 | foreach { $map.Add([string]$_,[char]$_)}

Each number is piped to ForEach object where I add it to the hash table. In order to get the hash table key to work properly I cast the number as a string and the hash table value is the same number cast as a [CHAR]. Now we can begin breaking the string apart and "translating" it.

$text.ToCharArray() | foreach {
#because $_ will change, save the current piped in character as a variable
$ltr=$_

The script splits the string into a character array using the default delimiter of a space. Because I'm going to be using a pipelined expression, I save the current letter as a variable. It will keep things straight in a moment.

The next step is to find the character in the hash table values. I found the best way to accomplish this was to call the hash table's GetEnumerator() method. This way I can pipe it to Where-Object and find the corresponding key.

[int]$i=($map.getEnumerator() | where {$_.value -ceq $ltr }).Name
#add the value to the array
$values+=$i

Notice I'm using the case sensitive -ceq operator. The Name property of the hash table enumerator is the key value, or in other words the corresponding [CHAR] integer. With me still? This value is added to an array for the final result. In fact the default isĀ to simply write $values to the pipeline. But, I've included a -Scriptblock parameter to have the script write a scriptblock to the pipeline using the -Join operator I mentioned earlier. Now for the interesting part.

I have an array variable which needs to be expanded into the scriptblock. This won't work:

$sb={-join [char[]]($values)}
write $sb

I'll end up with a scriptblock but have no way of resolving $values once the script ends. So instead I create a string with $values knowing that PowerShell will expand it. And because I want the array to be expanded as a comma separated string, I'll specify the $ofs variable as a comma. The default is a space.

$ofs=","
#create a variable so we get variable expansion of $values
$t="-join [char[]]($values)"

The variable $t is now a string with all of the integer values from $values as a comma separated list. I can turn this into scriptblock like this:

#put it back together as a script block and write to the pipeline
[scriptblock]::Create($t)

The scriptblock gets written to the pipeline. So, I could run the script like this:

PS C:\scripts> $a=.\Translate-ToChar.ps1
PS C:\scripts> $a
80
111
119
101
114
83
104
101
108
108
0
82
111
99
107
115
33

Now I can use $a however I want. Or I could create a scriptblock.

PS C:\scripts> $b=.\Translate-ToChar.ps1 -Scriptblock
PS C:\scripts> $b
-join [char[]](80,111,119,101,114,83,104,101,108,108,0,82,111,99,107,115,33)

I can invoke $b anytime I want to see the message.

While I don't expect you to be running this in production I hope you picked up some tips on using hash tables, arrays, scriptblocks and casting variable types.

Download Translate-ToChar


Behind the PowerShell Pipeline

Share this:

  • Share on X (Opens in new window) X
  • Share on Facebook (Opens in new window) Facebook
  • Share on Mastodon (Opens in new window) Mastodon
  • Share on LinkedIn (Opens in new window) LinkedIn
  • Share on Reddit (Opens in new window) Reddit
  • Print (Opens in new window) Print
  • Email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

3 thoughts on “Friday Fun What a CHAR!”

  1. Daniel says:
    September 23, 2011 at 6:39 pm

    Hi Jeffery,

    When reading the sample above I am confused about your usage of the hashtable called map. If you map from char to number (instead of the other way around) you end up with simpler code that produces the same output for the given sample.

    #create CHAR mapping hash table
    $map=@{}
    33..125 | foreach { $map.Add([Char]$_,[String]$_)}

    #create an empty array to hold the CHAR values
    $values=@()
    $text.ToCharArray() | foreach {
    $value = $map[$_]
    if (-not $value) { $value = 0 }
    $values += $value
    }

    Please correct me if I am wrong, since I have a feeling I missed something.

    Thanks for a great blog anyway.

    1. Jeffery Hicks says:
      September 23, 2011 at 8:08 pm

      I started down a similar path but couldn’t get my head around it. It took a bit to work your code but now I see. In my mind I always saw the ToCharArray() method as splitting the string into individual letters or characters. But now I see that it is splitting the string into an array of [CHAR] objects. Because PowerShell formats them back as “real” characters, it’s easy to miss that, which I have for years. I appreciate the elegance here, although fundamentally it probably doesn’t make much difference.

      1. Daniel says:
        September 24, 2011 at 11:22 am

        Agreed, in terms of correctness it does not matter. However, if our task at hand is to convert strings to arrays of numeric values we can simplify even further:

        # convert
        $a = “Powershell Rocks!”.ToCharArray() | % { [int]$_ }

        # convert back
        -join [char[]]$a

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2026 The Lonely Administrator | Powered by SuperbThemes!
%d