ConfigMgr 2012 – Change Application Source Path

Big thanks to Angel Redondo for helping out with this.

Changing the source path for packages in SCCM 2007 was pretty easy over the SMSProvider.
It’s a bit different in ConfigMgr 2012.

Looking through the WMI Classes you’ll find SMS_Application, SMS_DeploymentType, and eventually SMS_Content. This last one has the source path for the application content but you’ll soon find out you can’t manipulate this because it is a system class and only allowed to be used by the provider itself.

What you need to do is leverage the dlls provided with the AdminConsole. Then you need to understand that information in ConfigMgr is handled completely differently from 2007. That being data is stored in XML format in WMI and SQL to allow for SQL Replication to look after much of the hierarchical and global replication. It is really good and much more efficient but might take a couple of attempts to get used to. Also the content source is defined on the Deployment Type object.

To alter Applications, in particular something like the source path, you need to connect to the Application class, the instance and then deserialize the XML data. Then you can edit this information, serialize it and inject it back into the WMI object.

I am assuming Powershell and that the Admin Console is installed on the machine running the script.
First of all get your ConfigMgr assemblies into your script:
#import assemblies
[System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.dll”)
[System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll”)
[System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll”)

#Specify your site server and sitecode:
$server = “configmgr01”
$code = “001”

#Get the applications (i’m only doing the latest version here):
#gwmi -ComputerName $server -Namespace root\sms\site_$code -class sms_application | ?{$_.IsLatest -eq $true}

#Either save this an object or loop on the fly, i’m looping on the fly:

gwmi -ComputerName $server -Namespace root\sms\site_$code -class sms_application | ?{$_.IsLatest -eq $true} | %{
#get the instance of the application
$app = [wmi]$_.__PATH
#deserialize the XML data
$appXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($app.SDMPackageXML,$true)
#loop through the deployment types
foreach($dt in $appXML.DeploymentTypes){
#find the installer element of the XML
$installer = $dt.Installer
#the content for each installer is stored as an single element array
$content = $installer.Contents[0]
“Current Path: ” + $content.Location
#use a regular expression to modify the existing path to your new location
$newPath = $content.Location -replace ‘\\\\domain.loc\\unc\\share’,’\\namespace.loc\dfs’
“New Path : ” + $newPath
if($newPath -ne $content.Location){
“Setting new path”
#this creates a new instance of content which will overwrite the older, this works cleaner than modifying the existing content path
#modifying existing tends to corrupt the data
$newContent = [Microsoft.ConfigurationManagement.ApplicationManagement.ContentImporter]::CreateContentFromFolder($newPath)
$newContent.FallbackToUnprotectedDP = $true
$newContent.OnFastNetwork = [Microsoft.ConfigurationManagement.ApplicationManagement.ContentHandlingMode]::Download
$newContent.OnSlowNetwork = [Microsoft.ConfigurationManagement.ApplicationManagement.ContentHandlingMode]::Download
$newContent.PeerCache = $false
$newContent.PinOnClient = $false
#set the content ID to the new content information you have created
$installer.Contents[0].ID = $newContent.ID
#inject the new data into the deserialized XML data
$installer.Contents[0] = $newContent
}
}
#reserialize the XML
$updatedXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::SerializeToString($appXML, $true)
#add the serialized XML data to the application object
$app.SDMPackageXML = $updatedXML
#put the changes to the instance
$app.Put()
}

Advertisements

29 thoughts on “ConfigMgr 2012 – Change Application Source Path

  1. Angel February 1, 2013 / 9:16 am

    Good done! We’re simply the best!

  2. Derek May 8, 2013 / 8:46 pm

    Great post! Thanks for pointing me in the right direction. I’m getting a generic failure when I attempt the Put() method. Have you run into this?

    • andrewdcraig May 8, 2013 / 9:44 pm

      Could be syntax… The worst thing about this blog site is the way it wordwraps scripts so that sometimes copying and pasting produces strange errors.. I would check through the script for false line breaks first of all. And i will post a text file version of this script as an attachment when i get a chance.

  3. Derek May 8, 2013 / 9:46 pm

    Thanks for the quick reply. I think you are correct, but it’s on my end, I believe. I’m trying to take what you’ve put above and use it to create a requirement rule using PowerShell. The 1 or 2 examples I can find are all in C#, and I would like to create the same in PS.

    • andrewdcraig May 9, 2013 / 5:30 am

      hi, the smsprov.log might show a more helpful error message…

      • andrewdcraig May 9, 2013 / 6:08 am

        are you using built-in requirements? if you want to create a new requirement and apply that, perhaps create the requirement first…? This is really interesting, perhaps you can post your code?

      • Derek May 9, 2013 / 8:12 pm

        I’m actually using a requirement I created. It ended up being a permssion issue that now works with my elevated account. Thanks for the great blog!

        On a side note, I put in a request on Connect for a PS cmdlet that will create the requirement rule for an existing global condition to whatever deployment type you choose.

  4. Johan Lundberg September 17, 2013 / 10:20 am

    Hi this is awesome
    Can I apply this somehow on other properties as well? I need to change Uninstall command for example?

    • andrewdcraig September 17, 2013 / 4:18 pm

      thanks. and yes you can. the deployment type properties are also contained in serialized xml.

      • Johan Lundberg September 17, 2013 / 6:08 pm

        I am a little new to all this SCCM together with Powershell could you just give me an example on how to change the uninstall Command? Cause I cant really figure out how to change the property?
        Thanks in advance!

      • andrewdcraig September 18, 2013 / 10:40 am

        i created a new comment thread for the script

  5. andrewdcraig September 18, 2013 / 10:39 am

    It’s even easier than updating content. Here you go, provided as is, no warranty, requires testing.
    #import assemblies
    [System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.dll”)
    [System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll”)
    [System.Reflection.Assembly]::LoadFrom(“C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll”)

    #Specify your site server and sitecode:
    $server = “configmgr01”
    $code = “001”

    gwmi -ComputerName $server -Namespace root\sms\site_$code -class sms_application | ?{$_.IsLatest -eq $true -and $_.localizeddisplayname -eq “Test App”} | %{
    #get the instance of the application
    $app = [wmi]$_.__PATH
    #deserialize the XML data
    $appXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($app.SDMPackageXML,$true)
    #loop through the deployment types
    foreach($dt in $appXML.DeploymentTypes){
    #find the installer element of the XML
    $installer = $dt.Installer
    $UninstallCommandLine = $installer.UninstallCommandLine
    $newUninstallCommandLine = “msiexec /x jhkdfhs”
    #inject the new data into the deserialized XML data
    $installer.UninstallCommandLine = $newUninstallCommandLine
    }
    #reserialize the XML
    $updatedXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::SerializeToString($appXML, $true)
    #add the serialized XML data to the application object
    $app.SDMPackageXML = $updatedXML
    #put the changes to the instance
    $app.Put()
    }

  6. syed September 3, 2014 / 10:06 pm

    I am trying to change the application properties in SCCM Configmgr2012 of over 2000 applications, i need to have the Application Catalog name changed to match the package Name, for doing this i need to design a power shell script, since i am new to power shell i am not sure what parameters i should use and appropriate functions to be used.
    Example

    Path: Software library-Overview-Application Management-Applications-Adobe

    Application-Right click-properties-General Information tab-Name Adobe_Acrobat X Pro_10.0.0_01

    Application-Right click-properties-Application catalog-Localized application name Adobe_Acrobat X Pro -English

    Can i do this task with the above script? Moreover i need to do this on 2000 applications, will i have to write a separate script?

    • andrewdcraig September 3, 2014 / 10:53 pm

      You will need to modify the script to edit the app catalog display name. I will have a look tomorrow and post it here

      • andrewdcraig September 4, 2014 / 1:43 pm

        it’s a much simpler script:
        Use at own risk… This will change all applications.
        Save the below script to a .ps1 file and run from powershell with an account with ConfigMgr permissions
        —————————————————-
        $adminDir = (gwmi -Class Win32_Directory -Filter “Name like ‘%Microsoft Configuration Manager\\AdminConsole\\bin'”).Name
        #Specify your site server and sitecode:
        $server = “configmgr01”
        $code = “XXX”
        #Get all latest versions of applications and set the AppCatalog DisplayName to the LocalizedDisplayName of the App
        gwmi -ComputerName $server -Namespace root\sms\site_$code -class sms_application | ?{$_.IsLatest -eq $true} | %{
        #get the instance of the application
        $app = [wmi]$_.__PATH
        #deserialize the XML data
        $appXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($app.SDMPackageXML,$true)
        $appXML.DisplayInfo[0].Title = $app.LocalizedDisplayName
        #reserialize the XML
        $updatedXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::SerializeToString($appXML, $true)
        #add the serialized XML data to the application object
        $app.SDMPackageXML = $updatedXML
        #put the changes to the instance
        $app.Put()
        }

  7. syed September 4, 2014 / 2:36 pm

    Thanks a ton for a quick reply!!! i will definitely dig into this and will let you know if it works my side! cheers.

  8. syed September 4, 2014 / 8:01 pm

    Does this work for single application too in sccm? i wanted to try this for a single application like adobe in my server but its throwing an error for me which says the string is missing the terminator:”., i used the following format, please correct me if i am using the wrong syntax, also in the beginning do i have to load any assemblies? please guide.

    $adminDir = (gwmi -Class Win32_Directory -Filter “Name like ‘%Microsoft Configuration Manager\\AdminConsole\\bin’”).Name
    $server = “configmgr01″
    $code = “xyz”
    $app=get-cmapplication -name adobe
    $appXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($app.SDMPackageXML,$true)
    $appXML.DisplayInfo[0].Title = $app.LocalizedDisplayName
    $updatedXML = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::SerializeToString($appXML, $true)
    $app.SDMPackageXML = $updatedXML
    $app.Put()

    Thanks.

    • andrewdcraig September 4, 2014 / 8:20 pm

      This is typical of wordpress. Remove all single and double quotes and retype them. Look closely you will see some seem to be in a different font… Because of this powershell cannot recognize them… So paste the whole thing into the powershell isee and then correct the quotation marks… No assemblies required for this script but you are using the configmgr cmdlets? You have them imported and are using the sitecode drive? And you are running this on the site server? Sorry, as many questions as answers…

  9. syed September 4, 2014 / 8:55 pm

    AWESOME!!! you were right it works after changing the parameters and modifying the single and double quotes, i tried this for single application like adobe by using $app=get-cmapplication -name adobe!!, Thank you so much, will try this for all applications too, will test it and post.

  10. syed September 9, 2014 / 6:09 pm

    Can you explain the importance of this line in the code, why we are defining this in the beginning as name? As far as i know it is the admin console directory, i am trying to figure out whats the point in using this directory!

    $adminDir = (gwmi -Class Win32_Directory -Filter “Name like ‘%Microsoft Configuration Manager\\AdminConsole\\bin’”).Name

    also
    $app = [wmi]$_.__PATH
    i didn’t understand the _path, does this means the path for all the applications base path?

  11. mack September 10, 2014 / 3:10 pm

    got it thanks

  12. syed September 24, 2014 / 7:34 pm

    for the above script, heard the xml manipulation is not recommended by Microsoft for renaming application catalog localized application name, can you give an example with get-cmapplication and set-cmapplication cmdlets for application catalog rename to match the localized display name?

    • andrewdcraig September 24, 2014 / 8:48 pm

      Well, set-cmapplication has a -localizeddisplayname parameter so should be easy. If you are not familiar with the cmdlets, you need to load them and switch to the configmgr drive to use them. I don’t use them that much myself as I find them too limiting. Give me a few minutes and I’ll put it together for you.

  13. andrewdcraig September 24, 2014 / 10:31 pm

    #You can use ByPropertyName Binding in the Pipeline to achieve this.
    #Bear in mind that the CMDLETS have a tendency to KILL WMI (which is another reason i don’t use them, despite what some people might recommend) so be very careful and test it out properly first if you want to modify this for all applications
    #The following will Change the App Name of Application called “Office” to the same as the Name of the App:

    Get-CMApplication -Name “Office” | Select *,@{“Label”=”LocalizedApplicationName”;Expression={$_.LocalizedDisplayName}} | Set-CMApplication

    # i could rant on about the cmdlets but i wont. just to say that i havent seen any official Statement from Microsoft about not using the XML. And IMO editing the XML is far safer and more efficient than using the cmdlets

  14. syed September 25, 2014 / 7:52 pm

    of course cmdlets are powerful but wasn’t sure the best way to do this, Thank you so much for the script with (get and set) cmdlets!, that’s a cool trick there, Works perfectly for renaming single application,
    However for renaming all applications i removed the name part(“get-cmapplication -name”) and used get-cmapplication itself which will retrieve all applications.

    Can i use this for all applications ? hope this syntax is correct :
    Get-CMApplication | Select * ,@{“Label”=”LocalizedApplicationName”;Expression={$_.LocalizedDisplayName}} | Set-CMApplication

    i ran this on test lab but threw lines of error (i guess something wrong with my lab!!!) saying :

    set-cmapplication: cannot validate argument on parameter ‘description’. the argument is null or empty. provide an argument that is not null or empty. at line 1 char 103.

    cheers

    • andrewdcraig September 26, 2014 / 2:53 pm

      Hi, watch for the double-quotes again, try removing them and retyping. Also, depending on how many apps get-cmapplication | set-cmapplication could quickly fill up the wmi Cache on your Server. watch this in taskmgr when you just use get-cmapplication without Parameters… 80Mb for wmiprvse and you may have a Problem.

  15. syed September 30, 2014 / 2:26 pm

    Cool, will try this out, Thanks.

  16. Tom September 4, 2015 / 7:09 pm

    Sorry to drag this old post up. I’m trying to make my life easier and make it so that any apps that have say “All Windows 7 64bit” in the deployment type requirements get “All Windows 10 64bit” checked as well. I seem to get it to modify it correctly when I check the values in powershell, but it doesn’t seem to actually write it back into the application after it is re-Serialized…any advice?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s