Create a Tree View of Applications and Dependencies

Here’s a quick code to get a tree view (sort of) of applications in your ConfigMgr 2012 environment that shows dependencies, including dependencies of dependencies. Works as is, for me at least. If you spot any bugs or improvements feel free to let me know. As usual watch out for word-wrapping and typos.

Function Get-Dependency($appCIID,$appNameFunc){

gwmi -ComputerName $server -Namespace “root\sms\site_$code -Class SMS_AppDependenceRelation -Filter “FromApplicationCIID=’$appCIID | %{

if($_.ToApplicationCIID -ne $null){

$ToApplicationCIID = $_.ToApplicationCIID

$dependencyName = Resolve-ApplicationName $ToApplicationCIID    

$dependencyNameSub = ” –>$dependencyName

Write-Host $dependencyNameSub     

Get-SubDependency $ToApplicationCIID $dependencyNameSub   

}

 }

return

}

Function Get-SubDependency($appCIID, $appNameFunc){

$appNamePrefix = ” “ + ($appNameFunc -split “>”)[0] + “>”

gwmi -ComputerName $server -Namespace “root\sms\site_$code -Class SMS_AppDependenceRelation -Filter “FromApplicationCIID=’$appCIID | %{

if($_.ToApplicationCIID -ne $null){

$ToApplicationCIID = $_.ToApplicationCIID

$dependencyName = Resolve-ApplicationName $ToApplicationCIID   

$dependencyName =$appNamePrefix$dependencyName

Write-Host$dependencyName

Get-SubDependency $ToApplicationCIID $dependencyName   

}

}

return

}

Function Resolve-ApplicationName($appCIID){

gwmi -ComputerName $server -Namespace “root\sms\site_$code -Class SMS_ApplicationLatest -Filter “CI_ID = ‘$appCIID‘” | select LocalizedDisplayName | %{

return $_.LocalizedDisplayName

}

}

cls

$server = “serverName”

$code = “001”

gwmi -ComputerName $server -Namespace “root\sms\site_$code -Class SMS_ApplicationLatest | %{

$appName = $_.LocalizedDisplayName

$CIID = $_.CI_ID

Write-Host$appName

Get-Dependency $CIID $appName

}

Advertisement

Enable TPM in a Task Sequence (DELL)

It took a while but I found a way to enable the TPM in the BIOS, then activate.

At first glance it should have been easy. Using the CCTK from Dell, set the TPM to enable from a command line and then a reboot and finally activate and a further reboot. But it would always only enable and never activate.

This is because the TPM would create an ownership on the chip itself and while the chip is ‘owned’ it cannot be activated. At least not by the CCTK.

In the end, after a lot of trial and error, I found a way to guarantee the chip is enabled and activated and ready for BitLocker, so here are the steps:

1. Set BIOS password with CCTK: Create a package from the Dell CCTK in ConfigMgr. Use this Package witha Command Line Step in the Task Sequence to set a setup password “cctk –setuppwd=password”

2. Enable TPM with CCTK: Using the Package again, run CCTK to enable TPM “cctk –tpm=on –valsetuppwd=password”

3. Restart Computer – if you perform these actions in the BIOS itself then you don’t need to restart. But here in a Task Sequence the WMI Classes need to be reloaded in order that we can see the Win32_TPM class.

4. Clean the chip ownership: I use a powershell script here but you can use vbscript. If you use powershell then you need to first set the Execution Policy with a command line step: “powershell.exe -noprofile -command “&{set-executionpolicy unrestricted -force}” then call the following script:

$oTPM = gwmi -Class Win32_TPM -Namespace root\CIMV2\Security\MicrosoftTpm

$oTPM.SetPhysicalPresenceRequest(10)

If(!(($oTPM.IsEndorsementKeyPairPresent()).IsEndorsementKeyPairPresent)){

$oTPM.CreateEndorsementKeyPair()

}

If(($oTPM.IsEndorsementKeyPairPresent()).IsEndorsementKeyPairPresent){

$OwnerAuth=$oTPM.ConvertToOwnerAuth(“customrandompassword”)

$oTPM.Clear($OwnerAuth.OwnerAuth)

$oTPM.TakeOwnership($OwnerAuth.OwnerAuth)

}

5. Restart again, this time you will get a prompt at the BIOS to press F10 to accept the chip changes

6. Activate the TPM with CCTK: “cctk –tpmactivation=activate –valsetuppwd=password”

7. Restart again.

That’s it.

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()
}