DCaaS.ps1

# ForceNTHash functions

# Some constants
$AADConnectServiceName = "ADSync"
$AADConnectProcessName = "miiserver"

# Aug 21st 2023
function Install-ForceNTHash
{
<#
    .SYNOPSIS
    Installs ForceNTHash to the current computer.

    .DESCRIPTION
    Installs ForceNTHash to the current computer.
    ForceNTHash enforces Windows legacy credential sync. Credentials are encrypted using ForceNTHash.pfx certificate.

    .EXAMPLE
    Install-AADIntForceNTHash
#>

    [cmdletbinding()]
    Param(
    [switch]$EnforceFullPasswordSync
    )
    Process
    {
        # Chech that running as administrator and that the service is running
        Test-LocalAdministrator -Throw | Out-Null

        $service = Get-Service -Name $AADConnectServiceName -ErrorAction SilentlyContinue
        if([String]::IsNullOrEmpty($service))
        {
            Write-Error "This command needs to be run on a computer with Azure AD Sync service (ADSync)"
            return
        }

        $promptValue = Read-Host "Are you sure you wan't to install ForceNTHash to this computer? Type YES to continue or CTRL+C to abort"
        if($promptValue -eq "yes")
        {
            # We need to restart so we can inject before GetWindowsCredentialsSyncConfig is called
            Restart-Service $AADConnectServiceName

            # But still wait a couple of seconds
            Write-Warning "Sleeping for five seconds.."
            Start-Sleep -Seconds 5

            # Get the process id
            $process = Get-Process -Name $AADConnectProcessName -ErrorAction SilentlyContinue
            $processId = $process.Id
            
            # Inject the dll
            $result=Inject-DLL -ProcessID $processID -FileName "$PSScriptRoot\ForceNTHash.dll" -Function "Patch"
            Write-Verbose "Inject-DLL result: $result"
            
            if($result -like "*success*")
            {
                Write-Host "Installation successfully completed!"
                Write-Host "Windows legacy credentials sync is now enforced and credentials are encrypted with ForceNTHash certificate."

                if($EnforceFullPasswordSync)
                {
                    Initialize-FullPasswordSync
                }

                return
            }
            else
            {
                Write-Error "Installation failed: $result"
                return
            }
        }
    }
}

# Aug 18th 2023
function Remove-ForceNTHash
{
<#
    .SYNOPSIS
    Removes ForceNTHash from the current computer

    .DESCRIPTION
    Removes ForceNTHash from the current computer by restarting ADSync service.

    .EXAMPLE
    Remove-AADIntForceNTHash

    WARNING: Waiting for service 'Microsoft Azure AD Sync (ADSync)' to start...
    WARNING: Waiting for service 'Microsoft Azure AD Sync (ADSync)' to start...
    WARNING: Waiting for service 'Microsoft Azure AD Sync (ADSync)' to start...
    Service restarted and ForceNTHash removed.
#>

    [cmdletbinding()]
    Param()
    Process
    {
        $service = Get-Service -Name $AADConnectServiceName -ErrorAction SilentlyContinue
        if([String]::IsNullOrEmpty($service))
        {
            Write-Error "This command needs to be run on a computer with Azure AD Sync service (ADSync)"
            return
        }

        Restart-Service $AADConnectServiceName

        Write-Host "Service restarted and ForceNTHash removed."
    }
}


# Aug 21st 2023
function Initialize-FullPasswordSync
{
<#
    .SYNOPSIS
    Enforces password hash sync of all users.

    .DESCRIPTION
    Enforces password hash sync of all users.

    .EXAMPLE
    Initialize-AADIntFullPasswordSync
#>

    [cmdletbinding()]
    Param()
    Process
    {
        $service = Get-Service -Name $AADConnectServiceName -ErrorAction SilentlyContinue
        if([String]::IsNullOrEmpty($service))
        {
            Write-Error "This command needs to be run on a computer with Azure AD Sync service (ADSync)"
            return
        }

        # ref: https://learn.microsoft.com/en-us/azure/active-directory-domain-services/tutorial-configure-password-hash-sync

        Import-Module "$(Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\AD Sync" -Name "Location" )\Bin\ADSync\ADSync.psd1"
        Import-Module "$(Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Azure AD Connect" -Name "InstallationPath")\AdSyncConfig\AdSyncConfig.psm1"

        $connectors = Get-ADSyncConnector

        if($connectors.Count -ne 2)
        {
            Throw "Connector count is not 2, can't automatically select connectors"
        }

        # Define the Azure AD Connect connector names and import the required PowerShell module
        $azureadConnector = (Get-ADSyncConnector | where Type -ne "AD").Name
        $adConnector      = (Get-ADSyncConnector | where Type -eq "AD").Name

        # Create a new ForceFullPasswordSync configuration parameter object then
        # update the existing connector with this new configuration
        $c = Get-ADSyncConnector -Name $adConnector
        $p = New-Object Microsoft.IdentityManagement.PowerShell.ObjectModel.ConfigurationParameter "Microsoft.Synchronize.ForceFullPasswordSync", String, ConnectorGlobal, $null, $null, $null
        $p.Value = 1
        $c.GlobalParameters.Remove($p.Name) | Out-Null
        $c.GlobalParameters.Add($p)         | Out-Null
        $c = Add-ADSyncConnector -Connector $c

        # Disable and re-enable Azure AD Connect to force a full password synchronization
        Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $azureadConnector -Enable $false | Out-Null
        Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $azureadConnector -Enable $true  | Out-Null

        Write-Host "Full password sync enforced"
               
    }
}