Converting a string to an array in PowerShell (why it works)

Edit 2016-01-18: If you’re interested in a few different ways of converting a string to an array, see this newer post. The post you’re looking at focuses a little more on how and why the .split() method works


Blue_fish posted a question over on powershellcommunity.org. The source of the question was a mysterious blank entry. This anomaly appeared when he tried to convert a string into an array of individual words. Without his actual code on hand I tried to guess what could cause that. Along the way I typed up the following… thinking out loud with my fingers. Afterwards I realized that this was the kind of information I was looking for when I started out. With that in mind enjoy…

Why did that work?  Powershell’s access to the .NET framework doesn’t require one to be a .NET dev.  Far from it instead it brings an incredible amount of power to a usable surface. So how did .split() come to be and why does where work. I think I can explain it… let’s see…

In PowerShell "" refers to a string, obviously, but it’s more than that.  A string in PowerShell is a .NET object with a type of string,  99.99% of the time that doesn’t matter, but in this case it’s quite pertinent.  As a first class object string carries with it many powerful methods free of charge.

Parenthesis () have several responsibilities within POSH, but mainly it’s just execution order i.e. (THIRD((FIRST)SECOND(FIRST))).  Part of that execution is PowerShell normalizing your data. For example 15 will be cast as an int, asdf as a string, and @(1,2,3,4,5) is an array of integers. As that cast operation is to objects, this is where all the free posh goodness comes from.  Therefore we need to enclose our string in () to perform the cast and have those methods available.

Believe it or not that’s the hard part…

And that’s how:

Transforms into:

Now that you have an array of words all that is left is to remove the false positives.  Enter Where-Object, think of where-object (a.k.a. where, and ?) as an extremely streamlined if, then, else filter.  {} in PowerShell represent a script block.

A script block is a chunk of code that is executed to its completion before the engine moves on.  In other words {} will overrule ().  Where-Object is a bool operator, if the script block evaluates to true then pass the object down the pipeline, else drop the object.

Before where {$_ -ne " "}

After where {$_ -ne " "}

*Only objects that evaluate to $TRUE in the where-object script block are passed down the pipeline. As you can see their really aren’t any “smoke and mirrors” in PowerShell. Instead the team provided a kick ass engine that does 90% of the work for us in a predictable and comprehensible fashion!

~Glenn

I started to post all of this in my response to blue_fish’s post over on powershellcommunity.org, but it occurred to me that I went way to in depth.  Sometimes I like to talk myself through the Nth degree to prove I know it 😉

Don’t be shy if I screwed something up please let me know.  That’s the other part of laying it out to the nth degree if I’m mistaken, you’ll correct me, and we all improve from that exercise!

Get-member and .net reflection why you should care.

The man the myth the legend, Jeffery Snover did it again!  If you haven’t seen it yet check out this post on the powershell team blog.  Jeffery does a phenomenal job walking one through .net reflection, and how Get-Member is THE most powerful cmdlet powershell contains.  While the [] accelerators may appear to be center stage make no mistake GM is the roady that makes the show possible.

If you haven’t guessed already I’m a huge fan of Get-Member…  While I teach powershell to my fellow admins daily, and we as a shop are slowly becoming elite.  Get-Member is incredibly hard to explain without going down the .net rabbit hole…  Leave it to the Architect to sum it up in a blog post.

~Glenn

Using –SupportsShouldProcess in Powershell V2 ScriptCmdlets

Okay so I’m a bit of an early adopter. My main admin rig at work has been running V2 for the past year. In the last six months I’ve fallen in love with scriptcmdlets. One thing that constantly reminded me that this was still a CTP, and not a shipped product was –SupportsShouldProcess. The included about docs are misleading at best. The hidden user guide in %windir%System32WindowsPowerShellv1.0en-US had nothing, and perhaps the biggest shock of all. There was nothing on the web. The only thing I could find was this PDF from a Server 2k8 launch event. I started to think I was the only one who wanted this functionality. Well all I needed was handed to me on a golden platter this morning when Mr. Snover posted this. At last, a working example!

To keep this as easy as possible take the following V1 function:

112508-0406-usingsuppor1

Now let make it a V2 scriptCmdlet:

112508-0406-usingsuppor2

Finally let’s give this little guy some kick!

112508-0406-usingsuppor3

Why should you care? Well simple I added three lines of code and one parameter. Look at all the functionality the PowerShell Team provided me with that small amount of code!

112508-0406-usingsuppor4

There you have it script cmdlets ShouldProcess support. Hope that helps anyone who’s been trying to figure that out.

~Glenn

Can you have too many Cmdlets?

So here I go again… I hit another roadblock and I would like your opinion. As I go through the Netapp OnTap SDK I’m finding a lot of duplication. At first I went the VMware path and was building one Cmdlet for every possible task. This methodology is heavily dependent upon the pipeline for usability sake. For example take the following…

So that’s all great right? Here’s my issue NetApp has several API’s for both Volumes and Aggregates that are identical. Well almost, they perform the same functions, but take different parameters. So would you rather have 25 cmdlets that perform very specific tasks? Or 10 slightly more complicated cmdlets? I’ll elaborate a little further…

etApp has two base storage allocation methods and aggregate, and a volume. For those of you who don’t know a Volume is what you would concider a traditional raid. An Aggregate is a logical unit that contains Flexible Volumes. They perform the same exact function, but maintain different usecases. Therefor the OnTap API treat’s them seperatley even when they are performing the same function. i.e.

Raid Validation:
The process of validating the integrity of a given unit.

As you can see they are identical in use, and indeed perform the same task. The rational for keeping them separate is simple. Per the OnTap API within the Start-NaAggrVerify Cmdlet the target is specified via an “aggregate” parameter. Likewise the Start-NaVolVerify has an identical parameter but named “Volume”. As you can see the simple approach is to keep them separate, but when you consider that there are at least four Cmdlets dealing with verification, and at least five API’s like it. The Cmdlet count quickly get’s bloated and confusing (or at least I think it does). The alternative is to add a param and require more from the admin at runtime. Ala

On the one hand I personaly do not like this approach because it leads to an obscure and misleading syntax, but it is the only way I know to prevent “cmdlet sprawl”. So what do you think is it okay to require one or three extra parameters per, or would you rather see separate perpouse built cmdlets? Keep in mind I’ve only converted Volumes, Aggregates, licenses, Disks, and Snapshots. That is a total of five out of 40+ regions and I’ve already amassed some 46 cmdlets!

Is there such thing as too many cmdlets?

~Glenn

And yes I know that all my code will break with ctp3… I would rather update it for the new syntax in dec. Then wait and be stuck in v1 fuctions, or code cmdlets!  😉

Playing with DateTime in PowerShell

I recently had to convert the DTG( Date Time Group ) from NetApp to Windows.  My tool of choice PowerShell! First things first what is the base of get-date.  Turns out that was the easy part.

A quick round of developer speak over at MSDN revealed that the base of datetime was 1 tick. A tick is defined as 100 nanoseconds… put that aside for a second. NetApp records time by the number of seconds that have elapsed since 1/1/1970 12:00 AM. So how do I convert NetApp seconds to ticks… The mathematicians in the room (calling you out Andrew) will certainly know a more elegant methodology, but this poor admin settled on the following.

First, convert 1/1/1970 12:00 AM to ticks!

Okay, so where do we go from here? Remember that number from before 100 nanoseconds… This is where it got fun. Since the NetApp reports in seconds since 1970, and DateTime works in ticks. What we really need is to convert seconds to ticks. Well a quick live search (okay so I used goggle but live is getting better!) revealed that there are approximately 10000000 ticks in a second. Knowing that, the formula should be something like (Ticks to 1970) + ((seconds since 1970) * (number of Ticks in a second)).

Does it work?

I Love this shell! Now my example is not a very general purpose one, but the core logic doesn’t change.

Recap:

[System.Datetime] – core time measurement is a tick.

Tick – a tick is 100 nanoseconds.

Seconds – There are 10000000 ticks in a second.

~Glenn

Oh yeah and PowerShell ROCKS!

PVUG Meeting #7 Announced!

PowerShell virtual user group meeting #7 will be on Thursday November 13th 2008!  It’s been a while since Marco has put one of these together.  Understandable given all the work he does.  If you’ve never attended one before I highly recommend it.  Looks to be another all start lineup with Nathan Winters (MVP), Joel ‘Jakul’ Bennett, and a product demo by Ideara (cross your fingers for Tobias!).   Remember these events are participation driven so, Go HERE NOW! 

See you there,
~Glenn

UPDATE:  I’ll be in Chantilly on the 13th 🙁  with a little luck I’ll get an (early am|late pm) flight back to Augusta, and be able to attend!

PowerShell Usability: Cmdlet design

So I basically haven’t slept in two weeks. I thought it would be a good idea to pick up the torch, and contribute on the NetApp Ontap SDK to PowerShell. I’m sure you’ve seen the Codeplex project by now if not here. I have a couple of personal issues with this first swing, and initially I set out to help. Two weeks later I have completely rewrote the whole cha-bang. I’m not a dev, and I don’t pretend to know as much as Adam. I am however an Administrator who uses PowerShell and NetApp’s every day. From that perspective I’m writing what I need the cmdlets to do. Very quickly I ran into a style issue… My question to the mob is simple of the three examples below, what would be your preference?

[1]PS > Get-NaDisk –disk v0.20| Fail-NaDisk –force

[2]PS > (Get-NaDisk –disk v0.20).FailDisk()

[3]PS > Get-NaDisk –disk v0.20 | set-NaDisk –Fail -confirm:$false

What do you think? One is the most intuitive, but will lead to over 500 cmdlets! Option two is the least intuitive, but would produce the tightest code. Finally option 3 per the PowerShell team documentation option 3 is the “correct way of doing it”…  I wan’t to use option 1 but It requires the use of an illegal unaproved verb “Fail”.

Help…

~Glenn

UPDATE: My basis for not using Fail-NaDisk. Although, I believe that Fail-NaDisk is more in line with the spirit of powershell.

I solved a problem with Powershell.

We’ve been having some strange issues at work with our email archive solution. The “fix” from the vendor, was to install some software on all of our backend exchange servers…. Yeah that’s how I felt about it as well. Being the kind of change that you must test it was time to set up a lab. I grabbed my white board and wrote down what was needed.

1 Domain Controller
3 Exchange Servers
2 SQL servers
2 WIN2K (email archive)

Without really even thinking about it I opened PowerShell, and went about getting this done. Four commands and 1hr later we were installing exchange!

[28]PS>Get-VirtualSwitch -VMHost (Get-VMHost esx15) -Name DEV04 | New-VirtualPortGroup -name "192.168.232.0" -VLanId 900

[29]PS>$folder = New-Folder -name DEV04 -Location (Get-Folder vm)

[36]PS>1..8 | % { New-VM -Name “EMAILDEV$($_)” -ResourcePool (get-ResourcePool ADMIN_DEV) -Location $folder -Template (get-template WIN2K3_ENT_x86) -OSCustomizationSpec (Get-OSCustomizationSpec WIN2K3_ENT_x86)
-datastore (get-datastore vmdata0) -VMHost (get-vmhost esx15) -RunAsync }

[263]PS>Get-Folder DEV04 | get-vm | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName “192.168.232.0”

A couple of things to note it took 4 or 5 -whatif attempts to get the new-VM cmd right, and the hour was waiting for the vm’s to deploy.  I know that there is nothing new here, but I often see too many “case studies” with powershell… they overcomplicate things.

yesterday I solved a problem with Powershell.  I didn’t write a script.  I didn’t need v2 remoting.   Just four very simple yet incredibly powerful commands…    Give it a try some time just open posh, and TRY to solve a problem… I’ll admit that it is daunting at first, but after a while the reward is ten fold.

~Glenn

P.S. Did I mention that the VI Toolkit is friggin amazing!

Backup services state

This morning I had a couple app servers just giving me fits. I turned to powershell to quickly to a diff on the servers. I started to backup the regisry and do a diff there, but decided that I should start somewhere simple. My solution was to “snap” the state of all the services on one that was working. I then restored those setting on one of the trouble nodes, rebooted problem solved.

gwmi win32_service | % { write-output "sc config $($_.name) start= $(($_.startmode).replace('Manual','demand')) " } | out-file restore_service.bat

Convert DN to Canonical and back

I’ve been revamping our user account creation process lately (more on that when I finish it).  I started with the quest cmdlets, but performance/limitations lead me back to adsi.  Along the way I kept having to go from canonical naming (domain.comousubousizemore, glenn) to the more common distinguished name.  After the third time I did this by hand i decided to script it.  I wrote the following functions to handle the conversion.

Note:  Should these be named ConvertTo-* or ConvertFrom-* ?