Public/Start-DPGroupContentDistribution.ps1

function Start-DPGroupContentDistribution {
    <#
    .SYNOPSIS
        Distributes objects to a given distribution point group.
         
        The function can accept input object from Get-DPContent, by manually specifying -ObjectID and -ObjectType or by using -Folder where it will distribute all objects for .pkgx files found in said folder.
    .PARAMETER InputObject
        A PSObject type "PSCMContentMgmt" generated by Get-DPContent
    .PARAMETER DistributionPointGroup
        Name of distribution point group you want to distribute objects to.
    .PARAMETER ObjectID
        Unique ID of the content object you want to distribute.
 
        For Applications the ID must be the CI_ID value whereas for all other content objects the ID is PackageID.
 
        When using this parameter you must also use ObjectType.
    .PARAMETER ObjectType
        Object type of the content object you want to distribute.
 
        Can be one of the following values: "Package", "DriverPackage", "DeploymentPackage", "OperatingSystemImage", "OperatingSystemInstaller", "BootImage", "Application".
 
        When using this parameter you must also use ObjectID.
    .PARAMETER Folder
        For all .pkgx files in this folder that use the following naming convention "<ObjectType>_<ObjectID>.pkgx", distribute the <ObjectID> of type <ObjectType> to -DistributionPoint.
 
        This can be useful if you have a folder filled with .pkgx files, generated by Export-DPContent, and want to distribute those objects to a distribution point.
    .PARAMETER SiteServer
        It is not usually necessary to specify this parameter as importing the PSCMContentMgr module sets the $CMSiteServer variable which is the default value for this parameter.
         
        Specify this to query an alternative server, or if the module import process was unable to auto-detect and set $CMSiteServer.
    .PARAMETER SiteCode
        Site code of which the server specified by -SiteServer belongs to.
         
        It is not usually necessary to specify this parameter as importing the PSCMContentMgr module sets the $CMSiteCode variable which is the default value for this parameter.
         
        Specify this to query an alternative site, or if the module import process was unable to auto-detect and set $CMSiteCode.
    .EXAMPLE
        PS C:\> Compare-DPGroupContent -Source "London DPs" -Target "Mancester DPs" | Start-DPGroupContentDistribution -DistributionPointGroup "Mancester DPs" -WhatIf
 
        Compares the missing content objects in group Manchester DPs compared to "London DPs", and distributes them to distribution point group Manchester DPs.
    .EXAMPLE
        PS C:\> Start-DPGroupContentDistribution -Folder "E:\exported" -DistributionPointGroup "London DPs" -WhatIf
 
        For all .pkgx files in folder "E:\exported" that use the following naming convention "<ObjectType>_<ObjectID>.pkgx", distributes them to distribution point group "London DPs".
    .EXAMPLE
        PS C:\> Start-DPGroupContentDistribution -ObjectID ACC00007 -ObjectType Package -DistributionPointGroup "London DPs" -WhatIf
         
        Nothing more than a wrapper for Start-CMContentDistribution. Distributes package ACC00007 to distribution point group "London DPs".
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")]
    param (
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName="InputObject")]
        [PSTypeName('PSCMContentMgmt')]
        [PSCustomObject]$InputObject,

        [Parameter(Mandatory, ParameterSetName="Properties")]
        [ValidateNotNullOrEmpty()]
        [String]$ObjectID,

        [Parameter(Mandatory, ParameterSetName="Properties")]
        [ValidateSet("Package","DriverPackage","DeploymentPackage","OperatingSystemImage","OperatingSystemInstaller","BootImage","Application")]
        [SMS_DPContentInfo]$ObjectType,

        [Parameter(Mandatory, ParameterSetName="Folder")]
        [ValidateScript({
            if (!([System.IO.Directory]::Exists($_))) {
                throw "Invalid path or access denied"
            } elseif (!($_ | Test-Path -PathType Container)) {
                throw "Value must be a directory, not a file"
            } else {
                return $true
            }
        })]
        [String]$Folder,

        [Parameter(ParameterSetName="InputObject")]
        [Parameter(Mandatory, ParameterSetName="Properties")]
        [Parameter(Mandatory, ParameterSetName="Folder")]
        [ValidateNotNullOrEmpty()]
        [String]$DistributionPointGroup,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [String]$SiteServer = $CMSiteServer,
        
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [String]$SiteCode = $CMSiteCode
    )
    begin {
        switch ($null) {
            $SiteCode {
                Write-Error -Message "Please supply a site code using the -SiteCode parameter" -Category "InvalidArgument" -ErrorAction "Stop"
            }
            $SiteServer {
                Write-Error -Message "Please supply a site server FQDN address using the -SiteServer parameter" -Category "InvalidArgument" -ErrorAction "Stop"
            }
        }

        $TargetDPGroup = $DistributionPointGroup

        if ($PSCmdlet.ParameterSetName -ne "InputObject") {
            $InputObject = [PSCustomObject]@{
                ObjectID               = $ObjectID
                ObjectType             = $ObjectType
                DistributionPointGroup = $TargetDPGroup
            }
        }

        if ($PSCmdlet.ParameterSetName -eq "Folder") {
            $Files = Get-ChildItem -Path $Folder -Filter "*.pkgx"

            try {
                Resolve-DPGroup -Name $TargetDPGroup -SiteServer $SiteServer -SiteCode $SiteCode
            }
            catch {
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }

        $OriginalLocation = (Get-Location).Path

        if ($null -eq (Get-PSDrive -Name $SiteCode -PSProvider "CMSite" -ErrorAction "SilentlyContinue")) {
            $null = New-PSDrive -Name $SiteCode -PSProvider "CMSite" -Root $SiteServer -ErrorAction "Stop"
        }

        Set-Location ("{0}:\" -f $SiteCode) -ErrorAction "Stop"
    }
    process {
        try {
            switch ($PSCmdlet.ParameterSetName) {
                "Folder" {
                    foreach ($File in $Files) {
                        if ($File.Name -match "^(?<ObjectType>0|3|5|257|258|259|512)_(?<ObjectID>[A-Za-z0-9]+)\.pkgx$") {
                            $InputObject = [PSCustomObject]@{
                                ObjectID   = $Matches.ObjectID
                                ObjectType = $Matches.ObjectType
                            }
        
                            $result = @{
                                PSTypeName = "PSCMContentMgmtDistribute" 
                                ObjectID   = $InputObject.ObjectID
                                ObjectType = [SMS_DPContentInfo]$InputObject.ObjectType
                                Message    = $null
                            }

                            $Command = 'Start-CMContentDistribution -{0} "{1}" -DistributionPointGroupName "{2}" -ErrorAction "Stop"' -f [SMS_DPContentInfo_CMParameters][SMS_DPContentInfo]$InputObject.ObjectType, $InputObject.ObjectID, $TargetDPGroup
                            $ScriptBlock = [ScriptBlock]::Create($Command)
                            try {
                                if ($PSCmdlet.ShouldProcess(
                                    ("Would distribute '{0}' ({1}) to '{2}'" -f $InputObject.ObjectID, [SMS_DPContentInfo]$InputObject.ObjectType, $TargetDPGroup),
                                    "Are you sure you want to continue?",
                                    ("Distributing '{0}' ({1}) to '{2}'" -f $InputObject.ObjectID, [SMS_DPContentInfo]$InputObject.ObjectType, $TargetDPGroup))) {
                                        Invoke-Command -ScriptBlock $ScriptBlock -ErrorAction "Stop"
                                        $result["Result"] = "Success"
                                }
                                else {
                                    $result["Result"] = "No change"
                                }
                            }
                            catch {
                                Write-Error -ErrorRecord $_
                                $result["Result"] = "Failed"
                                $result["Message"] = $_.Exception.Message
                            }
                            
                            if (-not $WhatIfPreference) { [PSCustomObject]$result }
                        }
                        else {
                            Write-Warning ("Skipping '{0}'" -f $File.Name)
                        }
                    }
                }
                default {
                    foreach ($Object in $InputObject) {
                        switch ($true) {
                            ($LastDPGroup -ne $Object.DistributionPointGroup -And -not $PSBoundParameters.ContainsKey("DistributionPointGroup")) {
                                $TargetDPGroup = $Object.DistributionPointGroup
                            }
                            ($LastDPGroup -ne $TargetDPGroup) {
                                try {
                                    Resolve-DPGroup -Name $TargetDPGroup -SiteServer $SiteServer -SiteCode $SiteCode
                                }
                                catch {
                                    Write-Error -ErrorRecord $_
                                    return
                                }
                                
                                $LastDPGroup = $TargetDPGroup
                            }
                            default {
                                $LastDPGroup = $TargetDPGroup
                            }
                        }

                        $result = @{
                            PSTypeName = "PSCMContentMgmtDistribute" 
                            ObjectID   = $Object.ObjectID
                            ObjectType = $Object.ObjectType
                            Message    = $null
                        }
        
                        $Command = 'Start-CMContentDistribution -{0} "{1}" -DistributionPointGroupName "{2}" -ErrorAction "Stop"' -f [SMS_DPContentInfo_CMParameters][SMS_DPContentInfo]$Object.ObjectType, $Object.ObjectID, $TargetDPGroup
                        $ScriptBlock = [ScriptBlock]::Create($Command)
                        try {
                            if ($PSCmdlet.ShouldProcess(
                                ("Would distribute '{0}' ({1}) to '{2}'" -f $Object.ObjectID, $Object.ObjectType, $TargetDPGroup),
                                "Are you sure you want to continue?",
                                ("Distributing '{0}' ({1}) to '{2}'" -f $Object.ObjectID, $Object.ObjectType, $TargetDPGroup))) {
                                    Invoke-Command -ScriptBlock $ScriptBlock -ErrorAction "Stop"
                                    $result["Result"] = "Success"
                            }
                            else {
                                $result["Result"] = "No change"
                            }
                        }
                        catch {
                            Write-Error -ErrorRecord $_
                            $result["Result"] = "Failed"
                            $result["Message"] = $_.Exception.Message
                        }
                        
                        if (-not $WhatIfPreference) { [PSCustomObject]$result }
                    }
                }
            }
        }
        catch {
            Set-Location $OriginalLocation 
            $PSCmdlet.ThrowTerminatingError($_)
        }
    }
    end {
        Set-Location $OriginalLocation
    }
}