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
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