While I was busy working, it turned into Friday which means time for a little PowerShell fun. I can't say you'll find any deep, meaningful, production use from today's post, but you might pick up a few techniques, which is really the point. Today we're going to have some fun with strings and arrays.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
The first thing I want to do is reverse a string. So that a string like "Every good boy deserves fudge" becomes "egduf sevresed yob doog yrevE". This is also a great example of how we can take advantage of the object nature of PowerShell. Without nitpicking the semantics, I'm not parsing the string to get a reverse version, I'm taking advantage of objects. First off, a string object has a single property: length.
[cc lang="PowerShell"]
PS C:\> $s="PowerShell"
PS C:\> $s.length
10
PS C:\>
[/cc]
The string object is also an array of characters which means I can access any character I want by an index number. Remember PowerShell arrays start at 0.
[cc lang="PowerShell"]
PS C:\> $s[4]
r
PS C:\> $s[5]
S
PS C:\> $s[0,6]
P
h
PS C:\> $s[3..6]
e
r
S
h
PS C:\>
[/cc]
So to reverse the string, all I need to do is get the characters in reverse order and build a new string.
[cc lang="PowerShell"]
PS C:\> [string]$reverse=""
PS C:\> for ($i=($s.length-1);$i -ge 0; $i--) {
>> #append to $reverse
>> $reverse+=$s[$i]
>> }
>>
PS C:\> $reverse
llehSrewoP
PS C:\>
[/cc]
I defined an empty string object, and then using the FOR construct start at the end of $s and add each character to $reverse. Taking this a step further I put together a function, Out-Reverse, so that you could pipe strings, or even entire text files to it. Each reversed line will be written to the pipeline.
[cc lang="PowerShell"]
Function Out-Reverse {
Param(
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a line of text",
ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[string[]]$Text
)
Process {
ForEach ($str in $Text) {
Write-Verbose "Reversing: $str"
$str | foreach {
#define an empty variable for the reversed result
[string]$reverse=""
for ($i=($_.length-1);$i -ge 0; $i--) {
#append to $reverse
$reverse+=$_[$i]
}
#write the result
Write-Host "Reversed" -ForegroundColor Yellow
$reverse
}
}# Foreach
} #process
} #end function
[/cc]
Want to see it in action?
[cc lang="PowerShell"]
PS C:\> "The quick brown fox jumped over the lazy dog" | out-reverse
Reversed
god yzal eht revo depmuj xof nworb kciuq ehT
[/cc]The function uses Write-Host to show you what happened but you could comment that out. Now let's look at one other way to play with strings.
Since we know the string is an array of characters which we can access by index number. let's create a randomized version of the string. Naturally I made a function.
[cc lang="PowerShell"]
Function Out-Random {
Param(
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a line of text",
ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[string[]]$Text
)
Process {
ForEach ($str in $Text) {
Write-Verbose "Randomizing: $str"
#initialize an empty array
$a=@()
Write-Verbose "Generating random number array"
do {
#get a random number between 0 and length of string
$x=get-random -Minimum 0 -Maximum $str.length
#add the number to the array if it doesn't already exist
if (-not ($a -contains $x)) {
$a+=$x
}
#repeat until every number has been added to the array
} Until ($a.count -eq $str.length)
#define a varialble for the randomized output
[string]$randout=""
Write-Verbose "Constructing random output"
#get the corresponding random element and construct the random output
$a | foreach { $randout+=$str[$_] }
#write the result
Write-Host "Randomized" -ForegroundColor Yellow
$randout
} #foreach
} #Process
} #end function
[/cc]
Now I couldn't just get a random number for each character in the array because I'd end up with duplicates. If the string was 10 characters long, then I need an array of numbers 0 to 9 in a random order. To accomplish my goal, I created an empty array. Then using the Get-Random cmdlet, I generated a number between 0 and the string length. If the number did not already exist in my empty array I add it, otherwise I looped and tried again. I hope this is a good example of a Do/Until loop.
[cc lang="PowerShell"]
$a=@()
Write-Verbose "Generating random number array"
do {
#get a random number between 0 and length of string
$x=get-random -Minimum 0 -Maximum $str.length
#add the number to the array if it doesn't already exist
if (-not ($a -contains $x)) {
$a+=$x
}
#repeat until every number has been added to the array
} Until ($a.count -eq $str.length)
[/cc]
The process continues until the number of items in my array equals the length of the string. Now, it's just a matter of enumerating the array of random numbers, getting the corresponding character from the string array and building a new string.
[cc lang="Powershell"]
[string]$randout=""
Write-Verbose "Constructing random output"
#get the corresponding random element and construct the random output
$a | foreach { $randout+=$str[$_] }
[/cc]
My Out-Reverse function in action:
[cc lang="PowerShell"]
PS C:\> "The quick brown fox jumped over the lazy dog" | out-random
Randomized
eine gdoxk mu o buazloeorcfhqv dt pjThwyre
[/cc]
You can have even more fun by piping between functions.
[cc lang="PowerShell"]
PS C:\> "Every good boy deserves fudge" | out-reverse | out-random
Reversed
Randomized
sdr yedesbdreoeyefvEv og guo
PS C:\> "Every good boy deserves fudge" | out-random | out-reverse
Randomized
Reversed
dfdgeuoesyb rogs er dyeEvevo
PS C:\> "Every good boy deserves fudge" | out-reverse | out-reverse
Reversed
Reversed
Every good boy deserves fudge
[/cc]
The last example is kind of silly. But it shows you can undo the change. Actually, if you save the randomized array ($a), you can also "decode" the randomized string. But I'll leave that for you to play with. A hint: you'll most likely need a hash table.
So have some fun today and maybe even learn something new. You can download a script file with both functions here.
It seems I overthought the reverse string function.
PS C:\> $s=”I am a string”
PS C:\> [string]$reverse=””
PS C:\> $s[$s.length..0] | foreach {[string]$reverse+=$_}
PS C:\> $reverse
gnirts a ma I
Thanks to @zimakki for setting me straight.
Hi,
there is another one possible solution:
PS C:\> $str = ‘PowerShell’
PS C:\> -join $str[$str.Length..0]
llehSrewoP
David