SCCM Application Objects - Enhanced Registry Detection

Over the years I've posted a number of atricles related to using PowerShell with SCCM.  The most read of these was about creating SCCM Applications with Enhanced Detection methods - specifically for File Based Detection.  A number of people have asked for an example of the same script using Registry based detection for installed applications.

Not to go over old ground - the earlier blogs that may be of interest are found here:

Creating SCCM Applications with Powershell,

Constructing SCCM Rules with Powershell,  

Scripting SCCM Application Dependencies

Creating SCCM Global Conditions

The script below uses the presence of a registry key to indicate that an application is installed.

#####################################################
# Add Required Type Libraries
 
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.dll"
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll"
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ManagementProvider.dll"
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll"
#used for creating rules
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\DcmObjectModel.dll"
#WQL Connection to Server
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\AdminUI.WqlQueryEngine.dll"
#Application Wrapper and Factory
Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\AdminUI.AppManFoundation.dll"
 
 
 
#####################################################
# Core Application Details
 
[string]$sPackageDirectory         ="\\sccmserver\d$\Applications\7Zip_09.20_64a"
[string]$sApplicationName          = "7Zip_09.20_64a"
[string]$sApplicationDestription   = "Example Application"
[string]$sApplicationVersion       = "02.00"
[string]$sApplicationPublisher     = "Vendor A"
[string]$ApplicationOwner          = ""
 
[string]$sSCCMServerName           = "mySCCMServer"
[string]$sSCCMUsername             = "myusername"
[string]$sSCCMPassword             = "mypassword"
 
 
 
 
#####################################################
# Functions
 
# WQLConnect
# Purpose: To create a WQL query connection to an SCCM Server
#          This will utilise credentials if script isn't being run on the server itself
#
function WQLConnect($Server, $User, $Password) {
 
  $namedValues              = New-Object Microsoft.ConfigurationManagement.ManagementProvider.SmsNamedValuesDictionary
  if ($namedValues -ne $null) { write-host " namedValues object Created"} else {write-host " namedValues object Creation failed"; exit}
 
  $connection               = New-Object Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager
  if ($connection  -ne $null) { write-host " connection  object Created"} else {write-host " connection  object Creation failed"; exit}
 
 
  # Connect with credentials if not running on the server itself
  if ($env:computername.ToUpper() -eq $Server.ToUpper()){
     write-host  "Local WQL Connection Made"
     [void]$connection.Connect($Server)
  }
  else
  {
     write-host  "Remote WQL Connection Made: " + $sSCCMServerName
     [void]$connection.Connect($Server, $User, $Password)
 
  }
  return $connection
 
}

# Store
# Purpose: To commit the completed application to SCCM
#
function store ($Application){
 
                # Set the application into the provider object.
                $oAppManWrapper.InnerAppManObject = $Application
 
                # "Initializing the SMS_Application object with the model."
                $oApplicationFactory.PrepareResultObject($oAppManWrapper);
 
                # Save to the database.
                $oAppManWrapper.InnerResultObject.Put();
}
 
 #####################################################
# Main
 
#create connection to SCCMServer (not used until the end of the script)
$oServerConnection                       = WQLConnect $sSCCMServerName $sSCCMUsername $sSCCMPassword
$oApplicationFactory                     = New-Object Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.ApplicationFactory
$oAppManWrapper                           = [Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.AppManWrapper]::Create( $oServerConnection , $oApplicationFactory)
 
 
write-output   "Creating Application Object"
$oApplication                        = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.Application
   if ($oApplication -ne $null) { write-output  " oApplication object Created"} else {write-output  " oApplication object Creation failed"; exit}
 
$oApplication.Title                       = $sApplicationName
$oApplication.SoftwareVersion             = $sApplicationVersion
$oApplication.Publisher                   = $sApplicationPublisher
$oApplication.DisplayInfo.DefaultLanguage = "en-US"
 
write-output   "Creating Application Display Info"
$oApplicationDisplayInfo = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.AppDisplayInfo
  if ($oApplicationDisplayInfo -ne $null) { write-output  " oApplicationDisplayInfo object Created"} else {write-output  " oApplicationDisplayInfoo object Creation failed"; exit}
 
 
$oApplicationDisplayInfo.Title            = $sApplicationName
$oApplicationDisplayInfo.Description      = $sApplicationDestription
$oApplicationDisplayInfo.Language         = "en-US"
$oApplication.DisplayInfo.DefaultLanguage = "en-US"
$oApplication.DisplayInfo.Add($oApplicationDisplayInfo)
 
 
$oAppinstaller = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.ScriptInstaller
  if ($oAppinstaller -ne $null) { write-output " oAppinstaller object Created"} else {write-output " oAppinstaller object Creation failed"; exit}
 
#Note that this example hardcodes install and remove syntax by using
#a launcher for all applications
 
$oAppinstaller.InstallCommandLine          = '"Launcher.exe"'
$oAppinstaller.UninstallCommandLine        = '"Launcher.exe" /Remove'
 
#####################################################
# Upload File Content to Server
 
write-output   "Upload Content"
 
$oContent                                   = [Microsoft.ConfigurationManagement.ApplicationManagement.ContentImporter]::CreateContentFromFolder($sPackageDirectory)
$oContent.OnSlowNetwork                     = "Download"
$oAppinstaller.Contents.Add($oContent)
 

#####################################################
# Main Creating Enhanced File Detection Method (file based)
# This uses a standard Package signature file under c:\windows\logs
# to determine if the package is installed
 
#write-output   "Enabling Enhanced File Detection"
$oAppinstaller.DetectionMethod = [Microsoft.ConfigurationManagement.ApplicationManagement.DetectionMethod]::Enhanced
$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
  if ($oEnhancedDetection -ne $null) { write-output  " oEnhancedDetection object Created"} else {write-output  " oEnhancedDetection object Creation failed"; exit}
 
$oDetectionType              = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemPartType]::RegistryKey
#$oFileSetting                 = New-Object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.FileOrFolder( $oDetectionType , $null)
#  if ($oFileSetting -ne $null) { write-output  " oFileSetting object Created"} else {write-output  " oFileSetting object Creation failed"; exit}
 
#$oFileSetting.FileOrFolderName = $sApplicationName + ".sig"
#$oFileSetting.Path             = "%Windir%\Logs"
#$oFileSetting.Is64Bit          = 1
#$oFileSetting.SettingDataType  = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Int64
 
#$oEnhancedDetection.Settings.Add($oFileSetting)
 
# Registry Setting
$oRegSetting = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.RegistrySetting(@($null))
$oRegSetting.Name
$oRegSetting.RootKey = "LocalMachine"
$oRegSetting.Key = "Software\7-Zip"
$oRegSetting.Is64Bit = $true
$oRegSetting.ValueName = "path"
$oRegSetting.CreateMissingPath = $false
$oRegSetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::String #Int64/String/?
 
$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
$oEnhancedDetection.Settings.Add($oRegSetting)




write-output   "Settings Reference"
$oSettingRef                  = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.SettingReference(
$oApplication.Scope,
$oApplication.Name,
$oApplication.Version,
$oRegSetting.LogicalName,
$oRegSetting.SettingDataType,
$oRegSetting.SourceType,
[bool]0 )




# setting bool 0 as false
if ($oSettingRef -ne $null) { write-output  " oSettingRef object Created"} else {write-output  " oSettingRef object Creation failed"; exit}
 
 
$oSettingRef.MethodType    = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Value
$oConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue("MY VALUE",$oRegSetting.SettingDataType)

   if ($oConstValue -ne $null) { write-output  " oConstValue object Created"} else {write-output  " oConstValue object Creation failed"; exit}

$oCheckOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
$oCheckOperands.Add($oSettingRef)
$oCheckOperands.Add($oConstValue)


 $oExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
 [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::IsEquals, $oCheckOperands) 

$oRule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule",
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::None, $null,$oExpression)
if ($oRule  -ne $null) { write-output  " rule object Created"} else {write-output  " rule object Creation failed"; exit}
 
 
$oEnhancedDetection.Rule = $oRule 
$oAppinstaller.EnhancedDetectionMethod = $oEnhancedDetection
 
#####################################################
# Add Deployment Type to Application
 
 
write-output   "Adding Deployment Type"
$oApplicationDeploymentType = new-object Microsoft.ConfigurationManagement.ApplicationManagement.DeploymentType($oAppinstaller, 
[Microsoft.ConfigurationManagement.ApplicationManagement.ScriptInstaller]::TechnologyId, 
[Microsoft.ConfigurationManagement.ApplicationManagement.NativeHostingTechnology]::TechnologyId)
 
if ($oApplicationDeploymentType -ne $null) { write-output  " NewApplicationDeploymentType object Created"} else {write-output  " NewApplicationDeploymentType object Creation failed"; exit}
 
 
$oApplicationDeploymentType.Title = $oApplication.Title
 
 
 
#####################################################
 
write-output  "Limiting Collections to 64bit workstations"
 
$oOperands = new-object "Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.RuleExpression]]"
   ####if ($oOperands -ne $null) { write-output  " oOperands object Created"} else {write-output  " oOperands object Creation failed"; exit}
 
# Its possible to limit the deployment of application to specific operating systems
# A current list of possible values may be found t:
# http://www.laurierhodes.info/?q=node/60
 
$oOperands.Add("Windows/All_x64_Windows_XP_Professional")
$oOperands.Add("Windows/All_x64_Windows_7_Client")
$oOperands.Add("Windows/All_x64_Windows_8_Client")
$oOperands.Add("Windows/All_x64_Windows_8.1_Client")
 
$oOSExpression           = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.OperatingSystemExpression -ArgumentList ([Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::OneOf), $oOperands    
 
$oAnnotation             = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Annotation      
$oAnnotation.DisplayName = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.LocalizableString -ArgumentList "DisplayName", "Operating system One of {All x86 Windows XP (64bit)}", $null
 
$oDTRule = new-object "Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule" -ArgumentList `
            ("Rule_" + [Guid]::NewGuid().ToString()), 
            ([Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::None), 
             $oAnnotation, 
             $oOSExpression
 
write-output  "Adding Deployment Type rule to Application"     
$oApplicationDeploymentType.Requirements.Add($oDTRule)
 
############################################
# Finish
 
 
# Add Deployment Type to Application
$oApplication.DeploymentTypes.Add($oApplicationDeploymentType)
 
# Verify the Application structure
write-output  "Verifying Application Object"  
$oApplication.Validate
 
#Add Application to SCCM
write-output  "Loading SCCM Application"  
Store $oApplication