A few weeks ago an Iron Scripter PowerShell challenge was issued that involved playing with words and characters. Remember, the Iron Scripter challenges aren't intended to create meaningful, production worthy code. They are designed to help you learn PowerShell fundamentals and scripting techniques. This particular challenge was aimed at beginner and intermediate experience levels. I have my own solutions to share, but they are not necessarily the only solution or even the best.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Beginner
The beginner challenge wanted you take a string and calculate the sum of its character values. Of course you first need a string.
$w = "PowerShell Iron Scripter"
Each letter is actually represented by a [CHAR]. Technically the string is an array of System.Char objects. If you run:
$w[0] | Get-Member
You can verify this. $w[0] is the first element in the array of characters.
What isn't especially clear, is that this object has an underlying integer value. Try this:
$w[0] -as [int]
This command tells PowerShell to treat the object, $w[0] AS an integer. You should get a value back of 80. In fact, if you run this:
[char]80
You should get a result of P. By the way, you could also have calculated the integer value this way:
$w[0].ToInt32($null)
But this is not something I would expect a beginner to know.
With this knowledge it is time to calculate the total sum of all characters. Hopefully you know about Measure-Object. You can do a quick test with a single character.
$w[0] | Measure-Object -sum
You should see a Sum value of 80. Make sure you understand this pattern. You are telling PowerShell, "Take all of the characters to the left of the pipe (|) and send them to Measure-Object. Have the cmdlet get the sum. There is no need to specify a property because the [CHAR] object doesn't really have any. Once you recognize this pattern it is easy to take this to the next step to turn the string into an character array. If you pipe $w to Get-Member you'll see this method.
$w.toCharArray()
On the screen, PowerShell will display the values as something you can read. But you can actually send this array to Measure-Object per the pattern you discovered a moment ago.
$w.toCharArray() | Measure-Object -sum | Select-Object -property Sum
I took this the next step to pipe the measurement object result to Select-Object to display only the Sum property. When you run this you'll still get an object with a single property, Sum. If you only want the value, you can tell Select-Object to expand the property.
$w.toCharArray() | Measure-Object -sum | Select-Object -expandproperty Sum
You should have been able to discover this by reading the help and examples for Select-Object.
Once you get your head around the PowerShell pipeline, you can simplify the command to this:
($w.ToCharArray() | Measure-Object -sum).sum
You are telling PowerShell, run the code inside the parentheses (which you can do so you can see what is happening) and then display the Sum property of that object. Using my text in $w you should get a sum total of 2345.
The second part of the beginner challenge was to turn the array into a string of their integer values. You already know how to create the array. The next step is to display them as their integer values.
$w.ToCharArray() | ForEach-Object {$_ -as [int] }
This creates another array. To join them together you can use the -Join operator, which you could have found by searching for help.
help join
Using the nested pipeline pattern from above, converting the text into string of corresponding integer values can be done with a one-line command.
($w.ToCharArray() | ForEach-Object {$_ -as [int] }) -join " "
Or you could use this slightly advanced alternative.
[int[]]$w.ToCharArray() -join " "
This command is telling PowerShell to turn the results of the ToCharArray() method into an array of integers. Then join that result with a space between each value.
If you are running PowerShell 7, you have another option and that is a cmdlet called Join-String.
[int[]]$w.ToCharArray() | Join-String -Separator " "
Intermediate
The next level challenge was to take this knowledge and write a set of functions to create strings using double the character value. Let's start with a new string of text.
$t = "Today, I am a PowerShell Iron Scripter!"
Here is some proof of concept code.
$c = $t.ToCharArray() | ForEach-Object -begin {$out = @()} -process { $val = [int]([char]$_) $nval = $val*2 $out += [char]$nval } -end { $out -join ""}
The first part of this is similar to what you did as a beginner. The array is piped to ForEach-Object. Most of you are probably used to running this with a single scriptblock, which is the process scriptblock. Code runs once for every piped in object using $_ as a placeholder to indicate the current object. But there are also Begin and End scriptblocks. In the Begin block, you can define an arrary, $out. This is done once before any pipeline processing is done. In the process block, the [CHAR] object's integer value is retrieved. A new value is calculated by multiplying by 2 and this new value is then converted back to a [CHAR] which is added to the array. Eventually, you'll have enough experience to reduce these several lines of code into one but I wanted to make sure you could visualize what is happening. The code in the End scriptlbock runs once after everything in the pipeline has been processed. You can join the values. These script blocks are the same that you use when creating an advanced PowerShell function.
You should get an odd-looking result.
¨ÞÈÂòX@@ÂÚ@Â@ ÞîÊä¦ÐÊØØ@äÞÜ@¦ÆäÒàèÊäB
Depending on the [CHAR] values you might even get non-printing characters. To reverse the process is merely a matter of taking each [CHAR] integer value and divide by 2.
$c.ToCharArray() | ForEach-Object -begin {$out = @()} -process { $val = [int]([char]$_) $nval = $val/2 $out += [char]$nval } -end { $out -join ""}
This will output the original string. Now that you have working code, you can build functions around them.
Function ConvertTo-DoubleChar { [cmdletbinding()] Param( [Parameter(Mandatory, ValueFromPipeline)] [string]$Text ) Begin { Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)" } #begin Process { Write-Verbose "[PROCESS] Converting $text" $Text.ToCharArray() | ForEach-Object -begin { $out = @() } -process { $val = [int]([char]$_) $nval = $val*2 $out += [char]$nval } -end { $converted = $out -join "" } Write-Verbose "[PROCESS] to $converted" $converted } #process End { Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)" } #end } Function ConvertFrom-DoubleChar { [cmdletbinding()] Param( [Parameter(Mandatory, ValueFromPipeline)] [string]$Text ) Begin { Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)" } #begin Process { Write-Verbose "[PROCESS] Converting $text" $Text.ToCharArray() | ForEach-Object -begin { $out = @() } -process { $val = [int]([char]$_) $nval = $val/2 $out += [char]$nval } -end { $out -join "" } } #process End { Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)" } #end }
Let's do a "round-trip" test.
"PowerShell is wicked fun!" | ConvertTo-DoubleChar -OutVariable in | ConvertFrom-DoubleChar
If the functions are designed properly the plain text string is converted to its double [CHAR] version which is then converted back.
PS C:\> "PowerShell is wicked fun!" | ConvertTo-DoubleChar -OutVariable in | ConvertFrom-DoubleChar PowerShell is wicked fun!
To double validate, my example is using the common parameter OutVariable to save the results from ConvertTo-DoubleChar.
PS C:\> $in ÞîÊä¦ÐÊØØ@Òæ@îÒÆÖÊÈ@ÌêÜB PS C:\> ConvertFrom-DoubleChar $in PowerShell is wicked fun!
Here's another example piping multiple strings.
As I mentioned at the beginning, these are not the only solutions. There are no short cuts to learning PowerShell. You need to get in the habit of reading help. Develop patterns and practices that you can re-use. Once you are comfortable with the fundamentals, it doesn't matter if you are working with a character object or a service or an Azure virtual machine.
If you have any questions on what I've come up with, please ask them in the comments.
Learn More
If you are looking for more ways to test and teach yourself PowerShell, I encourage you to grab a copy of The PowerShell Practice Primer.
2 thoughts on “PowerShell Word Play”
Comments are closed.