Scripts/Export-BundleContents.ps1

[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
#>