Migrating Certificate Services from Server 2012 R2 to Server 2019, the right way.

So firstly, it’s been about 4 years since my last blog post so I think an apology is in order. Honestly I thought the Ubuntu Server GuestVM I had this site running on was deleted years ago when I moved house. Turns out it wasn’t and I just had it mis-configured it with the wrong DNS settings (Reverse Proxy; yada, yada, yada). I can’t believe this server has been here all this time with no one (including myself) ever seeing it, particularly when I’m always periodically looking at my Hyper-V console.

Anyways, as the title suggests I’m currently in the midst of a server refresh, because you know, you have to do that everyone once and a while. This task in-particular is for Active Directory Certificate Services and moving it to Server 2019 Core.

The server I’m moving from is Server 2012 R2 Core. So you can already get a sense the instructions that everyone uses because it works with any edition of Window Server wont work here because yep, I don’t have a GUI. I shouldn’t need to tell you why in 2019, Server GUI is a bad, lazy way to so Server stuff

Because I’m already running a SHA256 root CA the process is a bit more straight forward. If for whatever you’re still running SHA1, then I’d suggest move the Certificate Services database first then do the changes and certificate reissue for the new root. Tip: The GUI steps in this link are done command line below!

So let’s start with building our new Server 2019. Get the operating installed and go ahead and join it to the domain. On top of those, install the like-for-like Certificate Services role from the old server on the new server but don’t configure them just yet! You can easily do a side-by-side comparison with running “Get-WindowsFeature” on the old and then just installing those roles with “Install-WindowsFeature” on the new.

When your new server has the new roles, Server Manager will show it like this. Leave it as is.

Moving onto the Root Certificate and Certificate Service Database backup phase now. Get onto your old server and start up an administrative PowerShell window (TIP: just type powershell.exe). Run the following PS cmdlets:

cd C:\
mkdir C:\CertificateServicesBackup
Backup-CARoleService c:\CertificateServicesBackup -Password (Read-Host -prompt "Password:" -AsSecureString)

When prompted, provide a password that you’ll remember. You’ll need it later.


Okay, so backup of Certificate Root and Database done, now to backup some important registry settings. In the same PS window, lets backup the important registry now.

reg export HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc C:\CertificateServicesBackup\backup.reg

Great! Now take a copy of the C:\CertificateServicesBackup folder and keep it safe, maybe even on the new server. (TIP: “xcopy /e /s C:\CertificateServicesBackup \\newserver.fqdn.com\c$”)

At this point we’ve got what we need, everything is backed up. Now for what people would think is the scary bit and that’s the removal of the old server! This is an important step because doing this later, not at all or after the migration will seriously screw up Active Directory… so don’t do that. Let’s remove it now and be done with it.

Safely remove the old certficate server roles with the “Remove-WindowsFeature” cmdlet. Once that’s done, remove the server from domain.

Now it’s onto the new. With Server Manger or Windows Admin Center lets now click that link to complete the set up we said we would never touch. Tricked you! Go through the wizard until you get to this screen…

Look familiar? It should, because we’re following the same step as the everyone uses blog!

As the everyone uses blog article suggests, we’re going to provide an existing certificate and private key (protected by password). That certificate is the one you backed up earlier and the password you remembered.

Now, continue through the wizard with all the defaults, including the questions about the database to use as we’ll restore over the new database with the backed up data. When the wizard is done, jump onto the server and launch an administrative PowerShell window again. This time we’re running the restore PS cmdlet.

Restore-CARoleService c:\CertificateServicesBackup -Password (read-host -prompt "Password:" -AsSecureString) -Force 

Again the password is the one we remembered. With that done, we just needed to import the registry settings in. Before you do this, I suggest you open the .reg file in notepad.exe and just check to make sure there is no FQDN’s, Hostnames or IP’s that need updating. If they do, so that before import the registry file by running the below.

reg import HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc C:\CertificateServicesBackup\backup.reg

At this point you’re basically done! I’d restart the service and make sure it comes back up.

Restart-Service certsvc
Get-EventLog (for errors)

Your last task is to re-issue your certificate templates into Active Directory. Easy to just do this with the certsrv.msc management console go to “Certificate Templates (right click) > New > Certificate Template to issue”

The last step! Hooray!

That’s it from me, have a splendid day!



Remove disabled users from AD groups

I had an interesting request from a client today in so far they wanted AD to be cleaned out completely… Hrrm? Okay? So what do you mean by cleaned? *Insert joke about dcpromo demoting the domain*. 

The response I got was –  "We want you to delete all the disabled AD accounts".

While I thought okay, that's possible I still had my questions. Why? What are these disabled accounts hurting? Why do they need to vanish off the face of the earth? 

It's an interesting topic to discuss around the industry as I'm personally not one to delete users ever! Though I have worked with others who insist on deleting and even moving disabled AD users in another OU. The latter being simply administrative overhead and something that is easily averted by using an LDAP query that doesn't show them. Plus if another administrator later on enables them again and forgets to move them back to the appropriate OU then that account could be getting the right the right Group Policy settings!

Accounts that have been disabled for well beyond 10+ years I believe still have a place in your AD. Why? Well that person could still one day could return at any time. Why not give them their old account again rather than worry about provision a new one. Sure you can delete their mailbox which is consuming space and maybe delete the contents of their home share (not the actual folder thouht) but that account still belongs to someone… It still has an idenity and a face that needs to be kept for historical and future purporses.

To give you an example, I had another client have the same user leave and return three times in as many weeks! Yike right! Well no problem, I didn't have to go repeating the account provisioning process over and over.

Another reason not to go blowing your accounts away to hell is how indenity management is making massive inroads in our industry. For one example Office 365 with one way provisiong (DirSync or the coming WAAD) use your AD as the authoritive source. When you start deleting accounts you're disjoining those objects in the synchronisation metaverse. Not a problem when you delete, but when a new account with the same old UPN comes back, it can be quite a pain. 

So after a bit of coming and going with the client they finally came back to me with their reasoning…. "I don't like seeing all the disabled members in ADUC/ ADAC when I'm modifying group memberhship."

This particular client allows their in-line managers to manage group memebership for their files shares and some distribution groups. This was possible thanks to some nifty AD delegation I set up for them a few months earlier.

So no worries I now know what they want me to do. They don't want the accounts to dissappear, but they do want them to be isolated from all their old security groups. I supported this request as it's always good practice for any business to review users group memberships and there is no better time to do that then when the new user or a user returns…. "Okay Jimmy, what access do you actually need".

So rather than go around and delete the same 100 account or so from 500 different security groups I got onto PowerShell again. Scripting is seriously good for things like this! 

WARNING: Do not use this script if you has placed all your users and groups so to speak in the original "Users" container (not OU) in a domain. Many Microsoft services etc. can leverage disabled accounts in group membership for delgation etc. and running this script over those groups will pull them out. This script also doesn'y log very well as it justs spits the output to the console… So it will be difficult to go add all the accounts back in, especially if dealing with a lot of users or groups.

Import-Module ActiveDirectory
foreach ($group in (Get-ADObject -Filter { (ObjectClass -eq "group") -and (mailNickname -like "*") } -SearchBase "ou=groups,ou=staff,ou=contoso,dc=contoso,dc=com")) {
  Write-Host $group.Name -Foreground "green";
  foreach ($member in (Get-ADGroupMember -Identity $group)) {
    if ($member.objectClass -eq "user" -and ($member.distinguishedName.ToLower().Contains("ou=users,ou=staff"))) {
      $user = Get-ADUser -Identity $member.distinguishedName
      if ($user.enabled -eq $false) {
        Write-Host $user.Name
        Remove-ADGroupMember -Identity $group -Members $user -Confirm:$false

There are some important aspects of this groups you should take note of. These are:

  1. The –SearchBase parameter is where your AD groups you wish to clean are.
  2. The $member.distinguishedName.ToLower().Contains is where you store your AD users.
  3. The if ($user.enabled -eq $false) is what makes sure the account is Disabled. You could change this if statement for example if you wanted to remove all users with a particular office location, phone number or event last name!

That's it for now, next blog post will be whenever I feel a need to put something up! 

Copy AD groups from one user to another

It seems that a lot of my posts recently have been around AD group membership and I guess that makes sense as for the past few weeks I have been mostly cleaning up a lot of the mistakes by other IT professionals for my new clients. Alas it's coming a long way with PowerShell.

This script is very simple but a goody. It copies the group memberships of one user and gives it to another. 

  [parameter(Position=0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, mandatory=$true)][string]$SourceUser,
  [parameter(Position=0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, mandatory=$true)][string]$DestinationUser

Import-Module ActiveDirectory;

$originalErrAction = $ErrorActionPreference;
$ErrorActionPreference = "SilentlyContinue";

$groups = (Get-ADUser -Identity $SourceUser -Properties MemberOf).MemberOf;

foreach ($group in $groups) {
  Add-ADGroupMember -Identity $group -Members $DestinationUser;

$ErrorActionPreference = $originalErrAction;

Save this as Copy-ADGroups.ps1 or something similar and call is by running .\Copy-ADGroups.ps1 $SourceUser $DestinationUser where the $value is replaced with the AD user idenity. E.g. "Trent Steenholdt".

Audit Active Directory quick and dirty. Find all administrators, disabled users and lastlogin (UTC)

I had the need today to do a quick audit of Active Directory and see where it was at for a client. Not just the norm like dcdiag.exe, repadmin and checking the Event Viewer to see if there were any issues but also how many administrators there are, who is disabled (if any as I had my doubts) and the last last login for each user. PowerShell to the rescue. 

if ((Get-Module -Name ActiveDirectory) -eq $nul) { Import-Module ActiveDirectory }

$admins = Get-ADGroupMember -Identity "Administrators" -Recursive
$admins += Get-ADGroupMember -Identity "Domain Admins" -Recursive
$admins += Get-ADGroupMember -Identity "Enterprise Admins" -Recursive

Write-Host "Administrative accounts" -ForegroundColor Green
foreach ($admin in ($admins | Sort-Object -Property sAMAccountName -Unique)) { if ($admin.objectClass -eq "user") {Write-Host $admin.sAMAccountName} }

Write-Host "Disabled users" -ForegroundColor Green
foreach ($user in (Get-ADUser -Filter {Enabled -eq $false} | Sort-Object -Property sAMAccountName)) { Write-Host $user.sAMAccountName }

# I'd STRONGLY recommend using the -SearchBase parameter to reduce query load if at all possible
Write-Host "Last logon times (UTC)" -ForegroundColor Green
foreach ($user in (Get-ADUser -Filter * -Property lastLogonTimestamp | Sort-Object -Property sAMAccountName)) { if ($user.lastLogonTimestamp -eq $null) {$dt = ''} else { $dt = [datetime]$user.lastLogonTimestamp }; Write-Output($user.sAMAccountName +","+ $dt) | Write-Host }

Rename all computers with a Powershell script

It's an activity that all of us will have done numerous times in the past and will do in the future… rename a computer! But what happens when say the organisation you work for changes their workstation naming standard and want to have all the workstations renamed straight away?! Well, a simple powershell script is your answer! 

What you need?

  • RSAT Tools. In particular the Active Directory powershell module. Aka, "Import-Module ActiveDirectory"
  • Rights to rename these workstations assuming AD delegation is set up. It doesn't have to be Domain Admins
  • Permission to run the script from the business (Refer below note).
$organizationalunit = "OU=Computers,OU=Staff,DC=contoso,DC=com"
$computers = Get-ADComputer -SearchBase $organizationalunit | where {$_.name -notlike "Contoso-*"}
$num = 0001
Foreach($computer in $computers)
	For($num=1;$num -lt $computers.count;$num++)
        Rename-Computer -Computername $computer -NewName "Contoso-$num" -Force -Restart

This powershell script will search the OU of "OU=Computers,OU=Staff,DC=contoso,DC=com", get all the AD computers in this OU that doesn't have the name like "Contoso-*" and will rename them "Contoso-0001" and upwards until all the computers are renamed. It's easy to change the 'Get-ADComputer' cmdlet to get say only Windows XP machines! Just add:

		-Filter {OperatingSystem -Like "*XP*"}

Just to note: This script will restart the remote computers! So do this out-of-hours or when you organisation has approved the change. Removing the -restart switch will cause authenication issues until the workstation is of course, restarted.

Hope this helps renaming all thos computers!