Scripts/New-MPBFile.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
# New-MPBFile.ps1
# this takes files (.mp or .xml) and creates a .mpb file
param (
    $mpFile = $( throw "Must have mpfile" ),
    [string]$mpbname = "testmpb",
    $computername = "localhost",
    [switch]$useFileStore,
    [switch]$debug
    )

# VARIABLES NEEDED BY SCRIPT
$VerbosePreference = "continue"
$SMDLL    = "Microsoft.EnterpriseManagement.Core"
$SMPKG    = "Microsoft.EnterpriseManagement.Packaging"
$MPTYPE   = "Microsoft.EnterpriseManagement.Configuration.ManagementPack"
$MRESTYPE = "Microsoft.EnterpriseManagement.Configuration.ManagementPackResource"
$SIGTYPE  = "Microsoft.EnterpriseManagement.Packaging.ManagementPackBundleStreamSignature"
$FACTYPE  = "Microsoft.EnterpriseManagement.Packaging.ManagementPackBundleFactory"
$EMGTYPE  = "Microsoft.EnterpriseManagement.EnterpriseManagementGroup"
$OPEN     = [System.IO.FileMode]"Open"
$READ     = [System.IO.FileAccess]"Read"

if ( $debug ) { $debugpreference = "Continue" }

# make sure the appropriate assemblies are loaded.
$SMCORE      = [reflection.assembly]::LoadWithPartialName($SMDLL)
$SMPACKAGING = [reflection.assembly]::LoadWithPartialName($SMPKG)
$EMPTY       = $SMCORE.GetType($SIGTYPE)::Empty
$TYPEOFMP    = $SMCORE.GetType($MPTYPE)
$TYPEOFMPR   = $SMCORE.GetType($MRESTYPE)
$BFACTORY    = $SMPACKAGING.GetType($FACTYPE)

# Functions
# Invoke-GenericMethod
# allows scripts to call generic methods.
# arguments
# mytype - the type inspect for the needed method
# mymethod - the method name
# typearguments - an array of types used by MakeGenericMethod
# object - the object against which invoke is called
# parameters - any parameters needed by invoke
# it returns whatever is returned by invoke
function Invoke-GenericMethod
{
    param (
        [type]$mytype, 
        [string]$mymethod, 
        $TypeArguments, 
        $object, 
        [object[]]$parameters = $null 
        )
    $Method = $mytype.GetMethod($mymethod)
    $genericMethod = $Method.MakeGenericMethod($TypeArguments)
    $genericMethod.Invoke($object,$parameters)
}

# Get-Resources
# this function retrieves resources from the MP. Because our GetResources API
# uses generics, it's a bit tricky to call
# it returns a hash table of the stream, and the name for each resource
# it takes a Management Pack object
function Get-Resources
{
    param ( $mpObject )
    invoke-GenericMethod $TYPEOFMP "GetResources" $TYPEOFMPR $mpObject | %{  
        # check to see if we could find the file
        $filename = $_.filename
        $fullname = (resolve-path $_.FileName -ea SilentlyContinue).path
        if ( ! $fullname ) 
        { 
            write-host -for red "
    WARNING:
    Cannot find resource: $filename
    Skipping this resource, your MPB will probably not import
    Make sure that the resources are in the same directory as the MP"

        }
        else
        {
            $stream = new-object io.filestream $fullname,$OPEN,$READ
            @{ Stream = $stream; Name = $_.Name }
        }
    }
}

# Start
# Collect all the mps to add to the mpb!
$mpfileArray = @()
foreach ( $file in $mpFile )
{
    foreach ( $item in resolve-path $file )
    {
        if ( $item.path ) 
        { 
            $mpfileArray += $item.path
        }
        else
        {
            Write-Host -for red "ERROR: Cannot find file $item, skipping" 
        }
    }
}

# Check to see if we have any management packs, if not, exit.
if ( $mpFileArray.Count -eq 0 )
{
    Write-Host -for red "Error: No files to add"
    exit
}

if ( $useFileStore )
{
    # if we're using a filestore, we need to create it by getting the files
    # from the local disk
    $EMG = new-object Microsoft.EnterpriseManagement.Configuration.IO.ManagementPackFileStore
    $EMG.AddDirectory(([io.path]::GetDirectoryName($myInvocation.mycommand.definition) + "\Library"))
    $mpFileArray|sort-object -uniq|%{ $EMG.AddDirectory([io.path]::GetDirectoryName($_)) }
    $EMG.Directories | %{ write-debug "Add to MPFileStore: $_" }
}
else
{
    # we need a connection to the server when we start creating
    # the management pack objects
    $EMG = new-object $EMGTYPE $computername
}
# In order to create .mpb, we need to create one
# we'll use the BundleFactory for this
$BUNDLE = $BFACTORY::CreateBundle()
# we'll keep a collection of all the resources that we open
$AllResources = @()
foreach($mpfilepath in $mpfileArray)
{
    # This should handle creating mpb from a local file store.
    # For now, just create the mp object using the EnterpriseManagementGroup
    $theMP = new-object $MPTYPE $mpfilepath,$EMG
    Write-Verbose ("Adding MP: " + $theMP.Name)
    $BUNDLE.AddManagementPack($theMP) 
    # Add the resources if any are associated with the MP
    $Resources = Get-Resources $theMP
    # Add the resources for this MP to the collection
    $AllResources += $Resources
    if ( $Resources )
    {
        $Resources  | %{ 
            Write-Verbose ("Adding stream: " + $_.Name)
            $BUNDLE.AddResourceStream($theMP,$_.Name,$_.Stream,$EMPTY) 
        }
    }
}

# WRITE THE mpb
# First we need a BundleWriter
$bundleWriter = $BFACTORY::CreateBundleWriter(${PWD})
# then we can write out the .mpb
$mpbfullpath = $bundleWriter.Write($BUNDLE,$mpbname)
write-verbose "wrote mpb: $mpbfullpath"
# Cleanup the resources
if ( $AllResources )
{
    $AllResources | %{ if ( $_.Stream ) { $_.Stream.Close(); $_.Stream.Dispose() } }
}