Public/Update-ConfigMgrApplicationDeploymentTypeScript.ps1

Function Update-ConfigMgrApplicationDeploymentTypeScript
{
    [CmdletBinding(SupportsShouldProcess = $True,ConfirmImpact = 'High')]
    
    Param(
        [Parameter(Mandatory = $True)]
        [System.IO.FileInfo]$ScriptPath
    )
    
    DynamicParam{
        $CMSite = Get-ConfigMgrSite
        
        $RuntimeParamDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
        
        $DynamicParameterOptions = @(
            @{
                Name                = 'ApplicationName'
                Mandatory           = $True
                ParameterDictionary = $RuntimeParamDictionary
                ValidateSetOptions  = Get-WmiObject -ComputerName $CMSite.SiteServer -Namespace "root\SMS\site_$($CMSite.SiteCode)" -Class SMS_Application -Filter 'IsLatest=1' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty LocalizedDisplayName
            }, 
            @{
                Name                = 'DeploymentTypeName'
                Mandatory           = $True
                ParameterDictionary = $RuntimeParamDictionary
                ValidateSetOptions  = Get-WmiObject -ComputerName $CMSite.SiteServer -Namespace "root\SMS\site_$($CMSite.SiteCode)" -Class SMS_DeploymentType -Filter 'IsLatest=1' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty LocalizedDisplayName
            }
        )
        
        Foreach($Param in $DynamicParameterOptions)
        {
            $null = New-DynamicParameter @Param
        }
        
        $RuntimeParamDictionary
    }
    
    Begin{
        $ApplicationName = $PSBoundParameters['ApplicationName']
        
        $DeploymentTypeName = $PSBoundParameters['DeploymentTypeName']
    
        # Ensure FileSystem location is used as Get-Content functionality used below only functions with the FileSystem PS Provider.
        Push-Location -Path C:\Windows\System32
    
        $EncodedScriptBeginTag = "`r`n`r`n# ENCODEDSCRIPT # Begin Configuration Manager encoded script block # "

        $EncodedScriptEndTag = " # ENCODEDSCRIPT# End Configuration Manager encoded script block`r`n`r`n"
    }

    Process{
        If(-not $ScriptPath.Exists)
        {
            Throw "Script file '$ScriptPath' does not exist."
        }
        
        # Obtain script contents in both text and binary form. Binary form is necessary for proper parsing by ConfigMgr client.
        $Script = Get-Content -Path $ScriptPath -Raw -ErrorAction Stop
        $BinaryScript = Get-Content -Path $ScriptPath -Encoding byte -Raw -ErrorAction Stop
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        
        # Connect to ConfigMgr site so ConfigurationManager cmdlets and functions can be used.
        Connect-ConfigMgr
        
        # Choose application deployment to update
        $DeploymentType = Get-CMDeploymentType -ApplicationName $ApplicationName -DeploymentTypeName $DeploymentTypeName
        
        If($null -eq $DeploymentType)
        {
            Throw 'Could not find application or deployment type matching input parameters.'
        }
        
        If($DeploymentType.Technology -notmatch 'MSI|Script')
        {
            Throw "Can only modify MSI & Script deployment types. Deployment type was of type '$($DeploymentType.Technology)'"
        }
    
        If($PSCmdlet.ShouldProcess($($DeploymentType.LocalizedDisplayName)))
        {   
            # Add script text to StringBuilder
            # This part isn't completely necessary but we want to make sure anybody casually looking at this in the admin console will know that editing it is a bad idea
            $null = $StringBuilder.AppendLine('## WARNING!! DO NOT MANUALLY EDIT THIS SCRIPT IN THE ADMINISTRATOR CONSOLE.')
            $null = $StringBuilder.AppendLine('## IT WILL BREAK THE SCRIPT EXECUTION ON THE CLIENT.')
            $null = $StringBuilder.AppendLine()
            $null = $StringBuilder.Append($Script)
        
            # Append binary blob including begin/end tags to StringBuilder.
            # This part is absolutely critical as it is this blob that will be processed by the ConfigMgr client during detection.
            $null = $StringBuilder.Append($EncodedScriptBeginTag)
            $null = $StringBuilder.Append([Convert]::ToBase64String($BinaryScript))
            $null = $StringBuilder.Append($EncodedScriptEndTag)
            
            $ScriptContent = $StringBuilder.ToString()
            
            # Update detection script with script contents in both text and binary form
            $DeploymentType | Set-CMDeploymentType -MsiOrScriptInstaller -ScriptType PowerShell -ScriptContent $ScriptContent -DetectDeploymentTypeByCustomScript -ErrorAction Stop
        }
    }
    
    End{
        Pop-Location
    }
}