Scripts/Export-BundleContents.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
[CmdletBinding(SupportsShouldProcess=$true)]
param ( 
    [Parameter(ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)][string[]]$fullname, 
    [Parameter()][switch]$mponly
    )
Begin
{
    # VARIABLES NEEDED BY SCRIPT
    $VerbosePreference = "continue"
    $MPTYPE   = "Microsoft.EnterpriseManagement.Configuration.ManagementPack"
    $MRESTYPE = "Microsoft.EnterpriseManagement.Configuration.ManagementPackResource"
    $OPEN     = [System.IO.FileMode]"Open"
    $READ     = [System.IO.FileAccess]"Read"

    # load the approprate assemblies
    $SMCORE = [reflection.assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.Core")
    $PKGASM = [reflection.assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.Packaging")
    add-pssnapin smcmdletsnapin -ea silentlycontinue
    # if we can't load the packaging assembly, we shouldn't continue
    if ( ! $PKGASM ) { throw "Can't load packaging dll" }
    $BUNDLEFACTORY = $PKGASM.GetType("Microsoft.EnterpriseManagement.Packaging.ManagementPackBundleFactory")
    $BUNDLEREADER = $BUNDLEFACTORY::CreateBundleReader()
    $EMG = new-object Microsoft.EnterpriseManagement.EnterpriseManagementGroup LOCALHOST

    # Get some times that we need
    $TYPEOFMP    = $SMCORE.GetType($MPTYPE)
    $TYPEOFMPR   = $SMCORE.GetType($MRESTYPE)
 

    # create the function which will allow us to export the resources
    function Export-MPResource
    {
        param ( $directory, $filename, $stream )
        # just continue in the face of errors, we'll check the various
        # elements we need for nulls, etc in the script
        trap { continue }
        # we know that if HasNullStream is true, there's nothing that we can do
        # we know that if there's no filename property we can't create anything
        $outputFile = "${directory}/${filename}"
        $buffer = new-object byte[]($stream.length)
        $result = $stream.read($buffer,0,$buffer.length)
        $stream.close()
        # if the stream is empty, don't continue
        if ( $result -le 0) { return }
        # Check to be sure we should continue, this handles -whatif
        if($PSCmdlet.ShouldProcess("Create Resource '$outputFile'"))
        {
            # we have to check this because the filename may have a directory component
            # create the directory if needed. This should probably have some error
            # checking code
            $outputDir = split-path $outputFile
            if ( ! ( test-path $outputDir )) 
            { 
                new-item -type directory $outputDir | out-null 
            }
            if ( $verbose ) { Write-Verbose "Creating resource file $outputFile" }
            $fs = new-object io.filestream ("$outputFile"),OpenOrCreate
            $result = $fs.write($buffer,0,$buffer.length)
            $fs.close()
            $fs.dispose()    
            # tidy up
        }
    }
    
    # this function retrieves the filename
    function Get-MPResourceFileName ( $mp, $key )
    {
        # use reflection to get call the method
        $Method = $TYPEOFMP.GetMethod("GetResource")
        $genericMethod = $Method.MakeGenericMethod($TYPEOFMPR)
        $resource = $genericMethod.Invoke($mp,$key)
        $resource.FileName
    }

}
# for each object that is passed to the script
Process
{
    $paths = (resolve-path $fullname).path
    foreach($path in $paths)
    {
        # only act on files with the proper extension
        if ( ([io.fileinfo]$path).Extension -ne ".mpb" ) 
        { 
            write-error "`nERROR: $path must end with '.mpb'"
            continue
        }
        $mpb = $BUNDLEREADER.Read($path,$EMG)
        # if the mponly parameter is used, just return the management packs
        if ( $mponly ) 
        { 
            if ( $PSCmdlet.ShouldProcess("$fullname"))
            {
                $mpb.ManagementPacks 
            }
        }
        else
        {
            # for each management pack in the bundle, get the resources
            $mpb.ManagementPacks | %{
                $ManagementPack = $_
                $MPName = $ManagementPack.Name
                # use the export-SCSMManagementPack cmdlet to export the MP
                if ($PSCmdlet.ShouldProcess($ManagementPack.Name))
                {
                    if ( $verbose ) { Write-Verbose "Exporting MP '${MPName}'" }
                    $ManagementPack | export-SCSMManagementpack -targ $PWD
                    # now get the streams
                    $streams = $mpb.GetStreams($ManagementPack)
                    # only create the directory if there are actual streams that
                    # we need to save off
                    if ( $streams.count -gt 0)
                    { 
                        if ( $verbose ) { Write-Verbose " Exporting resources for '${MPName}'" }
                        # save the resources in the directory "$MPNAME_Resources"
                        $ResourceDir = "${MPName}_Resources"
                        if (!(test-path ${ResourceDir}))
                        { 
                            # create the directory if it's not there
                            new-item -type directory ${ResourceDir}|out-null
                        }
                        # we need the full path for the Export process which needs a path
                        $ResourceDirFullName = (Resolve-Path ${ResourceDir}).Path
                        # now go export the resources
                        $keys = $streams.Keys
                        foreach ( $key in $keys )
                        {
                            $ResourceFileName = Get-MPResourceFileName $ManagementPack $Key
                            Export-MPResource "$ResourceDirFullName" "$ResourceFileName" $streams.Item($key)
                        }
                    }
                }
            }  
        }
    }
}
<#
.SYNOPSIS
    Export the contents of a management pack bundle
.DESCRIPTION
    The cmdlet takes a management pack bundle file and exports the management
    pack as well as the resources associated with the management pack. The
    management packs are placed in the current directory and the resources
    are placed in a directory named <managementpack>_Resources. Any directories
    needed by the resources are created. This means that if the resource path
    indicated by the filename property of the resource contains a directory,
    that directory will be created as well.
.PARAMETER fullname
    The fullname of the management pack bundle file
.PARAMETER mponly
    When this parameter is used, the cmdlet returns only the management pack
    objects which are contained within the management pack bundle file. It
    does not extract the management packs nor the associated resources.
.PARAMETER whatif
    When -whatif is used, no contents are extracted.
.PARAMETER verbose
    When -verbose is used, the name of the management pack and resources
    are written as verbose statements.
.EXAMPLE
ls *.mpb | Export-BundleContents
.EXAMPLE
ls *.mpb | Export-BundleContents -mponly
.INPUTS
    A management pack bundle, this can be piped to the cmdlet or provided
    as a parameter value
.OUTPUTS
    When used with the 'mponly' parameter, management pack objects are
    emited. By default, no output is produced by this script.
.LINK
#>