I’m really big fan of one liners. When I was playing with bash, cmd and other shells I liked the idea of doing something in one, single line. One problem though: you had to think all the time what comes out of the first command in the pipeline. Than do the same for the next. And again, and again… Quite frustrating and really difficult to develop. And once you did it – you’ve tried to launch it on a different OS version, where output looked slightly different and *BOOM* – unpredictable results.

It’s totally different story with PowerShell. Piped object is usually easy to track, modify, pushed to next pipe element. In fact the only thing that was better in text consoles (and I hope it’s feature that will be added in next PowerShell version) is && and || which I used a lot both in batch and cmd.

So, I wrote tones of one-liners in Powershell but after a while I got into problem: OK, I know I managed to solve this problem in a single line, but… Memoria fragilis est

I’ve decided one day, that if I create one-liner it would be good to have it stored somewhere. One thing led to another and I end up with $OneLiners array that contains few objects with three properties: name, command and description. It’s all done via Export/Import-Csv, but because comma would be dangerous in this case I’ve decided to separate values with “#” sign. I also put everything in .ps1 file, so any editor used that supports syntax highlighting would show command properly. And, of course, I’ve included function to do it directly from PowerShell, but it’s so simple that it’s not worth mentioning. 😉 Anyway, file format is something like:

gqadu -SearchRoot $LDAP_WAR | Select SAMAccountName, Name | % { $groups = @(Get-QADMemberOf $_.SAMAccountName | select Name | % { $_.Name.ToString() } ); if ( ( $groups -contains "SmartCard_No_NovellClient") -and ($groups -contains "+Warsaw-CRA") ) { $_.Name } }#AutoNovell#List all CRA-s that are automatically logged on Novell
gqadu -SearchRoot $LDAP_WAR | select Name, PasswordExpires | ? { ($_.PasswordExpires -lt $(Get-Date).AddDays(7) ) -and ($_.PasswordExpires -gt $(Get-Date).AddDays(-7) ) }#SoonExpire#Get list of users whos password expired/ will expire soon
Get-QADGroup -SearchRoot $LDAP_WAR | ? { $_.Name -match "L3$" } | % { $group = $_.Name; $groupMember = "" | select Name, SAM, L3; Get-QADGroupMember $group | % { $groupMember.SAM = $_.SAMAccountName; $groupMember.Name = $_.Name; $groupMember } }#L3User#List users that are members of L3 group

(gqadu is alias that I use for Get-QADUser).

OK, but how would I launch this line? In fact it’s quite simple. I’ve just added Import to my $profile. And use Invoke-Expression (or iex, to make things quicker to write):

$OneLiners = @(Import-Csv -Delimiter '#' "C:TMPPowershellOneLiners.ps1")
Invoke-Expression $OneLiners[0].command

Today I’ve tried to move a bit closer to the thing I would like to accomplish – why use property as a parameter to command, why not add a method to an object and do it directly. So I did something like that:

foreach ($line in $OneLiners) 
    $line | Add-Member ScriptMethod Run {Invoke-Expression $this.command }

Yuppi! It worked! Well… it for some reason ‘killed’ pipe (all results came out once everything was collected), and for some reason one of one-liners misbehaved when launched via $OneLiners[x].Run() – but besides that… 😉

Now I need to find out why is it so. For now – I have no clue. 😦


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s