The Setup

Sometime around late August of 2016, VisioBot3000 stopped working. It was sometime after the Windows 10 anniversary update, and I noticed that when I ran any of the examples in the repo, PowerShell hung whenever it tried to place a container on the page.

I had not made any recent changes to the code. It failed on every box I had.

First attempts at debugging

So…I really get fed up with people who want to blame “external forces” for problems in their code. When I found that none of the examples worked (though they obviously did when I wrote them), I figured that I must have done something stupid.

Hey! I’m using Git! Since I’ve got a history of 93 commits going back to march, I figured I could isolate the problem.

So…I reverted to a commit a few weeks earlier. And it failed exactly the same way.

Back a few weeks before that. No change.

Back to the first talk I gave at a user group….no change.

I gave up.

For several months.

Reaching out for help

After Thanksgiving, I posted a question on /r/Powershell explaining the situation. I got one reply, suggesting that I watch things in ProcMon while debugging. Seemed like a great thing to do, When I got around to trying it, however, it didn’t show anything useful (at least to me…digging through the thousands of lines of output is somewhat difficult).

Making it Simple

Late last year, I thought, I should come up with a minimal verifiable example. Rather than say “all of my code breaks”, I should be able to come up with the smallest possible example that breaks. To that end, I wanted to include as little VisioBot3000 code as I could, and show that something’s up with Visio’s COM interface (or something like that). To that end, I went back to the slides I used when demonstrating Visio automation to the St. Louis PSUG back in March of 2016 and cobbled together an example:

$Visio = New-Object –ComObject Visio.Application $doc= $Visio.Documents.Add('') $page= $doc.Pages[1] $stencilPath='SERVER_U.VSSX' $stencil=$Visio.Documents.OpenEx($stencilPath,64) $ServerMaster=$stencil.Masters['Server'] $bert=$page.Drop($ServerMaster,5,5) $containerStencil=$Visio.Documents.OpenEx($Visio.GetBuiltinStencilFile(2,2),64) $ContainerMaster=$containerStencil.Masters['Plain'] $container=$page.DropContainer($ContainerMaster,$Bert)

And of course, that worked just fine on all of the boxes I had. That meant I had code that worked and code that didn’t work on the same box. Sounds like a great opportunity for debugging. I just needed to slowly change the working code until it didn’t work, right? That’s how my brain works, anyway.

Here’s what I came up with:

Import-Module c:\temp\VisioBot3000 -Force New-VisioApplication New-VisioDocument C:\temp\VisioPrimitives1.vsdx $visio=get-visioapplication $doc= $visio.ActiveDocument Register-VisioStencil -Name Containers -BuiltIn Containers Register-VisioStencil -path SERVER_U.VSSX -name Servers Register-VisioShape -Name WebServer -From Servers -MasterName Server Register-VisioContainer -Name Domain -From Containers -MasterName 'Plain' $foo=$doc.Pages['Page-1'] New-VisioContainer -shape Domain -Label MyDomain -contents { New-VisioShape -master WebServer -Label PrimaryServer -x 5 -y 5 }

That code works, and uses VisioBot3000 functions for just about everything. Notice the three variable assignment lines. They don’t have any logical effect on the code. The $foo variable is not used. However, if I leave the line assigning to $foo out, it stops working.

Import-Module c:\temp\VisioBot3000 -Force New-VisioApplication New-VisioDocument C:\temp\VisioPrimitives1.vsdx $visio=get-visioapplication $doc= $visio.ActiveDocument Register-VisioStencil -Name Containers -BuiltIn Containers Register-VisioStencil -path SERVER_U.VSSX -name Servers Register-VisioShape -Name WebServer -From Servers -MasterName Server Register-VisioContainer -Name Domain -From Containers -MasterName 'Plain' #Commenting out the following line makes the code hang when dropping the container #$foo=$doc.Pages['Page-1'] New-VisioContainer -shape Domain -Label MyDomain -contents { New-VisioShape -master WebServer -Label PrimaryServer -x 5 -y 5 }

To add insult to injury, changing that line to [void]$doc.Pages[‘Page-1’] or [void]$doc.Pages[1] both result in a script that doesn’t hang.

So…somehow accessing the Pages property of the current document is fixing the problem.

My brain hurts.

Anyone have any ideas about this? I’d love to get some feedback on what in the world is going on.

–Mike