Check the AD Schema version before and after the upgrade to verify the schema as updated by running this in Powershell:
$root = [ADSI]"LDAP://RootDSE" $m = [ADSI]("LDAP://" + "CN=ms-Exch-Schema-Version-Pt," + $root.schemaNamingContext) $m.rangeUpper

Compare this number to the table on the official MS Site here to verify the version.

There is an issue in Server 2012 R2 if you apply the Windows Update KB3097966. This can cause upgrades and installations to take 50% longer. To fix this, you only ever need to run this once on all your machines:
%windir%\Microsoft.NET\Framework64\v4.0.30319\ngen.exe update

Prepare AD schema and domain on the Schema Master using Enterprise Admin account first (As done during initial Exchange 2016 setup)

I ran these three on my schema master
setup.exe /PrepareSchema /IAcceptExchangeServerLicenseTerms

setup.exe /PrepareAD /IAcceptExchangeServerLicenseTerms

setup.exe /PrepareAllDomains /IAcceptExchangeServerLicenseTerms

If your Exchange Servers are load-balanced, or in a DAG:

Set-ServerComponentState <server> –Component HubTransport –State Draining –Requester Maintenance Redirect-Message -Server <server> -Target <url>

If in a DAG:
Suspend-ClusterNode –Name <server> Set-MailboxServer <server> –DatabaseCopyActivationDisabledAndMoveNow $true

Note the database copy auto-activation policy to set it back to normal after the upgrade:
Get-MailboxServer <server> | Select DatabaseCopyAutoActivationPolicy

If the policy is showing anything other than blocked, run this to set it:
Set-MailboxServer <server> –DatabaseCopyAutoActivationPolicy Blocked

Check to make sure no database copies are mounted:
Get-MailboxDatabaseCopyStatus -Server <server> | Where {$_.Status -eq "Mounted"}

Not put the server into Maintenence mode to do the upgrade:
Set-ServerComponentState EX2016SRV1 –Component ServerWideOffline –State InActive –Requester Maintenance

Now verify on your Load Balancer (if you have one), the Server is marked offline, so switch over to your active one.

Restart the server if there are any pending reboots.

To perform the upgrade:

setup.exe /m:upgrade /IAcceptExchangeServerLicenseTerms

Once upgrade is complete, reboot.

Check event logs for any excessive errors or warnings
Check all auto-start services have started correctly

Note: Some of the newer update installers for Exchange 2013 and Exchange 2016 experience issues with services failing to start which fails the installation. You then need to re-run setup and it will pick up from where it left off, however it will throw the same error again. This is because during each install step the services are disabled while the components are updated and the services fail to re-enable before the installer starts the service it is currently updating. If this happens, each time a step is completed, wait for the services to become disabled (keep refreshing the services window).
Then type this into powershell:
Get-Service | where-object {$_.DisplayName -like "Microsoft Exchange*"} | Set-Service -StartupType Manual
This sets all Exchange services to manual, to allow the installer to continue. When it moves on to the next step you will need to set the services back to manual with the above command again as the services will get disabled again.

Now remove it from maintenance mode:
Set-ServerComponentState EX2016SRV1 –Component ServerWideOffline –State Active –Requester Maintenance

If in a DAG:
Resume-ClusterNode –Name EX2016SRV1

Set-MailboxServer EX2016SRV1 –DatabaseCopyAutoActivationPolicy Unrestricted (If in a DAG, use the activation policy that was originally set)

Set-MailboxServer EX2016SRV1 –DatabaseCopyActivationDisabledAndMoveNow $false

Set-ServerComponentState EX2016SRV1 –Component HubTransport –State Active –Requester Maintenance

Post-install DAG checks:
Get-ClusterNode (Ensure all cluster nodes are up and none are in a suspended state)

Test-ServiceHealth - Verify all services are running on each server

Test-MAPIConnectivity - Verify all databases are mounted

Get-MailboxDatabaseCopyStatus - Verify all database copies, copy/replay queues and content indexes show a healthy state

Test-ReplicationHealth - Verify replication health is showing a good status

Get-ServerComponent - Verify there are no servers in maintennece mode