{"id":76801,"date":"2016-02-15T00:01:25","date_gmt":"2016-02-15T00:01:25","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/?p=76801"},"modified":"2019-02-18T09:19:52","modified_gmt":"2019-02-18T16:19:52","slug":"migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-1\/","title":{"rendered":"Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 1"},"content":{"rendered":"<p><strong>Summary<\/strong>: Thomas Rayner, Microsoft Cloud &amp; Datacenter Management MVP, shows how to start the migration of a Windows certification authority from CSP to KSP and from SHA-1 to SHA-256.<\/p>\n<p>Hello! I\u2019m Thomas Rayner, a proud Cloud &amp; Datacenter Management Microsoft MVP, filling in for The Scripting Guy this week. You can find me on Twitter (<a href=\"https:\/\/twitter.com\/MrThomasRayner\">@MrThomasRayner<\/a>) or on my blog, <a href=\"http:\/\/workingsysadmin.com\/\" target=\"_blank\">Working Sysadmin: Figuring stuff out at work<\/a>.<\/p>\n<p>I recently had the chance to work with Microsoft PFE, Mike MacGillivray, on an upgrade of some Windows certification authorities, and I want to share some information about it with you. This script has only been tested on Windows Server 2012 and later.<\/p>\n<p><strong>\u00a0 Note<\/strong>\u00a0\u00a0\u00a0This is a five-part series that includes the following posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/02\/15\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-1\/?preview=true&amp;preview_id=76801&amp;preview_nonce=34b8f8d799&amp;post_format=standard\" target=\"_blank\">Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 1<\/a>\nExplore why you may need to perform this work, configure logging, and set up variables.<\/li>\n<li><a href=\"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/02\/16\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-2\/\" target=\"_blank\">Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 2<\/a>\nBack up your certification authority (CA) and test the script.<\/li>\n<li><a href=\"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/02\/17\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-3\/\" target=\"_blank\">Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 3<\/a>\nDelete the certificate and crypto provider so they can be rebuilt as a KSP and SHA-256 solution.<\/li>\n<li><a href=\"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/02\/18\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-4\/\" target=\"_blank\">Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 4<\/a>\nImport keys and certificate into a KSP.<\/li>\n<li><a href=\"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/02\/19\/migrate-windows-ca-from-csp-to-ksp-and-from-sha-1-to-sha-256-part-5\/\">Migrate Windows CA from CSP to KSP and from SHA-1 to SHA-256: Part 5<\/a>\nModify the registry for SHA-256.<\/li>\n<\/ul>\n<h2>Do I need to do this?<\/h2>\n<p>First things first. You need to know if this series of posts is for you. Presumably, you are running a Windows certification authority (CA) and want to upgrade from SHA-1 to SHA-256. With SHA-1 on its way to deprecation, this is an important piece of work that you should perform sooner rather than later. These posts assume you have a base-level knowledge of Windows CAs and how the public key infrastructure (PKI) works. The SHA-1 to SHA-256 upgrade isn\u2019t very difficult\u2014but that\u2019s a conditional statement.<\/p>\n<p>Open your CA MMC, right-click the name of your CA, and click <strong>Properties<\/strong>. If it looks exactly like the following image, give yourself a pat on the back because you\u2019re already done.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-1.png\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-76814\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-1-223x300.png\" alt=\"Image of menu\" width=\"223\" height=\"300\" \/><\/a><\/p>\n<p>What you\u2019re looking for is that the <strong>Provider<\/strong> is Microsoft Storage Key Service Provider and that the <strong>Hash algorithm<\/strong> is SHA256.<\/p>\n<p>If the <strong>Provider<\/strong> is Microsoft Storage Key Service Provider but the <strong>Hash algorithm<\/strong> is SHA1, you\u2019re not in very bad shape. Launch an elevated Command Prompt and simply run this command, then you\u2019re done.<\/p>\n<p style=\"padding-left: 30px\">certutil -setreg ca\\csp\\CNGHashAlgorithm SHA256<\/p>\n<p>There\u2019s another way this screen could look, though, and it\u2019s the situation we\u2019re focusing on this week.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-2.png\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-76821\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-2-223x300.png\" alt=\"Image of menu\" width=\"223\" height=\"300\" \/><\/a><\/p>\n<p>Not only is the <strong>Hash algorithm<\/strong> SHA-1, but the <strong>Provider<\/strong> is Microsoft Strong Cryptographic Provider. Not good! This scenario doesn\u2019t support simply moving from SHA-1 to SHA-256. Upgrading to a Key Storage Provider (KSP) from a Cryptographic Service Provider (CSP) is a bit more involved. Luckily, you can follow along with me this week to see how it\u2019s done.<\/p>\n<h2>Let\u2019s get set up<\/h2>\n<p>Today, we\u2019re going to set up some logging and variables to get our environment ready for the rest of the script. First things first\u2026<\/p>\n<p>This script is needs to be run as an administrator and it needs Windows PowerShell 2.0 or later. I can ensure both by using <strong>#requires<\/strong> statements.<\/p>\n<p style=\"padding-left: 30px\">#requires -Version 2<\/p>\n<p style=\"padding-left: 30px\">#requires -RunAsAdministrator<\/p>\n<p>I also want to make sure the <strong>ErrorActionPreference<\/strong> is <strong>Stop<\/strong>. If I run into problems, I want the script to die instead of keep fumbling through.<\/p>\n<p style=\"padding-left: 30px\">$OldEAP = $ErrorActionPreference<\/p>\n<p style=\"padding-left: 30px\">$ErrorActionPreference = &#8216;stop&#8217;<\/p>\n<p>I\u2019m storing the current <strong>ErrorActionPreference<\/strong> in <strong>$OldEAP<\/strong> so I can set it back at the end of the script. Now, I want to configure some logging. There are billions of ways to do this, but here\u2019s one function I like (because I wrote it):<\/p>\n<p style=\"padding-left: 30px\">Function Add-LogEntry<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">[CmdletBinding()]<\/p>\n<p style=\"padding-left: 30px\">Param(<\/p>\n<p style=\"padding-left: 30px\">[Parameter(Position = 0,<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $True,<\/p>\n<p style=\"padding-left: 30px\">ValueFromPipeline = $True)]<\/p>\n<p style=\"padding-left: 30px\">[string]$LogLocation,<\/p>\n<p style=\"padding-left: 30px\">[Parameter(Position = 1,<\/p>\n<p style=\"padding-left: 30px\">Mandatory = $True,<\/p>\n<p style=\"padding-left: 30px\">ValueFromPipeline = $True)]<\/p>\n<p style=\"padding-left: 30px\">[string]$LogMessage<\/p>\n<p style=\"padding-left: 30px\">)<\/p>\n<p style=\"padding-left: 30px\">$LogThis = &#8220;$(Get-Date -Format &#8216;MM\/dd\/yyyy hh:mm:ss&#8217;): $LogMessage&#8221;<\/p>\n<p style=\"padding-left: 30px\">Out-File -InputObject $LogThis -FilePath $LogLocation -Append<\/p>\n<p style=\"padding-left: 30px\">write-output $LogThis<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>There\u2019s nothing crazy going on here. The <strong>Add-LogEntry<\/strong> function takes two parameters, the location of the log file and the message to log. It prepends the time and date, and writes the log message to the log file, and then out to the screen. You could use <strong>Tee-Object<\/strong> here in Windows PowerShell\u00a05.0 but I\u2019m creating some backwards compatibility. You use the function like this:<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry &#8216;C:\\temp\\log.txt&#8217; &#8216;This message will be logged&#8217;<\/p>\n<p>Now, why don\u2019t we set up some variables before we wrap up today\u2019s post? Thinking about this in no particular order, I\u2019m going to need:<\/p>\n<ul>\n<li>A place to put log files<\/li>\n<li>A place to put a backup of my CA (stay tuned for tomorrow\u2019s post)<\/li>\n<li>The name of the CA I\u2019m working on<\/li>\n<li>A password to use for the CA backup<\/li>\n<\/ul>\n<p>Let\u2019s do the password first. I\u2019m not storing it in this script as a secure string because using it later in the script gets complicated. You probably should store it more securely, but I\u2019m being a cowboy. The password doesn\u2019t have any complexity requirements.<\/p>\n<p style=\"padding-left: 30px\">$Password = Read-Host -Prompt &#8216;Set password for key backup (not stored in script as securestring)&#8217;<\/p>\n<p style=\"padding-left: 30px\">How about a drive letter and folder for where the backup is going to go?<\/p>\n<p style=\"padding-left: 30px\">$Drivename = Read-Host -Prompt &#8216;Set drive letter including colon [C:]&#8217;<\/p>\n<p style=\"padding-left: 30px\">if ([string]::IsNullOrWhiteSpace($Drivename))<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">$Drivename = &#8216;C:&#8217;<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">$Foldername = Read-Host -Prompt &#8220;Set folder name [CA-KSPMigration_$($env:computername)]&#8221;<\/p>\n<p style=\"padding-left: 30px\">if ([string]::IsNullOrWhiteSpace($Foldername))<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">$Foldername = &#8220;CA-KSPMigration_$($env:computername)&#8221;<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">if (Test-Path -Path &#8220;$Drivename\\$Foldername&#8221;)<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">Remove-Item -Path &#8220;$Drivename\\$Foldername&#8221; -Recurse -Force<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">New-Item -ItemType Directory -Path &#8220;$Drivename\\$Foldername&#8221;<\/p>\n<p>This one\u2019s longer. I\u2019m prompting you for a drive letter first and informing you that the default value is <strong>C:<\/strong> by putting it in square brackets. You can either type the drive letter, or press ENTER to accept the default. If you accept the default, I\u2019m detecting if your input is empty and setting the <strong>$Drivename<\/strong> variable. I\u2019m doing the same thing with the folder part of the name. I\u2019m suggesting \u201cCA-KSPMigration_NameOfComputer.\u201d<\/p>\n<p>If that folder exists already, I\u2019m deleting it and then creating a new folder for it.<\/p>\n<p>How about we get the name of the CA now?<\/p>\n<p style=\"padding-left: 30px\">$CAName = cmd.exe \/c &#8216;certutil.exe -cainfo name&#8217;<\/p>\n<p style=\"padding-left: 30px\">$CAName = $CAName[0].split(&#8216; &#8216;)[-1]<\/p>\n<p>The syntax \u201ccmd.exe \/c &lt;command&gt;\u201d isn\u2019t explicitly required, but I prefer it. I find it makes life easier when dealing with PowerShell variables as part of a cmd.exe command. If you look at the output of <strong>certutil.exe \u2013cainfo name<\/strong>, you\u2019ll see that it\u2019s pretty easy to strip out everything except the CA name.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-3.png\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-76811\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-15-16-3-300x126.png\" alt=\"Image of code\" width=\"300\" height=\"126\" \/><\/a><\/p>\n<p>This should be pretty foolproof. You may have to tweak this part if you\u2019ve got some strange business going on with special characters. My tests with names including parentheses have been fine, though.<\/p>\n<p>Finally, let\u2019s set up the location for our log file.<\/p>\n<p style=\"padding-left: 30px\">$Logpath = Read-Host -Prompt &#8220;Set log path [$($Drivename)\\$($Foldername)\\log.txt]&#8221;<\/p>\n<p style=\"padding-left: 30px\">if ([string]::IsNullOrWhiteSpace($Logpath))<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">$Logpath = &#8220;$($Drivename)\\$($Foldername)\\log.txt&#8221;<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>Like the drive name and folder name, I\u2019m suggesting a location for the log file. I\u2019m going to log the settings for all the variables, and that\u2019ll be it for the environment preparation!<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8216;Variables configured&#8217;<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8220;Password: $($Password)&#8221;<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8220;Drivename: $($Drivename)&#8221;<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8220;Foldername: $($Foldername)&#8221;<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8220;CAName: $($CAName)&#8221;<\/p>\n<p style=\"padding-left: 30px\">Add-LogEntry $Logpath &#8220;Logpath: $($Logpath)&#8221;<\/p>\n<p>Now, we\u2019re ready to get on with the dirty work of upgrading from CSP to KSP and SHA-1 to SHA-256. Join me tomorrow when I\u2019ll cover backing up the existing CA.<\/p>\n<p>If you are in a big hurry and want the full script, you can find it on my blog: <a href=\"http:\/\/www.workingsysadmin.com\/quick-script-share-upgrade-windows-certificate-authority-from-csp-to-ksp-and-from-sha-1-to-sha-256\/\" target=\"_blank\">Upgrade Windows Certification Authority from CSP to KSP and from SHA-1 to SHA-256<\/a>. I\u2019d sincerely recommend reading all of the posts in this series first, though, so you understand what it is you\u2019re running.<\/p>\n<p>~Thomas<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\">Official Scripting Guys Forum<\/a>. Also check out my <a href=\"https:\/\/blogs.technet.microsoft.com\/msoms\/\" target=\"_blank\">Microsoft Operations Management Suite Blog<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Thomas Rayner, Microsoft Cloud &amp; Datacenter Management MVP, shows how to start the migration of a Windows certification authority from CSP to KSP and from SHA-1 to SHA-256. Hello! I\u2019m Thomas Rayner, a proud Cloud &amp; Datacenter Management Microsoft MVP, filling in for The Scripting Guy this week. You can find me on Twitter [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[568],"tags":[217,56,3,63,652,45],"class_list":["post-76801","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hey-scripting-guy","tag-certificates","tag-guest-blogger","tag-scripting-guy","tag-security","tag-thomas-rayner","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Thomas Rayner, Microsoft Cloud &amp; Datacenter Management MVP, shows how to start the migration of a Windows certification authority from CSP to KSP and from SHA-1 to SHA-256. Hello! I\u2019m Thomas Rayner, a proud Cloud &amp; Datacenter Management Microsoft MVP, filling in for The Scripting Guy this week. You can find me on Twitter [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/76801","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=76801"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/76801\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=76801"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=76801"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=76801"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}