Trying to implement authentication against *either* Active Directory, or local Windows user accounts

I’m trying to use the following code for within authentication.ps1 (PowerShell Universal is installed on a Windows Server):

Set-PSUAuthenticationMethod -Type "Form" -ScriptBlock {
    param(
        [PSCredential]$Credential
    )

    $AddTypeSplat = @{
        AssemblyName = System.DirectoryServices.AccountManagement
    }
    Add-Type @AddTypeSplat

    If ([boolean](Get-WmiObject -Class 'Win32_ComputerSystem').PartOfDomain) {
        $ContextType, $Context = [System.DirectoryServices.AccountManagement.ContextType]::Domain, $Env:USERDOMAIN
    }
    Else {
        $ContextType, $Context = [System.DirectoryServices.AccountManagement.ContextType]::Machine, $Env:COMPUTERNAME
    }
    $PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ContextType, $Context)

    If ([boolean]($PrincipalContext.ValidateCredentials($Credential.Username, $Credential.GetNetworkCredential().Password))) {
        New-PSUAuthenticationResult -Success -UserName $Credential.Username
    }
    Else {
        New-PSUAuthenticationResult -ErrorMessage "Bad username or password"
    }
} 

Trying to log on fails (with Bad username or password message); and in the PowerShellCore Operational eventlog, I see the following error:
Error Message = Cannot find an overload for "PrincipalContext" and the argument count: "2"..
When testing the same code (leaving out the PSU related cmdlets) directly in a powershell shell; this code works correctly.

How can I make this code work, or how can I troubleshoot this in more details?

Product: PowerShell Universal
Version: 2.5.3

Personally I’ve never seen it done this way - using form auth inside PSU.
I host my instance in IIS and originally used windows pass thru authentication, until I recently switched to azure based OIDC.

Lets take a step back,
You can enable windows authentication in the app settings file.
If you’re using IIS this is probably relevant:

Otherwise there’s this:

I think if you hit the site with a non AD account, it would still ‘pass thru’ the current local user e.g hostname\username.

The idea being that as long as the user is logged in - they wouldn’t need a login form, it’ll just pass through. You can then use role based auth inside PSU to either allow them in or not (or to specific pages, or controls) depending on whatever criteria you use for example, username, group memberships, and so on.

Is there any specific reason you’re trying to use forms?

The reasoning is that I want to deploy appliances with REST API; and I am expecting these appliances to be deployed in greenfield environments where they will either be domain-joined, or not.

The appliances will also be accessed from systems that are not part of the customer’s environment (support engineers servicing multiple projects)

It could be that I misunderstood the purpose of authentication.ps1 and that enabling Windows actually is sufficient; I am going to test this :slight_smile:

Regardless, I am still curious why the method .PrincipalContext isn’t working within PSU…

How are you hosting your PSU instance? if it’s running as system, maybe that could be why?
I’m not really familiar with validate credentials though, never used it that way.
One way you could test is running it as a scheduled task non interactively, seeing if it works that way too.

You could also output a test user and password to a text file in authentication.ps1 and make sure that the values are actually getting passed in correctly.

Hmm, good one; I’ll try to run it as System (by the way, using psexec -i -s cmd allows you to run commands as System more easily than through a scheduled task).

Regarding the credentials possibly not being passed through correctly (they are, I tested it with hardcoded values); the script doesn’t even reach that part though.

EDIT: Just tested; running the same code under System works without issues.

If I run the same above code in a PSUEndpoint; I am getting the same error Error Message = Cannot find an overload for "PrincipalContext" and the argument count: "2".

Why is this code not working within PSU’s environments, when it is working as regular PowerShell code?

It might have to do with the fact that PSU (by default) is running the security code in the integrated environment (PS 7.1.4). Does your code work in Windows PowerShell? Have you tried in 7.1.4? You can also change your security environment by navigating to Settings \ General \ Environments.

The problem seems to have gone away, I’m not sure why or how… :frowning: