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()
}
Good done! We’re simply the best!
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?
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.
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.
hi, the smsprov.log might show a more helpful error message…
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?
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.
Hi this is awesome
Can I apply this somehow on other properties as well? I need to change Uninstall command for example?
thanks. and yes you can. the deployment type properties are also contained in serialized xml.
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!
i created a new comment thread for the script
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()
}
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?
You will need to modify the script to edit the app catalog display name. I will have a look tomorrow and post it here
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()
}
Thanks a ton for a quick reply!!! i will definitely dig into this and will let you know if it works my side! cheers.
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.
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…
Also check the line breaks…
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.
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?
got it thanks
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?
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.
#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
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
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.
Cool, will try this out, Thanks.
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?