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

PowerShell Code Review Guidelines

I get asked to look at other people’s PowerShell code a lot at work, and I really enjoy it.  I also find myself looking at my “old” code from several years ago (back to 2007!) and think…there’s a lot of work to be done.

To that end, I’ve compiled a list of “PowerShell code review guidelines” to help keep the ideas flowing.

Before I show them, though, I have some ground rules to share.  BTW…I use function, script, and code somewhat interchangably, so please don’t get confused by that.

  1. The most important thing is whether the script solves the problem at hand.  In my book, if it does that, the rest is extra.
  2. Remember that everyone is at a different place in the “path to true PowerShell enlightenment”.  Don’t beat people over the head because they’re not using DSC, or Remoting, or Workflows, or whatever your favorite thing is.  That doesn’t mean you don’t mention those options, but the focus should be on the code in front of you.
  3. You can’t and shouldn’t try to solve all of the problems at once.  This goes right along with #2 above.  If the script is full of Write-Host output, and uses Read-Host in loops to validate parameters, you probably should deal with those and not worry so much that they haven’t used a lot of pipelines.

In my mind, a code review is an opportunity to help a scripter use best practices more consistently.  It is an opportunity to help them write more flexible, more maintainable, and more reliable code.

Most importantly, it’s not a humiliation session in how much better you are at PowerShell.  If you use them in this way, don’t be surprised if you don’t get a lot of return customers.

General

  1. Does the function or script accomplish the intended task?
  2. Is there any comment-based help including examples?
  3. Is the function or script “advanced” using [CmdletBinding()]?
  4. Are risk mitigation parameters supported if appropriate?
  5. Does the code use aliases for cmdlets?
  6. Does the script or function follow the Verb-Noun Convention?
  7. Is the verb in the approved list?
  8. Is it the correct verb?
  9. Are the noun(s) consistent?
  10. Is the function or script in a module with a discoverable name?
  11. Parameters

  12. Do the Parameters have specified types?
  13. Are the parameters named appropriately?
  14. Are parameters set as mandatory when appropriate?
  15. Is any declarative parameter validation used?
  16. Are arrays allowed when appropriate?
  17. Is pipeline input allowed and implemented properly?
  18. Are switch parameters used to flag options?
  19. Do parameters have appropriate default values?
  20. Are “use cases” divided into ParameterSets?
  21. Are named parameters used instead of positional parameters?
  22. Output

  23. Is the output in the form of objects?
  24. Is output produced in the PROCESS block if possible?
  25. Are format cmdlets used?
  26. Is write-verbose used to supply user-directed output messages?
  27. Is write-warning or write-error used for problem messages?
  28. Is write-debug used for developer-directed output messages?
  29. Flow

  30. Are filtering operations as far to the left in pipelines as possible?
  31. Are pipelines used appropriately in place of sequential logic?
  32. Are pipelines overly used (extremely long pipelines?)
  33. Comments

  34. Are comments used to explain logic (and not statements)?
  35. Is commented-out code present?
  36. Error Handling

  37. Are try/catch/finally used for terminating errors?
  38. Are errors signaled with write-error?
  39. Are terminating errors forced with –ErrorAction STOP?
  40. Are console apps checked using $LastExitCode
  41. Do write-error calls use the -TargetObject parameter?

Let me know what you think.

Should have it posted to github for revisions tomorrow sometime.

–Mike

PowerShell And Visio Part 5 – Connections (updated)

It’s been a while since the last post.  I decided that if I had to chose between writing PowerShell and writing about PowerShell, I should favor the former.

In this episode, I’ll talk about how to create connections between objects in a Visio diagram.  Turns out it’s not really that hard (just like most things with Visio so far), but there some interesting things we can do with the connections once they exist.

So, to start with, let’s get a some shapes on a page.  If this doesn’t look familiar, refer back to the earlier posts in this series here:

 

$visio=New-Object -ComObject Visio.Application
$Document=$Visio.Documents.Add('')
$rect1=$Visio.ActivePage.DrawRectangle(1,1,2,2)
$rect2=$Visio.ActivePage.DrawRectangle(4,4,5,5)

Here’s what that got us:
2Rectangles

Now, we have 2 shapes ($rect1 and $rect2). To connect them, we’ll use the AutoConnect() method on one of the 2 shapes. Since Visio connectors are directional (that is, they have a start and an end), it matters which one we use.

$rect1.AutoConnect($rect2,0)

The AutoConnect() method takes three arguments:

  1. The shape you want to connect to
  2. The direction (relative to the first shape) you want to move the connected shape to (0 means don’t move the second shape)
  3. The shape you want to use as a connector

In this example, we chose to not move the second shape, and used the default connector.

The result looks like this:
ConnectedRectangles

There are several interesting things about this connector:

  1. It doesn’t indicate direction (you can’t tell which way the connector goes)
  2. It’s dynamic (it will move/route as you move the two shapes)
  3. We didn’t get a reference to it as a result of the AutoConnect() method

We’ll start by addressing the last point. Since we didn’t get a reference to the connector, how can we find it? It turns out that just about everything in Visio is a shape, so we can look at the Shapes collection on the page:

$Visio.ActivePage.Shapes | Select-Object Name

In the output, you will see (at the end) a shape called “Dynamic connector”. That’s our new connector (duh).

$connector = $Visio.ActivePage.Shapes['Dynamic connector'] | select -Last 1

I picked the last one in the collection in case there were others. Visio adds to this collection as shapes are added to the list, so this should be safe.

Now that we’ve got a reference to the connector, how can we designate which end is which? In the Visio GUI, we would click the Line drop-down on the ribbon and select the arrows (or dots) that we wanted. In PowerShell, it’s a different story altogether.

First of all, there’s not an Arrows property that we can use. That would be too easy. It turns out that in Visio, everything has what’s called a ShapeSheet, which is kind of like a bunch of little spreadsheets that control every aspect of how the object behaves in Visio. Accessing cells in the ShapeSheet can be done several ways, but typically you either use the Section, Row, Column reference (SRC) or a special Named Cell. These references look something like this:

$Shape.CellsSRC($section,$row,$column) 

and

$Shape.Cells('CellName')

To set the ending arrow for a connector, there’s a “named cell” called EndArrow which tells Visio what symbol to draw at the end of the connector. We’re going to set the cell to 4. The number can apparently be anywhere from 1-45 to display different arrows.

$connector.Cells('EndArrow')=4

And the resulting arrow (zoomed in so you can see it):
Arrow

If we wanted the arrow to be bi-directional, we could also set the “BeginArrow” cell.

$connector.Cells('BeginArrow')=4

BeginArrow

Ok. Now for #2. Can we change how the connector routes? I often like to use straight lines because they’re easier to follow. Change the connector to be straight, we have to resort to the ShapeSheet again. However, there’s no named cell this time (see P.S…I found names). Now, we have to know the SRC to where the cell is. In fact, for this there are 2 cells that we have to set, so we need to know both SRCs.

 $connector.CellsSRC(1,23,10) = 16
 $connector.CellsSRC(1,23,19) = 1 

That’s pretty cryptic, right? Absolutely. It turns out with Visio, there are about 40 bajillion different constants to use. This link will help you with some, but they aren’t organized much. This page is organized a little better, but it’s still hard to know where to look. The constants in this example are:

  • visSectionObject = 1
  • visRowShapeLayout = 23
  • visSLORouteStyle = 10
  • visLORouteCenterToCenter = 16
  • visSLOLineRouteExt = 19
  • visLORouteExtStraight = 1

So that’s a mess (at least to me). How in the world do we figure these out? The easiest way is to record a macro and do what you want to find out about, then look at the VBA. The VBA code for setting a connector to a straight line looks like this:

Application.ActiveWindow.Page.Shapes.ItemFromID(3).CellsSRC(visSectionObject, visRowShapeLayout, visSLOLineRouteExt).FormulaU = "1"
Application.ActiveWindow.Page.Shapes.ItemFromID(3).CellsSRC(visSectionObject, visRowShapeLayout, visSLORouteStyle).FormulaU = "16"

That, with some googling, can get you what you need. I’m working on a better solution, but it’s not ready quite yet. 🙂

That’s enough about connectors.

Let me know what you think in the comments (or on Twitter)

Mike
@MikeShepard70

P.S. Found the “named cells” for making straight lines: ShapeRouteStyle and ConLineRouteExt.

PowerShell and Visio – Part 4 (Interlude)

Why mess with Visio from PowerShell?

I’ve got a couple of posts with some really basic code to access things in PowerShell and it occurred to me…I probably haven’t made it clear why you might want to do this (other than that you can).

So, instead of moving on to connections (which will be next, followed by containers), I thought I’d take a break and show you a really quick and practical script.

The Scenario

Imagine that you just got handed a network diagram of a bunch (dozens?) of servers that you manage.  The only problem is, the diagram only includes the server name.  Your boss needs it to include the IP Addresses for each item.  You have a choice.  You can either manually look up each name with Resolve-DNSName and copy-and-paste the IP Address into the diagram, or you can use PowerShell to solve the problem.

Here’s the script.  The funny part (to me, at least) is that the complexity is trying to get the IPV4 address out of Resolve-DNSName, the Visio part is simple.

 

$Visio = New-Object -ComObject Visio.Application
$Doc=$Visio.Documents.Open('c:\temp\ServerDiagram.vsdx')
$Page=$Visio.ActivePage

foreach($shape in $page.Shapes){
    if(!$shape.Text.Contains("`n")){
        $address=Resolve-DnsName $shape.text 
        $address=$address| where-object {$_.IP4Address } | select-object -First 1
        $newLabel="{0}`n{1}" -f $shape.text,$address.IP4Address
        $Shape.Text=$newLabel
    }
}

All it does is look for shapes on the page that don’t contain newlines, and update those shapes with the IP Address it wrestles out of Resolve-DNSName.

Here’s “before”
ServersBefore

And “after”
ServersAfter

I think you can see that something like this is a handy tool to have in your back pocket. I know that when I draw server diagrams I don’t label the IP Addresses manually anymore. This script (or one just like it) has saved me hours.

And that, my friend, is what PowerShell is all about.

–Mike

PowerShell and Visio Part 3 – Drawing Shapes

This is part 3…if you haven’t read part 1 or part 2 you probably want to go back and read those.

Now that we’re all up to speed, I promised I’d talk about drawing shapes in Visio.

We’ll start with an easy one.

Drawing Circles and Rectangles

Remember that you have to open Visio with PowerShell in order to access it from a script.

$Visio= New-Object -ComObject Visio.Application

We can open a new (blank) document using the same technique we saw last time to open a document, except we will pass an empty string:

$Doc=$Visio.Documents.Add('')

Now, we can get a reference to the active (only) page in the document by accessing the ActivePage property of $Visio.  We could also have looked at the Pages collection on $Doc and referenced it either by ID (1) or name (Page-1)

$Page=$Visio.ActivePage
#Or
#$Page=$Doc.Pages(1)
#$Page=$Doc.Pages('Page-1')

Now that we’ve got a page, let’s see what Draw methods we have:

$Page | get-member Draw*

Draw methods
DrawOval and DrawRectangle sound pretty straightforward.  Let’s try them:

$Page.DrawRectangle(1,1,5,5)
$Page.DrawOval(6,6,8,8)

Here’s what it looks like in Visio (note that my diagrams are using US measurements, so the numbers correspond to inches):

Visio_Rect_Circle

The functions also returned the objects that were drawn to the console (which we could have saved in variables if we were paying attention).
Visio_Rect_Circle_Objects

Drawing Shapes

Notice that there weren’t any methods for drawing shapes, which is what you really want to do in Visio. Shapes in Visio are stored in what Visio calls stencils, and are typically separate files. To open a stencil and not show it in Visio you can use the OpenEx method of the application object (which we are calling $Visio) and pass the filename and the constant 64 (which means “open hidden”). Here, I’m opening a stencil which contains a bunch of shapes for different kinds of servers. The _U at the end of the filename means that it uses US measurements rather than metric.

$stencilPath='C:\Program Files (x86)\Microsoft Office\Office15\Visio Content\1033\SERVER_U.VSSX'
$stencil=$Visio.Documents.OpenEx($stencilPath,64)

I’ve stored the loaded stencil in a variable because we want to work with it.

The shapes in the stencil are stored in a collection called Masters.
Masters

Let’s put an FTP Server somewhere on the page:

$Master=$stencil.Masters('FTP Server')
$Page.Drop($Master,4,4)

DropppedMaster
And here’s the output:
FTP_Server

That’s enough for today. Next time we’ll think about connecting objects together.

Let me know what you think in the comments!

–Mike