8000 Script error at call for targetcred variable · Issue #1 · JeremyWx/PKISync · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Script error at call for targetcred variable #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
z3r0th3h3r0 opened this issue May 31, 2023 · 1 comment
Open

Script error at call for targetcred variable #1

z3r0th3h3r0 opened this issue May 31, 2023 · 1 comment

Comments

@z3r0th3h3r0
Copy link

Hi there,

I know this is a long shot based on the age of the script, but I am trying to use this in an environment that does not allow an account with privileges for multiple forests, so I need to specify credentials. When trying to run your script, I receive the following error:

C:\temp\pkisync2.ps1 : The script has encoutnered a fatal error. Terminating script.
At line:1 char:1

  • .\pkisync2.ps1 -sourceforest paper-excellence.com -targetforest tld.a ...
  •   + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
      + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,pkisync2.ps1
    
    
    
    

Cannot find an overload for "Replace" and the argument count: "6".
At C:\temp\pkisync2.ps1:283 char:11

  •     $($TargetCred.GetNetworkCredential().password ),
    
  •       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
    • FullyQualifiedErrorId : MethodCountCouldNotFindBest

line 283 is:

$($TargetCred.GetNetworkCredential().password),

which is part of the GetPKIServicesContainer function

Seems that something doesn't like the number of arguments tied to the regex replace but only a guess.

If you have any idea as to what I am doing wrong, please let me know!

@z3r0th3h3r0
Copy link
Author

All good. I sorted it myself. Had to remove the regex login and use New-ADObject instead. Also removed requirement for target creds as they are not required (and fail the script) if specified. Only source creds are required.

This script allows updating PKI objects in Active Directory for the

cross-forest certificate enrollment

#This sample script is not supported under any Microsoft standard support
#program or service. This sample script is provided AS IS without warranty of
#any kind. Microsoft further disclaims all implied warranties including,
#without limitation, any implied warranties of merchantability or of fitness
#for a particular purpose. The entire risk arising out of the use or
#performance of the sample scripts and documentation remains with you. In no
#event shall Microsoft, its authors, or anyone else involved in the creation,
#production, or delivery of the scripts be liable for any damages whatsoever

(including, without limitation, damages for loss of business profits, business

#interruption, loss of business information, or other pecuniary loss) arising
#out of the use of or inability to use this sample script or documentation,
#even if Microsoft has been advised of the possibility of such damages.

Command line variables

$SourceForestName = ""
$TargetForestName = ""
$SourceDC = ""
$TargetDC = ""

$ObjectType = "all"
$ObjectCN = $null

$DryRun = $FALSE
$DeleteOnly = $FALSE
$OverWrite = $FALSE

function ParseCommandLine()
{
if (2 -gt $Script:args.Count)
{
write-warning "Not enough arguments"
Usage
exit 87
}

for($i = 0; $i -lt $Script:args.Count; $i++)
{
    switch($Script:args[$i].ToLower())
    {
        -sourceforest 
        {
            $i++
            $Script:SourceForestName = $Script:args[$i]
        }
        -targetforest 
        {
            $i++
            $Script:TargetForestName = $Script:args[$i]
        }                 
        -cn 
        {
            $i++
            $Script:ObjectCN = $Script:args[$i]
        }
        -type 
        {
            $i++
            $Script:ObjectType = $Script:args[$i].ToLower()
        }
        -f 
        {
            $Script:OverWrite = $TRUE
        }
        -whatif
        {
            $Script:DryRun = $TRUE
        }
        -deleteOnly
        {
            $Script:DeleteOnly = $TRUE
        }
        -targetdc
        {
            $i++
            $Script:TargetDC = $Script:args[$i]
        }
        -sourcedc
        {
            $i++
            $Script:SourceDC = $Script:args[$i]
        }
        default 
        {
            write-warning ("Unknown parameter: " + $Script:args[$i])
            Usage
            exit 87
        }
    }
}

}

function Usage()
{
write-host ""
write-host "Script to copy or delete PKI objects (default is copy)"
write-host ""
write-host " Copy Command:"
write-host ""
write-host " .\PKISync.ps1 -sourceforest -targetforest [-sourceDC ] [-targetDC ] [-type <CA|Template|OID> [-cn ]] [-f] [-whatif]"
write-host ""
write-host " Delete Command:"
write-host ""
write-host " .\PKISync.ps1 -targetforest [-targetDC ] [-type <CA|Template|OID> [-cn ]] [-deleteOnly] [-whatif]"
write-host ""
write-host "-sourceforest -- DNS of the forest to process object from"
write-host "-targetforest -- DNS of the forest to process object to"
write-host "-sourcedc -- DNS of the DC in the source forest to process object from"
write-host "-targetdc -- DNS of the DC in the target forest to process object to"
write-host "-type -- Type of object to process, if omitted then all object types are processed"
write-host " CA -- Process CA object(s)"
write-host " Template -- Process Template object(s)"
write-host " OID -- Process OID object(s)"
write-host '-cn -- Common name of the object to process, do not include the cn= (ie "User" and not "CN=User"'
write-host " This option is only valid if -type <> is also specified"
write-host "-f -- Force overwrite of existing objects when copying. Ignored when deleting."
write-host "-whatif -- Display what object(s) will be processed without processing"
write-host "-deleteOnly -- Will delete object in the target forest if it exists"
write-host ""
write-host ""
}

Build a list of attributes to copy for some object type

function GetSchemaSystemMayContain($ForestContext, $ObjectType)
{
# first get all attributes that are part of systemMayContain list
$SchemaDE = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySchemaClass]::FindByName($ForestContext, $ObjectType).GetDirectoryEntry()
$SystemMayContain = $SchemaDE.systemMayContain

# if schema was upgraded with adprep.exe, we need to check mayContain list as well
if($null -ne $SchemaDE.mayContain)
{
    $MayContain = $SchemaDE.mayContain
    foreach($attr in $MayContain)
    {
        $SystemMayContain.Add($attr)
    }
}
    
# special case some of the inherited attributes
if (-1 -eq $SystemMayContain.IndexOf("displayName"))
{
    $SystemMayContain.Add("displayName")
}
if (-1 -eq $SystemMayContain.IndexOf("flags"))
{
    $SystemMayContain.Add("flags")
}
if ($objectType.ToLower().Contains("template") -and -1 -eq $SystemMayContain.IndexOf("revision"))
{
    $SystemMayContain.Add("revision")
}

return $SystemMayContain

}

Copy or delete all objects of some type

function ProcessAllObjects($SourcePKIServicesDE, $TargetPKIServicesDE, $RelativeDN)
{
$SourceObjectsDE = $SourcePKIServicesDE.psbase.get_Children().find($RelativeDN)
$ObjectCN = $null

foreach($ChildNode in $SourceObjectsDE.psbase.get_Children())
{
    # if some object failed, we will try to continue with the rest
    trap
    {
        # CN maybe null here, but its ok. Doing best effort. 
        write-warning ("Error while coping an object. CN=" + $ObjectCN)
        write-warning $_
        write-warning $_.InvocationInfo.PositionMessage
        continue
    }

    $ObjectCN = $ChildNode.psbase.Properties["cn"]
    ProcessObject $SourcePKIServicesDE $TargetPKIServicesDE $RelativeDN $ObjectCN
    $ObjectCN = $null
}

}

Copy or delete an object

function ProcessObject($SourcePKIServicesDE, $TargetPKIServicesDE, $RelativeDN, $ObjectCN)
{
$SourceObjectContainerDE = $SourcePKIServicesDE.psbase.get_Children().find($RelativeDN)
$TargetObjectContainerDE = $TargetPKIServicesDE.psbase.get_Children().find($RelativeDN)

# when copying make sure there is an object to copy
if($FALSE -eq $Script:DeleteOnly)
{
    $DSSearcher =  [System.DirectoryServices.DirectorySearcher]$SourceObjectContainerDE
    $DSSearcher.Filter = "(cn=" +$ObjectCN+")"
    $SearchResult = $DSSearcher.FindAll()
    if (0 -eq $SearchResult.Count)
    {
        write-host ("Source object does not exist: CN=" + $ObjectCN + "," + $RelativeDN)
        return
    }
    $SourceObjectDE = $SourceObjectContainerDE.psbase.get_Children().find("CN=" + $ObjectCN)
}

# Check to see if the target object exists, if it does delete if overwrite is enabled.
# Also delete is this a deletion only operation.
$DSSearcher =  [System.DirectoryServices.DirectorySearcher]$TargetObjectContainerDE
$DSSearcher.Filter = "(cn=" +$ObjectCN+")"
$SearchResult = $DSSearcher.FindAll()
if ($SearchResult.Count -gt 0)
{
    $TargetObjectDE = $TargetObjectContainerDE.psbase.get_Children().find("CN=" + $ObjectCN)

    if($Script:DeleteOnly) 
    {
        write-host ("Deleting: " + $Targ
7E52
etObjectDE.DistinguishedName)
        if($FALSE -eq $DryRun)
        {
            $TargetObjectContainerDE.psbase.get_Children().Remove($TargetObjectDE)
        }
        return
    } 
    elseif ($Script:OverWrite)
    {
        write-host ("OverWriting: " + $TargetObjectDE.DistinguishedName)
        if($FALSE -eq $DryRun)
        {
            $TargetObjectContainerDE.psbase.get_Children().Remove($TargetObjectDE)
        }
    } 
    else 
    {
        write-warning ("Object exists, use -f to overwrite. Object: " + $TargetObjectDE.DistinguishedName)
        return
    }
} 
else 
{
    if($Script:DeleteOnly) 
    {
        write-warning ("Can't delete object. Object doesn't exist. Object: " + $ObjectCN + ", " + $TargetObjectContainerDE.DistinguishedName)
        return
    } 
    else 
    {        
        write-host ("Copying Object: " + $SourceObjectDE.DistinguishedName)
    }
}

# Only update the object if this is not a dry run
if($FALSE -eq $DryRun -and $FALSE -eq $Script:DeleteOnly)
{
    #Create new AD object   
    $NewDE = $TargetObjectContainerDE.psbase.get_Children().Add("CN=" + $ObjectCN, $SourceObjectDE.psbase.SchemaClassName)

    #Obtain systemMayContain for the object type from the AD schema
    $ObjectMayContain = GetSchemaSystemMayContain $SourceForestContext $SourceObjectDE.psbase.SchemaClassName
    #Copy attributes defined in the systemMayContain for the object type
    foreach($Attribute in $ObjectMayContain)
    {
        $AttributeValue = $SourceObjectDE.psbase.Properties[$Attribute].Value
        if ($null -ne $AttributeValue)
        {
            $NewDE.psbase.Properties[$Attribute].Value = $AttributeValue
            $NewDE.psbase.CommitChanges()
        }
    }
    #Copy secuirty descriptor to new object. Only DACL is copied. 
    $BinarySecurityDescriptor = $SourceObjectDE.psbase.ObjectSecurity.GetSecurityDescriptorBinaryForm()
    $NewDE.psbase.ObjectSecurity.SetSecurityDescriptorBinaryForm($BinarySecurityDescriptor, [System.Security.AccessControl.AccessControlSections]::Access)
    $NewDE.psbase.CommitChanges()
}

}

Get parent container for all PKI objects in the AD

function GetPKIServicesContainer([System.DirectoryServices.ActiveDirectory.DirectoryContext] $ForestContext, $dcName, $TargetCred)
{
$ForObj = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
$DE = $ForObj.RootDomain.GetDirectoryEntry()

if("" -ne $dcName)
{
  #  $newPath = [System.Text.RegularExpressions.Regex]::Replace($DE.psbase.Path, "LDAP://\S*/", "LDAP://" + $dcName + "/",
  #  $($TargetCred.UserName),  
  #  $($TargetCred.GetNetworkCredential().password),   
  #  [System.DirectoryServices.AuthenticationTypes]::Secure  
  #  )
  #  $DE = New-Object System.DirectoryServices.DirectoryEntry $newPath

    $Tnamingcontext = "LDAP://" + (Get-ADRootDSE -Server $TargetDC).defaultnamingcontext
    $DE = New-Object System.DirectoryServices.DirectoryEntry -ArgumentList $tnamingcontext

} 

$PKIServicesContainer = $DE.psbase.get_Children().find("CN=Public Key Services,CN=Services,CN=Configuration")
return $PKIServicesContainer

}

function GetPKIServicesContainerSource([System.DirectoryServices.ActiveDirectory.DirectoryContext] $ForestContext, $dcName, $SourceCred)
{
$ForObj = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
$DE = $ForObj.RootDomain.GetDirectoryEntry()

if("" -ne $dcName)
{
  #  $newPath = [System.Text.RegularExpressions.Regex]::Replace($DE.psbase.Path, "LDAP://\S*/", "LDAP://" + $dcName + "/",
  #  $($SourceCred.UserName),  
  #  $($SourceCred.GetNetworkCredential().password ),   
  #  [System.DirectoryServices.AuthenticationTypes]::Secure  
  #  )
  #  $DE = New-Object System.DirectoryServices.DirectoryEntry $newPath 

    $snamingcontext = "LDAP://" + (Get-ADRootDSE -Server $SourceDC).defaultnamingcontext

    $DE = New-Object System.DirectoryServices.DirectoryEntry -ArgumentList $snamingcontext,$($sourceCred.Username),$($sourceCred.GetNetworkCredential().password)

} 

$PKIServicesContainer = $DE.psbase.get_Children().find("CN=Public Key Services,CN=Services,CN=Configuration")
return $PKIServicesContainer

}

#########################################################

Main script code

#########################################################

$SourceCred = Get-Credential -Message "Enter credentials for Source Forest"
#$TargetCred = Get-Credential -Message "Enter credentials for Target Forest"

All errors are fatal by default unless there is another 'trap' with 'continue'

trap
{
write-error "The script has encoutnered a fatal error. Terminating script."
break
}

ParseCommandLine

Get a hold of the containers in each forest

write-host ("Target Forest: " + $TargetForestName.ToUpper())
$TargetForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext Forest, $TargetForestName
$TargetPKIServicesDE = GetPKIServicesContainer $TargetForestContext $Script:TargetDC #$TargetCred
#$TargetPKIServicesDE.PsBase.UserName = $($TargetCred.UserName)
#$TargetPKIServicesDE.PsBase.Password = $($SourceCred.GetNetworkCredential().password)

Only need source forest when copying

if($FALSE -eq $Script:DeleteOnly)
{
write-host ("Source Forest: " + $SourceForestName.ToUpper())
$SourceForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext Forest, $SourceForestName
$SourcePKIServicesDE = GetPKIServicesContainerSource $SourceForestContext $Script:SourceDC $SourceCred
}
else
{
$SourcePKIServicesDE = $TargetPKIServicesDE
}

if("" -ne $ObjectType) {write-host ("Object Category to process: " + $ObjectType.ToUpper())}

Process the command

switch($ObjectType.ToLower())
{
all
{
write-host ("Enrollment Serverices Container")
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=Enrollment Services"
write-host ("Certificate Templates Container")
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=Certificate Templates"
write-host ("OID Container")
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=OID"
}
ca
{
if($null -eq $ObjectCN)
{
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=Enrollment Services"
}
else
{
ProcessObject $SourcePKIServicesDE $TargetPKIServicesDE "CN=Enrollment Services" $ObjectCN
}
}
oid
{
if($null -eq $ObjectCN)
{
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=OID"
}
else
{
ProcessObject $SourcePKIServicesDE $TargetPKIServicesDE "CN=OID" $ObjectCN
}
}
template
{
if($null -eq $ObjectCN)
{
ProcessAllObjects $SourcePKIServicesDE $TargetPKIServicesDE "CN=Certificate Templates"
}
else
{
ProcessObject $SourcePKIServicesDE $TargetPKIServicesDE "CN=Certificate Templates" $ObjectCN
}
}
default
{
write-warning ("Unknown object type: " + $ObjectType.ToLower())
Usage
exit 87
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant
0