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:
HTH.
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:\>
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.
Please ignore previous post. I needed to setup execution policy. Thanks a lot.
Post your comment:
Comments: