In my previous posts: New-OpsMgrRequest and Install-OpsMgrCertificate I posted two nice scripts. However there is a little bug that operating system version is not recognized correctly. Also these scripts have limited Windows versions support — only Windows Vista and higher. Now I have updated both scripts by fixing several bugs and added Windows XP/Windows Server 2003 (including R2) support. The following scripts demonstrates as well as CertEnroll and XEnroll CryptoAPI interfaces and how you can deal with them in Windows PowerShell. Here is an updated code:

#####################################################################
# OpsMgrCertMgmt.ps1
# Version 1.0
#
# Manages certificates for OpsMgr managed agent (generate requests,
# installs responses and checks certificates for proper configuration)
#
# Vadims Podans (c) 2010
# http://en-us.sysadmins.lv/
#####################################################################
#requires -Version 2.0

function New-OpsMgrRequest {
<#
.Synopsis
    Generates certificate request for System Center Operations Manager managed client
.Description
    Generates certificate request for System Center Operations Manager managed client
    and request file that can be submited to either Standalone or Enterprise CA.
    To use request with Enterprise CA you must specify CertificateTemplate argument.
.Parameter Path
    Specifies a path to save certificate request file (including file name).
    By default, request is saved in C:\ drive root.
.Parameter CertificateTemplate
    Specifies certificate template Common Name. This is mandatory paramter in
    conjuction with Enterprise Certification Authority.
.EXAMPLE
    New-OpsMgrRequest
    
    If no arguments are asserted, certificate request will be saved in C:\ with
    local computer name. This request can be submitted to Standalone Certification
    Authority only.
.Example
    New-OpsMgrRequest -Path C:\Requests\OpsMgr.req -CertificateTemplate OpsMgrAgentV2
    
    This command will create certificate request to use with Enterprise Certification
    Authority and save certificate request in C:\Requests\OpsMgr.req.
#>
[CmdletBinding()]
    param (
        [string]$Path = "$env:UserProfile\$env:computername.req",
        [string]$CertificateTemplate
    )
    trap {continue}
    # get managed computer FQDN. If this workgroup computer, NetBIOS name is used
    $domain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name
    if ($domain -eq $null) {
        $fqdn = $Env:COMPUTERNAME
    } else {
        $fqdn = $env:COMPUTERNAME + "." + $domain
    }
    $OS = (Get-WmiObject Win32_OperatingSystem).Version
    if ([int]$OS[0] -eq 53) {
        $xenroll = New-Object -ComObject CEnroll.Cenroll
        $xenroll.ProviderName = "Microsoft Base Cryptographic Provider v1.0"
        $xenroll.GenKeyFlags = 2048 * (256 * 256)
        $xenroll.MyStoreFlags = 0x20000
        $xenroll.KeySpec = 0x1
        # I use hardcoded Client and Server Suthentication EKUs. They are encoded
        # in Base64 string
        $xenroll.addExtensionToRequest(0,"2.5.29.37","MBQGCCsGAQUFBwMBBggrBgEFBQcDAg==")
        if ($CertificateTemplate -ne $null) {
            # if Certificate Template is used (for request submission to Enterprise CA
            # instantiate EncodedStringArray object that will encode template name
            $EncodedString = New-Object -ComObject CertificateAuthority.EncodeStringArray
            # initialize object with one element in array and Unicode value type
            $EncodedString.Reset(1,12)
            $EncodedString.SetValue(0,$CertificateTemplate)
            $bin = $EncodedString.Encode()
            # Enode() method produces extra trailing info, so I remove this
            # info that is stored in the first char of encoded string
            $bin = $bin.Substring(1, $bin.Length - 1)
            # and convert encoded data to Base64 string
            $BinChars = $bin.ToCharArray() | %{"{0:x4}" -f [int][char]$_}
            $BinArray = $BinChars | %{$_.Substring(2,2);$_.substring(0,2)}
            $Base64 = [Convert]::ToBase64String($($BinArray | %{Invoke-Expression 0x$_}))
            $xenroll.addExtensionToRequest(0,"1.3.6.1.4.1.311.20.2",$Base64)
        }
        $xenroll.createFileRequest(1,"CN=$fqdn","",$Path)
    } elseif ([int]$OS[0] -eq 54) {
        $SubjectDN = New-Object -ComObject X509Enrollment.CX500DistinguishedName
        $SubjectDN.Encode("CN=$fqdn", 0x0)
        
        $OIDs = New-Object -ComObject X509Enrollment.CObjectIDs
        foreach ($OIDstring in "1.3.6.1.5.5.7.3.1","1.3.6.1.5.5.7.3.2") {
            $OID = New-Object -ComObject X509Enrollment.CObjectID
            $OID.InitializeFromValue($OIDstring)
            $OIDs.Add($OID)
        }
    
        $EKU = New-Object -ComObject X509Enrollment.CX509ExtensionEnhancedKeyUsage
        $EKU.InitializeEncode($OIDs)
    
        $PrivateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey
        $PrivateKey.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
        $PrivateKey.KeySpec = 0x1
        $PrivateKey.KeyUsage = 0xf0
        $PrivateKey.Length = 2048
        $PrivateKey.MachineContext = 0x1
        $PrivateKey.Create()
    
        $PKCS10 = New-Object -ComObject X509Enrollment.CX509CertificateRequestPkcs10
        $PKCS10.InitializeFromPrivateKey(0x2,$PrivateKey,"")
        $PKCS10.Subject = $SubjectDN
        $PKCS10.X509Extensions.Add($EKU)
        if ($CertificateTemplate -ne "") {
            $Template = New-Object -ComObject X509Enrollment.CX509ExtensionTemplateName
            $Template.InitializeEncode($CertificateTemplate)
            $PKCS10.X509Extensions.Add($Template)
        }
        $Request = New-Object -ComObject X509Enrollment.CX509Enrollment
        $Request.InitializeFromRequest($PKCS10)
        $Base64 = $Request.CreateRequest(0x3)
        Set-Content $path -Value $Base64
    }
}

function Install-OpsMgrCertificate {
<#
.Synopsis
    Installs and configures response from Certification Authority for OpsMgr
    managed client.
.Description
    Installs Certification Authority response for OpsMgr certificate request and
    configures OpsMgr to use installed certificate.
.Parameter CertPath
    Specifies path to issued certificate.
.Parameter MomCertImport
    Specifies path to a folder where MOMcertImport.exe utility is located.
.EXAMPLE
    Install-OpsMgrCertificate C:\OpsMgrCert.cer \\server\share
    
    Installs certificate from C:\OpsMgrCert.cer and runs MomCertImport utility
    to confgure OpsMgr to use installed certificate.
#>
[CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$CertPath,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$MOMCertImportPath
    )
    function Get-Base64FromFile ($Path) {
        $cert = New-Object Security.Cryptography.X509Certificates.X509Certificate2
        try {
            $cert.Import($CertPath)
        } catch {Write-Warning "Specified file is not valid certificate. Aborting"; throw}
        $([Convert]::ToBase64String($cert.RawData))
        $Base64
    }
    $OS = (Get-WmiObject Win32_OperatingSystem).Version
    if ([int]$OS[0] -eq 53) {
        $xenroll = New-Object -ComObject CEnroll.Cenroll
        $xenroll.MyStoreFlags = 0x20000
        $xenroll.acceptResponse($(Get-Base64FromFile $CertPath))
    } elseif ([int]$OS[0] -eq 54) {
        $Base64 = Get-Base64FromFile $CertPath
        $Response = New-Object -ComObject X509Enrollment.CX509Enrollment
        $Response.Initialize(0x2)
        $Response.InstallResponse(0x4,$Base64,0x1,"")
    }
    try {gi $MOMCertImportPath\MoMCertImport.exe}
    catch {Write-Warning "Unable to find MomCertImport.exe in specified directory. Aborting"; throw}
    cmd /c "$MOMCertImportPath\MoMCertImport.exe /SubjectName %computername%"
}

You must save this code in a file with PS1 file extension, launch PowerShell console and type:

. path\script.ps1

don't miss first point sign. This instructs PowerShell to attach contained functions to current session. And run one of the following commands.

you must have local administrator permissions to generate certificate request and install certificate response to local computer certificate store.

To generate OpsMgr requests:

New-OpsMgrRequest C:\Request.req

New-OpsMgrRequest C:\Request.req "OpsMgrCertificateTemplateName"

First command is used to generate request for Standalone CA (that don't use certificate templates) and the second command is used for Enterprise CA requests. If you omit certificate template name, Enterprise CA will reject this request. The following sections describes necessary steps to configure certificate template:

To submit certificate request to CA server you may use the following sections:

When certificate is issued, transfer this certificate back to the managec computer and run the following command:

Install-OpsMgrCertificate path\CertificateFile.cer path\MOMCertImportFolder

First argument is used to specify issued certificate path and second argument is used to specify the folder that contains MOMcertImport.exe utility. This command also automatically configure managed client to use this certificate.

For additional info you may check internal help by typing:

Get-Help New-OpsMgrRequest –full

Get-Help Install-OpsMgrCertificate -full

for security reasons I don't support OpsMgr certificate export with corresponding private key (even OpsMgr product group recommend it). Therefore all specified commands must be completed on particular managed computer.

Also here is attached full script version that includes the following cmdlets:

  • New-OpsMgrRequest
  • Install-OpsMgrCertificate
  • Test-OpsMgrCertificate

 

HTH.


Share this article:

Comments:

Unknown Identity

Hi, Thank you for doing great job. when i try to run the script i am getting following error: PS C:\> .\OpsMgrCertMgmt.ps1 File C:\OpsMgrCertMgmt.ps1 cannot be loaded. The contents of file C:\OpsMgrCertMgmt.ps1 may have been tampered because the hash of the file does not match the hash stored in the digital signature. The script will not execute on the system . Please see "get-help about_signing" for more details.. At line:1 char:21 + .\OpsMgrCertMgmt.ps1 <<<< + CategoryInfo : NotSpecified: (:) [], PSSecurityException + FullyQualifiedErrorId : RuntimeException PS C:\>

Unknown Identity

it looks like you have edited my script and break signature. Re-download the script and run the command: . .\OpsMgrCertMgmt.ps1 this command will not execute the script, but attach contained functions to a PowerShell session (this operation is known as dot-sourcing). Therefore you should type dot, space and path to a file.

Unknown Identity

Please ignore previous post. I needed to setup execution policy. Thanks a lot.


Post your comment:

Please, solve this little equation and enter result below. Captcha