Welcome to the Inedo Forums! Check out the Forums Guide for help getting started.

If you are experiencing any issues with the forum software, please visit the Contact Form on our website and let us know!

$PSCredential- round two



  • So, I am still struggling to pass the windows credentials stored in the resource credentials stored in the DB. I don't want to enter credentials manually or via in plain text, so unless I can get that stored password value, I fail to see the value in this for Windows Domain authentication. I found the documentation here:

    https://docs.inedo.com/docs/otter/reference/functions/powershell/pscredential

    But that does nothing to explain it. Does this have the username and password stored from the resource credentials so they can be used like a get-credential variable for domain authentication? I really need to pass the credentials stored in the DB to authenticate, thanks!


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    I'm sorry about this, but it looks like our documentation was out of date. We just updated our documentation and this should help to answer your question. $PSCredential now can be called in two different ways; with a username and password or by passing the resource credential name.

    In order to use a resource credential within your PowerShell, you would just need to pass your resource credential name. For example:

    # convert a resource credential named MyCredential to a PSCredential object
    PSCall MyPowerShellScript
    (
        Credentials: $PSCredential(MyCredential)
    );
    

    Please let me know if this doesn't work for you.

    Thanks,
    Rich



  • Well, my question is not being answered I feel. That example lacks any context of use, so I can't really articulate what I can do with that. It's like if I called you and said some random thing like "rock" and hung up. OK, what is a person supposed to do with that information? I want to be able to do something like this in my configure portion of a psensure:

    Move-ADObject -Identity (Get-ADComputer -Identity $env:COMPUTERNAME).ObjectGuid -Server $pdc -TargetPath $TargetOU -Credential "$PSCredential"

    Is that all I need to do? If so, this is not working. The line of code works fine without the credential line in PowerShell, but does not work in Otter. I am having authentication issues, and need to be able to pass stored credentials I would like these questions answered:

    1. Is the $PSCredential being populated from the resource credentials stored in Otter for each server?
    2. Are the Username and Password sections populated from a plain text entry or manual intervention to populate the $PSCredential?
    3. If 1 and 2 have the answer of no, where are they coming from?

  • inedo-engineer

    Hi @Jonathan-Engstrom,

    You will need to create a Resource Credential named MyCredential and then you can use that within your psensure PowerShell like this:

    Move-ADObject -Identity (Get-ADComputer -Identity $env:COMPUTERNAME).ObjectGuid -Server $pdc -TargetPath $TargetOU -Credential $PSCredential(MyCredential)
    

    By using a Resource Credential in Otter, the username and password will be securely stored in the Otter database. Please let me know if this does not work for you.

    Thanks,
    Rich



  • OK, thank you for the example, that makes much more sense with context around it. However, I am still not able to get this to work. I am not able to get the Move-ADObject cmdlet to work in Otter regardless even though I can get them to work every time outside of Otter. OK, so tried to do something different just in case. Same issue again, I can't get this line of code to work in an PSEnsure either:

    ([adsisearcher]"samaccountname=$($env:computername)$").FindOne()

    This should return some simple AD attributes for the computer and runs fine outside of Otter. This does not work either when put inside of Otter. Wondering if there is something that is not allowing this code to work?


  • inedo-engineer

    Hi @Jonathan-Engstrom,

    Could you please reply with the log output from the failed PowerShell operation?

    Thanks,
    Rich



  • Here is the output. I also tested trying to use the method Findall instead of FindOne, it didn't make a difference.

    Configuration job is targeting 1 servers by name.
    Building configuration plan for server server.domain.test to target 1 roles.
    Finished processing role configuration plans.
    server.domain.test does not have a configuration plan in raft Default.
    Finished processing 2 scripts.
    Beginning collection run...
    Collecting configuration...
    Importing Name...
    Importing ModuleName...
    Invoke-DscResource -Name $Name -Method Get -Property $Property -ModuleName $ModuleName
    Importing Name...
    Importing Property...
    Importing ModuleName...
    Invoke-DscResource -Name $Name -Method Test -Property $Property -ModuleName $ModuleName
    Importing Name...
    Importing Property...
    Importing ModuleName...
    Comparing configuration...
    Configuration matches template.
    Collecting configuration...
    Importing TargetOU...
    Comparing configuration...
    Difference: Value
    =Template=> True
    = Actual => , False
    Configuration drift detected.
    Adding to execution plan.
    Collection run complete.
    Collection run succeeded.
    Beginning execution run...
    Importing TargetOU...
    Importing ServerName...
    Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
    "
    You cannot call a method on a null-valued expression.
    Storing configuration template...
    Execution run failed.
    Recording configuration for server (ID=#2050)...
    Configuration for server (ID=#2050) recorded.
    Cleaning up temporary files on PowerShell...


  • inedo-engineer

    Hi @Jonathan-Engstrom,

    In the log I see:

    @Jonathan-Engstrom said in $PSCredential- round two:

    Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
    "
    You cannot call a method on a null-valued expression.

    Can you please include the OtterScript PowerShell command you are calling? Also, do you see any errors in the Diagnostic Center found at http://{YOUR_OTTER_SERVER}/administration?

    Thanks,
    Rich



  • I have a variable that specifies the TargetOU, it's just the path of the OU of where I want to move the computer account to. This is what is in the configure block of my PSEnsure:

    $newOU =  [adsi]"LDAP://$TargetOU"
    $test = ([adsisearcher]"samaccountname=$($ServerName)$").FindOne
    $comp.GetDirectoryEntry.MoveTo($newOU)
    

    There is no errors in the Diagnostic Center pertaining to this error.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    Sorry for the delay. I'm working on recreating the error locally. I'll follow up with you once I have more information.

    Thanks,
    Rich


  • inedo-engineer

    Hi @Jonathan-Engstrom,

    Can you try switching up your PowerShell a bit to this:

    $samAccountName = $ServerName
    $newOU =  [adsi]"LDAP://$TargetOU"
    $test = ([adsisearcher]"samaccountname=$($samAccountName)$").FindOne()
    $comp.GetDirectoryEntry.MoveTo($newOU)
    

    Thanks,
    Rich



  • @rhessinger said in $PSCredential- round two:

    $samAccountName = $ServerName
    $newOU = [adsi]"LDAP://$TargetOU"
    $test = ([adsisearcher]"samaccountname=$($samAccountName)$").FindOne()

    Good morning, I made this this change, and there was no change. I had the same error.


  • inedo-engineer

    Hi @Jonathan-Engstrom,

    I entered your PowerShell locally on my computer this way

    $newOU =  [adsi]"LDAP://$TargetOU"
    $comp= ([adsisearcher]"samaccountname=$($ServerName)$").FindOne()
    $comp.GetDirectoryEntry().MoveTo($newOU)
    

    And that seems to work for me. The main thing I did have to change was adding in parentheses after FindOne and GetDirectoryEntry and I had to change $test to $comp. Is it possible that your PowerShell has the same issues?

    Thanks,
    Rich



  • I am not having a problem running the code locally, I am having a problem running it in Otter. The code I have works fine when run in PowerShell by itself; hence why I am wondering what is going on here.

    That code does not work in Otter for me btw, I did not test outside of Otter.


  • inedo-engineer

    Hi @Jonathan-Engstrom

    I'm sorry, I should have clarified. I have a local install of Otter and I put that PowerShell inside a PSEnsure operation in my configuration for my server. It ran without issue for me, outside of the small tweaks I had to make to the syntax that I noted earlier. Would you be able to post your Otter Script operation for the PSEnsure block? Also, when you are testing the PowerShell directly, are you testing it using the same account that the otter service (or agent) is running as?

    Thanks,
    Rich



  • Here is the code for the PSEnsure:

    ##AH:UseTextMode

    #Assembled Jonathan Engstrom 20200219

    PSEnsure
    (
    Key: $KeyName,
    Value: True,
    Collect: >>

    $ErrorActionPreference = 'SilentlyContinue'
    $Value = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName -match $TargetOU
    $CurrentValue = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName
    ((($Value -eq $true) -and (($env:COMPUTERNAME) -match 'sql')) -or ($env:COMPUTERNAME -notmatch 'sql'))
    

    ,
    Configure: >>

    $samAccountName = $ServerName
    $newOU =  [adsi]"LDAP://$TargetOU"
    $comp= ([adsisearcher]"samaccountname=$($ServerName)$").FindOne()
    $comp.GetDirectoryEntry().MoveTo($newOU)
    

    );

    KeyName and TargetOU variables are set. I am not running an agent, I am doing everything agentless.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    I'm stumped on this one. I took your Otter script and put it in my local version of otter. I swapped sql for my computer name and didn’t run the actual .MoveTo operation and everything runs perfectly fine in my instance.

    Here is my OtterScript:

    PSEnsure
    (
        Key: RSHStuff,
        Value: True,
        Collect: >>
    
            $ErrorActionPreference = 'SilentlyContinue'
            $TargetOU = 'Users'
            $Value = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName -match $TargetOU
            $CurrentValue = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName
            ((($Value -eq $true) -and (($env:COMPUTERNAME) -match 'MyComputerName')) -or ($env:COMPUTERNAME -notmatch 'MyComputerName')) 
            >>,
        Configure: >>
                    
            $samAccountName = $ServerName
            $newOU = [adsi]"LDAP://$TargetOU"
            $comp= ([adsisearcher]"samaccountname=$($ServerName)$").FindOne()
            Write-Host $comp.GetDirectoryEntry()
                                    
                                    >>,
        Debug: true,
        Verbose: true
    );
    

    Thanks,
    Rich



  • Looking at your example, I am not sure how it could work. Your TargetOU is not in distinguished name format. Should be something like "'CN='Users',DN='Domain',DN='Test'". Did you move the computer object from one OU to another? I am curious about the results there.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    The $TargetOU was intentionally malformed to force a configuration drift. In the Configure property, it did not matter because I did not actually run the MoveTo operation. That was the only thing I didn't actually do. But according to your error:

    Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
    "
    You cannot call a method on a null-valued expression.`.

    The only line that could have caused that error was ([adsisearcher]"samaccountname=$($ServerName)$").FindOne(). I actually decompiled the MoveTo method from Microsoft to verify that it did not call a FindAll or FindOne method. I did verify that Microsoft calls FindAll from within FindOne by decompiling FindOne.

    If you are trying to verify which line it actually threw the error on, you could use Write-Host in your PowerShell between each line and enable Debug and Verbose on your PSEnsure operation. The execution log will then show you the Write-Host outputs.

    Currently, my best guess is that the machine and user combination that you are remotely attempting to run this on either does not have access to query/update the domain or does not have adsisearcher library installed on that machine for that user.

    Thanks,
    Rich



  • Strange. I am running the code locally on the target server in powershell, and it is working flawlessly. The FindOne and FindAll work to limit the machine. Intellisense also auto completes these, so they are present and working.

    ([adsisearcher]"samaccountname=$($env:computername)$").FindOne()

    works fine and returns the result on the sql machine I am targeting the psensure configuration on. I am not changing the code or machine I am testing on; changing anything or introducing variables would not constitute a very scientific observation. Same code, same machine. When run locally, works fine. When run in Otter, it does not work. I am guessing it is how Otter formats things sometimes; that would be my guess. But Otter is not handling this line of code. and it would help to understand why.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    I have noticed the $ServerName uses the name of my server configured in Otter, not the actual computer name. Have you tried running the remediation using $env.computername instead of $ServerName? Or can you verify the Server Name in Otter matches the computers name?

    Thanks,
    Rich



  • That's a good idea, but I actually started off using the $env:computername and switched to $servername thinking that maybe somehow Otter wasn't using the $env:computername variable, but it didn't make any difference.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    What version of PowerShell do you have installed on your SQL server? I'm running 5.1.18362.628.

    Thanks,
    Rich



  • It's a 2016 Server, so it comes preinstalled with 5.1. 5.1.14393.3471 is the specific version.


  • inedo-engineer

    @Jonathan-Engstrom said in $PSCredential- round two:

    Same code, same machine.

    Same user?

    @Jonathan-Engstrom said in $PSCredential- round two:

    it would help to understand why.

    FYI -- Otter doesn't format PowerShell; it parses the PowerShell script (using MIcrosoft's parser), looks for variable tokens, and "injects" a variable into the runtime if there's a matching variable.

    The interactive Powershell Host (which you're using, ps.exe) also does things differently. There's a ton of layers-upon-layers with active directory. so it'll take some trial/error to find out what's happening.



  • Yes, same user. Like I said, I have taken great care to eliminate variables trying to understand what is going on.


  • inedo-engineer

    Hi @Jonathan-Engstrom ,

    Have you tried wrapping your PSEnsure inside of a with block to force everything to run as a specific Resource Credential?

    Example using a resource credential named AdAdminResourceCredentials:

    with credentials = AdAdminResourceCredentials
    {
    	PSEnsure
    	(
    	    Key: RSHStuff,
    	    Value: True,
    	    Collect: >>
    
    	        $ErrorActionPreference = 'SilentlyContinue'
    	        $TargetOU = 'Users'
    	        $Value = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName -match $TargetOU
    	        $CurrentValue = (Get-ADComputer -Identity $env:COMPUTERNAME).DistinguishedName
    	        ((($Value -eq $true) -and (($env:COMPUTERNAME) -match 'MyComputerName')) -or ($env:COMPUTERNAME -notmatch 'MyComputerName')) 
    	        >>,
    	    Configure: >>
    	                
    	        $samAccountName = $ServerName
    	        $newOU = [adsi]"LDAP://$TargetOU"
    	        $comp= ([adsisearcher]"samaccountname=$($ServerName)$").FindOne()
    	        Write-Host $comp.GetDirectoryEntry()
    	                                
    	                                >>,
    	    Debug: true,
    	    Verbose: true
    	);
    }
    

    Please note that my PowerShell in collect and configure is not 1 to 1 with yours, I would replace my PowerShell script with yours in those two properties.

    I also was talking with one of the solutions architects on a similar Otter execution question. He suggested that sometimes it is easier to figure out PowerShell issues by running PSExec under the local system account and attempting to run your PowerShell commands that way. It will sometimes show you more detailed errors than Otter. I would try running PSExec -s powershell, which will open up a PowerShell console as the local system account, and then typing in the lines of PowerShell you have had trouble with.

    Thanks,
    Rich


Log in to reply
 

Inedo Website HomeSupport HomeCode of ConductForums GuideDocumentation