Learn about Windows PowerShell
Hey, Scripting Guy! I have been excited about the Microsoft Visio Week articles since I heard your interview back during the holidays. When I read your tweets as you were the writing the Hey, Scripting Guy! posts, I really got excited. I must say that reading yesterday’s article where you added a square to a Microsoft Visio drawing was cool but somewhat of a letdown. I am a network administrator and want to be able to use Microsoft Visio to do network drawings and stuff like that. I imagine my six-year-old daughter would enjoy running your draw-a-square script, but even she would get bored before too long. How about showing us network shapes and symbols?
Microsoft Scripting Guy Ed Wilson. I just realized something. I have no tea, no music playing, and there is no sun outside. It is as if the weather outside is mirroring my poor dismal existence. Wait a second, please. Okay, I am back. I am using my new tea pot the Scripting Wife got for me to brew a pot of rooibos tea. I fell in love with rooibos tea in Hamburg when I was teaching a Windows PowerShell workshop. I took the picture of the town hall (Rathaus) that is seen just below from a little sidewalk café that served awesome rooibos tea.
CF, we need some music. I am dying to listen to my new Bruce Hornsby disk that the Scripting Wife gave me. Music, tea—we are all set. Let’s get to work.
The first thing we need to do when automating Microsoft Visio is to create an instance of the application object. The application object is the main object for working with Microsoft Visio and controls the way the application runs. Use the New-Object cmdlet with the –comobject parameter to create an instance of the visio.application object. Store the returned application object in the $application variable, as seen here:
$application = New-Object -ComObject Visio.Application
The application object has the visible property that accepts a Boolean value. It is used to govern whether the application will be visible while it is running. Because we are doing everything programmatically, there is no reason to waste resources watching the drawing unfold. Besides, on my computer it happens so fast, it is not much of a show. You will see a flicker as the application object is created, and then the visible property is set to false. After that you will not know if the script has completed until you see the return code in either the Windows PowerShell console or the Windows PowerShell ISE. Setting the visible property to false makes the application invisible. Setting it to true, will cause it to be displayed on the screen. The line of code that controls this behavior is seen here:
$application.visible = $false
The next several lines of code are basically the same as were seen yesterday. Refer to yesterday’s Hey, Scripting Guy! post for more information about this. Because we are going to make a network diagram, we choose to use the Basic Network Diagram.vst template. This name is obtained by clicking New in the File menu and choosing the type of drawing to create. This is seen here.
The code that creates the document object, adds the template, and adds a new page to the pages collection is seen here:
$documents = $application.Documents
$document = $documents.Add("Basic Network Diagram.vst")
$pages = $application.ActiveDocument.Pages
$page = $pages.Item(1)
Now we run into our first problem. In yesterday’s Hey, Scripting Guy! post, I stated that to add a stencil, you could use the name of the stencil that was displayed in the Shapes section of Microsoft Visio. The Shapes section is seen in the following image.
This technique works for many of the stencils. You just need to remember to add the .vss extension to the name. The problem came when I wanted to add the Network and Peripherals stencil to the drawing. After spending nearly an hour trying various permutations and ensuring I had the word “peripheral” spelled correctly, I was about to give up. I searched MSDN for a list of included stencil names, as well as the Microsoft Visio online Help to no avail. But it is really hard to do a network diagram without using some of the network and peripheral shapes. Then I remembered an old trick I had written about in one of my VBScript books—use the macro recorder. Even though the code will be completely bogus, the name of the object being added will be correct. I quickly opened Microsoft Visio and recorded a macro that added the Network and Peripherals (Metric) stencil. I then opened the macro editor by clicking Macro in the Tools menu, clicking Macro, choosing the newly recorded macro (macro1 by default), and clicking Edit. The Microsoft Visual Basic Macro editor appears. As seen in the following image, the stencil sheet is named “periph_m.vss”—something I would never have guessed.
As I mentioned earlier, the VBA code won’t work for our purposes, but because the only thing I did was add the stencil, it is a pretty safe bet we have found the secret name of our stencil. Use the add method from the documents object to add the desired stencil, and store the returned document object in the $NetworkStencil variable:
$NetworkStencil = $application.Documents.Add("periph_m.vss")
We add the other two stencils by using the display names without further incident. This is shown here:
$ComputerStencil = $application.Documents.Add("Computers and Monitors.vss")
$ConnectorStencil = $application.Documents.Add("Connectors.vss")
Next we use the same procedure we used yesterday to add four computers and an ethernet network to the Microsoft Visio drawing. Because the Basic Network Diagram.vst template is in landscape orientation instead of portrait orientation, the numbers we use for placing the shapes on the drawing will need to change. One other thing to keep in mind is that the size and shape of the shapes will dictate the numbers you choose for placement as well. If you keep in mind the size and shape of an 8.5-by-11-inch sheet of paper, the numbers make a little sense. This is not a strict measurement, but will give you a feel for the numbers. The numbers are x/y coordinates. To add a second line to the text property of the shape, use the “`r`n” characters that Windows PowerShell recognizes as the line-feed sequence. The PC shape comes from the Computers and Monitors stencil, as seen in the following image.
To retrieve the PC shape, use the Item method from the masters collection of the stencil stored in the $computerStencil variable. The code to add a PC shape to the lower right hand side of the drawing is seen here:
$pc = $ComputerStencil.Masters.Item("PC")
$shape1 = $page.Drop($pc, 11.0, 1.0)
$shape1.Text = "Lower Right`r`nShape1"
Next add the other three PC shapes to the three remaining corners of the Microsoft Visio drawing. Use the same technique that was used to add shape1:
$shape2 = $page.Drop($pc, 2.2, 1.0)
$shape2.Text = "Lower Left`r`nShape2"
$shape3 = $page.Drop($pc, 11.0, 6.8)
$shape3.Text = "Upper Right`r`nShape3"
$shape4 = $page.Drop($pc, 2.2, 6.8)
$shape4.Text = "Upper Left`r`nShape4"
It is time to add the Ethernet shape. The Ethernet shape is contained in the Network and Peripherals stencil, which is stored in the $networkStencil variable. Use the same technique to create an instance of the Ethernet shape and add it to the drawing that was used to add the PC shapes to the drawing. This is seen here:
$etherNet = $NetworkStencil.Masters.Item("Ethernet")
$shape5 = $page.Drop($etherNet,6.0,4.2)
$shape5.Text = "center"
To connect the shapes, we need to add a connector. The dynamic connector is fun to use and is contained on the Connectors stencil, which we have stored in the $connectorStencil variable. Use the item method to retrieve an instance of the Dynamic Connector shape and store the returned shape in the $connector variable as seen here:
$connector = $ConnectorStencil.Masters.item("Dynamic Connector")
When you have created a connector shape, use the AutoConnect method from the shape object to connect the PCs and the Ethernet shapes to each other. The AutoConnect method takes three parameters: the shape to connect, the direction of the connection, and the connector to use. In our script we are connecting to the Ethernet shape that is stored in the $shape5 variable, and we are using the dynamic connector that is stored in the $connector variable. The enumeration value 0 means to connect without relocating the shapes. Other enumeration values for the VisAutoConnectDir enumeration are seen in Table 1.
Table 1 Enumeration Values of the VisAutoConnectDir Enumeration
Connect to the left.
Connect without relocating the shapes.
Connect to the right
The code to connect the objects in the Microsoft Visio network drawing is shown here:
$shape1.AutoConnect($shape5, 0, $connector)
$shape2.AutoConnect($shape5, 0, $connector)
$shape3.AutoConnect($shape5, 0, $connector)
$shape4.AutoConnect($shape5, 0, $connector)
You can center the drawing by using the CenterDrawing method from the page object. This is seen here:
Now save the drawing and quit the application:
When you run the script, the following drawing is saved in the location that was supplied to the SaveAs method. When you open the file, this drawing is displayed.
CF, that is all there is to using Microsoft Visio to create a basic network drawing. The complete script for today can be seen here at the Script Repository. Microsoft Visio Week will continue tomorrow when we will talk about….
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at email@example.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Nice article, Ed. I think it just needs a final touch: a screenshot from Visio showing the results. It also might be useful for this and other articles to have a code listing in a single paragraph (at the bottom of the page). That way I could do a single copy/paste action into an editor and click run to reproduce your results immediately. For example, I personally may not read the every article in depth, I might skim one and want to...see the punch line. Does that make sense?
Thanks for the recommendation. I have added a link to the entire script from the script repository to the blog. http://bit.ly/5KUr4t