0

In no alternative reality can i be considered a sysadmin. To the contrary, i support an ERP system and use PowerShell as a programming language to do BI kinds of things because i don't have access to the language the ERP is written in. So, please overlook my ignorance on the subject of this question.

To keep our ERP in sync with an engineering system, i've created a suite of programs. The first one validates the AD account's password used to signon the PC and outputs it to a file for later use. The program works on the Windows 7 machine it was developed on. However, it gives this error when run on a Windows 10 machine. The function "Test-ADCredential" was stolen from the interned and is not mine.

Exception calling "ValidateCredentials" with "2" argument(s): "The server cannot handle directory requests."
At C:\GitRepo\PowerShellScripts\TeamCenter2M3AdCheck.ps1:20 char:9
+         $DS.ValidateCredentials($UserName, $Password)
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DirectoryOperationException

PowerShell on the development machine (Windows 7):

Name                           Value
----                           -----
PSVersion                      5.1.14409.1012
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14409.1012
CLRVersion                     4.0.30319.34209
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Version on Windows 10:

Name                           Value
----                           -----
PSVersion                      5.1.15063.786
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.15063.786
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Here is the program:

# TeamCenter2M3AdCheck.ps1  Verify the password for current user and pass the user/id for MDI update
#  02/05/2018

param ([string]$IniFile)

Import-Module "C:\GitRepo\PowerShellScripts\TeamCenter2M3Setup.psm1" -Force

function Test-ADCredential {
  [CmdletBinding()]
    Param ([string]$UserName,
           [string]$Password)
    if (!($UserName) -or !($Password)) {
        Write-Warning 'Test-ADCredential: Please specify both user name and password'
    } else {
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('domain')
        $DS.ValidateCredentials($UserName, $Password)
    }
}  # function Test-ADCredential

# Initilize globlal variables from the INI file
IniParameters -IniFile $IniFile

$PasswordFile = $TC2M3Dir + "TeamCenterPassword.csv"
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
[Byte[]] $Key = (1..16)

$UserId = $env:USERNAME
Do {  #loop until password is okay
    # Request the account's password
    $SecurePassword = Read-Host -AsSecureString  -Prompt "Enter password for $UserId"
    $UnsecurePassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword))
    $Okay = Test-ADCredential -UserName $UserId -Password $UnsecurePassword

    If ($Okay) {
      $PasswordString = ConvertFrom-SecureString -SecureString $SecurePassword -Key $Key
     $CsvText = "AdAccount,Password`n$UserId,$PasswordString"
     Out-File -FilePath $PasswordFile -InputObject $CsvText -Encoding ascii
   }
   else {
        Write-Host "Password failed.  Please try again or press Ctrl+c" -ForegroundColor Red
    }
} Until ($Okay)

Thanks in advance for your help.

rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
RickInGarland
  • 93
  • 1
  • 8
  • 1
    Wait, you are saving the password in an open text file? – EBGreen Mar 13 '18 at 18:04
  • "validates the AD account's password used to signon the PC and outputs it to a file for later use." I just have to say that this sounds insane, please don't. With regards to the issue you describe, are both machines and the user accounts that run the scripts all in the same domain? – Mathias R. Jessen Mar 13 '18 at 18:07
  • That would get you a stern talking to at the very least and often fired at most companies that I have worked at. – EBGreen Mar 13 '18 at 18:17
  • The text file passed out of this program is encrypted. Yes, both machines are in the same domain and the passwords are the same because I'm using my account for testing. – RickInGarland Mar 13 '18 at 19:11
  • Are there different .net frameworks on the two systems? Or is one system domain joined and the other isn't? Do both systems run the script as admin? – Nick W. Mar 13 '18 at 19:31

1 Answers1

1

Change:

$DS.ValidateCredentials($UserName, $Password)

To:

$DS.ValidateCredentials($UserName, $Password, [DirectoryServices.AccountManagement.ContextOptions]::Negotiate -bor [DirectoryServices.AccountManagement.ContextOptions]::Sealing)

Essentially, on the new machine, it is likely falling back to trying to use Basic Authentication, and not using "Negotiate" (i.e. Use Kerberos or NTLM to encrypt connection to AD) to do the validation. By explicitly setting the Context option to force Negotiate or Sealing (another encryption variant), this should fix the issue.

I confirmed that I was able to have the code work on Windows 10.

References:

HAL9256
  • 12,384
  • 1
  • 34
  • 46