PowerShell / PSDscResources

MIT License
129 stars 53 forks source link

User: Docker windows container - UserResource FindByIdentity error #99

Open dazinator opened 6 years ago

dazinator commented 6 years ago

I am trying to use the UserResource in order to provision a windows docker container.

The error I see is:

VERBOSE: [7FA4183C543B]: LCM: [ Start Resource ] [[User]IisRemoteAdminUser] VERBOSE: [7FA4183C543B]: LCM: [ Start Test ] [[User]IisRemoteAdminUser] VERBOSE: [7FA4183C543B]: LCM: [ End Test ] [[User]IisRemoteAdminUser] in 0.6100 seconds. PowerShell DSC resource MSFT_UserResource failed to execute Test-TargetResource functionality with error message: System.InvalidOperationException: There could be a possible multiple matches exception while trying to use the System.DirectoryServices API's.Exception calling "FindByIdentity" with "2" argument(s): "The Server service is not started. "

  • CategoryInfo : InvalidOperation: (:) [], CimException
  • FullyQualifiedErrorId : ProviderOperationExecutionFailure
  • PSComputerName : localhost

My DSC script tries to create a user and assign to the local administrators group:

Note I import the PSDscResources module at the start of the script, due to the answer here which suggested importing PSDesiredStateConfiguration is older and PSDscResources may have this issue fixed: https://github.com/PowerShell/DscResources/issues/235


Configuration BasicIIS
{  

    Import-DscResource -ModuleName PSDscResources 
    node localhost
    {       

 param(
    [Parameter(Mandatory = $true)][PSCredential]$credential,
    [Parameter(Mandatory = $true)][string]$userName
    )

        Group AdminGroupIncludeIisRemoteAdminUser
        {
            # This removes TestGroup, if present
            # To create a new group, set Ensure to "Present“            
            Ensure = "Present"
            GroupName = "Administrators"
            MembersToInclude= "$userName"
            Credential = $credential
            DependsOn = "[User]IisRemoteAdminUser"
        }
        User IisRemoteAdminUser # User for remote IIS administration
        {
            Ensure = "Present"  
            UserName = $userName
            Password = $credential# This needs to be a credential object           
        }    

    }
}

$userName= "Foo"
$secUserPassword = ConvertTo-SecureString "Passw0rd" -AsPlainText -Force
$userCreds = New-Object System.Management.Automation.PSCredential ($userName, $secUserPassword )

$cd = @{
    AllNodes = @(
        @{
            NodeName = 'localhost'
            PSDscAllowPlainTextPassword = $true
        }
    )
}

BasicIIS -credential $userCreds -userName $userName -ConfigurationData $cd

Start-DscConfiguration -Path .\BasicIIS -Wait -verbose -Force

My docker file looks like this:


# escape=`
FROM microsoft/aspnet

# Following script just does some prep to install some some tools like the nuget module provider for powershell, and chocolatey etc etc.
ADD ./SetupBasicTools.ps1 /SetupBasicTools.ps1
RUN powershell -NoProfile -File C:\SetupBasicTools.ps1

# The following runs the powershell script above with the user resource where I see the error.
ADD ./web/SetupBasicIIS.ps1 /SetupBasicIIS.ps1
RUN powershell -NoProfile -File C:\SetupBasicIIS.ps1 -logsDir C:/logs
dazinator commented 6 years ago

It looks like there is a problem when trying to create users on a windows docker container using active directory services: https://github.com/moby/moby/issues/26409

One suggestion is that Powershells New-LocalUser should work.

Is it possible the User resource could be changed to use Powershells New-LocalUser method to create a user when creating a local user, avoiding the need to call into Directory Services which doesn't work on windows containers?

johlju commented 6 years ago

@dazinator Thanks for the detailed information. I could reproduce it with that.

The resource seems to be using New-LocalUser.

https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_UserResource/MSFT_UserResource.psm1#L872

It seems it is the Test-TargetResource function that fails when it tries to evaluate the state. Not sure what the workaround would be for containers in this case. 🤔

https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_UserResource/MSFT_UserResource.psm1#L1288

I had to modify the scripts you provided to reproduce this. For anyone else wanting to reproduce this. Put both these files in the same folder then run docker build.

Dockerfile

FROM microsoft/aspnet

ADD ./SetupBasicIIS.ps1 /SetupBasicIIS.ps1
RUN powershell -NoProfile -Command 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'
RUN powershell -NoProfile -Command 'Install-Module -Name PSDscResources -Force'
RUN powershell -NoProfile -File C:\SetupBasicIIS.ps1 -logsDir C:/logs

SetupBasicIIS.ps1

Configuration BasicIIS
{
    param
    (
        [Parameter(Mandatory = $true)][PSCredential]$credential,
        [Parameter(Mandatory = $true)][string]$userName
    )

    Import-DscResource -ModuleName PSDscResources

    node localhost
    {
        User IisRemoteAdminUser # User for remote IIS administration
        {
            Ensure   = "Present"
            UserName = $userName
            Password = $credential# This needs to be a credential object
        }

        Group AdminGroupIncludeIisRemoteAdminUser
        {
            # This removes TestGroup, if present
            # To create a new group, set Ensure to "Present“
            Ensure           = "Present"
            GroupName        = "Administrators"
            MembersToInclude = @($userName)
            Credential       = $credential
            DependsOn        = "[User]IisRemoteAdminUser"
        }
    }
}

$userName = "Foo"
$secUserPassword = ConvertTo-SecureString "Passw0rd" -AsPlainText -Force
$userCreds = New-Object System.Management.Automation.PSCredential ($userName, $secUserPassword )

$cd = @{
    AllNodes = @(
        @{
            NodeName                    = 'localhost'
            PSDscAllowPlainTextPassword = $true
        }
    )
}

BasicIIS -credential $userCreds -userName $userName -ConfigurationData $cd

Start-DscConfiguration -Path .\BasicIIS -Wait -verbose -Force
dazinator commented 6 years ago

Thanks for confirming. I worked around this by using net user commands directly to create the user and add them to the admin group, bypassing powershell completely.

johlju commented 6 years ago

Thanks for sharing the workaround!

kwirkykat commented 6 years ago

@johlju New-LocalUser is only called in this resource if the resource detects that it's running on a Nano Server. Is the container running Nano Server? Otherwise this UserPrincipal call creates a user: https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_UserResource/MSFT_UserResource.psm1#L1321

From the error message it sounds like the command is trying to call into the server.msc service which isn't running in the container so it fails.

It sounds like the test for which version of the resource we should run needs to be "Are we running on an older PowerShell?" and if yes then run the UserPrincipal call. Otherwise, run the New-LocalUser call by default. Or it could be "Is the cmdlet New-LocalUser available?" and if yes then run with that newer code rather than the principal stuff that seems buggy.

dazinator commented 6 years ago

@kwirkykat

Is the container running Nano Server?

The docker container I was using is based on microsoft/aspnet which is windows server core.

johlju commented 6 years ago

@kwirkykat To me it feels like it never get to the Set-function, it fails in the Test-function. Here is the verbose output. I forgot to add it to my previous comment. But still, you are correct, there need to by another method of checking for this on the windowsservercore container.

VERBOSE: Perform operation 'Invoke CimMethod' with following parameters,
''methodName' = SendConfigurationApply,'className' =
MSFT_DSCLocalConfigurationManager,'namespaceName' =
root/Microsoft/Windows/DesiredStateConfiguration'.
VERBOSE: An LCM method call arrived from computer 03D719EA5C35 with user sid
S-1-5-93-2-1.
VERBOSE: [03D719EA5C35]: LCM:  [ Start  Set      ]
VERBOSE: [03D719EA5C35]: LCM:  [ Start  Resource ]  [[User]IisRemoteAdminUser]
VERBOSE: [03D719EA5C35]: LCM:  [ Start  Test     ]  [[User]IisRemoteAdminUser]
VERBOSE: [03D719EA5C35]: LCM:  [ End    Test     ]  [[User]IisRemoteAdminUser]
 in 1.7070 seconds.
PowerShell DSC resource MSFT_UserResource  failed to execute
Test-TargetResource functionality with error message:
System.InvalidOperationException: There could be a possible multiple matches
exception while trying to use the System.DirectoryServices API's.Exception
calling "FindByIdentity" with "2" argument(s): "The Server service is not
started.
"
    + CategoryInfo          : InvalidOperation: (:) [], CimException
    + FullyQualifiedErrorId : ProviderOperationExecutionFailure
    + PSComputerName        : localhost

VERBOSE: [03D719EA5C35]: LCM:  [ End    Set      ]
The SendConfigurationApply function did not succeed.
    + CategoryInfo          : NotSpecified: (root/Microsoft/...gurationManager
   :String) [], CimException
    + FullyQualifiedErrorId : MI RESULT 1
    + PSComputerName        : localhost

VERBOSE: Operation 'Invoke CimMethod' complete.
VERBOSE: Time taken for configuration job to complete is 9.556 seconds