Categories

13906

PowerShell and Visio: Opening a file 3

We have seen how to open a file and add the stencil that goes with it.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
$visio = New-Object -ComObject Visio.Application
$doc = $visio.Documents.Open("C:\Scripts\Visio\adtest.vsd")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\ADO_M.vss"
$stencil = $visio.Documents.Add($mysten)

$page.Shapes | Format-Table Name, Text, Id, Index -a

## create variables
foreach ($shape in $page.Shapes) {
    if ($shape.Name -like "Directory connector*") {
        New-Variable -Name $($Shape.Name) -Value $shape -Force
    }
    else {
        New-Variable -Name $($Shape.Text) -Value $shape -Force
    }
}

In this version we extend the script to display information about the shapes

Name                    Text       ID Index
----                    ----       -- -----
Domain                  manticore   1     1
Organizational unit     England    47     2
Directory connector                57     3
Organizational unit.58  Yorkshire  58     4
Directory connector.68             68     5
Organizational unit.69  York       69     6
Directory connector.79             79     7
Organizational unit.80  London     80     8
Directory connector.90             90     9
Organizational unit.91  Scotland   91    10
Directory connector.101           101    11
Organizational unit.102 Wales     102    12
Directory connector.112           112    13
Organizational unit.113 Ireland   113    14
Directory connector.123           123    15
Organizational unit.124 Portugal  124    16
Directory connector.134           134    17
Organizational unit.135 Lisbon    135    18
Directory connector.145           145    19
Organizational unit.146 Belgium   146    20
Directory connector.156           156    21
Organizational unit.157 Latvia    157    22
Directory connector.167           167    23

 

and then to create a variable for each shape.  Now we can start to manipulate the objects

PowerShell and Visio: Opening a file 2

If you run the AD diagramming script we looked at recently and save the Vision drawing on problem is that the stencil doesn’t open with it. We have to go back and add it

001
002
003
004
005
006
007
008
009
010
$visio = New-Object -ComObject Visio.Application
$doc = $visio.Documents.Open("C:\Scripts\Visio\adtest.vsd")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\ADO_M.vss"
$stencil = $visio.Documents.Add($mysten)

That enables us to start working on the document manually but can we discover the objects in the drawing?

PowerShell and Visio – Opening a file

If all you want to do is open a Visio drawing then the simplest way is to use

Start-Process test.vsd

This will open the file in Visio ready for you to start work on it.

If you want to open the file and work on it programmatically then we have a little bit more to do.

001
002
$visio = New-Object -ComObject Visio.Application
$doc = $visio.Documents.Open("C:\Scripts\Visio\test.vsd")

Now we have our drawing we can start to do stuff with it

PowerShell and Visio – Documenting AD: 3

Up to now we have been dealing with a single level of OUs. There are few AD implementations that don’t have child OUs so how do we deal with them.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
function Add-Domain {
 param (
    [string]$name
 )
    $dom = $page.Drop($domain, 1, 11)
    $dom.Resize(1, 5, 70)
    $dom.Text = $name
    return $dom
 
}

function Add-Ou {
 param (
    [string]$name,
    [double]$x,
    [double]$y,
    $parent
)
    $ou = $page.Drop($orgunit, $x, $y)
    $ou.Resize(1, 5, 70)
    $ou.Text = $name   

    $link = $page.Drop($dircon,1,$y)
    $start = $link.CellsU("BeginX").GlueTo($parent.CellsU("PinX"))
    $end = $link.CellsU("EndX").GlueTo($ou.CellsU("PinX"))
   
    return $ou
}

$visio = New-Object -ComObject Visio.Application
$docs = $visio.Documents

## use blank drawing
$doc = $docs.Add("")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\ADO_M.vss"
$stencil = $visio.Documents.Add($mysten)

## Add objects
$domain = $stencil.Masters.Item("Domain")
$orgunit = $stencil.Masters.Item("Organizational Unit")
$dircon = $stencil.Masters.Item("Directory connector")

$file = "manticore.txt"
$domname = ($file -split "\.")[0]

$ous = Get-Content $file

$dom = Add-Domain $domname

$y = 11
$x = 1

foreach ($ou in $ous) {
    $names = $ou -split ","
    $ouname = $names[0] -replace "ou=", ""
    $parent = $names[1].Remove(0,3)
    #$parent
   
    $y = $y - 0.75
   
    if ($parent -eq $domname) {  
        New-Variable -Name "$ouname" -Value (Add-ou $ouname ($x + 0.5) $y $dom) -Force
    }
    else {
        $linkto =  Get-Variable -Name $parent -ValueOnly
        New-Variable -Name "$ouname" -Value (Add-ou $ouname ($x + $names.length -2.5 ) $y $linkto) -Force
    }   
}

 

The difference here is in the way we handle the OUs.  We get the parent of the OU we are working with.  If the parent is the domain we link back to that as before. If its another OU we link to that.

A variable is created for every OU object in the diagram at the time we create it. We can then use get-variable to find the value of the variable to be our parent for linking

Listing all of the OUs in a domain

In this post - http://msmvps.com/blogs/richardsiddaway/archive/2010/06/13/powershell-and-visio-documenting-ad-2.aspx – I showed how to start creating a diagram of the OU structure in your AD domain.  In case you are wondering how to get a text file like the one I used check out PowerShell in Practice - http://www.manning.com/siddaway/ – especially Technique 103 on page 300

Extended properties

In the last post I showed how to read the Extended Properties of a Visio stencil. But how do we know how which property to use?

We can adapt our script to list the possible Extended Properties

001
002
003
004
005
$direc = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033"
$shell = New-Object -ComObject "Shell.Application"
$folder = $shell.Namespace($direc)

0..300 | foreach { "$_ $($folder.GetDetailsOf($null,$_))"}

 

On Windows 7 I counted 286 properties.  Its a long scroll but you will find what you want.

Identifying Visio Stencils

In the previous posts on using Visio I’ve shown how to load and use a particular stencil.  But how do you know which stencil to use?

One way is to use Windows Explorer, hover the mouse over the stencil and read the Extended File Properties. That’s a bit manual so we’ll look at producing a list of stencils and for what they are used. To do this we can’t use PowerShell directly but this is where things get real easy – we can use the scripting shell just like we did with VBScript.

001
002
003
004
005
006
007
008
$direc = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033"
$shell = New-Object -ComObject "Shell.Application"
$folder = $shell.Namespace($direc)

Get-ChildItem -Path $direc -Filter "*.vss" | foreach {
    $file = $folder.Items().Item($_.Name)
    "{0,-12} {1}" -f $_.Name, $($folder.GetDetailsOf($file,21))
}

 

Define the directory holding the Visio stencils – mine is Office 2010 on Windows 7.

Create an object for the shell and get the folder object using the Namespace method.

Jump back to PowerShell to run get-childitem on the folder using a filter of *.vss to restrict the output to stencils – always cheaper to filter at source.

We then use the Items() method of our folder to identify the file and use getdetailsof method to return the Title (Extended property number 21) of the stencil. The output is formatted using a .NET formatted string.

PowerShell and Visio – Documenting AD: 2

I’ve taken the script to add OUs to a drawing and modified it so that the addition is performed by a function.

I started with a text file containing some OUs

ou=England,dc=Maticore,dc=org
ou=Scotland,dc=Maticore,dc=org
ou=Wales,dc=Maticore,dc=org
ou=Ireland,dc=Maticore,dc=org
ou=Portugal,dc=Maticore,dc=org
ou=Belgium,dc=Maticore,dc=org
ou=Latvia,dc=Maticore,dc=org

Notice that they are all top level OUs – lets not get too ambitious!

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
function Add-Domain {
 param (
    [string]$name
 )
    $dom = $page.Drop($domain, 1, 11)
    $dom.Resize(1, 5, 70)
    $dom.Text = $name
    return $dom
 
}

function Add-Ou {
 param (
    [string]$name,
    [double]$x,
    [double]$y
)
    $ou = $page.Drop($orgunit, $x, $y)
    $ou.Resize(1, 5, 70)
    $ou.Text = $name   

    $dom_ou = $page.Drop($dircon,1,$y)
    $start = $dom_ou.CellsU("BeginX").GlueTo($dom.CellsU("PinX"))
    $end = $dom_ou.CellsU("EndX").GlueTo($ou.CellsU("PinX"))
       
}

$visio = New-Object -ComObject Visio.Application
$docs = $visio.Documents

## use blank drawing
$doc = $docs.Add("")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\ADO_M.vss"
$stencil = $visio.Documents.Add($mysten)

## Add objects
$domain = $stencil.Masters.Item("Domain")
$orgunit = $stencil.Masters.Item("Organizational Unit")
$dircon = $stencil.Masters.Item("Directory connector")

$file = "manticore.txt"
$domname = ($file -split "\.")[0]

$ous = Get-Content $file

$dom = Add-Domain $domname

$y = 11

foreach ($ou in $ous) {
    $ouname = ($ou -split ",")[0] -replace "ou=", ""
   
    $y = $y - 0.75
      
    Add-ou $ouname 1.5 $y
}

The functions add the domain and OU objects to the drawing.  Only change is that I set the text property of the OU and domain.

The main body of the script creates the drawing as before.  Uses the file name to get the domain and then reads the file. It splits out the OU names and calculates the Y co-ordinate then adds the OU

Next up I need to deal with child OUs

PowerShell and Visio – Documenting AD: 1

If we take the concept of our last script that added objects to a drawing we can use this as the basis of a way to automate the documentation of our AD.

One of the first things we need to document is the OU structure.  If you have ever produced one of these it is a tedious affair and they are difficult to maintain. So lets automate it.

This is how we create a basic OU structure.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
$visio = New-Object -ComObject Visio.Application
$docs = $visio.Documents

## use blank drawing
$doc = $docs.Add("")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\ADO_M.vss"
$stencil = $visio.Documents.Add($mysten)

## Add objects
$domain = $stencil.Masters.Item("Domain")
$ou = $stencil.Masters.Item("Organizational Unit")
$dircon = $stencil.Masters.Item("Directory connector")

$dom = $page.Drop($domain, 1, 11)
$dom.Resize(1, 5, 70)

$ou1 = $page.Drop($ou, 1.5, 10.25)
$ou1.Resize(1, 5, 70)

$ou2 = $page.Drop($ou, 1.5, 9.5)
$ou2.Resize(1, 5, 70)

$dom_ou1 = $page.Drop($dircon,2,10.25)
$start = $dom_ou1.CellsU("BeginX").GlueTo($dom.CellsU("PinX"))
$end = $dom_ou1.CellsU("EndX").GlueTo($ou1.CellsU("PinX"))

$dom_ou1 = $page.Drop($dircon,2,9.5)
$start = $dom_ou1.CellsU("BeginX").GlueTo($dom.CellsU("PinX"))
$end = $dom_ou1.CellsU("EndX").GlueTo($ou2.CellsU("PinX"))

 

The basic changes from last time are that I’m starting with a blank drawing and adding the Active Directory stencil.  Objects are added and resized as before.  I’m also using the directory connector object rather than the default connector.

If you look at the positions of the objects you can see that I’m automatically aligning them in vertical columns by defining the X co-ordinate.

This script is OK as an experiment to discover how things work but we usually have a lot more objects than this and the depth of the child OUs needs to be considered. We need to be able to read in the OU data and move some of this activity into functions so we can reuse the code.

That’s the next job.

Powershell and Visio: Move objects and add text

Lets take our look a Visio a bit further and move objects around and change the text labels

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
## create visio document
$visio = New-Object -ComObject Visio.Application
$docs = $visio.Documents

## use basic template
$doc = $docs.Add("Basic Diagram.vst")

## set active page
$pages = $visio.ActiveDocument.Pages
$page = $pages.Item(1)

## Add a stencil
$mysten = "C:\Program Files\Microsoft Office\Office14\Visio Content\1033\EntApp_M.vss"
$stencil = $visio.Documents.Add($mysten)

## Add objects
$server = $stencil.Masters.Item("Server")
$workstn = $stencil.Masters.Item("Workstation")

$shape1 = $page.Drop($server, 2, 2)
$shape2 = $page.Drop($workstn, 5, 5)

## Resize Objects
$shape1.Resize(1, 5, 70)
$shape2.Resize(1, 5, 70)

## Connect Objects
$connect = $page.Drop($page.Application.ConnectorToolDataObject,0,0)
$start = $connect.CellsU("BeginX").GlueTo($shape1.CellsU("PinX"))
$end = $connect.CellsU("EndX").GlueTo($shape2.CellsU("PinX"))

## move objects
$shape2.SetCenter(4,9)
$shape1.SetCenter(4,4)

## Add text
$shape1.Text = "File Server"
$shape2.Text = "My Workstation"

$doc.SaveAs("c:\scripts\visio\draw1.vsd")
$visio.Quit()

 

To move an object we can use the SetCenter method.  The numbers are X & Y co-ordinates.  The origin is at the bottom left corner (0,0).  Depending on what units and paper size you are using – using A4 I get 8,11 as an approximation to the top right corner so I’m guessing the co-ordinates represent inches. Check on your implementation.

The text is simply changed by setting the Text property as shown.

Now we have the basics of working with Visio – its time to think what we can do with it.