Public/Export-XLShape.ps1
Function Export-XLShape { <# .SYNOPSIS Export Excel shapes. .DESCRIPTION This script exports properties of every shapes in a Excel file. It's intended to use them to analyze a diagram made by Excel shapes programatically. This script only works on Windows with Excel installed. Almost all properties in exported objects are simply copied from underlying API (Excel COM objects). So you can find thier meanings or functionalities by searching them on the internet. .PARAMETER Path Path to a Excel file .PARAMETER Excel Use this parameter to specify your own instance of Excel Application to deal with the Excel file. If not specified, the script uses its own Excel Application. .EXAMPLE PS> Export-ExcelShape -Path .\test.xlsx | Export-Csv -Path .\out.csv -Encoding UTF8 -NotypeInformation Export shapes in .\test.xlsx as CSV. .EXAMPLE PS> Get-ChildItem -Filter *.xlsx | Export-ExcelShape | Tee-Object -Variable out | Out-GridView Extract shapes from *.xlsx in current directory, Set into $out, and display in gridview. #> [CmdletBinding()] Param( [Parameter(ValueFromPipeline = $true)] $Path, $Excel ) Begin { $_excel = $null if ($null -eq $Excel) { Write-Verbose 'Starting Excel app ...' $_excel = New-Object -ComObject Excel.Application } else { $_excel = $Excel } # @see https://docs.microsoft.com/en-us/office/vba/api/office.msoshapetype $MsoShapeType = @{ -2 = 'msoShapeTypeMixed' # Mixed shape type 1 = 'msoAutoShape' # AutoShape 2 = 'msoCallout' # Callout 3 = 'msoChart' # Chart 4 = 'msoComment' # Comment 5 = 'msoFreeform' # Freeform 6 = 'msoGroup' # Group 7 = 'msoEmbeddedOLEObject' # Embedded OLE object 8 = 'msoFormControl' # Form control 9 = 'msoLine' # Line 10 = 'msoLinkedOLEObject' # Linked OLE object 11 = 'msoLinkedPicture' # Linked picture 12 = 'msoOLEControlObject' # OLE control object 13 = 'msoPicture' # Picture 14 = 'msoPlaceholder' # Placeholder 15 = 'msoTextEffect' # Text effect 16 = 'msoMedia' # Media 17 = 'msoTextBox' # Text box 18 = 'msoScriptAnchor' # Script anchor 19 = 'msoTable' # Table 20 = 'msoCanvas' # Canvas 21 = 'msoDiagram' # Diagram 22 = 'msoInk' # Ink 23 = 'msoInkComment' # Ink comment 24 = 'msoIgxGraphic' # SmartArt graphic 26 = 'msoWebVideo' # Web video 27 = 'msoContentApp' # Content Office Add-in 28 = 'msoGraphic' # Graphic 29 = 'msoLinkedGraphic' # Linked graphic 30 = 'mso3DModel' # 3D model 31 = 'msoLinked3DModel' # Linked 3D model } # @see https://docs.microsoft.com/en-us/office/vba/api/office.msoautoshapetype $MsoAutoShapeType = @{ -2 = 'msoShapeMixed' # Return value only; indicates a combination of the other states. 1 = 'msoShapeRectangle' # Rectangle 2 = 'msoShapeParallelogram' # Parallelogram 3 = 'msoShapeTrapezoid' # Trapezoid 4 = 'msoShapeDiamond' # Diamond 5 = 'msoShapeRoundedRectangle' # Rounded rectangle 6 = 'msoShapeOctagon' # Octagon 7 = 'msoShapeIsoscelesTriangle' # Isosceles triangle 8 = 'msoShapeRightTriangle' # Right triangle 9 = 'msoShapeOval' # Oval 10 = 'msoShapeHexagon' # Hexagon 11 = 'msoShapeCross' # Cross 12 = 'msoShapeRegularPentagon' # Pentagon 13 = 'msoShapeCan' # Can 14 = 'msoShapeCube' # Cube 15 = 'msoShapeBevel' # Bevel 16 = 'msoShapeFoldedCorner' # Folded corner 17 = 'msoShapeSmileyFace' # Smiley face 18 = 'msoShapeDonut' # Donut 19 = 'msoShapeNoSymbol' # "No" symbol 20 = 'msoShapeBlockArc' # Block arc 21 = 'msoShapeHeart' # Heart 22 = 'msoShapeLightningBolt' # Lightning bolt 23 = 'msoShapeSun' # Sun 24 = 'msoShapeMoon' # Moon 25 = 'msoShapeArc' # Arc 26 = 'msoShapeDoubleBracket' # Double bracket 27 = 'msoShapeDoubleBrace' # Double brace 28 = 'msoShapePlaque' # Plaque 29 = 'msoShapeLeftBracket' # Left bracket 30 = 'msoShapeRightBracket' # Right bracket 31 = 'msoShapeLeftBrace' # Left brace 32 = 'msoShapeRightBrace' # Right brace 33 = 'msoShapeRightArrow' # Block arrow that points right 34 = 'msoShapeLeftArrow' # Block arrow that points left 35 = 'msoShapeUpArrow' # Block arrow that points up 36 = 'msoShapeDownArrow' # Block arrow that points down 37 = 'msoShapeLeftRightArrow' # Block arrow with arrowheads that point both left and right 38 = 'msoShapeUpDownArrow' # Block arrow that points up and down 39 = 'msoShapeQuadArrow' # Block arrows that point up, down, left, and right 40 = 'msoShapeLeftRightUpArrow' # Block arrow with arrowheads that point left, right, and up 41 = 'msoShapeBentArrow' # Block arrow that follows a curved 90-degree angle. 42 = 'msoShapeUTurnArrow' # Block arrow forming a U shape 43 = 'msoShapeLeftUpArrow' # Block arrow with arrowheads that point left and up 44 = 'msoShapeBentUpArrow' # Block arrow that follows a sharp 90-degree angle. Points up by default. 45 = 'msoShapeCurvedRightArrow' # Block arrow that curves right 46 = 'msoShapeCurvedLeftArrow' # Block arrow that curves left 47 = 'msoShapeCurvedUpArrow' # Block arrow that curves up 48 = 'msoShapeCurvedDownArrow' # Block arrow that curves down 49 = 'msoShapeStripedRightArrow' # Block arrow that points right with stripes at the tail 50 = 'msoShapeNotchedRightArrow' # Notched block arrow that points right 51 = 'msoShapePentagon' # Pentagon 52 = 'msoShapeChevron' # Chevron 53 = 'msoShapeRightArrowCallout' # Callout with arrow that points right 54 = 'msoShapeLeftArrowCallout' # Callout with arrow that points left 55 = 'msoShapeUpArrowCallout' # Callout with arrow that points up 56 = 'msoShapeDownArrowCallout' # Callout with arrow that points down 57 = 'msoShapeLeftRightArrowCallout' # Callout with arrowheads that point both left and right 58 = 'msoShapeUpDownArrowCallout' # Callout with arrows that point up and down 59 = 'msoShapeQuadArrowCallout' # Callout with arrows that point up, down, left, and right 60 = 'msoShapeCircularArrow' # Block arrow that follows a curved 180-degree angle 61 = 'msoShapeFlowchartProcess' # Process flowchart symbol 62 = 'msoShapeFlowchartAlternateProcess' # Alternate process flowchart symbol 63 = 'msoShapeFlowchartDecision' # Decision flowchart symbol 64 = 'msoShapeFlowchartData' # Data flowchart symbol 65 = 'msoShapeFlowchartPredefinedProcess' # Predefined process flowchart symbol 66 = 'msoShapeFlowchartInternalStorage' # Internal storage flowchart symbol 67 = 'msoShapeFlowchartDocument' # Document flowchart symbol 68 = 'msoShapeFlowchartMultidocument' # Multi-document flowchart symbol 69 = 'msoShapeFlowchartTerminator' # Terminator flowchart symbol 70 = 'msoShapeFlowchartPreparation' # Preparation flowchart symbol 71 = 'msoShapeFlowchartManualInput' # Manual input flowchart symbol 72 = 'msoShapeFlowchartManualOperation' # Manual operation flowchart symbol 73 = 'msoShapeFlowchartConnector' # Connector flowchart symbol 74 = 'msoShapeFlowchartOffpageConnector' # Off-page connector flowchart symbol 75 = 'msoShapeFlowchartCard' # Card flowchart symbol 76 = 'msoShapeFlowchartPunchedTape' # Punched tape flowchart symbol 77 = 'msoShapeFlowchartSummingJunction' # Summing junction flowchart symbol 78 = 'msoShapeFlowchartOr' # "Or" flowchart symbol 79 = 'msoShapeFlowchartCollate' # Collate flowchart symbol 80 = 'msoShapeFlowchartSort' # Sort flowchart symbol 81 = 'msoShapeFlowchartExtract' # Extract flowchart symbol 82 = 'msoShapeFlowchartMerge' # Merge flowchart symbol 83 = 'msoShapeFlowchartStoredData' # Stored data flowchart symbol 84 = 'msoShapeFlowchartDelay' # Delay flowchart symbol 85 = 'msoShapeFlowchartSequentialAccessStorage' # Sequential access storage flowchart symbol 86 = 'msoShapeFlowchartMagneticDisk' # Magnetic disk flowchart symbol 87 = 'msoShapeFlowchartDirectAccessStorage' # Direct access storage flowchart symbol 88 = 'msoShapeFlowchartDisplay' # Display flowchart symbol 89 = 'msoShapeExplosion1' # Explosion 90 = 'msoShapeExplosion2' # Explosion 91 = 'msoShape4pointStar' # 4-point star 92 = 'msoShape5pointStar' # 5-point star 93 = 'msoShape8pointStar' # 8-point star 94 = 'msoShape16pointStar' # 16-point star 95 = 'msoShape24pointStar' # 24-point star 96 = 'msoShape32pointStar' # 32-point star 97 = 'msoShapeUpRibbon' # Ribbon banner with center area above ribbon ends 98 = 'msoShapeDownRibbon' # Ribbon banner with center area below ribbon ends 99 = 'msoShapeCurvedUpRibbon' # Ribbon banner that curves up 100 = 'msoShapeCurvedDownRibbon' # Ribbon banner that curves down 101 = 'msoShapeVerticalScroll' # Vertical scroll 102 = 'msoShapeHorizontalScroll' # Horizontal scroll 103 = 'msoShapeWave' # Wave 104 = 'msoShapeDoubleWave' # Double wave 105 = 'msoShapeRectangularCallout' # Rectangular callout 106 = 'msoShapeRoundedRectangularCallout' # Rounded rectangle-shaped callout 107 = 'msoShapeOvalCallout' # Oval-shaped callout 108 = 'msoShapeCloudCallout' # Cloud callout 109 = 'msoShapeLineCallout1' # Callout with border and horizontal callout line 110 = 'msoShapeLineCallout2' # Callout with diagonal straight line 111 = 'msoShapeLineCallout3' # Callout with angled line 112 = 'msoShapeLineCallout4' # Callout with callout line segments forming a U-shape 113 = 'msoShapeLineCallout1AccentBar' # Callout with horizontal accent bar 114 = 'msoShapeLineCallout2AccentBar' # Callout with diagonal callout line and accent bar 115 = 'msoShapeLineCallout3AccentBar' # Callout with angled callout line and accent bar 116 = 'msoShapeLineCallout4AccentBar' # Callout with accent bar and callout line segments forming a U-shape 117 = 'msoShapeLineCallout1NoBorder' # Callout with horizontal line 118 = 'msoShapeLineCallout2NoBorder' # Callout with no border and diagonal callout line 119 = 'msoShapeLineCallout3NoBorder' # Callout with no border and angled callout line 120 = 'msoShapeLineCallout4NoBorder' # Callout with no border and callout line segments forming a U-shape 121 = 'msoShapeLineCallout1BorderandAccentBar' # Callout with border and horizontal accent bar 122 = 'msoShapeLineCallout2BorderandAccentBar' # Callout with border, diagonal straight line, and accent bar 123 = 'msoShapeLineCallout3BorderandAccentBar' # Callout with border, angled callout line, and accent bar 124 = 'msoShapeLineCallout4BorderandAccentBar' # Callout with border, accent bar, and callout line segments forming a U-shape 125 = 'msoShapeActionButtonCustom' # Button with no default picture or text. Supports mouse-click and mouse-over actions. 126 = 'msoShapeActionButtonHome' # Home button. Supports mouse-click and mouse-over actions. 127 = 'msoShapeActionButtonHelp' # Help button. Supports mouse-click and mouse-over actions. 128 = 'msoShapeActionButtonInformation' # Information button. Supports mouse-click and mouse-over actions. 129 = 'msoShapeActionButtonBackorPrevious' # Back or Previous button. Supports mouse-click and mouse-over actions. 130 = 'msoShapeActionButtonForwardorNext' # Forward or Next button. Supports mouse-click and mouse-over actions. 131 = 'msoShapeActionButtonBeginning' # Beginning button. Supports mouse-click and mouse-over actions. 132 = 'msoShapeActionButtonEnd' # End button. Supports mouse-click and mouse-over actions. 133 = 'msoShapeActionButtonReturn' # Return button. Supports mouse-click and mouse-over actions. 134 = 'msoShapeActionButtonDocument' # Document button. Supports mouse-click and mouse-over actions. 135 = 'msoShapeActionButtonSound' # Sound button. Supports mouse-click and mouse-over actions. 136 = 'msoShapeActionButtonMovie' # Movie button. Supports mouse-click and mouse-over actions. 137 = 'msoShapeBalloon' # Balloon 138 = 'msoShapeNotPrimitive' # Not supported 139 = 'msoShapeFlowchartOfflineStorage' # Offline storage flowchart symbol 140 = 'msoShapeLeftRightRibbon' # Ribbon with an arrow at both ends 141 = 'msoShapeDiagonalStripe' # Rectangle with two triangles-shapes removed; a diagonal stripe 142 = 'msoShapePie' # Circle ('pie') with a portion missing 143 = 'msoShapeNonIsoscelesTrapezoid' # Trapezoid with asymmetrical non-parallel sides 144 = 'msoShapeDecagon' # Decagon 145 = 'msoShapeHeptagon' # Heptagon 146 = 'msoShapeDodecagon' # Dodecagon 147 = 'msoShape6pointStar' # 6-point star 148 = 'msoShape7pointStar' # 7-point star 149 = 'msoShape10pointStar' # 10-point star 150 = 'msoShape12pointStar' # 12-point star 151 = 'msoShapeRound1Rectangle' # Rectangle with one rounded corner 152 = 'msoShapeRound2SameRectangle' # Rectangle with two-rounded corners that share a side 154 = 'msoShapeSnipRoundRectangle' # Rectangle with one snipped corner and one rounded corner 155 = 'msoShapeSnip1Rectangle' # Rectangle with one snipped corner 156 = 'msoShapeSnip2SameRectangle' # Rectangle with two snipped corners that share a side 157 = 'msoShapeRound2DiagRectangle' # Rectangle with two rounded corners, diagonally-opposed # 157 = 'msoShapeSnip2DiagRectangle' # Rectangle with two snipped corners, diagonally-opposed 158 = 'msoShapeFrame' # Rectangular picture frame 159 = 'msoShapeHalfFrame' # Half of a rectangular picture frame 160 = 'msoShapeTear' # Water droplet 161 = 'msoShapeChord' # Circle with a line connecting two points on the perimeter through the interior of the circle; a circle with a chord 162 = 'msoShapeCorner' # Rectangle with rectangular-shaped hole. 163 = 'msoShapeMathPlus' # Addition symbol + 164 = 'msoShapeMathMinus' # Subtraction symbol - 165 = 'msoShapeMathMultiply' # Multiplication symbol x 166 = 'msoShapeMathDivide' # Division symbol 167 = 'msoShapeMathEqual' # Equivalence symbol = 168 = 'msoShapeMathNotEqual' # Non-equivalence symbol 169 = 'msoShapeCornerTabs' # Four right triangles aligning along a rectangular path; four 'snipped' corners. 170 = 'msoShapeSquareTabs' # Four small squares that define a rectangular shape 171 = 'msoShapePlaqueTabs' # Four quarter-circles defining a rectangular shape 172 = 'msoShapeGear6' # Gear with six teeth 173 = 'msoShapeGear9' # Gear with nine teeth 174 = 'msoShapeFunnel' # Funnel 175 = 'msoShapePieWedge' # Quarter of a circular shape 176 = 'msoShapeLeftCircularArrow' # Circular arrow pointing counter-clockwise 177 = 'msoShapeLeftRightCircularArrow' # Circular arrow pointing clockwise and counter-clockwise; a curved arrow with points at both ends 178 = 'msoShapeSwooshArrow' # Curved arrow 179 = 'msoShapeCloud' # Cloud shape 180 = 'msoShapeChartX' # Square divided into four parts along diagonal lines 181 = 'msoShapeChartStar' # Square divided into six parts along vertical and diagonal lines 182 = 'msoShapeChartPlus' # Square divided vertically and horizontally into four quarters 183 = 'msoShapeLineInverse' # Line inverse } # @see https://docs.microsoft.com/en-us/office/vba/api/Office.MsoArrowheadStyle $MsoArrowheadStyle = @{ -2 = 'msoArrowheadStyleMixed' # Return value only; indicates a combination of the other states. 1 = 'msoArrowheadNone' # No arrowhead 2 = 'msoArrowheadTriangle' # Triangular 3 = 'msoArrowheadOpen' # Open 4 = 'msoArrowheadStealth' # Stealth-shaped 5 = 'msoArrowheadDiamond' # Diamond-shaped 6 = 'msoArrowheadOval' # Oval-shaped } # @see https://docs.microsoft.com/en-us/office/vba/api/office.msolinestyle $MsoLineStyle = @{ -2 = 'msoLineStyleMixed' # Not supported. 1 = 'msoLineSingle' # Single line. 2 = 'msoLineThinThin' # Two thin lines. 3 = 'msoLineThinThick' # Thick line next to thin line. For horizontal lines, the thick line is below the thin line. For vertical lines, the thick line is to the right of the thin line. 4 = 'msoLineThickThin' # Thick line next to thin line. For horizontal lines, the thick line is above the thin line. For vertical lines, the thick line is to the left of the thin line. 5 = 'msoLineThickBetweenThin' # Thick line with a thin line on each side. } # @see https://docs.microsoft.com/en-us/office/vba/api/office.msofilltype $MsoFillType = @{ -2 = 'msoFillMixed' # Mixed fill 1 = 'msoFillSolid' # Solid fill 2 = 'msoFillPatterned' # Patterned fill 3 = 'msoFillGradient' # Gradient fill 4 = 'msoFillTextured' # Textured fill 5 = 'msoFillBackground' # Fill is the same as the background. 6 = 'msoFillPicture' # Picture fill } } Process { if ($null -eq $_excel) { Write-Error 'Excel app not exists.' return } if ([string]::IsNullOrEmpty($Path) -or $Path -notmatch '\.xls[xbm]?$') { Write-Warning ('Skipped because it seems like not excel file: {0}' -f $Path) return } Write-Verbose ('Opening Workbook: {0}' -f $Path) $book = $_excel.Workbooks.Open($Path, $False, $True) if ($null -eq $book) { return } $book.Worksheets | ForEach-Object -Process { $sheet = $_ Write-Verbose ('Processing Worksheet: {0} (Shapes.Count={1})' -f $sheet.Name, $sheet.Shapes.Count) for ($i = 1; $i -le $sheet.Shapes.Count; $i++) { Export-Shape -WorkbookName $book.Name -WorksheetName $sheet.Name -Shape $sheet.Shapes.Item($i) } $sheet = $null } Write-Verbose ('Closing Workbook') $book.Saved = $True $book.Close() $book = $null } End { if ($null -eq $Excel) { if ($null -ne $_excel) { Write-Verbose 'Closing Excel app ...' $_excel.Quit() $_excel = $null [GC]::Collect() } } } } Function Export-Shape { Param( $WorkbookName, $WorksheetName, $Shape ) $prop = [Ordered]@{ Path = $Path Workbook = $WorkbookName Worksheet = $WorksheetName Id = $Shape.Id Name = $Shape.Name Type = $Shape.Type TypeName = $MsoShapeType[$Shape.Type] AutoShapeType = $Shape.AutoShapeType AutoShapeTypeName = $MsoAutoShapeType[$Shape.AutoShapeType] ParentGroup = $( if ($null -ne $Shape.ParentGroup) { $Shape.ParentGroup.Id } ) Text = $( if ($Shape.TextFrame2.HasText) { $Shape.TextFrame2.TextRange.Text } ) Visible = $Shape.Visible TopLeftCell = $Shape.TopLeftCell.Address($False, $False) BottomRightCell = $Shape.BottomRightCell.Address($False, $False) Top = $Shape.Top Left = $Shape.Left Width = $Shape.Width Height = $Shape.Height HorizontalFlip = $Shape.HorizontalFlip VerticalFlip = $Shape.VerticalFlip Rotation = $Shape.Rotation ZOrderPosition = $Shape.ZOrderPosition 'Line.BackColor' = $Shape.Line.BackColor.RGB 'Line.ForeColor' = $Shape.Line.ForeColor.RGB 'Line.Style' = $Shape.Line.Style 'Line.StyleName' = $MsoLineStyle[$Shape.Line.Style] 'Line.Transparency' = $Shape.Line.Transparency 'Line.Weight' = $Shape.Line.Weight 'Line.BeginArrowheadStyle' = $Shape.Line.BeginArrowheadStyle 'Line.BeginArrowheadStyleName' = $MsoArrowheadStyle[$Shape.Line.BeginArrowheadStyle] 'Line.EndArrowheadStyle' = $Shape.Line.EndArrowheadStyle 'Line.EndArrowheadStyleName' = $MsoArrowheadStyle[$Shape.Line.EndArrowheadStyle] 'Fill.BackColor' = $Shape.Fill.BackColor.RGB 'Fill.ForeColor' = $Shape.Fill.ForeColor.RGB 'Fill.Transparency' = $Shape.Fill.Transparency 'Fill.Type' = $Shape.Fill.Type 'Fill.TypeName' = $MsoFillType[$Shape.Fill.Type] 'Nodes.Count' = $Shape.Nodes.Count 'Nodes.Points' = $( if (0 -lt $Shape.Nodes.Count) { # @see https://stackoverflow.com/questions/48168130/how-do-i-move-around-nodes-in-a-shape#answer-48169908 $Shape.Nodes.Insert($Shape.Nodes.Count, 0, 1, 0, 0) $Shape.Nodes.Delete($Shape.Nodes.Count) $points = '[' for ($i = 1; $i -le $Shape.Nodes.Count; $i++) { $points += '[{0},{1}],' -f $Shape.Nodes.Item($i).Points[1, 1], $Shape.Nodes.Item($i).Points[1, 2] } $points = $points.Substring(0, $points.Length - 1) + ']' Write-Output $points } else { Write-Output '[]' } ) 'ConnectorFormat.BeginConnectedShape' = $( if ($Shape.ConnectorFormat.BeginConnected) { $Shape.ConnectorFormat.BeginConnectedShape.Id } ) 'ConnectorFormat.BeginConnectionSite' = $( if ($Shape.ConnectorFormat.BeginConnected) { $Shape.ConnectorFormat.BeginConnectionSite } ) 'ConnectorFormat.EndConnectedShape' = $( if ($Shape.ConnectorFormat.EndConnected) { $Shape.ConnectorFormat.EndConnectedShape.Id } ) 'ConnectorFormat.EndConnectionSite' = $( if ($Shape.ConnectorFormat.EndConnected) { $Shape.ConnectorFormat.EndConnectionSite } ) } New-Object -TypeName PSObject -Property $prop if ($null -ne $Shape.GroupItems) { for ($i = 1; $i -le $Shape.GroupItems.Count; $i++) { Export-Shape -WorkbookName $WorkbookName -WorksheetName $WorksheetName -Shape $Shape.GroupItems.Item($i) } } $Shape = $null } |