vatson
vatson

Reputation: 25

Powershell script to update ldap data from servicenow

We are running powershelll script to update LDAP attributes from Servicenow. We get below error.

Access Request Console : LDAP Script Directory : C:\MID Server INT\agent\scripts\PowerShell
        Object DN : employeeNumber=L1009804,ou=people,ou=partenaires,dc=total,dc=com
        Exception : The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: At C:\MID Server INT\agent\scripts\PowerShell\LDAP\ldapFunctions.psm1:14 char:1
        + {
        + ~
        Missing closing '}' in statement block or type definition.

        At C:\MID Server INT\agent\scripts\PowerShell\LDAP\ldapFunctions.psm1:58 char:2
        + }
        + ~
        Unexpected token '}' in expression or statement.

        At C:\MID Server INT\agent\scripts\PowerShell\LDAP\ldapFunctions.psm1:60 char:1
        + }
        + ~
        Unexpected token '}' in expression or statement. .

Below is the Powershell script, which is triggered on raising request and is triggered via workflow. Data Inflow is working correctly but we have issue while outgoing from ServiceNow to LDAP . Script fails on every run.

    <#
    .Synopsis
    Create a new LdapConnection

    .EXAMPLE
    New-LdapConnection -LDAPServer 127.0.0.1 -Login admin -Password password1
    Description
    -----------
    Create a new LdapConnection on 127.0.0.1 server with admin credential
    #>
    [void][System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols")

    function New-LdapConnection
    {
        [OutputType([System.DirectoryServices.Protocols.LDAPConnection])]
        Param
        (
            # Description d'aide LDAPServer
            [String] $LDAPServer,
            # Description d'aide LDAPServerPort
            [Int32]  $LDAPServerPort=389,
            # Description d'aide Login
            [String] $Login,
            # Description d'aide Password
            [String] $Password,
            # Description d'aide AuhtenticationType
            [String] $AuhtenticationType="Basic",
            # Description d'aide ProtocolVersion
            [int] $ProtocolVersion=3,
            # Description d'aide SecureSocketLayer
            [Boolean] $SecureSocketLayer=$true,
            # Description d'aide EncryptionType
            [int] $EncryptionType=0
        )


        Process
        {
            #$LDAPServer = $ldapURL
            $Credentials = New-Object System.Net.NetworkCredential($Login,$Password)
            $LDAPConnection = New-Object System.DirectoryServices.Protocols.LDAPConnection($LDAPServer,$Credentials,$AuhtenticationType)
            $LDAPConnection.SessionOptions.ProtocolVersion = $ProtocolVersion
            $LDAPConnection.SessionOptions.SecureSocketLayer =$SecureSocketLayer
            # don't check certificate (feature enabled again on 24/11/2016 as requested by customer)

            $LDAPConnection.SessionOptions.VerifyServerCertificate = {
                param(
                    [DirectoryServices.Protocols.LdapConnection]$Connection,
                    [Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
                )      
                $Global:LdapCertificate = $Certificate    
                return $true
            }

            $LDAPConnection.Bind()
            return $LDAPConnection

        }

    }


    <#
    .Synopsis
    Find a Entry in LDAP
    .EXAMPLE
    Find-LdapEntry -LdapConnection $con -filter "(objectClass=person)" -rootDistinguishedName "DC=test,DC=lab"
    #>
    function Find-LdapEntry
    {
        [OutputType([System.DirectoryServices.Protocols.SearchResultEntry])]
        Param
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Ldap Filter
            [Parameter(Mandatory=$true)]
            [String] $filter,

            # Base DN
            [Parameter(Mandatory=$true)]
            [String] $rootDistinguishedName
        )

        Process
        {
            Write-Host "Begin Find Entry"

            $Filter = $filter
            $TimeOut = New-Object System.TimeSpan(1,0,0)
            $Request = New-Object System.DirectoryServices.Protocols.SearchRequest($rootDistinguishedName, $Filter, "Subtree", $null)
            $Response = $LdapConnection.SendRequest($Request,$TimeOut)

            if($Response.Entries.Count -gt 0){
                $Entry = $Response.Entries[0]
            }else{
                $Entry = $null
            }
            return $Entry 
        }

    }

    <#
    .Synopsis
    Add a Entry in LDAP
    .EXAMPLE
    New-LdapAddRequest -LdapConnection $con -Attrib $attrib -ObjectDN $obj_dn
    #>
    function New-LdapAddRequest
    {
        Param
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Attributes to Add 
            [Parameter(Mandatory=$true)]
            [System.Collections.Hashtable] $Attrib,

            # Object DN
            [Parameter(Mandatory=$true)]
            [String] $ObjectDN

        )

        Process
        {
            [string[]]$result = @()

            [string[]] $newObjClass = @()
            $newObjClass = $Attrib.Get_Item("defaultobjclass").split("^") | where {$_ -ne "^"}  
            Write-Host "Begin New-LdapAddRequest"

            $newEntry = (new-object "System.DirectoryServices.Protocols.AddRequest")
            $newEntry.DistinguishedName = $ObjectDN

            if($Attrib.Get_Item("objectclass") -ne $null -and $Attrib.Get_Item("objectclass") -ne ""){
                $objcl = $Attrib.Get_Item("objectclass")
                $objs = $objcl.split("^") | where {$_ -ne "^"}  

                foreach($i in $objs){
                    $newObjClass += $i
                }
            }
            Write-Host "Create new entry ", $ObjectDN, " with class ", $newObjClass
            $attrObjClass = New-Object System.DirectoryServices.Protocols.DirectoryAttribute("objectclass",$newObjClass)
            $newEntry.Attributes.Add($attrObjClass) 
            #add values of the attribute

            foreach ($line in $Attrib.GetEnumerator()) {
                $key = $($line.Name)
                $val = $($line.Value)
                if($key -ne "DN" -and $key -ne "objectclass" -and $key -ne "defaultobjclass"){
                    Write-Host "Key : ", $key ," ; Value : ", $val
                    if( $val.Contains("^") ){
                        [string[]] $tab = @()
                        $tab = $val.split("^") | where {$_ -ne "^"}
                        $attr = New-Object System.DirectoryServices.Protocols.DirectoryAttribute($key, $tab)                    
                    }else{
                        $attr = New-Object System.DirectoryServices.Protocols.DirectoryAttribute( $key, $val)
                    }

                    $newEntry.Attributes.Add($attr)
                }

            }

            $re = $LdapConnection.SendRequest($newEntry)

            #$result += "NewEntry_ResultCode: $($re.ResultCode)"
            if ($re.ResultCode -ne [System.directoryServices.Protocols.ResultCode]::Success){
                Write-Host "NewEntry_ErrorMessage: $($re.ResultCode.ErrorMessage)"
                throw "$($re.ResultCode.ErrorMessage)"
            }
            #return $result
        }
    }

    <#
    .Synopsis
    Update access for an object in LDAP
    .EXAMPLE
    New-LdapUpdateRequest -LdapConnection $connexion -Entry $Entry -AttribToUpd $hashAttrUpd -AttribToDlt $hashAttrDlt
    #>
    function New-LdapUpdateRequest
    {
        Param
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Entry Profile
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.SearchResultEntry] $Entry,

            # Attributes to Modify 
            [System.Collections.Hashtable] $AttribToUpd,

            # Attributes to Delete 
            [System.Collections.Hashtable] $AttribToDlt

        )

        Process
        {

            if ($AttribToUpd -ne $null) {
                $reUpt = New-LdapModifyRequest -LdapConnection $LdapConnection -Entry $Entry -Attrib $AttribToUpd
            }

            if ($AttribToDlt -ne $null) {
                $reDlt = New-LdapDeleteRequest -LdapConnection $LdapConnection -Entry $Entry -AttribToDelete $AttribToDlt
            }

        }
    }

    <#
    .Synopsis
    Delete a Entry in LDAP
    .EXAMPLE
    New-LdapDeleteRequest -LdapConnection $con -Entry $Entry -AttribToDelete $attrib
    #>
    function New-LdapDeleteRequest
    {
    #   [OutputType([System.DirectoryServices.Protocols.DirectoryResponse])]
        Param
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Entry Profile
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.SearchResultEntry] $Entry,

            # Attributes to delete
            [Parameter(Mandatory=$true)]
            [System.Collections.Hashtable] $AttribToDelete
        )

        Process
        {
            $r = (new-object "System.DirectoryServices.Protocols.ModifyRequest")
            $r.DistinguishedName = $Entry.DistinguishedName

            foreach($attrib in $AttribToDelete.GetEnumerator()){
                $key = $($attrib.Name)
                $val = $($attrib.Value)
                if($key -ne "objectclass" -and $Entry.Attributes[$key] -ne $null ){
                    if ($val -eq "" -or $val -eq $null){
                        Write-Host "Delete attribute : ", $key

                        $ope = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification"
                        $ope.Name = $key
                        $ope.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Delete

                        $r.Modifications.Add($ope)              
                    }

                }

            }

            $ObjClassVal = $AttribToDelete.Get_Item("objectClass")

            if($ObjClassVal -ne $null){     
                # process objectClass when provided
                [string[]] $DelObjClassValue = @()
                $DelObjClassValue = $ObjClassVal.split("^") | where {$_ -ne "^"}

                if(!$Entry.Attributes["objectclass"].GetValues([string]).Contains($DelObjClassValue[0])){
                    Write-Host "The entry does not have that objectClass"
                }else{
                    $tabObjClass = $Entry.Attributes["objectclass"].GetValues([string])
                    Write-Host "Object Class : ", $tabObjClass

                    [string[]] $newObjClass = @()

                    foreach($i in $tabObjClass){
                        $validValue = $true
                        foreach($j in $DelObjClassValue){
                            if($i -eq $j){
                                $validValue = $false
                            }
                        }
                        if($validValue -eq $true){
                            $newObjClass += $i
                        }   
                    }
                    Write-Host "New Object Class : ", $newObjClass
                }
                #prepare the request
                $objclass = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification"
                $objclass.Name = "objectclass"
                $objclass.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
                $objclass.AddRange($newObjClass)

                $r.Modifications.Add($objclass)

            }
            #Actually process the request through the server
            $re = $LDAPConnection.SendRequest($r);
            if ($re.ResultCode -ne [System.directoryServices.Protocols.ResultCode]::Success){
                Write-Host "SendRequest ResultCode : $($re.ResultCode) ; ErrorMessage : $($re.ResultCode.ErrorMessage)"
                throw "$($re.ResultCode.ErrorMessage)"
            }           
        }
    }

    <#
    .Synopsis
    Create access for a Entry in LDAP
    .EXAMPLE
    New-LdapModifyRequest -LdapConnection $con -Entry $Entry -Attrib $attrib
    #>
    function New-LdapModifyRequest
    {
        Param
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Entry Profile
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.SearchResultEntry] $Entry,

            # Attributes to Add 
            [Parameter(Mandatory=$true)]
            [System.Collections.Hashtable] $Attrib

        )

        Process
        {

            Write-Host "Begin Update LdapModifyRequest for", $Entry.DistinguishedName

            $r = (new-object "System.DirectoryServices.Protocols.ModifyRequest")

            $r.DistinguishedName = $Entry.DistinguishedName

            $obj = $Attrib.Get_Item("objectclass")
            if($obj -ne $null){
            # process objectClass when provided
                [string[]] $TabObjclass = @()
                $TabObjclass = $obj.split("^") | where {$_ -ne "^"}
                $getAccess = $false
                foreach($line in $TabObjclass){
                    if($Entry.Attributes["objectclass"].GetValues([string]).Contains($line)){
                        $getAccess = $true
                    }
                }

                if(!$getAccess){

                    Write-Host "Create Entry - set objectClass"
                    $newobjclass = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification"
                    $newobjclass.Name = "objectClass"
                    $newobjclass.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Add
                    #add values of the attribute
                    foreach($line in $TabObjclass){
                        $newobjclass.Add($line)
                    }
                    $r.Modifications.Add($newobjclass)

                }
            }
            Write-Host "Update Attributes"
            foreach ($line in $Attrib.GetEnumerator()) {
                $key = $($line.Name)
                $val = $($line.Value)
                if ($Entry.Attributes[$key] -or $val) {

                    if ($key -ne "objectclass" -and $key -ne "defaultobjclass") {
                        if ($Entry.Attributes[$key]){
                            Write-Host " Key : ", $key ," ; New Value : ", $val ," ; LDAP Value : ", $Entry.Attributes[$key].GetValues([string]) 
                        }else{
                            Write-Host " Key : ", $key ," ; New Value : ", $val ," ; LDAP Value : EMPTY "
                        }

                        $attr = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification"
                        $attr.Name = $key

                        if($Entry.Attributes[$key]){
                            $attr.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
                        }else{
                            $attr.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Add
                        }

                        if($val -Match "\^"){
                            [string[]] $tab = @()
                            $tab = $val.split("^") | where {$_ -ne "^"}
                            $attr.AddRange($tab)    
                        }else{
                            $attr.Add($val) 
                        }

                        $r.Modifications.Add($attr)     
                    }
                }
            }

            #Actually process the request through the server
            $re = $LdapConnection.SendRequest($r);
            if ($re.ResultCode -ne [System.directoryServices.Protocols.ResultCode]::Success){
                Write-Host "SendRequest ResultCode : $($re.ResultCode) ; ErrorMessage : $($re.ResultCode.ErrorMessage)"
                throw "$($re.ResultCode.ErrorMessage)"
            }

        }
    }

    <# AMO 18/08/2017 Nouvelle fonction pour la suppression de l'entrée
    .Synopsis
    Delete an object in LDAP
    .EXAMPLE
    New-LdapDeleteRecord -LdapConnection $connexion -Entry $Entry 
    #>
    function New-LdapDeleteRecord
    {
        Param 
        (
            # Ldap Connection
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.LDAPConnection] $LdapConnection,

            # Entry Profile
            [Parameter(Mandatory=$true)]
            [System.DirectoryServices.Protocols.SearchResultEntry] $Entry

        )

        Process
        {
                   Write-Host "New-LdapDeleteRecord Begin"
            #AMO 18/08/2017 Suppression de l'entrée
            $r = (new-object "System.DirectoryServices.Protocols.DeleteRequest")
            $r.DistinguishedName = $Entry.DistinguishedName

            Write-Host "New-LdapDeleteRecord sendRequest"
            #Actually process the request through the server
            $re = $LdapConnection.SendRequest($r);
            if ($re.ResultCode -ne [System.directoryServices.Protocols.ResultCode]::Success){
                Write-Host "SendRequest ResultCode : $($re.ResultCode) ; ErrorMessage : $($re.ResultCode.ErrorMessage)"
                throw "$($re.ResultCode.ErrorMessage)"
            }
             Write-Host "New-LdapDeleteRecord End"
        }
    }

    <#
    .Synopsis
    Transform a Json to HashTable
    .EXAMPLE
    Format-JsonToHashtable -JsonString $jsonStr
    #>
    function Format-JsonToHashtable
    {
        [OutputType([System.Collections.Hashtable])]
        Param
        (
            # Entry Profile
            [Parameter(Mandatory=$true)]
            [String] $JsonString
        )

        Process
        {

            $jsonConv = $JsonString -replace "\\", ""
            $jsonObject = $jsonConv | ConvertFrom-Json

            foreach ($myPsObject in $jsonObject) {
                $hashAttrJson = @{}
                $myPsObject | Get-Member -MemberType *Property | % {
                    $hashAttrJson.($_.name) = $myPsObject.($_.name)
                }
            }

            return $hashAttrJson
        }

    }

Upvotes: 2

Views: 983

Answers (1)

HAL9256
HAL9256

Reputation: 13483

I believe the error is here:

        $LDAPConnection.SessionOptions.VerifyServerCertificate = {
            param(
                [DirectoryServices.Protocols.LdapConnection]$Connection,
                [Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
            )      
            $Global:LdapCertificate = $Certificate    
            return $true
        }

You are creating a Script Block with parameters. The problem I believe is that you are not providing any parameters to the script block, and so PowerShell is looking at the subsequent commands to "fill" the parameters, which causes the error.

You will have to pass an -ArgumentList to "fill" the parameters if you are implementing it like this. e.g.:

        $LDAPConnection.SessionOptions.VerifyServerCertificate = {
            param(
                [DirectoryServices.Protocols.LdapConnection]$Connection,
                [Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
            )      
            $Global:LdapCertificate = $Certificate    
            return $true
        } -ArgumentList "Connection", "Certificate"

Upvotes: 2

Related Questions