Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JonWalz2/fde2e8d64b55da809c65c806d7335a2b to your computer and use it in GitHub Desktop.
Save JonWalz2/fde2e8d64b55da809c65c806d7335a2b to your computer and use it in GitHub Desktop.
Function Load-ConfigMgrAssemblies {
Param(
$AdminConsoleDirectory = ($env:SMS_ADMIN_UI_PATH | Split-Path -Parent)
)
#Add-Type -Path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\DcmObjectModel.dll"
$filesToLoad = "Microsoft.ConfigurationManagement.ApplicationManagement.dll","AdminUI.WqlQueryEngine.dll", "AdminUI.DcmObjectWrapper.dll","DcmObjectModel.dll","AdminUI.AppManFoundation.dll","AdminUI.WqlQueryEngine.dll","Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll","Microsoft.ConfigurationManagement.ManagementProvider.dll","Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll"
Set-Location $AdminConsoleDirectory
[System.IO.Directory]::SetCurrentDirectory($AdminConsoleDirectory)
foreach($fileName in $filesToLoad)
{
$fullAssemblyName = [System.IO.Path]::Combine($AdminConsoleDirectory, $fileName)
if([System.IO.File]::Exists($fullAssemblyName ))
{
$FileLoaded = [Reflection.Assembly]::LoadFrom($fullAssemblyName )
}
else
{
Write-Host ([System.String]::Format("File not found {0}",$fileName )) -backgroundcolor "red"
}
}
}
Load-ConfigMgrAssemblies
Function New-EDMSettingForDeploymentType {
Param(
[Parameter(Mandatory=$True)]
[ValidateSet("RegistryKey","File","MSI")]
$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","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,
$siteCode,
$version,
[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]$CheckForConstant,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$ConstantValue= $true,
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$ConstantDataType = 'String',
[Parameter(Mandatory=$False,ParameterSetName="RegistryDetection")]
$DcmObjectModelPath = "$($env:SMS_ADMIN_UI_PATH | split-path -parent)\DcmObjectModel.dll",
[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer
)
$application1 = [wmi](Get-WmiObject -Query "select * from sms_application where LocalizedDisplayName='$ApplicationName' AND ISLatest='true'" -ComputerName $sccmserver -Namespace "root\sms\site_$SiteCode").__PATH
#Deserialize the SDMPackageXML
$App1Deserializedstuff = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($application1.SDMPackageXML)
$Is64bit = $true
#$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
switch ($DetectionType){
"MSI"{
write-verbose "Creating Enhanced Product Code Detection Method"
#$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
$ProductCode = $version
$msiSetting = New-Object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.MSISettingInstance($ProductCode, $null)
#$oEnhancedDetection.Settings.Add($msiSetting)
$setting = $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)
$expression = $msiExpression
}
"File" {
write-verbose "Creating Enhanced File Detection Method"
#$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
$oDetectionType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemPartType]::File
$oFileSetting = New-Object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.FileOrFolder( $oDetectionType , $null)
$oFileSetting.FileOrFolderName = $FileName
$oFileSetting.Path = $FolderPath
if ($Is64bit){$Is64bits= 1}else{$Is64bits = 0}
$oFileSetting.Is64Bit = $Is64bits#$Is64bits
$oFileSetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Version
#$oFileSetting.ChangeLogicalName()
#$oEnhancedDetection.Settings.Add($oFileSetting)
$setting = $oFileSetting
#$oFileSetting
$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
$oSettingRef.MethodType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Value
$oSettingRef.PropertyPath = "Version"
$oConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue( $version,
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::Version)
$oFileCheckOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
$oFileCheckOperands.Add($oSettingRef)
$oFileCheckOperands.Add($oConstValue)
write-verbose "Operator is --> $($Operator)"
$FileCheckExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
[Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::$Operator, $oFileCheckOperands)
$expression = $FileCheckExpression
write-verbose "File check expression -->"
write-verbose "$($expression | out-string)"
}
"RegistryKey"{
$sourceFix = @"
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;
}
}
}
"@
#Hack to bypass bug in Microsoft.ConfigurationManagement.DesiredConfigurationManagement.registrySetting which doesn't allow us to create a enhanced detection method.
Add-Type -ReferencedAssemblies $DcmObjectModelPath -TypeDefinition $sourceFix -Language CSharp
$temp = New-Object RegistrySettingNamespace.RegistrySettingFix ""
$oRegistrySetting = $temp.GetRegistrySetting()
#$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 {Throw " oRegistrySetting object Creation failed"}
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
$oRegistrySetting.ValueName = $RegistryKeyValue
if ($Is64bit){$Is64bits= 1}else{$Is64bits = 0}
$oRegistrySetting.Is64Bit = $Is64bits#$Is64bits
$oRegistrySetting.SettingDataType = [Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::String#$RegistryKeyValueDataType
#$oRegistrySetting.ChangeLogicalName()
#$oEnhancedDetection.Settings.Add($oRegistrySetting)
$setting = $oRegistrySetting
#$oFileSetting
$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
#Registry Setting must satisfy the following rule
$oSettingRef.MethodType = [Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ConfigurationItemSettingMethodType]::Value
#this is needed if you are only checking to see if the registry value exists
#$oSettingRef.PropertyPath = "RegistryValueExists"
#$oSettingRef
<#
if (!($CheckForConstant)){
$ConstantValue = $true
$ConstantDataType = "boolean"
}
#>
$oConstValue = New-Object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ConstantValue($ConstantValue,
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.DataType]::$ConstantDataType)
$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)"
$RegistryCheckExpression = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
[Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::$Operator, $oRegistrySettingOperands)
$expression = $RegistryCheckExpression
}
#Expression, Annotation, Severity and an empty
Default {Throw "DetectionType $($DetectionType) not recognized as a valid detection type"}
} #End Switch
$returnobject = @()
$returnobject += $expression
$returnobject += $setting
return $returnobject
}
if ($DT.DetectionMethods){
$application1 = [wmi](Get-WmiObject -Query "select * from sms_application where LocalizedDisplayName='$ApplicationName' AND ISLatest='true'" -ComputerName $sccmserver -Namespace "root\sms\site_$SiteCode").__PATH
#Deserialize the SDMPackageXML
$App1Deserializedstuff = [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($application1.SDMPackageXML)
$oEnhancedDetection = New-Object Microsoft.ConfigurationManagement.ApplicationManagement.EnhancedDetectionMethod
$expressionlist = @()
foreach ($DM in $DT.DetectionMethods){
write-verbose "DM is $DM"
#if ($dm.dmpath -eq 'Windows Installer'){
# $detectiontype = 'MSI'
#}
#elseif ($DM.DMPath.split(':')[0].length -gt 1){
# $DetectionType = 'RegistryKey'
#}
#else{
# $DetectionType = 'file'
#}
$DetectionType = $dm.type
If ($DetectionType -eq 'RegistryKey'){
$Hive = $DM.DMPath.Split(':')[0]
switch ($hive)
{
'HKLM' {$hive = "HKEY_LOCAL_MACHINE"}
'HKU' {$hive = "HKEY_USERS"}
'HKCR' {$hive = "HKEY_CLASSES_ROOT"}
'HKCC' {$hive = "HKEY_CURRENT_CONFIG"}
'HKCU' {$hive = "HKEY_CURRENT_USER"}
Default {throw "Unable to identify registry hive"}
}
$DM.DMPath = (($DM.DMPath.Split(':')[1]).TrimStart('\')).TrimEnd('\')
}
If ($DetectionType -eq 'file' -or $detectiontype -eq 'MSI'){
$params = @{
Sitecode = $SiteCode
ApplicationName = $ApplicationName
DeploymentTypeName = $DeploymentTypeName
DetectionType = $detectiontype
Filename = $DM.DMItem
FolderPath = $DM.DMPath
version = $DM.DMExpectedValue
Operator = $DM.DMOperator
SCCMServer = $primary
}
write-verbose "Attempting to create $DeploymentTypeName with $DetectionType based EDM"
$resultlist = New-EDMSettingForDeploymentType @params
$expressionlist += $resultlist[0]
$oEnhancedDetection.Settings.Add($resultlist[1])
#write-verbose "$($oEnhancedDetection | Out-String)"
}
If ($DetectionType -eq 'RegistryKey'){
$params = @{
Sitecode = $SiteCode
ApplicationName = $ApplicationName
DeploymentTypeName = $DeploymentTypeName
DetectionType = $DetectionType
Operator = $DM.DMOperator
SCCMServer = $primary
RegistryHyve = $hive
RegistryKey = $dm.dmpath
RegistryKeyValue = $DM.DMItem
ConstantValue = $DM.DMExpectedValue
}
write-verbose "Attempting to create $DeploymentTypeName with $DetectionType based EDM"
$resultlist = New-EDMSettingForDeploymentType @params
$expressionlist += $resultlist[0]
$oEnhancedDetection.Settings.Add($resultlist[1])
#write-verbose "$($oEnhancedDetection | Out-String)"
}
#Set-CMMsiDeploymentType -ApplicationName $ApplicationName -DeploymentTypeName $DeploymentTypeName -AddRequirement $newrule
#write-verbose "$($oEnhancedDetection | Out-String)"
} #End DetectionMethod
If ($expressionlist.count -eq 1){
$Rule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule",
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::None, $null, $expressionlist[0])
if ($Rule -ne $null) { write-verbose "rule obect created with a single detection method"} else {throw "rule object Creation failed for a single detection method"}
}
else{
$rootOperands = new-object Microsoft.ConfigurationManagement.DesiredConfigurationManagement.CustomCollection``1[[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.ExpressionBase]]
foreach ($expression in $expressionlist){
$rootOperands.add($expression)
}
$rootExp = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Expressions.Expression(
[Microsoft.ConfigurationManagement.DesiredConfigurationManagement.ExpressionOperators.ExpressionOperator]::Or, $rootOperands)
$Rule = new-object Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.Rule("IsInstalledRule",
[Microsoft.SystemsManagementServer.DesiredConfigurationManagement.Rules.NoncomplianceSeverity]::None, $null, $rootExp)
if ($Rule -ne $null) { write-verbose "rule obect created with multiple detection methods"} else {throw "rule object Creation failed for multiple detection methods"}
}
$oEnhancedDetection.Rule = $Rule
$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 = $oEnhancedDetection
continue
}else{
$i++
}
}
$connection = New-Object Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager
[void]$connection.Connect($sccmserver)
# initialise management scope.
$factory = New-Object Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.ApplicationFactory
$wrapper = [Microsoft.ConfigurationManagement.AdminConsole.AppManFoundation.AppManWrapper]::Create($connection, $factory)
$wrapper.InnerAppManObject = $App1Deserializedstuff
$factory.PrepareResultObject($wrapper)
$wrapper.InnerResultObject.Put()
Remove-Variable oEnhancedDetection
} #end if DetectionMethods
@c0ss3tt3
Copy link

I'm trying to use your code and I get an error while adding the setting to the Enhanced Detection Method object. While executing this line :
$oEnhancedDetection.Settings.Add($resultlist[1])
#Line 361 of your code#

I'm getting this error :

Cannot find an overload for "Add" and the argument count: "1".

Since the New-EDMSettingForDeploymentType function executed well and $resultlist seems correctly populated, I am a bit lost on what to check next.

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