Thinking about errors in code pipelines

A while back I wrote a couple of posts on the subject of how code pipelines can work in a more functional .Net world. I’ve made use of those patterns in some code of my own, and I’ve found these posts have generated quite a lot of questions from readers here and followers on twitter. But I’ve never been quite happy with the implementation in my own code… Continue reading

Advertisements

Memory deltas in Visual Studio debugging

Working on a couple of personal projects recently, I’ve been reminded again how helpful I find the profiling tools that Visual Studio’s debugger gives you. As you may have guessed from some of my previous posts, every so often I get to worry about the performance of .Net code at work – but it’s useful for any sort of project, not just Sitecore. And investigating some issues in my own code, memory snapshots and deltas helped me out again. So maybe they could help you too? Continue reading

What do you mean you can’t fetch that item by its path?

There are some things in Sitecore that you just take for granted will work. Loading items is a good example of this. I’ll admit that user error can get in your way, but usually if you can see an item in the content tree, you can write code that will load it without issues. So I’ll admit I was pretty confused when I came across a scenario recently where this did not appear to work correctly. In case anyone else hits this challenge, here’s what happened: Continue reading

Obscure looking SIF certificate errors

Continuing my voyage of obscure-error-discovery around Sitecore 9, this week SIF has been putting a lot of red into console windows for me. I’m not sure how many people will have this scenario, but if you have multiple people who all need to install their own Sitecore 9 instance onto one machine, this may be of interest:

My issue…

Working in a web agency we have multiple development teams who share development and test infrastructure. Up until now we’ve been happily installing multiple instances of Sitecore onto web servers without issues using SIM. But recently I was the second person to try and use some shared scripts to install a site via SIF onto one machine. And it was not happy.

The first step in the SIF process is to generate the certificate used to communicate with xConnect:

#install client certificate for xconnect 
$certParams = @{     
    Path = "$PSScriptRoot\xconnect-createcert.json"     
    CertificateName = "$prefix.xconnect_client" 
}
Install-SitecoreConfiguration @certParams -Verbose 

But that bombed out for me. The logs included:

[---------------------------------------- CreateSignedCert : NewSignedCertificate ------------------------------------]
VERBOSE: Resolving ConfigFunction extension 'GetCertificate'
VERBOSE: Resolved 'Invoke-GetCertificateConfigFunction'
VERBOSE: Invoke-GetCertificateConfigFunction
VERBOSE: Id: DO_NOT_TRUST_SitecoreRootCert
VERBOSE: CertStorePath: cert:\LocalMachine\Root
VERBOSE: Found Cert with thumbprint: 763C0AA20CB3A8038928AC09CDD6DF2F7CFB2EBA 27A5D8877F35151B0DA7A27B8BDFA44B0006CB47
**********************
Command start time: 20180710101333
**********************
PS>TerminatingError(New-SignedCertificate): "Cannot process argument transformation on parameter 'Signer'. Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Security.Cryptography.X509Certificates.X509Certificate2"."
Install-SitecoreConfiguration : Cannot process argument transformation on parameter 'Signer'. Cannot convert the 
"System.Object[]" value of type "System.Object[]" to type 
"System.Security.Cryptography.X509Certificates.X509Certificate2".
At C:\Configs\HabitatHome\s9install-web.ps1:19 char:1
+ Install-SitecoreConfiguration @certParams -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-SitecoreConfiguration
Install-SitecoreConfiguration : Cannot process argument transformation on parameter 'Signer'. Cannot convert the
"System.Object[]" value of type "System.Object[]" to type
"System.Security.Cryptography.X509Certificates.X509Certificate2".
At C:\Configs\HabitatHome\s9install-web.ps1:19 char:1
+ Install-SitecoreConfiguration @certParams -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-SitecoreConfiguration

Working towards a solution

A bit of googling for that error brought up a Stack Overflow post that explained the background: What Powershell really means is “I asked the cert store for a specific certifciate ID, and I got back more than one” – and you can’t use a list-of-certificates where the script expected a single certificate…

You can see this in the log output, because there are two cert thumbprints listed:

VERBOSE: Found Cert with thumbprint: 763C0AA20CB3A8038928AC09CDD6DF2F7CFB2EBA 27A5D8877F35151B0DA7A27B8BDFA44B0006CB47

Following the comments under the accepted answer, I deleted the “newer” of the two certificates, and tried to work out what was going on. The SIF script had created a new version of the “DO_NOT_TRUST_SitecoreRootCert” certificate – which didn’t entirely make sense to me. That should have already existed, since there was already an instance of Sitecore running happily on the machine. And looking at the certificate store for the local machine, it was indeed there:

Seeing that, the first idea that popped into my head looking at this was “ah – perhaps that needs to be in my store as well?” so I copied the root cert from the machine store to my store. That got me a different, and equally obscure error:

For the benefit of Google, the error this time was:

[---------------------------------------- CreateSignedCert : NewSignedCertificate ------------------------------------]
VERBOSE: Resolving ConfigFunction extension 'GetCertificate'
VERBOSE: Resolved 'Invoke-GetCertificateConfigFunction'
VERBOSE: Invoke-GetCertificateConfigFunction
VERBOSE: Id: DO_NOT_TRUST_SitecoreRootCert
VERBOSE: CertStorePath: cert:\LocalMachine\Root
VERBOSE: Found Cert with thumbprint: 27A5D8877F35151B0DA7A27B8BDFA44B0006CB47
VERBOSE: Performing the operation "New-SignedCertificate: New signed certificate for HabitatHome.xconnect_client" on target "C:\Certs".
VERBOSE: Searching certificates in cert:\LocalMachine\My for Name HabitatHome.xconnect_client
VERBOSE: Failed to find certificate with Name HabitatHome.xconnect_client
VERBOSE: New-SignedCertificate: Create a signed certificate for 'HabitatHome.xconnect_client'
VERBOSE: New-SignedCertificate: Using PKI parameters for Windows Server 2016 and Windows 10
**********************
Command start time: 20180710102049
**********************
PS>TerminatingError(New-SelfSignedCertificate): "The certificate does not have a property that references a private key. 0x8009200a (-2146885622 CRYPT_E_UNEXPECTED_MSG_TYPE) CertEnroll::CSignerCertificate::Initialize: Cannot find object or property. 0x80092004 (-2146885628 CRYPT_E_NOT_FOUND)"
>> TerminatingError(New-SelfSignedCertificate): "The certificate does not have a property that references a private key. 0x8009200a (-2146885622 CRYPT_E_UNEXPECTED_MSG_TYPE) CertEnroll::CSignerCertificate::Initialize: Cannot find object or property. 0x80092004 (-2146885628 CRYPT_E_NOT_FOUND)"
Install-SitecoreConfiguration : The certificate does not have a property that references a private key. 0x8009200a 
(-2146885622 CRYPT_E_UNEXPECTED_MSG_TYPE) CertEnroll::CSignerCertificate::Initialize: Cannot find object or property. 
0x80092004 (-2146885628 CRYPT_E_NOT_FOUND)
At C:\Configs\HabitatHome\s9install-web.ps1:19 char:1
+ Install-SitecoreConfiguration @certParams -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-SitecoreConfiguration
Install-SitecoreConfiguration : The certificate does not have a property that references a private key. 0x8009200a
(-2146885622 CRYPT_E_UNEXPECTED_MSG_TYPE) CertEnroll::CSignerCertificate::Initialize: Cannot find object or property.
0x80092004 (-2146885628 CRYPT_E_NOT_FOUND)
At C:\Configs\HabitatHome\s9install-web.ps1:19 char:1
+ Install-SitecoreConfiguration @certParams -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-SitecoreConfiguration

At least this time it’s only reporting a single certificate thumbprint – so it’s a step forward at least. Now, the important message this time seems to be “The certificate does not have a property that references a private key” – and if you go and look at the details of the root certificate in the trusted store, you’ll see that it does not have a private key attached:

That makes some sense – you can’t use the “root” certificate to sign anything if you don’t have its private key. Signing relies on the private part of a key for its security.

Checking with the person who’d done the first SIF install on this machine, their copy of this certificate did have a private key.

So the answer is…

…that if you’re part of a group of devs who are sharing some “standard” SIF scripts and you happen to be the second (or subsequent) Windows user to install a Sitecore instance on a machine using them, you need to ensure that you have a copy of the original root certificate, which includes the private key.

You can get that by asking the user who did the install first to export it for you, from their personal certificate store:

If they export the certificate including the key, and you import it into your store, then the SIF script will complete successfully.

Now I know where the error is coming from, I guess there are some other approaches that could be used to solve this. Whether these are relevant to you probably depends on your precise working patterns with multiple installs:

  • If you don’t rely on all the sites sharing the same root certificate, you could adjust the SIF scripts to generate a separate root certificate for each site (by ensuring the root certificate’s ID has the instance name in it perhaps?)
  • If you do want all the sites to share a root certificate, but you don’t want to have to mess about with moving certificates about, you may be able to adjust the SIF scripts to use the machine’s personal cert store rather than the user’s when generating and reading the shared root cert.
  • [Edited to add] And as pointed out in the comments below, just having a single user account that everyone shares for doing installs would solve the problem too…

But those are things to investigate another day…

Simple background scheduling

Every so often I come across the need for some simple code to schedule a bit of work in the background of an application. Sometimes because a service (for integration tasks, perhaps) needs to kick off processing every so often, or sometimes because some background part of a larger program needs to happen in parallel with the main execution. A common part of these requirements is that the task should run every so often, but two instances of the task should not overlap no matter how long the background processing takes.

A few times I’ve come across projects with subtly broken implementations of this requirement, so I thought I’d write down a simple approach that has worked for me. That way next time I need it, I won’t have to go digging through git repos… Continue reading

An interesting side effect of compiled views

I read a blog post earlier this week that talked about the benefits of compiling your View files to increase performance in Sitecore applications. Reading that post (which I stupidly failed to keep track of the link to, so can’t reference it now the comments pointed me back to) reminded me of an interesting issue that came up on a project I was looking at recently. If you’re interested in the raw performance of your Sitecore sites, you might want to consider this as well when you’re planning your views: Continue reading