DSC Script resource and alternate credentials

This topic contains 4 replies, has 3 voices, and was last updated by Profile photo of Matthew Sullenberger Matthew Sullenberger 2 years ago.

  • Author
    Posts
  • #20660

    Having a heck of a time geting DSC Script resources to work with alternate credentials. I'm open to any suggestions right now.

    I have public/private certificates being used and am successfully encrypting credentials in my mof files, using a pull server. Passing the Credential parameter to a resource works fine on all other resources, however I am trying to automate some of my setup tasks using powershell scripts. It just doesn't seem to work! Here is a small example script resource for testing and verification. :

    Script Whodis
        {
            GetScript = { 
                return @{ 
                    SetScript = $SetScript
                    TestScript = $TestScript
                    GetScript = $GetScript                
                }
            }
            TestScript = { $false } # Always execute this script -- leave it up to script to be indempotent
            SetScript = ([String]{            
                whoami >> C:\test\whodis.txt
            })
        }
    

    Running that as is logs "nt authority\system" to the text file, as would be expected.

    It also appears that this will only run once regardless of TestScript always returning false, which is not how I'd expect this to work. If TestScript returns true the script will never run, but if it returns false it will run SetScript a single time and never again until the checksum changes. In my mind if TestScript continues to return false, SetScript will continue to run. But that is a digression.

    At this point everything is working like I'd expect, factoring in the single run. Get-DscConfiguration works and returns the expected results.

    So now we add the Credential parameter, and everything starts getting funky:

    Script Whodis
        {
            Credential = $Credential
            GetScript = { 
                return @{ 
                    SetScript = $SetScript
                    TestScript = $TestScript
                    GetScript = $GetScript                
                }
            }
            TestScript = { $false } # Always execute this script -- leave it up to script to be indempotent
            SetScript = ([String]{            
                whoami >> C:\test\whodis.txt
            })
        }
    

    Supposing 'contoso\admin' was the user specified by $Credential, the correct username is logged in the whodis.txt file, however now Get-DscConfiguration is busted:

    Get-DscConfiguration : PowerShell provider MSFT_ScriptResource  failed to execute Get-TargetResource functionality
    with error message: Failure to get the results from the script in a hash table format.
    

    and I haven't found anyway to fix that. Also, and this is the bigger issue for me, the script doesn't have access to any network resources regardless of the permission level of the account specified. I'm assuming this is a "double-hop" issue, but I don't know how to specify CredSSP for this. I can make it work by wrapping my SetScript code inside a "Invoke-Command" call and hard-coding the credentials, but that defeats the point of the public key encryption and I am unwilling to do it in production.

    Any thoughts?

    EDIT:
    Sorry, I just read the FAQ and saw that I shouldn't have replied to my own post. I apologize, I'm new to this community and did not read that prior to posting. I'd delete the second post if I could.

  • #20661

    Here is an example of a script resource with hard coded alternate credentials that can access network resources. This is the only way I've found so far that works.

    Script Whodis
    {
        GetScript = { 
            return @{ 
                SetScript = $SetScript
                TestScript = $TestScript
                GetScript = $GetScript                
            }
        }
        TestScript = { $false } # Always execute this script -- leave it up to script to be indempotent
        SetScript = ([String]{            
            $password = ConvertTo-SecureString 'password' -AsPlainText -Force
            $credential = New-Object System.Management.Automation.PSCredential "CONTOSO\admin",$password
            Invoke-Command { get-acl \\SERV1\ACLTemplates\test | set-acl c:\test } -ComputerName Localhost -EnableNetworkAccess -Credential $credential -Authentication CredSSP
        })
    }
    

    As a bonus, since this script doesn't specify a Credential parameter to the resource, Get-DscConfiguration works again. Removing -EnableNetworkAccess or -Authentication CredSSP breaks it again. And of course, the credentials are hard-coded and unencrypted in the mof file and the configuration on the server.

  • #20666
    Profile photo of Don Jones
    Don Jones
    Keymaster

    In terms of the Set- only running once, check the LCM and make sure it is set for ApplyAndAutoCorrect, not ApplyAndMonitor. The default isn't to continually run Set-.

  • #20667
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I wouldn't recommend putting the credentials into the SetScript like that, unless you're using plain-text credentials in your MOF documents anyway. The Credential parameter will be encrypted if you've set up certificates for that, but the code in the Set script will not. (Technically, you could manually encrypt this data when compiling the MOF document and decrypt it in the resource's script blocks, using the same certificate, if you really need to do this.) In fact, it's generally not recommended to use the Script resource at all, when it can be at all avoided; it's better to make resources that specifically do what you need done, if they don't exist already.

    As for your problems accessing remote resources, you can see the source code for the script resource in $pshome\Modules\PSDesiredStateConfiguration\DSCResources\MSFT_ScriptResource\MSFT_ScriptResource.psm1 . It looks like when the Credential property is set, it runs script blocks like this:

    $scriptExecutionResult = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName . -Credential $Credential
    

    Which probably means that you will run into second-hop problems there. You could make a community modification of the Script resource which allows you to specify the authentication type for the operation (and likely a dependency on xCredSSP to make sure that authentication type is enabled before the cScript resource runs.)

  • #20671

    In terms of the Set- only running once, check the LCM and make sure it is set for ApplyAndAutoCorrect, not ApplyAndMonitor. The default isn't to continually run Set-.

    Awesome. This corrected the only running once issue.

    Dave: Yeah I wouldn't do the hard coded credentials inside SetScript in production, that was just an example of how I could force it to behave. I'll look into building custom resources to replace what I do in scripts. I've only just begun investigating DSC and was just a little frustrated with the weirdness I was running into. Right now we have a system of setup scripts that get copied to a newly provisioned machine and run locally to handle all the configuration (create folderpaths, set ACLs, add to DFS replication groups, create connections, etc). I'll look into replacing those with Dsc resources. I just found a guide published yesterday on an MSDN blog called "PowerShell DSC Resource Design and Testing Checklist" — guess it is time to go through that!

    [url]http://blogs.msdn.com/b/powershell/archive/2014/11/18/powershell-dsc-resource-design-and-testing-checklist.aspx[/url]

    Thanks!

You must be logged in to reply to this topic.