Skip to content

Instantly share code, notes, and snippets.

@Stephanevg
Last active July 20, 2020 19:32
Show Gist options
  • Save Stephanevg/3572fdf44c7274bb3b74efe569781a9e to your computer and use it in GitHub Desktop.
Save Stephanevg/3572fdf44c7274bb3b74efe569781a9e to your computer and use it in GitHub Desktop.
This function will help to create custom detection deployment types for SCCM 2012
Function Set-SCCMDetectionRuleForDeploymentType {
Param(
[Parameter(Mandatory=$True)]
[ValidateSet("RegistryKey","File","Folder","MSI","Assembly","Other")]
$DetectionType,
[Parameter(Mandatory=$False,ParameterSetName="FileDetection")][ValidateNotNullOrEmpty()][String]$FileName,
[Parameter(Mandatory=$False,ParameterSetName="FileDetection")][ValidateNotNullOrEmpty()][String]$FolderPath,
[Parameter(Mandatory=$False,ParameterSetName="FileDetection")]$Is64bit,
[ValidateSet("And,","Or","Equals","IsEquals","NotEquals","GreaterThan","Between","GreaterEquals","LessEquals","BeginsWith","NotBeginsWith","EndsWith","NotEndsWith","Contains","NotContains","AllOf","OneOf","NoneOf","SetEquals","SupportedOperators")]
[Parameter(Mandatory=$False,ParameterSetName="FileDetection")]
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$Operator,
[Parameter(Mandatory=$false)]
[ValidateSet("None","Informational","Warning","Critical","CriticalWithEvent")]
$NoncomplianceSeverity = "None",
$ApplicationName,
$DeploymentTypeName,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
[ValidateSet("HKEY_LOCAL_MACHINE","HKEY_USERS","HKEY_CLASSES_ROOT","HKEY_CURRENT_CONFIG","HKEY_CURRENT_USER")]
[ValidateNotNullOrEmpty()][String]$RegistryHyve,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")][ValidateNotNullOrEmpty()][String]$RegistryKey,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")][String]$RegistryKeyValue,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")][string]$RegistryKeyValueDataType = "String",
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
[Parameter(Mandatory=$false)][switch]$CheckforPresenceOnly,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
[Parameter(Mandatory=$false)][String]$PropertyPath,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$ConstantValue,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$ConstantDataType,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$DcmObjectModelPath = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\DcmObjectModel.dll",
[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer
)
if ($Operator){
if ($Operator.ToUpper() -eq "EQUALS"){
$Operator = "IsEquals"
}
}
$application1 = [wmi](Get-WmiObject -Query "select * from sms_application where LocalizedDisplayName='$ApplicationName' AND ISLatest='true'" -ComputerName $sccmserver.Machine -Namespace $sccmserver.Namespace).__PATH
#Deserialize the SDMPackageXML
$connection = New-Object Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager
[void]$connection.Connect($sccmserver.Machine)
# initialise management scope.
$factory = New-Object Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.ApplicationFactory
$wrapper = [Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.AppManWrapper]::Create($connection, $factory)
$App1Deserializedstuff = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($application1.SDMPackageXML)
$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
switch ($DetectionType){
"File" {
write-verbose "--> Creating Enhanced File Detection Method"
$oDetectionType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemPartType]::File
$oFileSetting = New-Object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.FileOrFolder( $oDetectionType , $null)
if ($oFileSetting -ne $null) { write-verbose " oFileSetting object Created"} else {write-warning " oFileSetting object Creation failed"; break}
$oFileSetting.FileOrFolderName = $FileName
$oFileSetting.Path = $FolderPath
if ($Is64bit){$Is64bits= 1}else{$Is64bits = 0}
$oFileSetting.Is64Bit = $Is64bits#$Is64bits
$oFileSetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Int64
#$oFileSetting.ChangeLogicalName()
$oEnhancedDetection.Settings.Add($oFileSetting)
#$oFileSetting
write-verbose "Settings Reference"
$oSettingRef = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.SettingReference(
$App1Deserializedstuff.Scope,
$App1Deserializedstuff.Name,
$App1Deserializedstuff.Version,
$oFileSetting.LogicalName,
$oFileSetting.SettingDataType,
$oFileSetting.SourceType,
[bool]0 )
# setting bool 0 as false
if ($oSettingRef -ne $null) { write-verbose " oSettingRef object Created"} else {write-warning " oSettingRef object Creation failed"; exit}
$oSettingRef.MethodType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Value
$oConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue( 0,
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Int64)
if ($oConstValue -ne $null) { write-verbose " oConstValue object Created"} else {write-warning " oConstValue object Creation failed"; exit}
$oFileCheckOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
$oFileCheckOperands.Add($oSettingRef)
$oFileCheckOperands.Add($oConstValue)
$FileCheckExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
[Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::NotEquals, $oFileCheckOperands)
$oRule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule",
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::$NoncomplianceSeverity, $null, $FileCheckExpression)
if ($oRule -ne $null) { write-verbose " rule object Created"} else {write-warning " rule object Creation failed"; exit}
#$oEnhancedDetection.ChangeId()
$oEnhancedDetection.Rule = $oRule
}
"RegistryKey"{
if ($RegistryKeyValue -eq "" -or $RegistryKeyValue -eq "NULL" -or $RegistryKeyValue -eq $Null){
#Hack to bypass RegistryKey Bug
$sourceKeyFix = @"
using Microsoft.ConfigurationManagement.DesiredConfigurationManagement;
using System;
namespace RegistryKeyNamespace
{
public class RegistryKeyFix
{
private RegistryKey _registryKey;
public RegistryKeyFix(string str)
{
this._registryKey = new RegistryKey(null);
}
public RegistryKey GetRegistryKey()
{
return this._registryKey;
}
}
}
"@
Add-Type -ReferencedAssemblies $DcmObjectModelPath -TypeDefinition $sourceKeyFix -Language CSharp
$temp = New-Object RegistryKeyNamespace.RegistryKeyFix ""
$oRegistrySetting = $temp.GetRegistryKey()
write-verbose "--> Creating Enhanced RegistryKey Detection Method"
}else{
#Hack to bypass bug in Microsoft.ConfigurationManagement.DesiredConfigurationManagement.registrySetting which doesn't allow us to create a enhanced detection method.
$sourceSettingFix = @"
using Microsoft.ConfigurationManagement.DesiredConfigurationManagement;
using System;
namespace RegistrySettingNamespace
{
public class RegistrySettingFix
{
private RegistrySetting _registrysetting;
public RegistrySettingFix(string str)
{
this._registrysetting = new RegistrySetting(null);
}
public RegistrySetting GetRegistrySetting()
{
return this._registrysetting;
}
}
}
"@
Add-Type -ReferencedAssemblies $DcmObjectModelPath -TypeDefinition $sourceSettingFix -Language CSharp
$temp = New-Object RegistrySettingNamespace.RegistrySettingFix ""
$oRegistrySetting = $temp.GetRegistrySetting()
#$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
write-verbose "--> Creating Enhanced Registry Setting Detection Method"
}
$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
write-verbose "--> Creating Enhanced Registry Detection Method"
$oDetectionType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemPartType]::RegistryKey
if ($oRegistrySetting -ne $null) { write-verbose " oRegistrySetting object Created"} else {write-warning " oRegistrySetting object Creation failed";Break}
switch ($RegistryHyve){
"HKEY_CLASSES_ROOT"{
$oRegistrySetting.RootKey = "ClassesRoot"
Break
}
"HKEY_CURRENT_CONFIG"{
$oRegistrySetting.RootKey = "CurrentConfig"
Break
}
"HKEY_CURRENT_USER"{
$oRegistrySetting.RootKey = "CurrentUser"
Break
}
"HKEY_LOCAL_MACHINE"{
$oRegistrySetting.RootKey = "LocalMachine"
Break
}
"HKEY_USERS"{
$oRegistrySetting.RootKey = "Users"
Break
}
}
$oregistrysetting.Key = $RegistryKey
if ($RegistryKeyValue){
$oRegistrySetting.ValueName = $RegistryKeyValue
$oRegistrySetting.CreateMissingPath = $false
}
if ($Is64bit){$Is64bits= 1}else{$Is64bits = 0}
$oRegistrySetting.Is64Bit = $Is64bits#$Is64bits
if (!($RegistryKeyValue)){
$oRegistrySetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Boolean
}else{
$oRegistrySetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::$RegistryKeyValueDataType
}
#$oRegistrySetting.ChangeLogicalName()
#$oRegistrySetting.SupportsRemediation = $false
$oEnhancedDetection.Settings.Add($oRegistrySetting)
#$oFileSetting
write-verbose "Settings Reference"
$oSettingRef = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.SettingReference(
$App1Deserializedstuff.Scope,
$App1Deserializedstuff.Name,
$oApplicApp1Deserializedstuffation.Version,
$oRegistrySetting.LogicalName,
$oRegistrySetting.SettingDataType,
$oRegistrySetting.SourceType,
[bool]0 )
# setting bool 0 as false
if ($oSettingRef -ne $null) { write-verbose " oSettingRef object Created"} else {write-warning " oSettingRef object Creation failed"; break}
#Registry Setting must satisfy the following rule
$oSettingRef.MethodType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Value
if ($PropertyPath -ne "NULL"){
$oSettingRef.PropertyPath = $PropertyPath
}
#$oSettingRef
<#
if (!($CheckForConstant)){
$ConstantValue = $true
$ConstantDataType = "boolean"
}
#>
#$ConstantValue = $true
#$ConstantDataType = "boolean"
$oConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue($ConstantValue,
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::$ConstantDataType)
if ($oConstValue -ne $null) { write-verbose " oConstValue object Created"} else {write-warning " oConstValue object Creation failed";break}
$oRegistrySettingOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
$oRegistrySettingOperands.Add($oSettingRef)
$oRegistrySettingOperands.Add($oConstValue)
#$Operator = "IsEquals"
write-verbose "Operator is --> $($Operator)"
#$oRegistrySettingOperands
$RegistryCheckExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
[Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::$Operator, $oRegistrySettingOperands)
#$RegistryCheckExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression("isEquals",$oRegistrySettingOperands)
$oRule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule",
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::$NoncomplianceSeverity, $null, $RegistryCheckExpression)
if ($oRule -ne $null) { write-verbose " rule object Created"} else {write-warning " rule object Creation failed"; break}
#$oEnhancedDetection.ChangeId()
$oEnhancedDetection.Rule = $oRule
Break}
"Folder"{
Break
}
"MSI"{
Break
}
"Assembly"{
Break
}
"Other"{
Break
}
#Expression, Annotation, Severity and an empty
Default {Throw "DetectionType $($DetectionType) not recognized as a valid detection type"}
}
#$oAppinstaller.EnhancedDetectionMethod = $oEnhancedDetection
$DTR = $oEnhancedDetection
#return $oEnhancedDetection
#Set the detection method to the deserialized application
$i = 0
foreach ($DT in $App1Deserializedstuff.DeploymentTypes){
write-verbose "Analying $($DT.Title)"
if ($DT.Title -eq $DeploymentTypeName){
write-verbose "Adding Enhanced detection type to application $($ApplicationName) and deploymentType $($DeploymentTypeName)"
$App1Deserializedstuff.DeploymentTypes[$i].Installer.DetectionMethod = [Microsoft.ConfigurationManagement.ApplicationManagement.DetectionMethod]::Enhanced
$App1Deserializedstuff.DeploymentTypes[$i].Installer.EnhancedDetectionMethod = $DTR
continue
}else{
$i++
}
}
# save the application.
$wrapper.InnerAppManObject = $App1Deserializedstuff
$factory.PrepareResultObject($wrapper)
$wrapper.InnerResultObject.Put()
}
@JonWalz2
Copy link

`#Requires $ProductCode in the Parameter block of the function

    "MSI"{
        $msiSetting = New-Object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.MSISettingInstance($ProductCode, $null)
        $oEnhancedDetection.Settings.Add($msiSetting)
        $msiDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Int64
        $msiConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue('0', $msiDataType)

        $msiSettingRef = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.SettingReference(
            $App1Deserializedstuff.Scope,
            $App1Deserializedstuff.Name,
            $App1Deserializedstuff.Version,
            $msiSetting.LogicalName,
            $msiDataType,
            $msiSetting.SourceType,
            [bool]0
        )

        $msiSettingRef.MethodType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Count
        $msiOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
        $msiOperands.Add($msiSettingRef);
        $msiOperands.Add($msiConstValue);
        $msiExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
            [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::NotEquals, $msiOperands)

        $oRule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule", 
        [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::$NoncomplianceSeverity, $null, $msiExpression)
            if ($oRule  -ne $null) { write-verbose " rule object Created"} else {write-warning " rule object Creation failed"; exit}

        $oEnhancedDetection.Rule = $oRule 

    }

`

@wedanie
Copy link

wedanie commented Jul 23, 2018

Has anyone ever used the "Between" operator? I'm trying to set a requirement that gets a software version from the registry. It applies a patch based on that version between 17.00.00 to 17.00.80.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment