SCCM Software Update Group to Baseline Tool

Overview

I created this tool, SCCM SUG to Configuration Baseline, to allow you to easily convert an SCCM Software Upgrade Group to a Configuration Baseline. This would most likely be used if you wanted to target a specific Client Setting or Application based on computers which fail compliance for a particular Software Update Group to a collection. Although this might already be possible to do by selecting the software updates within a Software Update Group and creating a Configuration Baseline as a result, this tool can easily automate the process on a schedule in the background.

This tool gathers Software Updates within a Software Update Group via queries to WMI on your SCCM site server, then builds a Configuration Baseline XML and XML Resource File (.RESX) with those items that are used to import back into SCCM. The tool can either compress them as a .CAB file for direct importing via the SCCM Console GUI or import them through a WMI instance POST.

Installing the Tool

Download the required file below and unzip them into a directory of your choosing.

Once downloaded, edit New-DGMSCCMSUGBaseline.ps1 and update the line at the very end of the script to include your SCCM Site Server (ProviderMachineName), your siteCode and the Software Update Group Name (SUGName).


New-DGMSCCMSUGBaseline -ProviderMachineName SCCMSERVER001 -siteCode XXX -SUGName "Software Upgrade Group Name"

You can also specify a FileSavePath which is the location the XML and RESX and CAB files will save if you would like to manipulate them or import them manually.


-fileSavePath "C:\users\username\Desktop\"

Additionally, the tool will require and import the SCCM module \ConfigurationManager.psd1. This module is included when you install the SCCM Console, so typically this script needs to be run on a computer that has the SCCM Console installed, and from an account that can make WMI queries against the SCCM Site Server.

Using the Tool

To start the tool, run the New-DGMSCCMSUGBaseline.ps1 script within PowerShell. Remember to include your desired Software Update Group name as the SUGName argument. You can also pipe the SUGName into the tool by running it as:


"Software Upgrade Group Name" | New-DGMSCCMSUGBaseline -ProviderMachineName SCCMSERVER001 -siteCode XXX

This could be useful if you’d like to automate or iterate through a group of Software Update Groups such as this example which would convert every one of your Software Update Groups to a Configuration Baseline:


$SoftwareUpdateGroups = Get-CMSoftwareUpdateGroup | Select Name

Foreach  ($SoftwareUpdateGroup in $SoftwareUpdateGroups){
   $SoftwareUpdateGroup | New-DGMSCCMSUGBaseline -ProviderMachineName SCCMSERVER001 -siteCode XXX
}

If the tool was successful, you will see it create the importation files in the directory you chose (if none was chosen, look in C:\SUG):

Additionally in SCCM you will see a new Configuration Baseline based off the Software Update Group You Specified:

CB.Software.Update.(SVR – 1 – Pilot Server Updates – Net Framework 2018-02-13 07:50:09)

If a Configuration Baseline already exists you will be prompted if would like to replace it. If you’d like to automatically replacing the baseline without prompting you, replace this if logic within the Get-DGMSCCMWMISUGConfigurationBaselineDetails Function:


#A SUG Baseline Already Exists for a Valid SUG Group Name. Let's determine from the user if this should be replaced
if ((Read-Host $ProviderMachineName ": A Baseline for $SUGName already exists. Do you want to proceed? (Y/N)").Tolower() -eq "n")

With something that will never occur, such as


if ($x = “theskyisblue”)

Understanding the Exported XML

When the tool is run, it will create an XML of the Software Updates that will be imported back into SCCM. This is an XML in the same format that would be inside of a Configuration Baseline CAB file if you to export one from the Console. It can be useful to understand how this file works if you’d like to manipulate the one I create with this tool, or one that is created from a Configuration Baseline export in the console:

PowerShell Function: New-DGMSCCMSUGBaseline.ps1


function New-DGMSCCMSUGBaseline{
<#  
.SYNOPSIS  
    Create a Configuration Baseline Based off a Software Update Group  
.DESCRIPTION  
    Create a Configuration Baseline Based off a Software Update Group 
.NOTES  
    File Name  : New-DGMSCCMSUGBaseline.ps1  
    Author     : David Maiolo - david.maiolo@gmail.com
    Version    : 2018-03-07
.LINK  
#>
 
    param(

        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        $SUGName,
        [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
        $ProviderMachineName,
        [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
        $siteCode,
        [Parameter(Position=3,Mandatory=$false,ValueFromPipeline=$false)]
        [string]$fileSavePath = "c:\SUG\"
        

    )

    #Connect to SCCM
    # Import the ConfigurationManager.psd1 module
    $module = "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
    if((Get-Module ConfigurationManager) -eq $null) {
        Write-Host Importing $module ...
        Import-Module $module -Force
    }

    # Connect to the site's drive if it is not already present
    if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
        $NewPSDrive = New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName
    }


    function Get-DGMSUGGroupID{
    <#  
    .SYNOPSIS  
        Query WMI to get Configuration ID of Software Update Group  
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$ProviderMachineName,
            [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
            [ValidateLength(3,3)]
            [String]$Sitecode,
            [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$SUGName
        )
        

        #Set SCCM WMI NameSpace
        $SCCMnameSpace = "root\SMS\SITE_$siteCode"

        #Query for Software Update Group Information
        $qry = "SELECT CI_ID FROM SMS_AuthorizationList where LocalizedDisplayName = '$SUGName'"

        try{
            $objComputerSystemProduct = Get-WmiObject -ComputerName $ProviderMachineName -Namespace $SCCMnameSpace -Query $qry
            if ($objComputerSystemProduct -eq $null){
                 Write-Host $ProviderMachineName ": An invalid SUG Group name was SUGplied. Exiting." -foregroundcolor red
                 break
            }else{
                #Write-Host $ProviderMachineName ": Succesfully queried WMI for SUG Configuration ID." -foregroundcolor green
                return $objComputerSystemProduct.CI_ID
            }
                
        }catch{
            Write-Host $ProviderMachineName ": Could NOT query WMI for SUG Configuration ID:" ($error[0]) -foregroundcolor red
            break
        }

    }

    function Get-DGMSCCMWMISUGGroupChildren{
    <#  
    .SYNOPSIS  
        Query WMI to get all Software Updates in a Software Updae Group  
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$ProviderMachineName,
            [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
            [ValidateLength(3,3)]
            [String]$Sitecode,
            [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$SUGConfigurationID
        )
        

        #Set SCCM WMI NameSpace
        $SCCMnameSpace = "root\SMS\SITE_$siteCode"

        #Query for Software Update Group Information
        $qry = "SELECT upd.* FROM SMS_SoftwareUpdate upd, SMS_CIRelation cr WHERE cr.FromCIID= $SUGConfigurationID AND cr.RelationType=1 AND upd.CI_ID=cr.ToCIID"

        try{
            $objComputerSystemProduct = Get-WmiObject -ComputerName $ProviderMachineName -Namespace $SCCMnameSpace -Query $qry
            if ($objComputerSystemProduct.Length -le 0){
                 Write-Host $ProviderMachineName ": An invalid SUG CI ID was SUGplied or no Software Updates exist in the SUG. Exiting." -foregroundcolor red
                 break
            }else{
                #Write-Host $ProviderMachineName ": Succesfully queried WMI for SUG Group Information." -foregroundcolor green
                return $objComputerSystemProduct
            }
                
        }catch{
            Write-Host $ProviderMachineName ": Could NOT query WMI for SUG Group Information:" ($error[0]) -foregroundcolor red
            break
        }

    }

    function Get-DGMSCCMWMISUGConfigurationBaselineDetails{
    <#  
    .SYNOPSIS  
        Query WMI to get Details of a Configuration Baseline  
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$ProviderMachineName,
            [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
            [ValidateLength(3,3)]
            [String]$Sitecode,
            [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$SUGName,
            [Parameter(Position=3,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGGroupChildren
        )
        
        #Build Baseline Name
        $SUGBaselineNameStart = "CB.Software.Update."
        $SUGBaselineName = $SUGBaselineNameStart + "(" + $SUGName + ")"

        #Set SCCM WMI NameSpace
        $SCCMnameSpace = "root\SMS\SITE_$siteCode"

        #Query for Software Update Group Information
        $qry = "SELECT * FROM SMS_ConfigurationBaselineInfo where LocalizedDisplayName = '$SUGBaselineName'"

        try{
            $objComputerSystemProduct = Get-WmiObject -ComputerName $ProviderMachineName -Namespace $SCCMnameSpace -Query $qry

            if ($objComputerSystemProduct -eq $null){
                #No SUG Baseline Yet Exists for a Valid SUG Group Name. Let's set one up
                Write-Host $ProviderMachineName ": No SUG Baseline Exists Yet for $SUGName. Setting up details for XML..."
                $NewBaseLine = $TRUE
		        $ScopeID = $SUGGroupChildren[0].ModelName.Substring(0,$SUGGroupChildren[0].ModelName.IndexOf("/")) -replace "Site_", "ScopeID_"
		        $BaselineLogicalName = "Baseline_" + [guid]::NewGuid().ToString()
		        $BaselineVersion = 1
            }else{
                #A SUG Baseline Already Exists for a Valid SUG Group Name. Let's determine from the user if this should be replaced
                if ((Read-Host $ProviderMachineName ": A Baseline for $SUGName already exists. Do you want to proceed? (Y/N)").Tolower() -eq "n")
		        {
			        Write-Host $ProviderMachineName ": A duplicate baseline creation has been by the user, exiting without making changes." -ForegroundColor Yellow
			        break
		        }else{
                    $BaselineCI_ID = $objComputerSystemProduct.CI_ID 
		            $BaselineCI_UniqueID = $objComputerSystemProduct.CI_UniqueID
		            
                    $NewBaseLine = $FALSE
                    $ScopeID = $BaselineCI_UniqueID.substring(0,$BaselineCI_UniqueID.indexof("/"))
		            $BaselineLogicalName = $objComputerSystemProduct.CI_UniqueID.substring($objComputerSystemProduct.CI_UniqueID.indexof("/")+1)
		            $BaselineVersion = $objComputerSystemProduct.SDMPackageVersion + 1


                     #Query for CI Information
                    $qry = "SELECT * FROM SMS_ConfigurationItem where CI_ID = $BaselineCI_ID"

                    try{
                        $CI = Get-WmiObject -ComputerName $ProviderMachineName -Namespace $SCCMnameSpace -Query $qry
                        if ($CI -eq $null){
                             Write-Host $ProviderMachineName ": CI $BaselineCI_ID does not exist, no action taken." -foregroundcolor red
                             break
                        }
                    }
                    catch{
                        Write-Host $ProviderMachineName ": Could NOT query WMI for CI ID $BaselineCI_ID :" ($error[0]) -foregroundcolor red
                        break
                    }
                    
                }
            }
            

            $result = [PSCustomObject] @{
                'NewBaseLine' = $NewBaseLine;
                'SUGBaselineName' = $SUGBaselineName;
                'ScopeID' = $ScopeID;
                'BaselineLogicalName' = $BaselineLogicalName;
                'BaselineVersion' = $BaselineVersion;
                'CI' = $CI;
            }

            return $result
               
        }catch{
            Write-Host $ProviderMachineName ": Could NOT query WMI for SUG Baseline:" ($error[0]) -foregroundcolor red
            break
        }

    }

    function New-DGMSCCMWMISUGConfigurationBaselineXML{
    <#  
    .SYNOPSIS  
        Create a new XML formatted file that will be used as a Configuration Baseline Import
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$ProviderMachineName,
            [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
            [ValidateLength(3,3)]
            [String]$Sitecode,
            [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGConfigurationBaselineDetails,
            [Parameter(Position=3,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGGroupChildren


        )

        try{

            $SUGBaselineName = $SUGConfigurationBaselineDetails.SUGBaselineName
            $ScopeID = $SUGConfigurationBaselineDetails.ScopeID
            $BaselineLogicalName = $SUGConfigurationBaselineDetails.BaselineLogicalName
            $BaselineVersion = $SUGConfigurationBaselineDetails.BaselineVersion

            $baselineXML = @"
<?xml version="1.0" encoding="utf-8"?>
<DesiredConfigurationDigest xmlns="http://schemas.microsoft.com/SystemsCenterConfigurationManager/2009/07/10/DesiredConfiguration">
  <!--Authored against the following schema version: 5-->
  <!--Automated Software Update Group XML Creation for $SUGBaselineName created from New-DGMSCCMSUGBaseline.ps1 (by c-dmaiolo)-->
  <Baseline AuthoringScopeId="$ScopeID" LogicalName="$BaselineLogicalName" Version="$BaselineVersion">
    <Annotation xmlns="http://schemas.microsoft.com/SystemsCenterConfigurationManager/2009/06/14/Rules">
      <DisplayName Text="$SUGBaselineName" />
      <Description Text="Automated Software Update Group Creation for $SUGBaselineName created from New-DGMSCCMSUGBaseline.ps1 (by c-dmaiolo)" />
    </Annotation>
    <RequiredItems />
    <ProhibitedItems />
    <OptionalItems />
    <OperatingSystems />
    <SoftwareUpdates>

"@

	foreach($SUGGroupChild in $SUGGroupChildren)
	{
		$ModelName = $SUGGroupChild.ModelName.Substring(0,$SUGGroupChildren[0].ModelName.IndexOf("/"))
		$LogicalName = $SUGGroupChild.ModelName.Substring($SUGGroupChildren[0].ModelName.IndexOf("/")+1)
		
        $baselineXML += @"
      <SoftwareUpdateBundleReference AuthoringScopeId="$ModelName" LogicalName="$LogicalName" />

"@
	}

	    $baselineXML += @"
    </SoftwareUpdates>
    <Baselines />
    <OtherConfigurationItems />
  </Baseline>
</DesiredConfigurationDigest>
"@
        return $baselineXML
    }
    catch{
        Write-Host $ProviderMachineName ": Could NOT generate a Baseline XML based off the data provided:" ($error[0]) -foregroundcolor red
    }

    }

    function Get-DGMSCCMSUGXMLResource{
    <#  
    .SYNOPSIS  
        Create a new XML formatted resource file that will be used as a Configuration Baseline Import
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
    [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGConfigurationBaselineDetails
        )

        try{

            $SUGBaselineName = $SUGConfigurationBaselineDetails.SUGBaselineName
            $ScopeID = $SUGConfigurationBaselineDetails.ScopeID
            $BaselineLogicalName = $SUGConfigurationBaselineDetails.BaselineLogicalName
            $BaselineVersion = $SUGConfigurationBaselineDetails.BaselineVersion

            $ScopeID = $ScopeID -replace "Scope",""

            $SUGResourceXML = @"
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--Automated Software Update Group XML Resource Creation for $SUGBaselineName created from New-DGMSCCMSUGBaseline.ps1 (by c-dmaiolo)-->
  <xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="$ScopeID" xml:space="preserve">
    <value>$SUGBaselineName</value>
  </data>
</root>
"@

            return $SUGResourceXML
        }
        catch{
            Write-Host $ProviderMachineName ": Could NOT create XML Resource File:" ($error[0]) -foregroundcolor red
        }

    }

    function Import-DGMSCCMWMISUGConfigurationBaselineXML{
    <#  
    .SYNOPSIS  
        Import an XML formatted file and resource file that will be become a Configuration Baseline
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        [Alias()]
        Param
        (
            [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [String]$ProviderMachineName,
            [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
            [ValidateLength(3,3)]
            [String]$siteCode,
            [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
            $DGMSCCMSUGXMLResource,
            [Parameter(Position=3,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGConfigurationBaselineXML,
            [Parameter(Position=4,Mandatory=$true,ValueFromPipeline=$false)]
            $SUGConfigurationBaselineDetails
        )

        
        try{

            $NewBaseLine = $SUGConfigurationBaselineDetails.NewBaseLine
            $SUGBaselineName = $SUGConfigurationBaselineDetails.SUGBaselineName
            $ScopeID = $SUGConfigurationBaselineDetails.ScopeID
            $BaselineLogicalName = $SUGConfigurationBaselineDetails.BaselineLogicalName
            $BaselineVersion = $SUGConfigurationBaselineDetails.BaselineVersion

	        if ($NewBaseLine -eq $TRUE)
	        {
                Write-Host $ProviderMachineName ": Building Details for New Baseline: $SUGBaselineName..."


                 #Query for CI Information

                $LD = [PSCustomObject] @{
                'LocaleID' = 1033;
                'LocalizedData' = $DGMSCCMSUGXMLResource;
                }


                $CI = [PSCustomObject] @{
                    'SDMPackageLocalizedData' = $LD;
                    'IsBundle' = $false;
                    'IsExpired' = $false;
                    'IsUserDefined' = $true
                    'ModelID' = 16777367
                    'PermittedUses' = 0
                    'PlatformCategoryInstance_UniqueIDs' = "Platform:C92857DF-9FD1-4FAD-BAA1-BE9FAD4B4F74"
                    'SDMPackageXML' = $SUGConfigurationBaselineXML;
                }

	        }else{
                $CI = $SUGConfigurationBaselineDetails.CI

                Write-Host $ProviderMachineName ": Building Details for Pre-Existing Baseline: $SUGBaselineName..."
            }
	
	        if ($NewBaseLine -eq $FALSE) {
                Write-Host $ProviderMachineName ": Creating baseline..."
                $NameSpace = "root\SMS\SITE_$siteCode"
                Set-WmiInstance -ComputerName $ProviderMachineName -Namespace $NameSpace -Class SMS_ConfigurationItem -PutType Create -Argument $CI
            }else {
                Write-Host $ProviderMachineName ": Updating baseline..."
                $NameSpace = "root\SMS\SITE_$siteCode"
                Set-WmiInstance -ComputerName $ProviderMachineName -Namespace $NameSpace -Class SMS_ConfigurationItem -PutType UpdateOnly -Argument $CI
            }

            Write-Host $ProviderMachineName ": Baseline Import Succesful: $SUGBaselineName" -ForegroundColor Green
        }
        catch{
            Write-Host $ProviderMachineName ": Could NOT import XML data or XML Resource data for Baseline $SUGBaselineName into SCCM:" ($error[0]) -foregroundcolor red
        }
    }

    function New-CabinetFile {
    <#  
    .SYNOPSIS  
        Create a cabinet file using a list of files as the source. This is used best for importing into SCCM
    .NOTES  
        File Name  : New-DGMSCCMSUGBaseline.ps1  
        Author     : David Maiolo - david.maiolo@gmail.com
        Version    : 2018-03-07
    .LINK  
    #>
        [CmdletBinding()]
        Param(
            [Parameter(HelpMessage="Target .CAB file name.", Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
            [ValidateNotNullOrEmpty()]
            [Alias("FilePath")]
            [string] $Name,
 
            [Parameter(HelpMessage="File(s) to add to the .CAB.", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
            [ValidateNotNullOrEmpty()]
            [Alias("FullName")]
            [string[]] $File,
 
            [Parameter(HelpMessage="Default intput/output path.", Position=2, ValueFromPipelineByPropertyName=$true)]
            [AllowNull()]
            [string[]] $DestinationPath,
 
            [Parameter(HelpMessage="Do not overwrite any existing .cab file.")]
            [Switch] $NoClobber
            )
 
        Begin { 
    
            ## If $DestinationPath is blank, use the current directory by default
            if ($DestinationPath -eq $null) { $DestinationPath = (Get-Location).Path; }
            Write-Verbose "New-CabinetFile using default path '$DestinationPath'.";
            Write-Verbose "Creating target cabinet file '$(Join-Path $DestinationPath $Name)'.";
 
            ## Test the -NoClobber switch
            if ($NoClobber) {
                ## If file already exists then throw a terminating error
                if (Test-Path -Path (Join-Path $DestinationPath $Name)) { throw "Output file '$(Join-Path $DestinationPath $Name)' already exists."; }
            }
 
            ## Cab files require a directive file, see 'http://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax' for more info
            $ddf = ";*** MakeCAB Directive file`r`n";
            $ddf += ";`r`n";
            $ddf += ".OPTION EXPLICIT`r`n";
            $ddf += ".Set CabinetNameTemplate=$Name`r`n";
            $ddf += ".Set DiskDirectory1=$DestinationPath`r`n";
            $ddf += ".Set MaxDiskSize=0`r`n";
            $ddf += ".Set Cabinet=on`r`n";
            $ddf += ".Set Compress=on`r`n";
            ## Redirect the auto-generated Setup.rpt and Setup.inf files to the temp directory
            $ddf += ".Set RptFileName=$(Join-Path $ENV:TEMP "setup.rpt")`r`n";
            $ddf += ".Set InfFileName=$(Join-Path $ENV:TEMP "setup.inf")`r`n";
 
            ## If -Verbose, echo the directive file
            if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
                foreach ($ddfLine in $ddf -split [Environment]::NewLine) {
                    Write-Verbose $ddfLine;
                }
            }
        }
 
        Process {
   
            ## Enumerate all the files add to the cabinet directive file
            foreach ($fileToAdd in $File) {
        
                ## Test whether the file is valid as given and is not a directory
                if (Test-Path $fileToAdd -PathType Leaf) {
                    Write-Verbose """$fileToAdd""";
                    $ddf += """$fileToAdd""`r`n";
                }
                ## If not, try joining the $File with the (default) $DestinationPath
                elseif (Test-Path (Join-Path $DestinationPath $fileToAdd) -PathType Leaf) {
                    Write-Verbose """$(Join-Path $DestinationPath $fileToAdd)""";
                    $ddf += """$(Join-Path $DestinationPath $fileToAdd)""`r`n";
                }
                else { Write-Warning "File '$fileToAdd' is an invalid file or container object and has been ignored."; }
            }       
        }
 
        End {
    
            $ddfFile = Join-Path $DestinationPath "$Name.ddf";
            $ddf | Out-File $ddfFile -Encoding ascii | Out-Null;
 
            Write-Verbose "Launching 'MakeCab /f ""$ddfFile""'.";
            $makeCab = Invoke-Expression "MakeCab /F ""$ddfFile""";
 
            ## If Verbose, echo the MakeCab response/output
            if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
                ## Recreate the output as Verbose output
                foreach ($line in $makeCab -split [environment]::NewLine) {
                    if ($line.Contains("ERROR:")) { throw $line; }
                    else { Write-Verbose $line; }
                }
            }
 
            ## Delete the temporary .ddf file
            Write-Verbose "Deleting the directive file '$ddfFile'.";
            Remove-Item $ddfFile;
 
            ## Return the newly created .CAB FileInfo object to the pipeline
            Get-Item (Join-Path $DestinationPath $Name);
        }
    }


    $DGMSUGGroupID = Get-DGMSUGGroupID -ProviderMachineName $ProviderMachineName -Sitecode $siteCode -SUGName $SUGName
    $DGMSCCMWMISUGGroupChildren = Get-DGMSCCMWMISUGGroupChildren -ProviderMachineName $ProviderMachineName -Sitecode $siteCode -SUGConfigurationID $DGMSUGGroupID
    $DGMSCCMWMISUGConfigurationBaselineDetails = Get-DGMSCCMWMISUGConfigurationBaselineDetails -Sitecode $siteCode -SUGName $SUGName -ProviderMachineName $ProviderMachineName -SUGGroupChildren $DGMSCCMWMISUGGroupChildren
    $DGMSCCMSUGXMLResource = Get-DGMSCCMSUGXMLResource -SUGConfigurationBaselineDetails $DGMSCCMWMISUGConfigurationBaselineDetails
    $DGMSCCMWMISUGConfigurationBaselineXML = New-DGMSCCMWMISUGConfigurationBaselineXML -ProviderMachineName $ProviderMachineName -Sitecode $siteCode -SUGConfigurationBaselineDetails $DGMSCCMWMISUGConfigurationBaselineDetails -SUGGroupChildren $DGMSCCMWMISUGGroupChildren
    

    #Create Resource Files and Cab Files for Import

    $filePath = "c:\SUG\"

    $SUGGroupFileName = $SUGName -replace '[^a-zA-Z0-9]', ''

    $XMLFile = "$SUGGroupFileName.xml"
    $XMLResourceFile = "$SUGGroupFileName.resx"
    $CabinetFile = "$SUGGroupFileName.cab"

    $XMLFilePath = Join-Path $filePath $XMLFile
    $XMLResourceFilePath = Join-Path $filePath $XMLResourceFile
    $CabinetFilePath = Join-Path $filePath $CabinetFile

    $DGMSCCMWMISUGConfigurationBaselineXML | Out-File -FilePath $XMLFilePath
    $DGMSCCMSUGXMLResource | Out-File -FilePath $XMLResourceFilePath

    New-CabinetFile -Name $CabinetFile -File $XMLFilePath,$XMLResourceFilePath -DestinationPath $filePath

    #Import-DGMSCCMWMISUGConfigurationBaselineXML -ProviderMachineName $ProviderMachineName -siteCode $siteCode -DGMSCCMSUGXMLResource $DGMSCCMSUGXMLResource -SUGConfigurationBaselineXML $DGMSCCMWMISUGConfigurationBaselineXML -SUGConfigurationBaselineDetails $DGMSCCMWMISUGConfigurationBaselineDetails
    
    # Set the current location to be the site code and import the baseline
    Set-Location "$($SiteCode):\"
    Import-CMBaseline -FileName $CabinetFilePath -Force

    $XMLFile
    $XMLResourceFile
    $CabinetFile
}


New-DGMSCCMSUGBaseline -ProviderMachineName SCCMSERVER001 -siteCode XXX -SUGName "Software Upgrade Group Name" -fileSavePath "C:\users\you\Desktop\"

Leave a Comment

Your email address will not be published.