I am building ARM-templates to set up test-environments in Azure. I am using DSC to set up the different machines. One thing I want to automate is to import a certificate to the group-policies. You can do it like this manually on the domain-controller (Active-Directory server):
Group Policy Management -> Forest: mydomain.net -> Domains -> mydomain.net -> Group Policy Objects -> Default Domain Policy
Right click -> Edit
Default Domain Policy -> Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Public Key Policies -> Trusted Root Certification Authorities
Right click -> Import
I have laborated with Import-PfxCertificate, CertUtil.exe and .NET C# to accomplish it but haven’t succeeded. What I have tested you can see below, I have put some comments about my thoughts.
Can anyone help me? How should I do this?
First we create a certificate and export it and finally we delete it (we keep the exported one):
$certificateStoreLocation = "CERT:\LocalMachine\My";
$password = ConvertTo-SecureString -String "P#ssword12" -Force -AsPlainText;
$certificate = New-SelfSignedCertificate -CertStoreLocation $certificateStoreLocation -DnsName "Test-Certificate";
$certificateLocation = "$($certificateStoreLocation)\$($certificate.Thumbprint)";
$result = Export-PfxCertificate -Cert $certificateLocation -FilePath "C:\Data\Certificates\Test-Certificate.pfx" -Password $password;
Get-ChildItem $certificateLocation | Remove-Item;
List the certificate stores
foreach($item in Get-ChildItem "CERT:\")
{
Write-Host " - CERT:\$($item.Location)\";
foreach($store in $item.StoreNames.GetEnumerator())
{
Write-Host " - CERT:\$($item.Location)\$($store.Name)";
}
}
PowerShell – Import-PfxCertificate
$certificateStoreLocation = "CERT:\LocalMachine\Root";
$password = ConvertTo-SecureString -String "P#ssword12" -Force -AsPlainText;
Import-PfxCertificate -CertStoreLocation $certificateStoreLocation -FilePath "C:\Data\Certificates\Test-Certificate.pfx" -Password $password;
Get-ChildItem $certificateStoreLocation;
# Now you can find the certificate in the MMC Certificate Snapin:
# [Console Root\Certificates (Local Computer)\Trusted Root Certification Authorities\Certificates]
# Now you can find the certificate in the registry.
# Get-ChildItem "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\Root\Certificates\";
# I want to put the certificate here:
# Get-ChildItem "REGISTRY::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\SystemCertificates\Root\Certificates\";
PowerShell – CertUtil
CertUtil -p "P#ssword12" -ImportPfx "Root" "C:\Data\Certificates\Test-Certificate.pfx";
Get-ChildItem "CERT:\LocalMachine\Root";
CertUtil -p "P#ssword12" -ImportPfx -GroupPolicy "Root" "C:\Data\Certificates\Test-Certificate.pfx"; # No error but the same result as CertUtil -p "P#ssword12" -ImportPfx "Root" "C:\Data\Certificates\Test-Certificate.pfx".
.NET C#
using(var certificate = new X509Certificate2(#"C:\Data\Certificates\Test-Certificate.pfx", "P#ssword12"))
{
// We only have StoreLocation.CurrentUser and StoreLocation.LocalMachine.
// Can I use System.Management.Automation.Security.NativeMethods+CertStoreFlags.CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
// somehow to create/open a store by calling new X509Store(IntPtr storeHandle).
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
}
}
My imaginary solution
Thought this was a possible solution:
Import the certificate to “CERT:\LocalMachine\Root”
Move the registry-key “HKLM:\SOFTWARE\Microsoft\SystemCertificates\Root\Certificates\THUMBPRINT” to “HKLM:\Software\Policies\Microsoft\SystemCertificates\Root\Certificates\THUMBPRINT”
Restart the machine
The registry-keys get correct but the localmachine-root-certificate is still in the certificate-mmc-snapin and no root-certificate is found in the Group Policy Management console.
$certificateRegistryKeyPathPrefix = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\Root\Certificates\";
$certificateStoreLocation = "CERT:\LocalMachine\Root";
$password = ConvertTo-SecureString -String "P#ssword12" -Force -AsPlainText;
$pfxCertificatePath = "C:\Data\Certificates\Test-Certificate.pfx";
$policyCertificateRegistryKeyPathPrefix = "HKLM:\Software\Policies\Microsoft\SystemCertificates\Root\Certificates\";
# Get the thumbprint from the pfx-file so we can check if it's already in the registry.
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2;
$certificate.Import($pfxCertificatePath, $password, "DefaultKeySet");
$policyCertificateRegistryKeyPath = "$($policyCertificateRegistryKeyPathPrefix)$($certificate.Thumbprint)";
$policyCertificateRegistryKey = Get-Item -ErrorAction SilentlyContinue -Path $policyCertificateRegistryKeyPath;
if(!$policyCertificateRegistryKey)
{
$certificateRegistryKeyPath = "$($certificateRegistryKeyPathPrefix)$($certificate.Thumbprint)";
$certificateRegistryKey = Get-Item -ErrorAction SilentlyContinue -Path $certificateRegistryKeyPath;
if(!$certificateRegistryKey)
{
$certificate = Import-PfxCertificate -CertStoreLocation $certificateStoreLocation -FilePath $pfxCertificatePath -Password $password;
$certificateRegistryKey = Get-Item -Path $certificateRegistryKeyPath;
}
Move-Item -Destination $policyCertificateRegistryKeyPath -Path $certificateRegistryKeyPath;
# And then we need to reboot the machine.
}
Instead of trying to directly modify the registry under the 'Policies' path, create or modify an 'Registry.pol' file to populate it.
You could use the 'PolicyFileEditor' module from the PowerShell Gallery to do this, but the easiest way is to use the native GroupPolicy module to create and set a Registry.pol file as part of a domain GPO, which will also push out the certificate to member servers.
On a domain controller, import/create a cert so it has a blob value stored in the registry, create a GPO, then run something like the following to configure the GPO (named "DistributeRootCerts" here):
$certsGpoName = 'DistributeRootCerts'
$certThumbprint = '3A8E60952E2CDB7A31713258468A8F0C7FB3C6F6'
$certRegistryKeyPath = 'HKLM:\SOFTWARE\Microsoft\SystemCertificates\MY\Certificates\{0}' -f $certThumbprint
$certBlob = Get-ItemProperty -Path $certRegistryKeyPath -Name 'Blob' | Select -Expand 'Blob'
$certPoliciesRegistryKey = 'HKLM\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\Certificates\{0}' -f $certThumbprint
$null = Set-GPRegistryValue -Name $certsGpoName -Key $certPoliciesRegistryKey -ValueName 'Blob' -Type Binary -Value $certBlob
Then you just need to link the GPO into production with 'New-GPLink'.
Related
I used following PowerShell function to import PFX to my Windows 2008 R2 server's certificate store
function Import-PfxCertificate ([String]$certPath,[String]$certificateStoreLocation = "CurrentUser",[String]$certificateStoreName = "My",$pfxPassword = $null)
{
$pfx = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($certPath, $pfxPassword, "Exportable,PersistKeySet")
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certificateStoreName,$certificateStoreLocation)
$store.open("MaxAllowed")
$store.add($pfx)
$store.close()
return $pfx
}
The caller of the function looks like $importedPfxCert = Import-PfxCertificate $pfxFile "LocalMachine" "My" $password I installed it to local machine's My store. Then I granted read permission to my IIS Application pool.
I have a WCF service which needs to use it
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<serviceCertificate findValue="MyCertName" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
When I use a client to call the service, I got exception from WCF It is likely that certificate 'CN=MyCertName' may not have a private key that is capable of key exchange or the process may not have access rights for the private key.
If I remove it from MMC, and manually import the same PFX file from Certificate MMC, to same store and grant same permission, my client can call the service without problem.
So it leads me to think, for some reason if I use PowerShell the private key is screwed somehow.
The funny thing is in either way, I go to MMC and double click on my installed certificate I can see You have a private key that corresponds to the certificate. so it looks like private key is loaded even in PowerShell. permission settings are identical.
Any clue or experience?
Have same issue. Next script work:
function InstallCert ($certPath, [System.Security.Cryptography.X509Certificates.StoreName] $storeName)
{
[Reflection.Assembly]::Load("System.Security, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
$flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath, "", $flags)
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storeName, [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite);
$store.Add($cert);
$store.Close();
}
I updated Sergey's answer to the following. Note that the using namespace ... syntax is only valid for PS 5.0 and later. If you need this for an earlier version, you will have to add the full namespace, System.Security.Cryptography.X509Certificates, as needed.
using namespace System.Security
[CmdletBinding()]
param (
[parameter(mandatory=$true)] [string] $CertificateFile,
[parameter(mandatory=$true)] [securestring] $PrivateKeyPassword,
[parameter(mandatory=$true)] [string] $AllowedUsername
)
# Setup certificate
$Flags = [Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet `
-bor [Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet `
-bor [Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$Certificate = New-Object Cryptography.X509Certificates.X509Certificate2($CertificateFile, $PrivateKeyPassword, $Flags)
# Install certificate into machine store
$Store = New-Object Cryptography.X509Certificates.X509Store(
[Cryptography.X509Certificates.StoreName]::My,
[Cryptography.X509Certificates.StoreLocation]::LocalMachine)
$Store.Open([Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$Store.Add($Certificate)
$Store.Close()
# Allow read permission of private key by user
$PKFile = Get-ChildItem "$env:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$($Certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"
$PKAcl = $PKFile.GetAccessControl("Access")
$ReadAccessRule = New-Object AccessControl.FileSystemAccessRule(
$AllowedUsername,
[AccessControl.FileSystemRights]::Read,
[AccessControl.AccessControlType]::Allow
)
$PKAcl.AddAccessRule($ReadAccessRule)
Set-Acl $PKFile.FullName $PKAcl
Save this script to InstallCertificate.ps1, then run it as Administrator:
PS C:\Users\me> .\InstallCertificate.ps1
cmdlet InstallCertificate.ps1 at command pipeline position 1
Supply values for the following parameters:
CertificateFile: c:\my\path\mycert.pfx
PrivateKeyPassword: *********************
AllowedUsername: me
PS C:\Users\me> ls Cert:\LocalMachine\My
<Observe that your cert is now listed here. Get the thumbprint>
PS C:\Users\me> (ls Cert:\LocalMachine\My | ? { $_.Thumbprint -eq $Thumbprint }).PrivateKey
After rebooting, the last line should show that the private key is still installed even as non-Administrator.
Edited to add the ACL step as described in https://stackoverflow.com/a/37402173/7864889.
I had a similar issue on one of our dev servers when importing a certificate through the MMC. My problem was that the Administrators group did not have any permissions on the MachineKeys folder.
C:\Users\All Users\Microsoft\Crypto\RSA\MachineKeys
I added full control on the MachineKeys folder to Administrators and it was able to successfully create the private key when importing the certificate.
Make sure the user you're running Powershell under has access to write to the MachineKeys folder.
The following code referenced below, by Sergey Azarkevich, is what did the trick for me:
$flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
I landed on this SO thread as the built in Import-PfxCertificate was not importing CAPI certificates correctly. Unfortunately powerdude's answer cmdlet didnt work for me as it threw The property 'CspKeyContainerInfo' cannot be found on this object. Verify that the property exists. when setting the permissions.
After combining it with this wonderful gist from
milesgratz it worked.
Here is the final modified version made to look like a Import-PfxCertificate substitution.
# Import-CapiPfxCertificate.ps1
# for CNG certificates use built in Import-PfxCertificate
using namespace System.Security
[CmdletBinding()]
param (
[parameter(mandatory=$true)] [string] $FilePath,
[parameter(mandatory=$true)] [securestring] $Password,
[parameter(mandatory=$true)] [string] $CertStoreLocation,
[parameter(mandatory=$false)] [string] $AllowedUsername
)
if (-not ($CertStoreLocation -match '^Cert:\\([A-Z]+)\\([A-Z]+)$')) {
Write-Host "Incorrect CertStoreLocation. See usage in the Import-PfxCertificate documentation" -ForegroundColor Red
exit 1;
}
$StoreName = $Matches.2
$StoreLocation = $Matches.1
# Setup certificate
$Flags = [Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet `
-bor [Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet `
-bor [Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$Certificate = New-Object Cryptography.X509Certificates.X509Certificate2($FilePath, $Password, $Flags)
# Install certificate into the specified store
$Store = New-Object Cryptography.X509Certificates.X509Store(
$StoreName,
$StoreLocation)
$Store.Open([Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$Store.Add($Certificate)
$Store.Close()
if (-not ([string]::IsNullOrEmpty($AllowedUsername))) {
# Allow read permission of private key by user
$PKUniqueName = ([System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($Certificate)).key.UniqueName
$PKFile = Get-Item "$env:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$PKUniqueName"
$PKAcl = Get-Acl $PKFile
$PKAcl.AddAccessRule((New-Object AccessControl.FileSystemAccessRule($AllowedUsername, "Read", "Allow")))
Set-Acl $PKFile.FullName $PKAcl
}
Firstly, I know that very similar questions have been asked, but having read through the solutions and modifying my own workflow has not produced the correct results.
I am hoping that by showing the code I am using, someone may be able to point out where I am going wrong. I am trying to import a priate key from my windows 10 machine to my legacy windows 7 with powershell version 2 installed.
The error I am facing is that $cert.hasprivatekey returns true but $cert.privatekey always returns null. However this happens on the windows 10 machine as well so it seems to be a problem generating a key but every guide I have found uses the same syntax!
Here is the code to create the key:
$store = "cert:\CurrentUser\My"
$params = #{
CertStoreLocation = $store
Subject = "CN=Test1"
KeyLength = 2048
KeyAlgorithm = "RSA"
KeyUsage = "DataEncipherment"
Type = "DocumentEncryptionCert"
KeyExportPolicy = 'Exportable'
}
# generate new certificate and add it to certificate store
$cert = New-SelfSignedCertificate #params
Get-ChildItem -path $store
$pwd = ("P#ssword" | ConvertTo-SecureString -AsPlainText -Force)
$privateKey = "$home\Documents\Test1.pfx"
$publicKey = "$home\Documents\Test1.cer"
# Export private key as PFX certificate, to use those Keys on different machine/user
Export-PfxCertificate -FilePath $privateKey -Cert $cert -Password $pwd
# Export Public key, to share with other users
Export-Certificate -FilePath $publicKey -Cert $cert
I have aso tried this to no avail:
$TestCertificate = New-SelfSignedCertificate -Subject 'TestCertificate' -KeyExportPolicy 'Exportable'
Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertificate.pfx -Password (ConvertTo-SecureString 'TestPassword' -AsPlainText -Force)
I am then trying to import the private pfx certificate on windows 7 using the following:
$PfxFilePath = "C:\Users\user\Desktop\Test1.pfx"
$pwd = ("P#ssword" | ConvertTo-SecureString -AsPlainText -Force)
$Password = $pwd
$absolutePfxFilePath = Resolve-Path -Path $PfxFilePath
Write-Output "Importing store certificate '$absolutePfxFilePath'..."
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($absolutePfxFilePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$Store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
[System.Security.Cryptography.X509Certificates.StoreName]::My,
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::"ReadWrite")
$store.Add($cert)
$store.Close()
All ideas welcome!
The key is stored in Key Storage Provider which is not supported by PrivateKey property which is completely obsolete. Instead you need to use newer syntax to obtain private key:
$key = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
While investigating this problem myself, I was unable to find any start-to finish solutions on self-signing PowerShell scripts. So, how do you handle it all self-contained within PowerShell itself to utilize the AllSigned Execution Policy and help secure your systems better?
This is a modern approach to self-signed PowerShell scripts. I found older versions of PowerShell ISE (only confirmed 2.0) will encode your scripts in Big Endian vs UTF-8 and cause issues with signing. With this method, you shouldn't run into that since we're on v4+ here.
Requirement: PoSH 4.0+.
This function will: check if a Pfx cert exists and import it to LocalMachine\TrustedPublisher; check if a cert was passed to it, export to a Pfx cert and import it; or create the cert to LocalMachine\Personal, export it, and import it. I was unable to get the permissions to work with me to use the Cert:\CurrentUser stores outside of \My(Personal).
$ErrorActionPreference = 'Stop'
Function New-SelfSignedCertificate
{
Param([Parameter(Mandatory=$True)]$PfxCertPath,$CertObj)
# Creates a SecureString object
$Cred = (Get-Credential).Password
If (Test-Path $PfxCertPath)
{
Try {
Import-PfxCertificate -FilePath $PfxCertPath -Password $Cred -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
Write "$($PfxCertPath.FriendlyName) exists and is valid. Imported certificate to TrustedPublishers"
} Catch {
Write "Type mismatch or improper permission. Ensure your PFX cert is formed properly."
Write "[$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
}
} ElseIf ($CertObj) {
Try {
Export-PfxCertificate -Cert $CertObj -FilePath $PfxCertPath -Password $Cred -Force
Import-PfxCertificate -FilePath $PfxCertPath -Password $Cred -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
} Catch {
Write "[$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
}
} Else {
Try {
$DNS = "$((GWMI Win32_ComputerSystem).DNSHostName).$((GWMI Win32_ComputerSystem).Domain)"
$CertObj = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName $DNS -Type CodeSigningCert -FriendlyName 'Self-Sign'
Export-PfxCertificate -Cert $CertObj -FilePath $PfxCertPath -Password $Cred -Force
Import-PfxCertificate -FilePath $PfxCertPath -Password $Cred -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
} Catch {
Write "[$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
}
}
}
# Can be called like:
# Sign-Script -File C:\Script.ps1 -Certificate (GCI Cert:\LocalMachine\TrustedPublisher -CodeSigningCert)
#
# After the cert is imported to TrustedPublisher, you can use the
# exported pfx cert to sign on the machine instead of this method
Function Sign-Script
{
Param($File,$Cert)
If($Cert-is[String]){Try{$Cert=Get-PfxCertificate("$Cert")}Catch{}}
Set-AuthenticodeSignature -FilePath $File -Certificate $Cert -Force
}
Function Check-SignedScript
{
Param($File)
Get-AuthenticodeSignature -FilePath $File
}
After all is said and done, you can execute Set-ExecutionPolicy AllSigned as admin and use this script to sign all your scripts. Check-SignedScript will tell you if the sign is valid and you can tell if Sign-Script worked as your file will have # SIG # Begin signature block at the end. Any edits to a signed script need to be re-signed in order to execute.
I am working on power shell script to export certificate with private key which also includes all the certificates in the path. I wrote a script for that, it is not including the certificates in the path or the root certificate. Below is script. Kindly suggest me if there is any changes to make in my script.
Thanks in Advance.
$Password="#de08nt2128"; #password to access certificate after expting
$CertName="WMSvc-WIN-9KC7DG31JBV"; # name of the certificate to export
$RootCertName="WMSvc-WIN-9KC7DG31JBV"; # root certificate
$DestCertName="testcert"
$ExportPathRoot="C:\DestinationFolder"
$CertListToExport=Get-ChildItem -Path cert:\LocalMachine\My | ?{ $_.Subject -Like "*CN=$CertName*" -and $_.Issuer -eq "CN=$RootCertName" }
foreach($CertToExport in $CertListToExport | Sort-Object Subject)
{
$DestCertName=$CertToExport.Subject.ToString().Replace("CN=","");
$CertDestPath=Join-Path -Path $ExportPathRoot -ChildPath "$DestCertName.pfx"
$type = [System.Security.Cryptography.X509Certificates.X509Certificate]::pfx
$SecurePassword = ConvertTo-SecureString -String $Password -Force –AsPlainText
$bytes = $CertToExport.export($type, $SecurePassword)
[System.IO.File]::WriteAllBytes($CertDestPath, $bytes)
}
"Completed"
Updated script to export all certificates matching a particular name and issuer (along with the private key). Make sure you run this with admin privileges:
# Script to export certificate from LocalMachine store along with private key
$Password = "#de08nt2128"; #password to access certificate after exporting
$CertName = "WMSvc-WIN-9KC7DG31JBV"; # name of the certificate to export
$RootCertName = "WMSvc-WIN-9KC7DG31JBV"; # root certificate (the Issuer)
$ExportPathRoot = "C:\DestinationFolder"
$CertListToExport = Get-ChildItem -Path cert:\LocalMachine\My | ?{ $_.Subject -Like "*CN=$CertName*" -and $_.Issuer -Like "CN=$RootCertName*" }
foreach($CertToExport in $CertListToExport | Sort-Object Subject)
{
# Destination Certificate Name should be CN.
# Since subject contains CN, OU and other information,
# extract only upto the next comma (,)
$DestCertName=$CertToExport.Subject.ToString().Replace("CN=","");
$DestCertName = $DestCertName.Substring(0, $DestCertName.IndexOf(","));
$CertDestPath = Join-Path -Path $ExportPathRoot -ChildPath "$DestCertName.pfx"
$SecurePassword = ConvertTo-SecureString -String $Password -Force -AsPlainText
# Export PFX certificate along with private key
Export-PfxCertificate -Cert $CertToExport -FilePath $CertDestPath -Password $SecurePassword -Verbose
}
Updates from your scrip
For the check $_.Issuer -eq "CN=$RootCertName" to work you will have to include OU, O, S information as well so for it to work correctly so I modified it to be $_.Issuer -Like "CN=$RootCertName*" so that it matches all Issuer's who's name starts with variable $RootCertName
Using $CertToExport.Subject.ToString().Replace("CN=","") for generating pfx file name will cause the name to be of the format some-cert-name, OU=sometext, O=org, C=country.pfx so it is better to restrict upt o the next comma (,) so I added $DestCertName.Substring(0, $DestCertName.IndexOf(","))
Finally using Export-PfxCertifcate to export with private key
I want to install a certificate (X.509) created with makecert.exe on a remote server. I am not able to use psexec or something like that but have to use PowerShell.
Server operating system: Windows Server 2008 R2
PowerShell version: 4
Question: How to install a certificate with PowerShell on a remote server.
Scenario: ServerA has the SSL cert, ServerB would like the SSL cert imported
define two variables (ServerB only):
$afMachineName = "SomeMachineNameOrIp"
$certSaveLocation = "c:\temp\Cert.CER"
enable trust on both machines (ServerA & ServerB):
Function enableRemotePS() {
Enable-PSRemoting -Force
Set-Item wsman:\localhost\client\trustedhosts $afMachineName -Force
Restart-Service WinRM
}
Save the certificate (ServerB only):
Function saveCert([string]$machineName,[string]$certSaveLocation) {
Invoke-Command -ComputerName $machineName -ArgumentList $certSaveLocation -ScriptBlock {
param($certSaveLocation)
$cert = dir Cert:\LocalMachine\Root | where {$_.Subject -eq "CN=YOURCERTNAME" };
$certBytes = $cert.Export("cert");
[system.IO.file]::WriteAllBytes($certSaveLocation, $certBytes);
}
Copy-Item -Path \\$machineName\c$\temp\CertAF.CER -Destination $certSaveLocation
}
Import the certificate (ServerB only)
Function importCert([string]$certSaveLocation) {
$CertToImport = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $certSaveLocation
$CertStoreScope = "LocalMachine"
$CertStoreName = "Root"
$CertStore = New-Object System.Security.Cryptography.X509Certificates.X509Store $CertStoreName, $CertStoreScope
# Import The Targeted Certificate Into The Specified Cert Store Name Of The Specified Cert Store Scope
$CertStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$CertStore.Add($CertToImport)
$CertStore.Close()
}
To import a PFX file you can use Import-PfxCertificate, for example
Import-PfxCertificate -FilePath YOUR_PFX_FILE.pfx -Password (ConvertTo-SecureString -String "THE_PFX_PASSWORD" -AsPlainText -Force)
To do this on a remote computer, you can use Invoke-Command -ComputerName (and use an UNC path for the PFX file).