locked
Grant write permissions for 'Domain users' on custom WMI Namespace RRS feed

  • Question

  • I've created two functions in PowerShell, one that creates the Namespace ROOT\CustomCMClassesand one that creates the class Test. This piece works fine:

    Param (
        $Namespace = 'CustomCMClasses',
        $Class     = 'Test'
    )
    
    Function New-WMINamespaceHC{
        if (Get-WmiObject -Namespace 'root' -Class '__NAMESPACE' | Where-Object {$_.Name -eq $Namespace}) {
            Write-Verbose "WMI Namespace 'root\$Namespace' exists"
        }
        else {
            Write-Verbose "Create WMI namespace 'root\$Namespace'"
            $Ns = [WMICLASS]'root:__Namespace' 
            $NewNamespace = $Ns.createInstance() 
            $NewNamespace.Name = $Namespace 
            $NewNamespace.Put() 
        }
    }
    
    Function New-WMIClassHC {
        if (Get-WmiObject -List -Namespace "root\$Namespace" | Where-Object {$_.Name -eq $Class}) {
            Write-Verbose "WMI Class '$Class' exists"
        }
        else {
            Write-Verbose "Create WMI Class '$Class'"
            $NewClass = New-Object System.Management.ManagementClass ("root\$Namespace", [String]::Empty, $Null); 
            $NewClass['__CLASS'] = $Class
            $NewClass.Qualifiers.Add('Static', $true)
            $NewClass.Properties.Add('Key', [System.Management.CimType]::String, $false)
            $NewClass.Properties['Key'].Qualifiers.Add('Key', $true)
            $NewClass.Properties.Add('Value1', [System.Management.CimType]::UInt32, $false)
            $NewClass.Properties.Add('Value2', [System.Management.CimType]::String, $false)
            $NewClass.Put()
        }
    }

    At this point I need to grant Domain users permissions on the new namespace, so they are able to write data to it on their local client (no remoting needed). We'll run the scrip to create the namespace and set the permissions to WMI by using the SCCM 2012 client with 'System account' permissions. This is the point where I find a lot of information but am now stuck.

    On the Microsoft blog there is a script I tried to tweak, but it's overly complicated for my needs and it failed so I found and tweaked the following code:

    Function Add-WMIPermissions {
        [CmdLetBinding()]
        Param (
            [String]$Principal = 'DOMAIN.NET\Domain users',
            [String]$Namespace = 'CustomCMClasses'
        )
    
        Function Get-Sid {
            Param (
                $DSIdentity
            )
             $ID = new-object System.Security.Principal.NTAccount($DSIdentity)
             Return $ID.Translate([System.Security.Principal.SecurityIdentifier]).toString()
        }
    
        $Sid = Get-Sid $Principal
    
        $WMISDDL = "A;CI;CCWP;;;$Sid" 
        $WMISDDLPartialMatch = "A;\w*;\w+;;;$Sid"
    
        $security = Get-WmiObject -Namespace root\$Namespace -Class __SystemSecurity
        $binarySD = @($null)
        $result = $security.PsBase.InvokeMethod('GetSD',$binarySD)
    
        $converter = New-Object system.management.ManagementClass Win32_SecurityDescriptorHelper
        $CurrentWMISDDL = $converter.BinarySDToSDDL($binarySD[0])
    
        if (($CurrentWMISDDL.SDDL -match $WMISDDLPartialMatch) -and ($CurrentWMISDDL.SDDL -notmatch $WMISDDL)) {
            $NewWMISDDL = $CurrentWMISDDL.SDDL -replace $WMISDDLPartialMatch, $WMISDDL
        }
        else {
            $NewWMISDDL = $CurrentWMISDDL.SDDL += '(' + $WMISDDL + ')'
        }
    
        $WMIbinarySD = $converter.SDDLToBinarySD($NewWMISDDL)
        $WMIconvertedPermissions = ,$WMIbinarySD.BinarySD
    
        if ($CurrentWMISDDL.SDDL -match $WMISDDL) {
            Write-Verbose 'Current WMI Permissions matches desired value'
        }
        else {
            $result = $security.PsBase.InvokeMethod('SetSD',$WMIconvertedPermissions) 
            if($result='0'){
                Write-Verbose 'WMI permissions applied'
            }
        }
    }
    
    Add-WMIPermissions -Verbose

    It's clearly stating that the permissions are correctly applied but the user still can't write data to WMI. Working with WMI is new to me, so any help is greatly appreciated.

    The test code to see if a regular user (Domain users) has permissions:

    $WMIClass = [WMICLASS]('root\' + $Namespace + ':' + $Class)
    $WMIInstance = $WMIClass.CreateInstance()
    $WMIInstance.Key =  'Unique value identifier 5'
    $WMIInstance.Value1 = 101
    $WMIInstance.Value2 = 'Status Ok'
    $WMIInstance.Put()
    Tuesday, March 22, 2016 8:17 AM

Answers

  • Solved the problem for 'Partial Write':

    Function Set-WMIPermissionsHC {
        Param (
            [String]$Namespace = 'CustomCMClasses',
            [String]$Class     = 'Test',
            [String]$Account   = 'DOMAIN\Domain users',
            [String]$Computer  = $env:COMPUTERNAME
        )
    
        Function Get-Sid {
            Param (
                $Account
            )
            $ID = New-Object System.Security.Principal.NTAccount($Account)
            Return $ID.Translate([System.Security.Principal.SecurityIdentifier]).toString()
        }
    
        $SID = Get-Sid $Account
        $SDDL = "A;CI;CCSWWP;;;$SID"
        $DCOMSDDL = "A;;CCDCRP;;;$SID"
        $Reg = [WMICLASS]"\\$Computer\root\default:StdRegProv"
        $DCOM = $Reg.GetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction').uValue
        $Security = Get-WmiObject -ComputerName $Computer -Namespace "root\$Namespace" -Class __SystemSecurity
        $Converter = New-Object System.Management.ManagementClass Win32_SecurityDescriptorHelper
        $BinarySD = @($null)
        $Result = $Security.PsBase.InvokeMethod('GetSD', $BinarySD)
        $OutSDDL = $Converter.BinarySDToSDDL($BinarySD[0])
        $OutDCOMSDDL = $Converter.BinarySDToSDDL($DCOM)
        $NewSDDL = $OutSDDL.SDDL += '(' + $SDDL + ')'
        $NewDCOMSDDL = $OutDCOMSDDL.SDDL += '(' + $DCOMSDDL + ')'
        $WMIbinarySD = $Converter.SDDLToBinarySD($NewSDDL)
        $WMIconvertedPermissions = ,$WMIbinarySD.BinarySD
        $DCOMbinarySD = $Converter.SDDLToBinarySD($NewDCOMSDDL)
        $DCOMconvertedPermissions = ,$DCOMbinarySD.BinarySD
        $Result = $Security.PsBase.InvokeMethod('SetSD', $WMIconvertedPermissions)
        $Result = $Reg.SetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction', $DCOMbinarySD.binarySD)
        Write-Verbose 'WMI Permissions set'
    }

    Thanks to this blog and the Microsoft blog for explaining the permissions

    • Marked as answer by DarkLite1 Wednesday, March 23, 2016 11:20 AM
    Wednesday, March 23, 2016 11:20 AM

All replies

  • Users do not have "0write" permission anywhere in WMI.  You would need to grant them that permission globally.  This is not a good idea.


    \_(ツ)_/

    Tuesday, March 22, 2016 6:44 PM
  • Thanks for the feedback jrv. You are right, it's not best practice but let me explain to you why we need this:

    1. SCCM is running the script to create this custom namespace in WMI with the System account
    2. The user logs on to the system and we collect information with a PowerShell script launched by SCCM with the user's account (collecting PST file information)
    3. This data needs to be collected somewhere so we are able to create an SCCM report for it. SCCM relies on WMI so we need the user to be able to write this information in WMI, but only in this custom namespace

    The problem is that all of this can be done with the System account but not the writing of the data to WMI, this needs to be done by the user. Is there a way to set these permissions so that the user (domain users) can write to this specific namespace?

    Thank you for your help as I'm really stuck here.

    I've almost got it to work, the 'Domain users' are added now but only with 'Enable account 'and 'Remote enabled' permissions not with 'Partial Write' as I need it:

    Param (
        [String]$Namespace = 'root/CustomCMClasses',
        [String]$Computer,
        [String]$ADaccount = "DOMAIN\Domain users"
    )
    
    Function Get-Sid {
        Param (
            $DSIdentity
        )
        $ID = new-object System.Security.Principal.NTAccount($DSIdentity)
        Return $ID.Translate( [System.Security.Principal.SecurityIdentifier] ).toString()
    }
    $sid = Get-Sid $ADaccount
    $SDDL = "A;;CCWP;;;$sid"
    $DCOMSDDL = "A;;CCDCRP;;;$sid"
    
    $Reg = [WMIClass]"\\$Computer\root\default:StdRegProv"
    $DCOM = $Reg.GetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction').uValue
    $security = Get-WmiObject -ComputerName $strcomputer -Namespace $Namespace -Class __SystemSecurity
    $converter = New-Object System.Management.ManagementClass Win32_SecurityDescriptorHelper
    $binarySD = @($null)
    $result = $security.PsBase.InvokeMethod('GetSD',$binarySD)
    $outsddl = $converter.BinarySDToSDDL($binarySD[0])
    $outDCOMSDDL = $converter.BinarySDToSDDL($DCOM)
    $newSDDL = $outsddl.SDDL += '(' + $SDDL + ')'
    $newDCOMSDDL = $outDCOMSDDL.SDDL += '(' + $DCOMSDDL + ')'
    $WMIbinarySD = $converter.SDDLToBinarySD($newSDDL)
    $WMIconvertedPermissions = ,$WMIbinarySD.BinarySD
    $DCOMbinarySD = $converter.SDDLToBinarySD($newDCOMSDDL)
    $DCOMconvertedPermissions = ,$DCOMbinarySD.BinarySD
    $result = $security.PsBase.InvokeMethod('SetSD',$WMIconvertedPermissions)
    $result = $Reg.SetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction', $DCOMbinarySD.binarySD)




    • Edited by DarkLite1 Wednesday, March 23, 2016 9:46 AM
    Wednesday, March 23, 2016 7:47 AM
  • Solved the problem for 'Partial Write':

    Function Set-WMIPermissionsHC {
        Param (
            [String]$Namespace = 'CustomCMClasses',
            [String]$Class     = 'Test',
            [String]$Account   = 'DOMAIN\Domain users',
            [String]$Computer  = $env:COMPUTERNAME
        )
    
        Function Get-Sid {
            Param (
                $Account
            )
            $ID = New-Object System.Security.Principal.NTAccount($Account)
            Return $ID.Translate([System.Security.Principal.SecurityIdentifier]).toString()
        }
    
        $SID = Get-Sid $Account
        $SDDL = "A;CI;CCSWWP;;;$SID"
        $DCOMSDDL = "A;;CCDCRP;;;$SID"
        $Reg = [WMICLASS]"\\$Computer\root\default:StdRegProv"
        $DCOM = $Reg.GetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction').uValue
        $Security = Get-WmiObject -ComputerName $Computer -Namespace "root\$Namespace" -Class __SystemSecurity
        $Converter = New-Object System.Management.ManagementClass Win32_SecurityDescriptorHelper
        $BinarySD = @($null)
        $Result = $Security.PsBase.InvokeMethod('GetSD', $BinarySD)
        $OutSDDL = $Converter.BinarySDToSDDL($BinarySD[0])
        $OutDCOMSDDL = $Converter.BinarySDToSDDL($DCOM)
        $NewSDDL = $OutSDDL.SDDL += '(' + $SDDL + ')'
        $NewDCOMSDDL = $OutDCOMSDDL.SDDL += '(' + $DCOMSDDL + ')'
        $WMIbinarySD = $Converter.SDDLToBinarySD($NewSDDL)
        $WMIconvertedPermissions = ,$WMIbinarySD.BinarySD
        $DCOMbinarySD = $Converter.SDDLToBinarySD($NewDCOMSDDL)
        $DCOMconvertedPermissions = ,$DCOMbinarySD.BinarySD
        $Result = $Security.PsBase.InvokeMethod('SetSD', $WMIconvertedPermissions)
        $Result = $Reg.SetBinaryValue(2147483650,'software\microsoft\ole','MachineLaunchRestriction', $DCOMbinarySD.binarySD)
        Write-Verbose 'WMI Permissions set'
    }

    Thanks to this blog and the Microsoft blog for explaining the permissions

    • Marked as answer by DarkLite1 Wednesday, March 23, 2016 11:20 AM
    Wednesday, March 23, 2016 11:20 AM