During the last PowerShell Oneliner Contest, Simon came up with the shortest working solution to Task 2, and I am happy to say that he promptly accepted to be my guest blogger today.
Let’s see his three remarkable answers to my PowerShell contest:
TASK 1: MANIPULATING OUTPUT – 46 chars
Gwmi Win32_Share|%{"\\$($_|% P*e)\$($_.Name)"}
TASK 2: MANDELBROT JOKE – 50 chars
gv q* -v|% Su* 26 21|%{"The B in$_ stands for$_."}
TASK 3: TEXT MINING – 196 chars
"$t1 $t2"-split'\W'|group|%{$o=$i=$p=0}{if($q=$_.Name){$1,$2=$t1,$t2|%{($_-split'\W'|group|? name -eq $q).Count}}if($o+=$1*$1){$i+=$2*$2}$p+=$1*$2}{if($3,$4=$o,$i|%{[math]::Sqrt($_)}){$p/($3*$4)}}
1. Simon, tell us a bit about yourself and about the way you got to work with PowerShell
I’m working as consultant in Sweden helping customers planning and building all kinds of automation, mainly using PowerShell. With a background in IT support and IT operations and a strong passion for coding I’m trying to preach developer practices to the ITPro community such as sourceControl, continuous integration and testing. Being able to collaborate on PowerShell scripts with your team and have the scripts automatically tested, signed and delivered to where they can be run solves a lot of questions like for example: “how do I know this script hasn’t been changed since I ran it last time?”.
I started my PowerShell journey quite a few years back when I was in client management. We had tens of thousands of clients reporting to Altiris and McAfee ePO and it was my task to sort and delegate actions based on those reports. When I realized I could parse the reports with PowerShell and do some basic sorting and filtering, that job got a lot easier and I was sold.
2. Is there any PowerShell project of your you want to speak about?
I think Phosphor (https://github.com/PowerShell/Phosphor) is an amazing project that hasn’t got the attention it deserves. Phosphor can basically do a Get-Command and generate a web-form for each cmdlet. This could be used as a cross platform implementation of Show-Command or for building simple self-service portals. Imaging having a webserver that uses Kerberos Constrained Delegation to log the user in to a bunch of JEA endpoints and then generate a form for each command available to that user. This way any PowerShell savvy person in the Operations team could deliver self-service business value to the organization without depending on web-developers.
Each time I have an hour of spare time I try to learn some TypeScript so I can fully understand how Phosphor works and hopefully I can get to contributing to the project in the future.
3. I was impressed by your solution to Mandelbrot’s riddle. Can you explain your approach to it?
Thank you! I started by trying to find text that was similar in both the question and the answer and saw that the string ” Benoit B. Mandelbrot” was the longest text I could find in the question that was repeated in the answer.
I started by just figuring out the shortest way to insert that into a string and got this:
$x = " Benoit B. Mandelbrot" "The B in$x stands for$x."
Then I tried to find the shortest way to break out my string from the question and got to this:
$x = $Question.Substring(26,21) "The B in$x stands for$x."
This looked quite good to me, but I wanted to shorten the substring part. This took me to one of my favorite code-golf tricks, using Foreach-Object with the parameter MemberName. Foreach-Object has a not very well known parameter called MemberName that instead of running a piece of code for each object coming through the pipeline, it invokes the named member of each object that has such a member. In this case I want to invoke the member Substring and give it the arguments 26 and 21 using the parameter ArgumentsList. Like this:
$x = $Question | Foreach-Object -MemberName Substring -ArgumentList 26, 21 "The B in$x stands for$x."
Now this doesn’t look shorter, but we can shorten it! Let’s look at the parameters of Foreach-Object using Get-Help:
Get-Help -Name Foreach-Object -Parameter *
This tells us that the MemberName parameter belongs to a set called PropertyAndMethodSet, let’s filter on that set:
Get-Help -Name Foreach-Object -Parameter * | Where-Object -Property parameterSetName -like *PropertyAndMethodSet*
Ok, so we have three parameters:
InputObject accepts pipeline input ByValue and will be bound since we are piping $Question.
MemberName is a positional parameter with position 0 so the first positional value/argument will be bound to MemberName. I also happen to know that MemberName accepts wildcards!
ArgumentList is not positional, but it takes value “FromRemainingArguments” meaning that all values/arguments that remains after MemberName is bound will be bound to argument list.
Using Get-Alias we can also find that Foreach-Object has an alias ‘%’
Get-Alias -Definition Foreach-Object
With this knowledge we can shorten our code significantly:
$x = $Question | % Su* 26 21 "The B in$x stands for$x."
Now that looks good, but $Question is also quite long, what if we could use a wildcard to get the variable? Let’s try with Get-Variable which has an alias of gv. To get that value of the variable and not the variable itself we also use the parameter -ValueOnly, but we don’t need to write ValueOnly, PowerShell is happy as long as it can figure out that is what we want. Since ValueOnly is the only parameter starting with a v, -v is enough.
$x = gv q* -v | % Su* 26 21 "The B in$x stands for$x."
Let’s make this a one-liner using Foreach-Object and replacing $x with $_ and remove unnecessary spaces and we get this:
gv q* -v|% Su* 26 21|%{"The B in$_ stands for$_."}
4. Do you see any possible scenario where using Cosine Similarity in PowerShell could help?
Yes absolutely! I’m doing Active Directory migrations and identity projects where we need to match a user or person in one system with a user in another system. This is easy as long as we have a common and unique attribute like email to match on, but when we don’t we often need to match on for example givenname and surname. Using cosine similarity I can find persons with similar names.