Custom objects and PSTypeName

A couple of weeks ago, Adam Bertram wrote a post which got me really excited. As an aside, if you’re not following Adam you’re missing out. He posts ridiculously often and writes high quality posts about all kinds of cool stuff. I’m writing about one such post.

Anyway, his post was about using the PSTypeName property of PSCustomObjects and the PSTypeName() parameter attribute to restrict function parameters based on a “fake” type. By “fake”, I mean that there isn’t necessarily a .NET type with a matching name, and even if there was, these objects aren’t those types. An example might help:

First, by including a special property called PSTypeName in the PSCustomObject, the object “becomes” that type.

$obj=[pscustomobject]@{PSTypeName='Mike';
                       DisplayName='My custom object'}
$obj | Get-Member

PSTypeName1

So now we have an object which thinks it is of type “Mike”.

Using the PSTypeName() parameter attribute, we can create a parameter which only accepts objects of that type!

function Get-DisplayName{
    param([PSTypeName('Mike')]$obj)
    $obj.DisplayName
 }

Calling this function with our object and a string shows that it only accepted our object.

PSTypeNames2

The text of the error is as follows:

Get-DisplayName : Cannot bind argument to parameter ‘obj’, because PSTypeNames of the argument do not match the PSTypeName
required by the parameter: Mike.

It’s probably worth mentioning that we can’t just put [Mike] as the parameter type. PowerShell really wants “real” types in that situation.

So, now we can easily create our own types of objects without dealing with C# or PowerShell classes, and still get the “type” validated in a function parameter….Sweet!

But wait! Back in 2009, I wrote about modifying objects in order to get special formatting or special new members from PS1XML files, through PowerShell’s awesome Extended Type System. I did that by looking at the PSObject underlying the object (all objects in PowerShell do this), and inserting a value into the PSTypeNames array.

It turns out that the PSTypeName() parameter attribute recognizes objects that are “customized” this way as well:

$obj2=get-service | select-object -first 1
$obj2.PSOBject.TypeNames.Insert(0,'MIKE')
$obj2 | Get-Member

PSTypeNames3

Now that we have the object (which is really a ServiceController object, but we told it to pretend to be a Mike), let’s try it in the Get-DisplayName function we wrote above:
PSTypeNames4

So, we can use the PSTypeNames() parameter attribute for any object which has had its PSTypeNames() fiddled with. That’s great for me, because I get a lot of objects from a database, so they’re really DataRow objects. I add an entry to PSTypeNames to help represent what kind of objects they came from (e.g. what table or query they came from) but until I found out about this I was stuck using ValidateScript() to check parameters.

What do you think? Is this something you can see a use for?

Let me know in the comments or on social media.

–Mike

P.S. Adam says that Kirk Munro was the original source of this information. He’s awesome too, so I’m not really surprised.
P.P.S…Kirk commented below that Oisín Grehan and Jason Shirk were his sources in this. Great teamwork in the PowerShell community!

Translating Visio VBA to PowerShell

In working on VisioBot3000, I’ve spent a lot of time looking at VBA in Visio’s macro editor. It’s one of the easiest ways to find out how things work. I thought it would be fun to take some VBA and convert it to PowerShell to demonstrate the process.

We’ll start with a basic diagram using flowchart shapes and normal connectors. It doesn’t really matter what is on the diagram, though, because we’re just using it to make Visio tell us how to do things.

Here’s my diagram:
VBAExample

As our first “translation” exercise, let’s try setting the page layout to “circular”. To do that in the app, we’ll go to the Design tab, select the Re-Layout Page dropdown, and select Circular.

Before we do that, though, let’s turn on macro recording. The easiest way to do that is to click the icon on the status bar:
MacroRecorder

When we do that, a dialog will pop up asking you what to name the new macro. It doesn’t matter, just remember what name you use (or leave it alone) because we’re going to look at the macro to see what’s going on. I named mine circular after I took this screenshot:
NameTheMacro
After you click ok, select the menu item you wanted (Design/Re-Layout Page/Circular).
Circular
When you did that, it applied the new layout to the page, just as expected. Now, click the “stop” button on the status bar (which replaced the “record a macro” button on the status bar) to stop recording.
StopRecording
Now, you want to look at the macro, and to do that you need to go to the developer tab on the ribbon. If you don’t have a developer tab, you need to go to the file tab, select Options, Advanced, and under General, select “Run in Developer Mode”.
DeveloperMode

Whew…that’s a lot of work just to get a macro recorded. Next time it will be easier since you know how to do it.

Let’s look at the macro. On the developer tab, click the macros button, bringing up the list of macros that have been recorded in this document, and select the macro you just recorded. Click the Edit button to see the source.
ListOfMacros

Here’s what Visio recorded when we made that single formatting change:

Sub Circular()

    'Enable diagram services
    Dim DiagramServices As Integer
    DiagramServices = ActiveDocument.DiagramServicesEnabled
    ActiveDocument.DiagramServicesEnabled = visServiceVersion140 + visServiceVersion150

    Dim UndoScopeID1 As Long
    UndoScopeID1 = Application.BeginUndoScope("Lay Out Shapes")
    Application.ActiveWindow.Ptage.PageSheet.CellsSRC(visSectionObject, visRowPageLayout, visPLOPlaceStyle).FormulaForceU = "6"
    Application.ActiveWindow.Page.PageSheet.CellsSRC(visSectionObject, visRowPageLayout, visPLORouteStyle).FormulaForceU = "16"
    Application.ActiveWindow.Page.Layout
    Application.EndUndoScope UndoScopeID1, True

    'Restore diagram services
    ActiveDocument.DiagramServicesEnabled = DiagramServices

End Sub

I see the following basic steps:

  1. Save the current DiagramServicesEnabled setting (line 4-5)
  2. Set the DiagramServicesEnabled property to a new value (line 6)
  3. Set a checkpoint for “undo” (line 9)
  4. Do the layout that we asked for (line 10-12)
  5. End the “undo” checkpoint (line 13)
  6. Put the DiagramServicesEnabled property back how we found it (line 16)

The DiagramServicesEnabled property belongs to a document, so in our code we could use the Get-VisioDocument cmdlet to get the current one. The reference page on that property has a handy list of values for the different levels of diagram services (we need visServiceVersion140 and visServiceVersion150, which are 7 and 8, respectively).

It’s completely up to you if you want to provide the ability to undo operations. I haven’t included this “feature” in VisioBot3000, but it seems like it would be pretty easy.

The actual layout operation uses the current page, so now we could use Get-VisioPage to get the current page as an object. There are 2 calls to CellSRC (which stands for Section, Row, Column, btw) with a bunch of constants.
There are 2 different ways to handle these:
First, you can google the constants and replicate the lines verbatim (yuck). That works, but leaves the code full of “magic numbers”.
Alternatively, you can look at the last constant (visPLOPlaceStyle, visPLORouteStyle) and google them. Let’s look at the first (visPLOPlaceStyle). One of the first links is to the VisCellIndices page here. You probably want to bookmark that page if you’re dealing with the Visio API. You will use it all the time. Anyway, searching on the page for visPLOPlaceStyle tells you that this is the “PlaceStyle” cell. That means you can replace that huge call with:
$Page.Cells(‘PlaceStyle’)=6. You don’t really need the formula to set it, but if you want you can do $Page.Cells(‘PlaceStyle’).Formula=’=6′. Since it’s just a number (with no units), this works fine.

Similarly, the other CellSRC call can be replaced by $Page.Cells(‘RouteStyle’)=16.

Putting all of that together into a function with VisioBot3000 looks like this:

Import-Module VisioBot3000

function Set-VisioCircularLayout{
    
    $Visio=Get-VisioApplication

    $document=Get-VisioDocument    
    #or $document=$Visio.ActiveDocument

    #save the document setting
    $SaveSetting=$document.DiagramServicesEnabled
    $document.DiagramServicesEnabled=(7+8)

    $UndoScope=$Visio.BeginUndoScope("Lay Out Shapes")

    $page=Get-VisioPage

    #Make the layout change
    $Page.Cells('PlaceStyle')=6
    $Page.Cells('RouteStyle')=16

    $Page.Layout()


    $Visio.EndUndoScope($UndoScope,1)

    #put the setting back
    $document.DiagramServicesEnabled=$SaveSetting
}

Hope that made sense. Next time I’ll talk about how I deal with all of the Visio constants.

–Mike

More PowerShell User Group Fun

Been neglecting writing up my Missouri user group adventures.

Last month (4/21) we had a several-hour talk session at the STL PSUG. Met @migreene and had a great time.

Last week (5/5…probably not the best day to meet) I presented a talk on Advanced Functions to a small but fun group at the MidMo PowerShell.

Tuesday I sat in on the @MSPSUG meeting with Steven Murawski.

I’ve started the ball rolling on a Southwest Missouri PSUG…probably have a meeting in June.

I really love the PowerShell community and enjoy all of the interaction.

–Mike

Assignments in PowerShell If Statements

You probably learned early on in your PowerShell experience that -eq and = were very different things.

I still occasionally write

if($x=5)

when I mean to write

if($x -eq 5)

The first will always evaluate to $true, which is generally not what you want.

One trick I’ve seen before is to put the constant (if there is one) on the left-hand side, which causes the assignment to fail with an error, alerting you to the fact that you did something wrong:

if(5 -eq $x)
or 
if(5=$x)

I don’t know if I would be able to even type the second without seeing the problem. Anyway, the point of this post isn’t that you shouldn’t use = in an if statement, but a useful situation where you might consider using it.

As a scenario, consider looking for services that are set to automatically start, but are currently stopped. I know I’ve done that before. What if you wanted to write the list of services meeting that criteria to a log file, but only if there were some that matched.

You might do something like this:

$services=get-ciminstance win32_service -filter "StartMode='Automatic' and State='Stopped'"
if($services){
   $Services | out-csv c:\temp\StoppedServices.csv
}

Putting the assignment in the if statement saves you a line:

if($services=get-ciminstance win32_service -filter "StartMode='Automatic' and State='Stopped'"){
   $Services | out-csv c:\temp\StoppedServices.csv
}

The value of the assignment statement is the value of the right-hand side. If there aren’t any services, the condition is false and we don’t try to write an empty file.

This isn’t a world-changer, but it might come in handy.

What do you think?

–Mike

Introducing VisioBot3000 – Part 2 (Superman?)

In the last post I showed you how VisioBot3000 makes drawing simple Visio diagrams simpler by wrapping the Visio COM API and providing more straight-forward cmdlets do refer to stencils and masters, and to draw shapes, containers, and connectors on the page.

To be honest, that’s where I was expecting to end up when I started messing with Visio.  And I was ok with that.  Anything which simplifies drawing Visio diagrams is a win in my book.  I learned quite a bit getting that far, and it works pretty well.

I decided that I wanted more, though.  I’ll explain the “improvements” in steps.  Because I want to you to see the improvements, I’ll start with the sample code from the last post:

Import-Module VisioBot3000 -Force

#start Visio and create a new document
New-VisioApplication
New-VisioDocument C:\temp\TestVisioPrimitives.vsdx 

#tell Visio what Stencils I want to use and give them "nicknames"
Register-VisioStencil -Name Containers -Path C:\temp\MyContainers.vssx 
Register-VisioStencil -Name Servers -Path C:\temp\SERVER_U.vssx

#pick a master from one of those stencils and give it a nickname
Register-VisioShape -Name WebServer -From Servers -MasterName 'Web Server'
Register-VisioShape -Name DBServer -From Servers -MasterName 'Database Server'



#pick another master (this time a container) and give it a nickname
#note that this is a different cmdlet
Register-VisioContainer -Name Domain -From Containers -MasterName 'Domain'

#draw a container with two items in it
New-VisioContainer -shape (get-visioshape Domain) -name MyDomain -contents {
   New-VisioShape -master WebServer -name PrimaryServer -x 5 -y 5
   New-VisioShape -master DBServer -Name SQL01 -x 5 -y 7
}

#add a connector
New-VisioConnector -from PrimaryServer -to SQL01 -name SQL -color Red -Arrow

Aliases

An easy “facelift” is achieved by adding a few strategic aliases. Before you yell at me for using aliases in a script, I am viewing these “diagram scripts” as something a bit different from normal PowerShell scripts.

Anyway, the aliases make registering shapes, stencils, and containers much simpler.

Import-Module VisioBot3000 -Force

#start Visio and create a new document
New-VisioApplication
Diagram C:\temp\TestVisioPrimitives.vsdx 

#tell Visio what Stencils I want to use and give them "nicknames"
Stencil Containers -Path C:\temp\MyContainers.vssx 
Stencil Servers -Path C:\temp\SERVER_U.vssx

#pick a master from one of those stencils and give it a nickname
Shape -Name WebServer -From Servers -MasterName 'Web Server'
Shape -Name DBServer -From Servers -MasterName 'Database Server'

#pick another master (this time a container) and give it a nickname
#note that this is a different cmdlet
Container -name Domain -From Containers -MasterName 'Domain'

#draw a container with two items in it
New-VisioContainer -shape (get-visioshape Domain) -label MyDomain -contents {
   New-VisioShape -master WebServer -label PrimaryServer -x 5 -y 5
   New-VisioShape -master DBServer -label SQL01 -x 5 -y 7
}

#add a connector
New-VisioConnector -from PrimaryServer -to SQL01 -label SQL -color Red -Arrow

Positioning

Ok…I really hate specifying positions for the shapes I want on the page. Because of that, I include a very simple relative positioning algorithm in VisioBot3000. By default, VisioBot3000 places shapes in a single, horizontal line. That is, if you don’t tell it where to put a shape, it puts it just to the right of the last shape that it drew. If you want, you can tell it to draw in columns (rather than rows) by using Set-RelativePositionDirection cmdlet.

So I can simplify the “diagram” portion of the sample to be this. Note that the output isn’t quite the same, but the shapes are there and connected, so I’m still happy.:

#draw a container with two items in it
New-VisioContainer -shape (get-visioshape Domain) -label MyDomain -contents {
   Set-NextShapePosition -x 5 -y 5
   New-VisioShape -master WebServer -label PrimaryServer  
   New-VisioShape -master DBServer -label SQL01  
}

A couple of important points to note. First, if you haven’t placed any shapes yet, VisioBot will place the next shape at the top-left of the page. If you want to have it start somewhere else, you can pass coordinates to the Set-NextShapePosition cmdlet (as I did in the example).

Second, the next shape is relative to the position of the previous shape, not the place the shape was dropped. If you’re drawing the diagram hands-off, then there’s no difference. If you put a breakpoint (or are just “drawing” from the command-line), you can move the last shape before the next shape is drawn, and the next shape will be positioned relative to the new position rather than where it was originally placed. This allows you to “guide” the drawing in order to make it a bit more beautiful (as if that’s possible).

And now, the main attraction…a custom DSL

The sample code is pretty logical, in that you can easily see what’s going on, and it’s obvious which PowerShell cmdlets are being called to do certain things in the drawing of the diagram.

Unfortunately, the “high visibility” of the PowerShell in the diagram code obscures the “diagram description” in the code. Wouldn’t it be nice if you could just say this?:

Domain MyDomain {
   WebServer PrimaryServer
   DBServer SQL01
}

Isn’t that a much clearer “diagram description”? Of course it is. And the awesome thing is that the code above is perfectly valid PowerShell (and does exactly what the previous example did, except for the position).

How is that possible? Whenever you register a shape or container (or connector, but we didn’t do that), VisioBot3000 creates a function with the same name as what you register. So, when we executed “Register-VisioContainer -Name Domain …”, VisioBot3000 created a function called Domain which has the same parameters as New-VisioContainer (except for the shape, which is the Domain shape). Similarly, “Register-VisioShape -Name WebServer…” created a function called WebServer that lets you draw WebServers without using PowerShell-looking code.

Here’s a bigger example, along with the output. (I’ll leave out the stencil and shape definitions. You can find the whole script here):

Set-NextShapePosition -x 3.5 -y 7
Logical MyFarm {
    Location MyCity {
        Domain MyDomain  {
            WebServer PrimaryServer
            WebServer HotSpare

        }
    }
    Location DRSite {
        Domain MyDomain -name SiteB_MyDomain {
            Set-RelativePositionDirection Vertical
		    WebServer BackupServer 

	    }
    }
}
SQL -From PrimaryServer -To BackupServer

VisioBodDSL3

A quick note. All of my examples have been with servers, domains, etc. There’s nothing in VisioBot3000 that has anything to do with those. It’s just the topic of my diagrams. You could just as easily have a diagram with divisions, departments, and teams, showing directors, managers, team leaders and team members. The DSL for your diagrams would include those terms, possibly like this:

Division IT {
    Director "IT Director Name"
    Department HelpDesk {
           Manager "HD Manager Name" 
           Team FirstLineSupport {
                TeamLead "FirstLine Team Lead Name"
                Member "Member 1"
                Member "Member 2"
           }
}

So the “diagram description” or DSL is completely defined by the stencils and shapes you choose.

I think that’s amazing. And guess what? There’s a lot more. I’ll be blogging this week about other features in VisioBot3000 and plans I have. If you have ideas, I’d love to hear them.

It’s all still under active development (just me at this point, but if you want to jump in I’d be glad to share the load).

Let me know what you think!

–Mike

Introducing VisioBot3000 – Part 1 (Clark Kent)

For a while now, I’ve been demonstrating Visio automation in PowerShell. For the most part, the posts have included a bunch of short code snippets designed to illustrate simple concepts.

Unfortunately, the code has been filled with “magic” constants, and lots of method calls on the various Visio COM objects. Both of those make code hard to read and write, the exact opposite of what you want as a PowerShell scripter. What’s the solution? PowerShell makes it easy to wrap complex code in cmdlets (or advanced functions, if you prefer) and expose a much simpler interface.

Background

When I started looking at driving Visio from PowerShell, I ran across the VisioAutomation project (originally here) by Saveen Reddy.  Contained in that project (which is much broader in scope than my interests) was a module called VisioPS that exposed several Visio concepts as PowerShell cmdlets.  I played with it some, and it worked.  That was exciting.  A major downside for me was that the module was a binary module, which meant writing cmdlets in C#.  That’s a great approach for the project, which is geared towards .NET languages in general, but it limits the attractiveness for PowerShell developers (or at least for me).   I ended up re-writing parts of the module in PowerShell and decided eventually to write my own module.  There are probably some naming artifacts left over from its origin as a “re-implementation” of VisioPS.  I wanted to make sure to give credit for getting me started down this road.

What is VisioBot3000?

To start with, VisioBot3000 implements cmdlets to help you draw Visio diagrams using the things that I’ve introduced over the last several posts:

  • Documents
  • Pages
  • Stencils
  • Masters
  • Shapes
  • Containers
  • Connectors

It also has some support (barely) for Layers.

Here’s a simple (annotated) example of using VisioBot3000.  It uses a custom stencil that I have on my system (and a stock stencil that I copied to c:\temp), but that’s not terribly important:

Import-Module VisioBot3000 -Force

#start Visio and create a new document
New-VisioApplication
New-VisioDocument C:\temp\TestVisioPrimitives.vsdx 

#tell Visio what Stencils I want to use and give them "nicknames"
Register-VisioStencil -Name Containers -Path C:\temp\MyContainers.vssx 
Register-VisioStencil -Name Servers -Path C:\temp\SERVER_U.vssx

#pick a master from one of those stencils and give it a nickname
Register-VisioShape -Name WebServer -From Servers -MasterName 'Web Server'
Register-VisioShape -Name DBServer -From Servers -MasterName 'Database Server'



#pick another master (this time a container) and give it a nickname
#note that this is a different cmdlet
Register-VisioContainer -Name Domain -From Containers -MasterName 'Domain'

#draw a container with two items in it
New-VisioContainer -shape (get-visioshape Domain) -name MyDomain -contents {
   New-VisioShape -master WebServer -name PrimaryServer -x 5 -y 5
   New-VisioShape -master DBServer -Name SQL01 -x 5 -y 7
}

#add a connector
New-VisioConnector -from PrimaryServer -to SQL01 -name SQL -color Red -Arrow

That probably seems like a lot of code, but it’s a lot less than you’d have to write to draw the diagram. A lot of it is boilerplate code that you’d probably factor out into a “standard diagram stencils and masters script”. And look….the only “magic numbers” in the code are the x/y positions. Not super bad, in my opinion.

Here’s the output:
VisioBotPrimitives1

This code is a huge (yuge?) improvement over writing code against the bare COM objects. But it’s not even close to the best part of VisioBot3000.

Did you notice that the title said “Clark Kent”? Stay tuned until next time when VisioBot3000 takes of its glasses, so to speak, and the power is really revealed.

As usual, let me know what you think in the comments (or on Reddit, or Google+, or Twitter)

–Mike

P.S. VisioBot3000 lives on github here.

PowerShell and Visio Part 6 – Containers

Ok…I think this is the last of the “how to perform primitive operations in Visio” articles that I’m going to do.  Hope you’ve been enjoying them.  If you haven’t been keeping up, you can find them all here.

In this installment, I’m going to show you how to create a container in Visio.  Containers are really useful, because when you move them, you move the contents as well.  Along with connections, containers are probably the most important feature of Visio (at least for me).

Container Basics

The first thing to know is that containers are special kinds of shapes, just like the ones we used when we were dropping shapes on the page.  So if you have containers in a stencil you’re using, then you can use those.  If you don’t have any special containers you can use the built-in container stencil that you see in Visio when you go to insert a container from the ribbon:

insertContainerStencil

To use the built-in stencil, though, you have to know where to find it. Fortunately, you can ask Visio where to find it. If you have a reference to Visio in a variable (we’ve been using $Visio), you do it something like this:

$stencilPath=$Visio.GetBuiltInStencilFile(2,0)

The 2 represents the constant visBuiltinStencilContainers, and 0 is visMSDefault, meaning to use the default measurement units. If you’ve been reading along, you have already seen a bunch of constants. There are tons more, and I’ll let you in on how I’m making them a bit easier to deal with in the next post.

Once we have that stencil path, we can use the OpenEx method on the Documents collection to open the stencil (hidden, of course):

$stencil=$Visio.Documents.OpenEx($stencilPath,64)

That stencil has a bunch of masters on it:
containerMasters

There are a couple of approaches to adding a container to a document:

  1. Drop the container as a shape, and then add shapes to it.
  2. Drop the container as a container, listing the shapes that are in it.

Dropping containers as shapes

For the first option, you already know how to add a shape to a page using the Drop() method.

$page=$Visio.ActivePage
$container=$page.Drop($master,5,5)

droppedContainer

After you do that, you use the ContainerProperties property of the container (which is a special property other shapes don’t have), calling the AddMember() method to add shapes. You can also add Selection objects, but we haven’t talked about those.

Let’s draw a rectangle on the page (it’s quicker to show than a custom shape, but it works the same):

 $rec=$page.DrawRectangle(2,3,5,6)
 $container.ContainerProperties.AddMember($rec,1)

And we can see that the rectangle is inside the container. We passed a 1 to tell the container to resize to fit the shape we put in it. If you don’t do that, you will probably have shapes hanging over the edges of the container.

If you have more shapes you want in the container, you can add them as well by calling AddMember. Not very tricky.

The problem I have with this approach is that you have to know where to drop the container in the first place. Not a huge deal, but the less I have to know the better.

Dropping Containers around shapes

To use the second approach, you need to start by dropping the shapes that you want inside the container onto the page. Again, I’ll just drop a rectangle, but the idea is the same with any shapes. Once I’ve got the shape, I use the DropContainer method on the page to drop the new master shape (of the container) and tell it the shape I want it to contain.

 $rec=$page.DrawRectangle(2,3,5,6)
 $container=$page.DropContainer($master,$rec)

DropContainer_2

If you compare the output of the two approaches, you’ll see that the second give a “tighter” container, that is, since we didn’t tell Visio where to place the container, it calculated exactly how big it needed to be and where to put it.

Adding More Shapes

 
Now that you have a container you can loop through other shapes that need to be in it and use the ContainerProperties.AddMember method to add all of them (in a loop!). No need to bore you with the details. You’re sharp and can figure that out.

Let me know what you think

–Mike

P.S. If you want to add all of the shapes at once (with either method) you can use a Selection object. They’re not hard to use, but I wanted to keep this post focused on containers.

Thoughts on PowerShell Performance

Last night Rob Campbell (@mjolinor) and I were talking after his presentation on performance when using Get-Content with -ReadCount and different string matching techniques and I realized it’s time to verbalize my thoughts on performance in PowerShell.

Part 1 – It doesn’t matter

When people ask me if PowerShell is fast, my first response is usually either “It doesn’t matter” or “I don’t care”.  It’s not so much that I don’t care about it being fast (I kind of do) or that it isn’t fast (it is), but that when writing PowerShell solutions the primary goal in my mind should always be operator efficiency.  That is, does this make my life as a PowerShell user easier.  The main points for me are:

  • Consistency (does it always do the same thing)
  • Repeatability (is this something I can use over and over)
  • Accountability (does this log, audit, warn, etc.)
  • Maintainability (will I be able to change the code easily if I need to)

Part 2 – It sometimes does matter

With the understanding that the main thing (part 1) is covered, the truth is that sometimes performance does matter.  If you’re processing a single file with a dozen lines in it, it would be hard to have a solution that wasn’t acceptable performance-wise.  Dealing with a directory full of multi-gigabyte files presents a different challenge.

When you’re dealing with a huge volume of data, or operating under time constraints (near real-time alerts, for instance) it’s possible that you might want to think about optimizing your code.  In these instances, considerations like what @mjolinor was talking about (e.g. using read-count to speed things up, using -replace on arrays rather than single strings) make perfect sense.

Part 3 – the problem might not be what you think it is

When dealing with performance, it’s easy to try to squeeze a few milliseconds out of an operation.  If the operation is happening millions (billions?) of times, that will definitely have a measurable effect.  Often though, even more substantial gains can be found by changing to a more efficient agorithm.

As a (trivial) example, you could spend a lot of time trying to optimize the statements in a bubble-sort routine.  (sidebar…does anyone actually write sort routines anymore?)  You could conceivably double or triple the speed of the routine, but when dealing with a large dataset, you’d still be better off with a better sorting algorithm.

Part 4 – The moral of the story

Don’t stop investigating different approaches to see what’s faster.

Don’t just use “technique X” because it’s the fastest performing.  Consider code readability, and maintainability along with things like how often the code is run.  No point in optimizing a process that only runs once and takes 10 minutes.  Who cares if it ran in 3 minutes instead?  You probably spent more than 7 minutes “optimizing” the code.

PowerShell optimizes the user, not the code.  Make sure when you spend time making the code fast, you haven’t made the user slow.

Feel free to disagree in the comments!

–Mike

Fun at MidMo PowerShell User Group

Had a blast at the MidMo PowerShell user group meeting last night in Columbia,MO. It was just the second meeting for this group and there were over a dozen people present.

I started with a presentation on using PowerShell and Visio together (some of which you’ve seen here) and Rob Campbell (@Mjolinor) finished the meeting up with a discussion of performance using Get-Content with -ReadCount and also comparing different techniques to match lines in a huge file.

The group was really relaxed and engaged throughout both presentations.

Looking forward to more and more Missouri PowerShell user groups!

STL PSUG meeting coming up on 4/21!

–Mike

PowerShell User Group Fun!

I love local user groups.

I’ve been an off-and-on attender of the SQL Server user group and the .NET user group in my area.  Neither of these really are about what I do, but it’s been fun to connect with local people about technology.  I did speak about PowerShell (embedding in C# apps) once, too.  Until recently there hasn’t been a PowerShell-specific user group anywhere close,though.

That all changed at the beginning of the year. First, the St. Louis PowerShell User Group started meeting. I missed the first meeting (in January) but was able to attend in February and March.

I was honored to be a speaker at the March 17th meeting, presenting some of my recent work (which you may have been reading about here) on automating Visio with PowerShell.

Josh Castillo (@DoesItScript) also spoke that night about using Git with PowerShell. His talk, combined with the very positive feedback I received from my talk spurred me on to getting my Visio work up on GitHub and also to using Git at the command-line to manage updating it. It’s been fun so far, and I’ve learned a lot. I’m thinking that Josh might have had a big impact on how I work from now on.

Interestingly, though, another user group started up in Missouri on March 17 as well. This one, the MidMo PowerShell User Group met for the first time in Columbia, MO. The two groups are communicating so that they don’t schedule on top of each other in the future.

I’m super-excited about these groups and plan to attend them as often as I can. Both of these are around a three-hour drive for me, however, so I’m thinking seriously about starting a Southwest Missouri PowerShell User Group (SWMOPUG) in Springfield sometime soon. If you’re close by, let me know and we can talk about what I’m planning.

Here’s the picture from Josh’s tweet about my session:
STLPSUG_160317

 

He called me a “PowerShell guru” so that’s fun.  🙂

How are you sharing your PowerShell?  Blogging?  Teaching?  Contributing to projects?

Get involved.  You’ll have a lot of fun and help others at the same time.

Just my thoughts.

–Mike