Private/New-TemplateOID.ps1
Function New-TemplateOID { <# .SYNOPSIS Generates a new OID for certificate templates. .DESCRIPTION This function generates a new OID (Object Identifier) for certificate templates within Active Directory. It creates a unique combination of: - Template Name: [10000000-99999999].[32 hex characters] - Template OID: [Forest base OID].[1000000-99999999].[10000000-99999999] The function ensures both the name and OID are unique in the forest. .PARAMETER Server FQDN of a Domain Controller. Used for all AD operations. Must be a valid DC with access to the Configuration NC. .PARAMETER ConfigNC Configuration Naming Context of the domain. Example: "CN=Configuration,DC=EguibarIT,DC=local" Must be a valid Configuration NC path. .INPUTS System.String You can pipe the Server and ConfigNC parameters to this function. .OUTPUTS System.Collections.Hashtable Returns a hashtable with two properties: - TemplateOID: The full OID string - TemplateName: The template name string .EXAMPLE $result = New-TemplateOID -Server "DC01.EguibarIT.local" -ConfigNC "CN=Configuration,DC=EguibarIT,DC=local" $result.TemplateOID # Output: 1.3.6.1.4.1.311.21.8.12345678.87654321 $result.TemplateName # Output: 87654321.0123456789ABCDEF0123456789ABCDEF Generates a new template OID and returns it as a hashtable. .EXAMPLE $splat = @{ Server = "DC01.EguibarIT.local" ConfigNC = "CN=Configuration,DC=EguibarIT,DC=local" } $newOID = New-TemplateOID @splat -Verbose Creates a new template OID with verbose output. .NOTES Used Functions: Name ║ Module/Namespace ═══════════════════════════════════════╬══════════════════════════════ Get-RandomHex ║ EguibarIT Test-IsUniqueOID ║ EguibarIT Get-FunctionDisplay ║ EguibarIT Import-MyModule ║ EguibarIT Get-Random ║ Microsoft.PowerShell.Utility Get-ADObject ║ ActiveDirectory Select-Object ║ Microsoft.PowerShell.Utility Write-Verbose ║ Microsoft.PowerShell.Utility Write-Debug ║ Microsoft.PowerShell.Utility Write-Error ║ Microsoft.PowerShell.Utility .NOTES Version: 2.1 DateModified: 22/May/2025 LastModifiedBy: Vicente Rodriguez Eguibar vicente@eguibar.com Eguibar IT http://www.eguibarit.com .LINK https://github.com/vreguibar/EguibarIT/blob/main/Private/New-TemplateOID.ps1 .COMPONENT PKI .ROLE Certificate Management .FUNCTIONALITY OID Generation #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] [OutputType([System.Collections.Hashtable])] Param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'FQDN of a Domain Controller')] [ValidateNotNullOrEmpty()] [Alias('DomainController', 'DC')] [string] $Server, [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Configuration Naming Context path')] [ValidateNotNullOrEmpty()] [ValidatePattern('^CN=Configuration,(?:CN|DC)=')] [Alias('ConfigurationNC', 'ConfigurationNamingContext')] [string] $ConfigNC ) Begin { Set-StrictMode -Version Latest # Output header information if ($null -ne $Variables -and $null -ne $Variables.Header) { $txt = ($Variables.Header -f (Get-Date).ToString('dd/MMM/yyyy'), $MyInvocation.Mycommand, (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False) ) Write-Verbose -Message $txt } #end if ############################## # Module imports Import-MyModule -ModuleName 'ActiveDirectory' -Verbose:$false ############################## # Variables Definition # Constants Definition $script:MaxAttempts = 100 $script:AttemptCount = 0 } # End BEGIN Process { try { <# OID CN/Name [10000000-99999999].[32 hex characters] OID msPKI-Cert-Template-OID [Forest base OID].[1000000-99999999].[10000000-99999999] <--- second number same as first number in OID name #> Write-Debug -Message ('Generating new template OID using server: {0}' -f $Server) do { $script:AttemptCount++ Write-Debug -Message ('Attempt {0} of {1}' -f $script:AttemptCount, $script:MaxAttempts) $OID_Part_1 = Get-Random -Minimum 1000000 -Maximum 99999999 $OID_Part_2 = Get-Random -Minimum 10000000 -Maximum 99999999 $OID_Part_3 = Get-RandomHex -Length 32 # Get forest base OID $Splat = @{ Server = $Server Identity = 'CN=OID,CN=Public Key Services,CN=Services,{0}' -f $ConfigNC Properties = 'msPKI-Cert-Template-OID' } $OID_Forest = Get-ADObject @splat | Select-Object -ExpandProperty msPKI-Cert-Template-OID if (-not $OID_Forest) { throw 'Failed to retrieve forest base OID' } #end if # Construct OID and name $msPKICertTemplateOID = '{0}.{1}.{2}' -f $OID_Forest, $OID_Part_1, $OID_Part_2 $Name = '{0}.{1}' -f $OID_Part_2, $OID_Part_3 Write-Debug -Message ('Testing OID: {0}' -f $msPKICertTemplateOID) Write-Debug -Message ('Testing name: {0}' -f $Name) # Test uniqueness $isUnique = Test-IsUniqueOID -cn $Name -TemplateOID $msPKICertTemplateOID -Server $Server -ConfigNC $ConfigNC if ($script:AttemptCount -ge $script:MaxAttempts) { throw 'Maximum attempts reached while trying to generate unique OID' } #end if } until ($isUnique) Write-Verbose -Message ('Successfully generated unique template OID after {0} attempts' -f $script:AttemptCount) } catch { Write-Error -Message ('Failed to generate template OID: {0}' -f $_.Exception.Message) throw } # End TRY/CATCH } # End PROCESS End { # Display function footer if ($null -ne $Variables -and $null -ne $Variables.Footer) { $txt = ($Variables.Footer -f $MyInvocation.InvocationName, 'creating new Template OID (Private Function).' ) Write-Verbose -Message $txt } #end if # Return results @{ TemplateOID = $msPKICertTemplateOID TemplateName = $Name } } # End END Section } # End Function New-TemplateOID |