diff --git a/Examples/New-VisioRackShape_Example.ps1 b/Examples/New-VisioRackShape_Example.ps1 new file mode 100644 index 0000000..63311d3 --- /dev/null +++ b/Examples/New-VisioRackShape_Example.ps1 @@ -0,0 +1,49 @@ +<# + +Download the following Stencils from https://www.visiocafe.com/ + + HPE-Common - https://www.visiocafe.com/downloads/hp/HPE-Common.zip + HPE-ProLiant - https://www.visiocafe.com/downloads/hp/HPE-ProLiant.zip + +Unblock both files + +Unzip the contents into C:\Temp + +#> + +#Install the latest VisioBot3000 Module from PowerShell Gallery +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +Install-Module -Name VisioBot3000 + +#Import the VisioBot3000 Module +Import-Module -Name VisioBot3000 -Force + +#Close down any running Visio session **without saving** +Stop-Process -Name VISIO -ErrorAction SilentlyContinue + +#Clear All Variables +Remove-Variable -Name * -ErrorAction SilentlyContinue + +#Create a New Visio Session and Blank 'Page-1' +New-VisioDocument + +#Register the HPE Stencils +Register-VisioStencil -Name HPE-Racks -Path 'C:\Temp\HPE-Racks.vss' +Register-VisioStencil -Name HPE-ProLiant-DL -Path 'C:\Temp\HPE-ProLiant-DL.vss' + +#Register the HPE Shapes +Register-VisioShape -Name HPE42U600EntRackF -StencilName HPE-Racks -MasterName 'HPE 42U G2 Ent Rack Front' +Register-VisioShape -Name HPEDL180Gen108LFF -StencilName HPE-ProLiant-DL -MasterName 'DL180 Gen10 8LFF front' +Register-VisioShape -Name HPEDL580Gen10SFF -StencilName HPE-ProLiant-DL -MasterName 'DL580 Gen10 front' +Register-VisioShape -Name HPEDL360Gen108SFF -StencilName HPE-ProLiant-DL -MasterName 'DL360 Gen10 8SFF front' + +#Drop the New Rack Shape +New-VisioShape -Master HPE42U600EntRackF -Label Rack01 -x 1 -y 3 + +#Drop the New Rack Equipment Shapes into the Existing Rack Shape +New-VisioRackShape -Master HPEDL180Gen108LFF -Label Server1 -RackLabel Rack01 -RackVendor HPE -FirstU 1 +New-VisioRackShape -Master HPEDL580Gen10SFF -Label Server2 -RackLabel Rack01 -RackVendor HPE -FirstU 3 +New-VisioRackShape -Master HPEDL580Gen10SFF -Label Server3 -RackLabel Rack01 -RackVendor HPE -FirstU 7 +New-VisioRackShape -Master HPEDL360Gen108SFF -Label Server4 -RackLabel Rack01 -RackVendor HPE -FirstU 11 +New-VisioRackShape -Master HPEDL360Gen108SFF -Label Server5 -RackLabel Rack01 -RackVendor HPE -FirstU 12 + diff --git a/VisioBot3000.psd1 b/VisioBot3000.psd1 index 42c925e..5eeda08 100644 --- a/VisioBot3000.psd1 +++ b/VisioBot3000.psd1 @@ -83,7 +83,7 @@ FunctionsToExport = 'Get-VisioColorFormula', 'Open-VisioDocument', 'Import-Visio 'Register-VisioShape', 'Get-VisioShape', 'Add-StencilSearchPath', 'Remove-VisioPage', 'Register-VisioContainer', 'Set-NextShapePosition', 'Set-RelativePositionDirection', - 'Get-NextShapePosition' + 'Get-NextShapePosition', 'New-VisioRackShape' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() diff --git a/VisioShape.ps1 b/VisioShape.ps1 index 24466a1..6d708ce 100644 --- a/VisioShape.ps1 +++ b/VisioShape.ps1 @@ -1,132 +1,298 @@ -<# - .SYNOPSIS - Drops a shape on the page - - .DESCRIPTION - Drops a shape (provided as a master shape) on the page. If no X coordinate is given, the shape is positioned relative to the previous shape placed - The shape is given a name and label. - - .PARAMETER Master - Either the name of the master (previously registered using Register-VisioShape) or a reference to a master object. - - .PARAMETER X - The X position used to place the shape (in inches). If this is omitted, the shape is positioned relative to the previous shape placed. - - .PARAMETER Y - The Y position used to place the shape (in inches). - - .PARAMETER Name - The name for the new shape. - - .INPUTS - None. You cannot pipe objects to Add-Extension. - - .OUTPUTS - Visio.Shape - - .EXAMPLE - New-VisioShape MasterShapeName -Label 'My Shape' -x 5 -y 5 -Name MyShape - - -#> -Function New-VisioShape{ - [CmdletBinding(SupportsShouldProcess=$True)] - Param($Master,$Label,$X,$Y,$Name) - if($PSCmdlet.ShouldProcess('Visio','Drop shape on the page')){ - if($Master -is [string]){ - $Master=$script:Shapes[$Master] - } - if(!$Name){ - $Name=$Label - } - - $p=get-VisioPage - if($updateMode){ - $DroppedShape=$p.Shapes | Where-Object {$_.Name -eq $Label} - } - if(-not (get-variable DroppedShape -Scope Local -ErrorAction Ignore) -or ($null -eq $DroppedShape)){ - if(-not $X){ - $RelativePosition=Get-NextShapePosition - $X=$RelativePosition.X - $Y=$RelativePosition.Y - } - $DroppedShape=$p.Drop($Master.PSObject.BaseObject,$X,$Y) - $DroppedShape.Name=$Name - } else { - write-verbose "Existing shape <$Label> found" - } - $DroppedShape.Text=$Label - New-Variable -Name $Name -Value $DroppedShape -Scope Global -Force - write-output $DroppedShape - $Script:LastDroppedObject=$DroppedShape - } - -} - -<# - .SYNOPSIS - Copies a master from a stencil and gives it a name. - - .DESCRIPTION - Copies a master from a stencil and gives it a name. Also creates a function with the same name to drop the shape onto the active Visio page. - - .PARAMETER Name - The name used to refer to the shape - - .PARAMETER StencilName - Which stencil to get the master from - - .PARAMETER MasterName - The name of the master in the stencil - - .INPUTS - None. You cannot pipe objects to Register-VisioShape. - - .OUTPUTS - None - - .EXAMPLE - Register-VisioShape -Name Block -StencilName BasicShapes -MasterName Block - -#> -Function Register-VisioShape{ - [CmdletBinding()] - Param([string]$Name, - [Alias('From')][string]$StencilName, - [string]$MasterName) - - if(!$MasterName){ - $MasterName=$Name - } - $newShape=$stencils[$StencilName].Masters | Where-Object {$_.Name -eq $MasterName} - $script:Shapes[$Name]=$newshape - $outerName=$Name - new-item -Path Function:\ -Name "global`:$outername" -value {param($Label, $X,$Y, $Name) $Shape=get-visioshape $outername; New-VisioShape $Shape $Label $X $Y -name $Name}.GetNewClosure() -force | out-null - $script:GlobalFunctions.Add($outerName) | Out-Null -} - -<# - .SYNOPSIS - Retrieves a saved shape definition - - .DESCRIPTION - Retrieves a saved shape definition - - .PARAMETER Name - Describe Parameter1 - - .INPUTS - None. You cannot pipe objects to Get-VisioShape - - .OUTPUTS - Visio.Shape - - .EXAMPLE - Get-VisioShape Block - -#> -Function Get-VisioShape{ - [CmdletBinding()] - Param([string]$Name) - $script:Shapes[$Name] -} +<# + .SYNOPSIS + Drops a shape on the page + + .DESCRIPTION + Drops a shape (provided as a master shape) on the page. If no X coordinate is given, the shape is positioned relative to the previous shape placed + The shape is given a name and label. + + .PARAMETER Master + Either the name of the master (previously registered using Register-VisioShape) or a reference to a master object. + + .PARAMETER X + The X position used to place the shape (in inches). If this is omitted, the shape is positioned relative to the previous shape placed. + + .PARAMETER Y + The Y position used to place the shape (in inches). + + .PARAMETER Name + The name for the new shape. + + .INPUTS + None. You cannot pipe objects to Add-Extension. + + .OUTPUTS + Visio.Shape + + .EXAMPLE + New-VisioShape MasterShapeName -Label 'My Shape' -x 5 -y 5 -Name MyShape + + +#> +Function New-VisioShape{ + [CmdletBinding(SupportsShouldProcess=$True)] + Param($Master,$Label,$X,$Y,$Name) + if($PSCmdlet.ShouldProcess('Visio','Drop shape on the page')){ + if($Master -is [string]){ + $Master=$script:Shapes[$Master] + } + if(!$Name){ + $Name=$Label + } + + $p=get-VisioPage + if($updateMode){ + $DroppedShape=$p.Shapes | Where-Object {$_.Name -eq $Label} + } + if(-not (get-variable DroppedShape -Scope Local -ErrorAction Ignore) -or ($null -eq $DroppedShape)){ + if(-not $X){ + $RelativePosition=Get-NextShapePosition + $X=$RelativePosition.X + $Y=$RelativePosition.Y + } + $DroppedShape=$p.Drop($Master.PSObject.BaseObject,$X,$Y) + $DroppedShape.Name=$Name + } else { + write-verbose "Existing shape <$Label> found" + } + $DroppedShape.Text=$Label + New-Variable -Name $Name -Value $DroppedShape -Scope Global -Force + write-output $DroppedShape + $Script:LastDroppedObject=$DroppedShape + } + +} + +<# + .SYNOPSIS + Copies a master from a stencil and gives it a name. + + .DESCRIPTION + Copies a master from a stencil and gives it a name. Also creates a function with the same name to drop the shape onto the active Visio page. + + .PARAMETER Name + The name used to refer to the shape + + .PARAMETER StencilName + Which stencil to get the master from + + .PARAMETER MasterName + The name of the master in the stencil + + .INPUTS + None. You cannot pipe objects to Register-VisioShape. + + .OUTPUTS + None + + .EXAMPLE + Register-VisioShape -Name Block -StencilName BasicShapes -MasterName Block + +#> +Function Register-VisioShape{ + [CmdletBinding()] + Param([string]$Name, + [Alias('From')][string]$StencilName, + [string]$MasterName) + + if(!$MasterName){ + $MasterName=$Name + } + $newShape=$stencils[$StencilName].Masters | Where-Object {$_.Name -eq $MasterName} + $script:Shapes[$Name]=$newshape + $outerName=$Name + new-item -Path Function:\ -Name "global`:$outername" -value {param($Label, $X,$Y, $Name) $Shape=get-visioshape $outername; New-VisioShape $Shape $Label $X $Y -name $Name}.GetNewClosure() -force | out-null + $script:GlobalFunctions.Add($outerName) | Out-Null +} + +<# + .NOTES + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Function: New-VisioRackShape + Created by: Martin Cooper + Date: 14/11/2021 + GitHub: https://github.com/mc1903 + Version: 1.4 + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .SYNOPSIS + Drops and connects a new rack equipment shape (server, etc) into an existing rack shape. + + .DESCRIPTION + Drops and connects a new rack equipment shape (server, etc) into an existing rack shape at a specified first (lowest) U space. + + .PARAMETER Master + Either the name of the new rack equipment shape master (previously registered using Register-VisioShape) or a reference to a master object. + + .PARAMETER Label + The label for the new rack equipment shape. + + .PARAMETER Name + The name for the new rack equipment shape. If not provided then the Label will be used as the Name + + .PARAMETER RackLabel + The name for the existing rack shape. + + .PARAMETER RackVendor + The vendor name for the existing rack shape. + + Supported Rack Vendors are HPE, Dell, IBM & Cisco. + + Within each vendor only the shapes listed below are working. + + HPE shapes from the HPE-Racks set on VisioCafe - https://www.visiocafe.com/downloads/hp/HPE-Common.zip + + HPE 22U G2 Adv Rack Front + HPE 22U G2 Adv Rack Rear + HPE 36U G2 Adv Rack Front + HPE 36U G2 Adv Rack Rear + HPE 42U 800mm G2 Adv Rack Front + HPE 42U 800mm G2 Adv Rack Rear + HPE 42U 800mm G2 Ent Rack Front + HPE 42U 800mm G2 Ent Rack Rear + HPE 42U G2 Adv Rack Front + HPE 42U G2 Adv Rack Rear + HPE 42U G2 Ent Rack Front + HPE 42U G2 Ent Rack Rear + HPE 48U 800mm G2 Adv Rack Front + HPE 48U 800mm G2 Adv Rack Rear + HPE 48U 800mm G2 Ent Rack Front + HPE 48U 800mm G2 Ent Rack Rear + HPE 48U G2 Adv Rack Front + HPE 48U G2 Adv Rack Rear + HPE 48U G2 Ent Rack Front + HPE 48U G2 Ent Rack Rear + 50U Ent. Rack + + Dell shapes from the Dell-Racks set on VisioCafe - https://www.visiocafe.com/downloads/dell/Dell-Racks.zip + + 2420 Rack Frame + 4220 Rack Frame + 4220D Rack Frame + 4220W Rack Frame + 4820 Rack Frame + 4820D Rack Frame + 4820W Rack Frame + + IBM shapes from the IBM-Racks set on VisioCafe - https://www.visiocafe.com/downloads/ibm/IBM-Common.zip + + 7014-S11 Rack + 7014-S25 Rack + 7014-S00 Rack + 7014-T00 Rack + 7014-T42 Rack + + Cisco shapes from the Cisco R-Series set on Cisco.com - https://www.cisco.com/c/dam/assets/prod/visio/visio/racks-cisco-r-series.zip + + RACK2-UCS Front + RACK2-UCS Rear + RACK2-UCS2 Front + RACK2-UCS2 Rear + + .PARAMETER FirstU + The first (lowest) U space in which to place the new rack equipment shape. + + .OUTPUTS + Visio.Shape + + .EXAMPLE + New-VisioRackShape -Master HPEDL180Gen108LFF -Label Server1 -RackLabel Rack01 -RackVendor HPE -FirstU 1 +#> +Function New-VisioRackShape{ + [CmdletBinding(SupportsShouldProcess=$True)] + Param( + [Parameter(Mandatory=$true)]$Master, + [Parameter(Mandatory=$true)]$Label, + [Parameter(Mandatory=$false)]$Name, + [Parameter(Mandatory=$true)]$RackLabel, + [Parameter(Mandatory=$true)]$RackVendor, + [Parameter(Mandatory=$true)]$FirstU + ) + If($PSCmdlet.ShouldProcess('Visio','Drop a new rack equipment shape and connect to an existing rack shape')){ + If($Master -is [string]){ + $Master=$script:Shapes[$Master] + } + + If(!$Name){ + $Name=$Label + } + + $p=Get-VisioPage + + $p.Application.ScreenUpdating = 0 + + $ExistingRackShape=$p.Shapes | Where-Object {$_.Name -eq $RackLabel} + + If(!$ExistingRackShape){ + Write-Verbose "Existing rack shape $RackLabel was NOT found on the active page $($p.Name). Skipping!" + Break + } + Else{ + Write-Verbose "Existing rack shape $RackLabel was found on the active page $($p.Name)." + If($RackVendor -match 'HPE'){ + $FirstUBXY=$FirstU | ForEach-Object { $_.ToString("00") } + $FirstUEXY=$FirstU | ForEach-Object { $_.ToString("00") } + $BeginXY="=PAR(PNT($RackLabel!Connections.U$($FirstUBXY)B.X,$RackLabel!Connections.U$($FirstUBXY)B.Y))" + $EndXY="=PAR(PNT($RackLabel!Connections.U$($FirstUEXY)E.X,$RackLabel!Connections.U$($FirstUEXY)E.Y))" + } + ElseIf($RackVendor -match 'Dell'){ + $FirstUBXY=$FirstU*2+3 + $FirstUEXY=$FirstU*2+4 + $BeginXY="=PAR(PNT($RackLabel!Connections.X$($FirstUBXY),$RackLabel!Connections.Y$($FirstUBXY)))" + $EndXY="=PAR(PNT($RackLabel!Connections.X$($FirstUEXY),$RackLabel!Connections.Y$($FirstUEXY)))" + } + ElseIf($RackVendor -match 'IBM'){ + $FirstUBXY=$FirstU*2+3 + $FirstUEXY=$FirstU*2+4 + $BeginXY="=PAR(PNT($RackLabel!Connections.X$($FirstUBXY),$RackLabel!Connections.Y$($FirstUBXY)))" + $EndXY="=PAR(PNT($RackLabel!Connections.X$($FirstUEXY),$RackLabel!Connections.Y$($FirstUEXY)))" + } + ElseIf($RackVendor -match 'Cisco'){ + $FirstUBXY=$FirstU + $FirstUEXY=$FirstU + $BeginXY="=PAR(PNT($RackLabel!Connections.Cab$($FirstUBXY)A.X,$RackLabel!Connections.Cab$($FirstUBXY)A.Y))" + $EndXY="=PAR(PNT($RackLabel!Connections.Cab$($FirstUBXY)B.X,$RackLabel!Connections.Cab$($FirstUBXY)B.Y))" + } + Else{ + Write-Verbose "Rack Vendor $RackVendor is NOT known/supported. Skipping!" + Break + } + + } + + If($UpdateMode){ + $DroppedShape=$p.Shapes | Where-Object {$_.Name -eq $Label} + If(!$DroppedShape){ + $DroppedShape=$p.Drop($Master.PSObject.BaseObject,0,0) + $DroppedShape.Name=$Name + $DroppedShape.Text=$Label + } + } + Else{ + $DroppedShape=$p.Drop($Master.PSObject.BaseObject,0,0) + $DroppedShape.Name=$Name + $DroppedShape.Text=$Label + } + + $DroppedShape.Cells("BeginX").FormulaU=$BeginXY + $DroppedShape.Cells("BeginY").FormulaU=$BeginXY + $DroppedShape.Cells("EndX").FormulaU=$EndXY + $DroppedShape.Cells("EndY").FormulaU=$EndXY + + $p.Application.ScreenUpdating = -1 + + New-Variable -Name $Name -Value $DroppedShape -Scope Global -Force + $DroppedShape + $Script:LastDroppedObject=$DroppedShape + + Write-Verbose "Rack Vendor: $RackVendor" + Write-Verbose "BeginXY: $BeginXY" + Write-Verbose " EndXY: $EndXY" + Write-Verbose "Name: $Name" + Write-Verbose "Label: $Label" + Write-Verbose "Update Mode: $UpdateMode" + + } +}