@@ -25,46 +25,9 @@ function Get-OpenXML
2525 )
2626
2727 begin {
28- # First lets declare a little helper function to get the content of a part
29- filter getPartContent {
30- $part = $_
31- $partStream = $part.GetStream ()
32- if (-not $partStream ) { return }
33- switch ($part.ContentType ) {
34- # If the content type looks like XML, read it as XML
35- { $part.ContentType -match ' [\./\+]xml' } {
36- $streamReader = [IO.StreamReader ]::new($partStream )
37- $streamReader.ReadToEnd () -as [xml ]
38- $streamReader.Close ()
39- }
40- # If the part looks like JSON, read it as JSON
41- { $part.Uri -match ' \.json$' } {
42- $streamReader = [IO.StreamReader ]::new($partStream )
43- $jsonContent = $streamReader.ReadToEnd ()
44- $streamReader.Close ()
45- $jsonContent | ConvertFrom-Json
46- }
47- # Otherwise, read it as a memory stream and return the byte array
48- default {
49- $outputStream = [IO.MemoryStream ]::new()
50- $partStream.CopyTo ($outputStream )
51- $outputStream.Seek (0 , ' Begin' )
52- $outputStream.ToArray ()
53- }
54- }
55-
56- $partStream.Close ()
57- $partStream.Dispose ()
58- }
59- }
60-
61- process {
62- # Try to resolve the file path
63- $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath ($FilePath )
64- # If we could not resolve the path, exit
65- if (-not $resolvedPath ) { return }
6628
67- foreach ($filePath in $resolvedPath ) {
29+ filter openXMLFromFile {
30+ $filePath = $_
6831 # Get the file info and read the file as a byte stream.
6932 $fileInfo = $FilePath -as [IO.FileInfo ]
7033 # By reading the file with Get-Content -AsByteStream, we avoid locking the file
@@ -77,85 +40,62 @@ function Get-OpenXML
7740 # Create a memory stream from the byte array
7841 $memoryStream = [IO.MemoryStream ]::new($packageBytes )
7942 # and open the package from the memory stream
80- $filePackage = [IO.Packaging.Package ]::Open($memoryStream , " Open" , " Read " )
43+ $filePackage = [IO.Packaging.Package ]::Open($memoryStream , " Open" , " ReadWrite " )
8144 # If that did not work, return.
8245 if (-not $filePackage ) { return }
8346
84- # Get the package relationships.
85- # (these are important for key corner cases in OpenXML files)
86- $packageRelationships = $filePackage.GetRelationships ()
87- $packageContent = [Ordered ]@ {}
88- $packageParts = @ ($filePackage.GetParts ())
89-
90- # Now we will read each part in the package, and store it in an `[Ordered]` dictionary
91- # Since this _might_ take a while (if you used a lot of PowerPoint images) we want to show a progress bar.
92-
93- # Prepare the progress bar
94- $partCount = 0
95- $partTotal = $packageParts.Length
96- $partProgress = [Ordered ]@ {Id = Get-Random ;Activity = ' Reading Parts' }
97-
98- # Then read each part
99- foreach ($part in $packageParts ) {
100- $partCount ++
101- # update the progress bar
102- Write-Progress @partProgress - Status " Reading part $ ( $part.Uri ) ($partCount of $partTotal )" - PercentComplete (
103- [math ]::Round(($partCount * 100 / $partTotal ))
104- )
105- # and store the part in the dictionary
106- $packageContent [" $ ( $part.Uri ) " ] =
107- [PSCustomObject ]@ {
108- PSTypeName = ' OpenXML.Part'
109- Uri = $part.Uri
110- ContentType = $part.ContentType
111- # (we'll use our helper function to get the content)
112- Content = $part | getPartContent
113- FilePath = " $resolvedPath "
114- }
115- }
116- # Now that we've read all parts, we can close the package
117- $filePackage.Close ()
118- # and the memory stream, too.
119- $memoryStream.Close ()
120-
121- # and finally, complete the progress bar.
122- Write-Progress @partProgress - Status " Completed reading $partCount parts" - Completed
123-
124- # Now we can create the final object.
125- $OpenXMLObject = [PSCustomObject ]@ {
126- # It is a generic OpenXML file by default
127- PSTypeName = ' OpenXML.File'
128- # with a `.FilePath`, so we can re-read and update it.
129- FilePath = $resolvedPath
130- # all of the `.Parts` have been read.
131- Parts = $packageContent
132- # and the package relationships are included, too.
133- Relationships = $packageRelationships
134- }
135-
47+ $filePackage.pstypenames.insert (0 , ' OpenXML' )
48+ $filePackage.pstypenames.insert (0 , ' OpenXML.File' )
49+ $packageContent = $filePackage.Parts
50+ $openXMLObject = $filePackage |
51+ Add-Member NoteProperty FilePath $filePath - Force - PassThru |
52+ Add-Member NoteProperty MemoryStream $memoryStream - Force - PassThru
53+
13654 # Now we can get more specific about what type of OpenXML file this is.
13755 # By looking for certain key parts, we can determine if this is a PowerPoint, Excel, or Word file.
13856 # For example, if the package contains a part with `/ppt/` in the URI,
139- if ($packageContent .Keys -match ' /ppt/' ) {
57+ if ($filePackage .Parts .Keys -match ' /ppt/' ) {
14058 # it is an `OpenXML.PowerPoint.File`
14159 $openXmlObject.pstypenames.insert (0 , ' OpenXML.PowerPoint.File' )
14260 }
14361
14462 # If the package contains a part with `/xl/` in the URI,
145- if ($packageContent .Keys -match ' /xl/' ) {
63+ if ($filePackage .Parts .Keys -match ' /xl/' ) {
14664 # it is an `OpenXML.Excel.File`
14765 $openXmlObject.pstypenames.insert (0 , ' OpenXML.Excel.File' )
14866 }
14967
15068 # If the package contains a part with `/word/` in the URI, it is a Word file.
151- if ($packageContent .Keys -match ' /word/' ) {
69+ if ($filePackage .Parts .Keys -match ' /word/' ) {
15270 # it is an `OpenXML.Word.File`
15371 $openXmlObject.pstypenames.insert (0 , ' OpenXML.Word.File' )
15472 }
155-
73+
74+ # If the package contains a part with `/Documents/` in the URI,
75+ if ($filePackage.Parts.Keys -match ' /Documents/' ) {
76+ # it is an `OpenXML.XPS.File`
77+ $openXmlObject.pstypenames.insert (0 , ' OpenXML.XPS.File' )
78+ }
15679
15780 # Now we output our openXML object
15881 $OpenXMLObject
159- }
82+ }
83+ }
84+
85+ process {
86+ if ($filePath ) {
87+ # Try to resolve the file path
88+ $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath ($FilePath )
89+ # If we could not resolve the path, exit
90+ if (-not $resolvedPath ) { return }
91+
92+ $resolvedPath | openXMLFromFile
93+ } else {
94+ $memoryStream = [IO.MemoryStream ]::new()
95+ $EmptyPackage = [io.packaging.package ]::Open($memoryStream , ' Create' )
96+ $EmptyPackage | Add-Member NoteProperty - Name MemoryStream - Value $memoryStream - Force
97+ $EmptyPackage.pstypenames.insert (0 , ' OpenXML' )
98+ $EmptyPackage
99+ }
160100 }
161101}
0 commit comments