It’s been a while since I last spoke about VisioBot3000. I’ve got the project to a reasonably stable point…not quite feature complete but I don’t see a lot of big changes.
One of the things I found even as I wrote sample diagram scripts was that quite a bit of the script was taken up by things that wold probably be done exactly the same way in most diagrams. For instance, if you’re doing a lot of server diagrams, you will probably be using the exact same stencils and the same shapes on those stencils, with the same nicknames. Doing so makes it a lot easier to write your diagram scripts because you’re developing a “diagram language” which you’re familiar with.
For reference, here’s an example script from the project (without some “clean up” at the beginning):
Diagram C:\temp\TestVisio3.vsdx
# Define shapes, containers, and connectors for the diagram
Stencil Containers -From C:\temp\MyContainers.vssx
Stencil Servers -From SERVER_U.vssx
Shape WebServer -From Servers -MasterName 'Web Server'
Container Location -From Containers -MasterName 'Location'
Container Domain -From Containers -MasterName 'Domain'
Container Logical -From Containers -MasterName 'Logical'
Connector SQL -Color Red -arrow
#this is the diagram
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
Hyperlink $BackupServer -link http://google.com
Complete-Diagram
Lines 3-10 are all about setting up the standard shapes and stencils. The rest of the script is directly involved in the specific diagram I’m trying to build.
As an aside, one of the things I love about PowerShell is how much of the code I write is directly involved in solving the problem I’m working on. You don’t have to “code around PowerShell” very often.
Anyway, back to Visio. Since a lot of the code is duplicated, I thought…how can I get that out of the diagram script?
My first thought was to write a function which took the name of an “include script” and somehow run the script. The problem there is scoping. Since the function is called (not dot-sourced) it couldn’t easily affect the global state, so shape, container, and connection functions wouldn’t get created. That’s not useful.
My second thought was to allow an “include” script and have the user dot-scope the include script, but that wouldn’t be very obvious to someone looking at the diagram script. Also, they could put anything in that, and it would seem to be “hidden” (for instance, if they put code unrelated to stencils, shapes, etc.).
I finally decided that a .psd1 file (like a module manifest) would be the best approach. I could structure the hashtable in it to have the information I needed to set up the stencils, shapes, and connections, and read it in using PowerShell. I would just need to write a “dispatch” function which transformed the items in the hashtable into the correct function calls.
So…reading in a .psd1 file is interesting. I’m using PowerShell 5.0, so a choice (which I hadn’t heard of) is Import-PowerShellData. This cmdlet is specifically created for this instance. It has a -path parameter which points to the .psd1 file and returns a hashtable. Nothing could be easier. But….I really don’t want to pin the project to 5.0, especially just for this function.
Another option is Import-LocalizedData. This one is a bit trickier, since it’s meant to read psd1 files in language-specific folders for purposes of localization. To make it do what I want, I needed to split the path into a directory and filename, but then it does the trick. This is a 4.0 cmdlet, which I guess I’m ok with.
There are other options for reading .psd1 files. Most of them involve using Invoke-Expression, which I don’t like to use unless I can avoid it.
And now that I read those, I see the ArgumentToConfigurationDataTransformation parameter attribute, which is a 4.0 feature added for DSC. It’s even better than what I wrote (using Import-LocalizedData).
Time to re-write that function.
Any way you implement it, the function call in VisioBot3000 would look like this:
Import-VisioSettings -path <path to settings file>
and the settings file would look something like this:
@{
StencilPaths='c:\temp'
Stencils=@{Containers='C:\temp\MyContainers.vssx';
Servers='SERVER_U.vssx'}
Shapes=@{WebServer='Servers','Web Server';
DBServer='Servers','Database Server'
}
Containers=@{Domain='Containers','Domain'
}
Connectors=@{SQL=@{Color='Red';Arrow=$true}}
}
What do you think? Do you have anywhere you can use psd1 files to streamline your scripts?
–Mike