Search code examples
powershellcredentialsdsc

For a Desired State Configuration File resource, why does Credential work, and PsDscRunAsCredential does not?


I'm trying to learn how to use credentials with PowerShell Desired State Configuration, and I can't quite grok the difference between the Credential and PsDscRunAsCredential attributes of a resource.

As a simple test case, I'm trying to copy a folder and it's contents from a file share to a local folder on the target node. The computer account of the target node does not have access to the share, so I'm supplying credentials that do have access. If I assign the credentials to the Credential attribute of the File resource, it works. If I use the PsDscRunAsCredential attribute, I get an "access is denied" error when it tries to access the file share.

Configuration FileWithCredential {

    Import-DscResource -ModuleName PSDesiredStateConfiguration

    Node $AllNodes.NodeName {

        # copy files from a file share to a new folder on the target node
        File CopyFileShareFolder {
            Ensure = 'Present'
            Type = 'Directory'
            Recurse = $true
            SourcePath = '\\fileshare\folder\subfolder\stuff_I_want_to_copy'
            DestinationPath = 'c:\ps\DSC\filesharedestination'
            # If I use Credential instead of PsDscRunAsCredential, it works
            # Credential = Get-Credential -UserName ourdomain\myaccout -Message 'Enter Password'
            PsDscRunAsCredential = Get-Credential -UserName ourdomain\myaccout -Message 'Enter Password'
        }
    }
}

$ConfigData = @{
    AllNodes = @(
        @{
            NodeName = 'target-server'
            PsDscAllowDomainUser = $true
            PsDscAllowPlainTextPassword = $true
        }
    )
}

I'm compiling the MOF on a Windows 10 box and pushing the configuration to a Server 2016 box. Both are running PowerShell 5.1.

PS C:\Users\me\Documents\pscode\dsc_test2> FileWithCredential -ConfigurationData $ConfigData
PS C:\Users\me\Documents\pscode\dsc_test2> Start-DscConfiguration .\FileWithCredential\ -Verbose -Wait -Force

I understand that PsDscRunAsCredential is new, and I'm assuming there's a reason to prefer it over the old Credential, but I can't figure out what the real differences are. Are they basically interchangeable? If not, what am I missing that would make the "run as" credential work?

NOTE: I understand the security risk of allowing plain text passwords, but right now I'm just trying to understand how to pass credentials and make sure they work. Learning how to do so securely is next on my list.


Solution

  • It seems like my hunch might have been right; turning my comment into an answer:

    I just had a thought: the File resource is.. somewhat special. It's one of the only resources implemented as binary. It has some strange quirks like not returning a ModuleName when you run Get-DscResource. Maybe it's implemented in a way that the LCM cannot change its context. It would be interesting to turn on debugging for DSC, then break into the debugger and check out your context, try to access the share and local file system, etc.

    In running a test, it seems to be the case that (for whatever reason) the File resource simply doesn't properly support PsDscRunAsCredential.

    Here's a demonstration using Invoke-DscResource, comparing File with Script and showing that the owner of a resulting file is different.

    With File, the owner is always SYSTEM.

    With Script, the owner is SYSTEM when run with no credential (expected), but when run with a credential, the owner is different (in my case, the owner became the local Administrators group, because the credential I supplied is a local admin).

    $cred = Get-Credential
    
    $module = 'PsDesiredStateConfiguration'
    
    $fprop = @{
        DestinationPath = "$env:USERPROFILE\delme.txt"
        Contents = "Hello"
    }
    
    $sprop = @{
        GetScript = { @{} }
        TestScript = { $false }
        SetScript = [ScriptBlock]::Create("'Hello'|sc '$env:USERPROFILE\delme.txt'")
    }
    
    $cprop = @{ PsDscRunAsCredential = $cred }
    
    function Assert-FileTest { Get-Item -LiteralPath $fprop.DestinationPath | % { $_.GetAccessControl().Owner | Write-Verbose -Verbose ; $_ } | Remove-Item -Force }
    
    Invoke-DscResource -Name File -ModuleName $module -Method Set -Property $fprop -Verbose
    Assert-FileTest
    
    Invoke-DscResource -Name File -ModuleName $module -Method Set -Property ($fprop + $cprop) -Verbose
    Assert-FileTest
    
    
    Invoke-DscResource -Name Script -ModuleName $module -Method Set -Property $sprop -Verbose
    Assert-FileTest
    
    Invoke-DscResource -Name Script -ModuleName $module -Method Set -Property ($sprop + $cprop) -Verbose
    Assert-FileTest