functions/deployment/Install-DCDomainController.ps1

function Install-DCDomainController
{
    <#
    .SYNOPSIS
        Adds a new domain controller to an existing domain.
     
    .DESCRIPTION
        Adds a new domain controller to an existing domain.
        The target computer cannot already be part of the domain.
     
    .PARAMETER ComputerName
        The target to promote to domain controller.
        Accepts and reuses an already established PowerShell Remoting Session.
     
    .PARAMETER Credential
        Credentials to use for authenticating to the computer account being promoted.
     
    .PARAMETER DomainName
        The fully qualified dns name of the domain to join the DC to.
     
    .PARAMETER DomainCredential
        Credentials to use when authenticating to the domain.
     
    .PARAMETER SafeModeAdministratorPassword
        The password to use as SafeModeAdministratorPassword.
        Autogenerates and reports a new password if not specified.
     
    .PARAMETER NoDNS
        Disable deploying a DNS service with the new domain controller.
     
    .PARAMETER NoReboot
        Prevent reboot after finishing deployment
     
    .PARAMETER LogPath
        The path where the DC will store the logs.
     
    .PARAMETER SysvolPath
        The path where the DC will store sysvol.
     
    .PARAMETER DatabasePath
        The path where the DC will store NTDS Database.
 
    .PARAMETER NoResultCache
        Disables caching the result object of the operation.
        By default, this command will cache the result of the installation (including the SafeModeAdministratorPassword), to reduce the risk of user error.
     
    .PARAMETER EnableException
        This parameters disables user-friendly warnings and enables the throwing of exceptions.
        This is less user friendly, but allows catching exceptions in calling scripts.
     
    .PARAMETER Confirm
        If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
     
    .PARAMETER WhatIf
        If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
        PS C:\> Install-DCDomainController -Computer dc2.contoso.com -Credential $localCred -DomainName 'contoso.com' -DomainCredential $domCred
 
        Joins the server dc2.contoso.com into the contoso.com domain, as a promoted domain controller using the specified credentials.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [CmdletBinding(SupportsShouldProcess = $true)]
    Param (
        [PSFComputer]
        $ComputerName = 'localhost',

        [PSCredential]
        $Credential,

        [Parameter(Mandatory = $true)]
        [PsfValidatePattern('^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])){1,}$', ErrorString = 'DCManagement.Validate.ForestRoot.DnsDomainName')]
        [string]
        $DomainName,

        [PSCredential]
        $DomainCredential = (Get-Credential -Message 'Specify domain admin credentials needed to authorize the promotion to domain controller'),

        [securestring]
        $SafeModeAdministratorPassword = (New-Password -Length 32 -AsSecureString),

        [switch]
        $NoDNS,

        [switch]
        $NoReboot,

        [string]
        $LogPath,

        [string]
        $SysvolPath,

        [string]
        $DatabasePath,

        [switch]
        $NoResultCache,

        [switch]
        $EnableException
    )
    
    begin
    {
        $parameters = @{ Server = $ComputerName; IsDCInstall = $true }
        if ($Credential) { $parameters['Credential'] = $Credential }
        Invoke-PSFCallback -Data $parameters -EnableException $true -PSCmdlet $PSCmdlet
        
        $NoDNS = Resolve-ParameterValue -FullName 'DCManagement.Defaults.NoDNS' -InputObject $NoDNS
        $NoReboot = Resolve-ParameterValue -FullName 'DCManagement.Defaults.NoReboot' -InputObject $NoReboot
        $LogPath = Resolve-ParameterValue -FullName 'DCManagement.Defaults.LogPath' -InputObject $LogPath
        $SysvolPath = Resolve-ParameterValue -FullName 'DCManagement.Defaults.SysvolPath' -InputObject $SysvolPath
        $DatabasePath = Resolve-ParameterValue -FullName 'DCManagement.Defaults.DatabasePath' -InputObject $DatabasePath
        
        #region Main Scriptblock
        $scriptBlock = {
            param (
                $Configuration
            )
            function New-Result {
                [CmdletBinding()]
                param (
                    [ValidateSet('Success', 'Error')]
                    [string]
                    $Status = 'Success',

                    [string]
                    $Message,

                    $ErrorRecord,

                    $Data
                )

                [PSCustomObject]@{
                    Status = $Status
                    Success = $Status -eq 'Success'
                    Message = $Message
                    Error = $ErrorRecord
                    Data = $Data
                    SafeModeAdminPassword = $null
                }
            }
            
            # Check whether domain member
            $computerSystem = Get-CimInstance win32_ComputerSystem
            if ($computerSystem.PartOfDomain) {
                New-Result -Status Error -Message "Computer $env:COMPUTERNAME is part of AD domain: $($computerSystem.Domain)"
                return
            }
            
            $null = Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools

            $parameters = @{
                DomainName = $Configuration.DomainName
                Credential = $Configuration.DomainCredential
                DatabasePath = $Configuration.DatabasePath
                LogPath = $Configuration.LogPath
                SysvolPath = $Configuration.SysvolPath
                InstallDNS = $Configuration.InstallDNS
                SafeModeAdministratorPassword = $Configuration.SafeModeAdministratorPassword
                NoRebootOnCompletion = $Configuration.NoRebootOnCompletion
            }
            
            # Test Installation
            $testResult = Test-ADDSDomainControllerInstallation @parameters -WarningAction SilentlyContinue
            if ($testResult.Status -eq "Error") {
                New-Result -Status Error -Message "Failed validating Domain Controller Installation: $($testResult.Message)" -Data $testResult
                return
            }

            # Execute Installation
            try {
                $resultData = Install-ADDSDomainController @parameters -ErrorAction Stop -Confirm:$false -WarningAction SilentlyContinue
                if ($resultData.Status -eq "Error") {
                    New-Result -Status Error -Message "Failed installing Domain Controller: $($resultData.Message)" -Data $resultData
                    return
                }
                New-Result -Status 'Success' -Message "Domain $($Configuration.DomainName) successfully installed" -Data $resultData
                return
            }
            catch {
                New-Result -Status Error -Message "Error executing Domain Controller deployment: $_" -ErrorRecord $_
                return
            }
        }
        #endregion Main Scriptblock
    }
    process
    {
        if (-not $NetBiosName) { $NetBiosName = $DnsName -split "\." | Select-Object -First 1 }
        $configuration = [PSCustomObject]@{
            DomainName = $DomainName
            DomainCredential = $DomainCredential
            SafeModeAdministratorPassword = $SafeModeAdministratorPassword
            InstallDNS = (-not $NoDNS)
            LogPath = $LogPath
            SysvolPath = $SysvolPath
            DatabasePath = $DatabasePath
            NoRebootOnCompletion = $NoReboot
        }
        
        Invoke-PSFProtectedCommand -ActionString 'Install-DCDomainController.Installing' -ActionStringValues $DomainName -Target $DnsName -ScriptBlock {
            $result = Invoke-PSFCommand -ComputerName $ComputerName -Credential $Credential -ScriptBlock $scriptBlock -ErrorAction Stop -ArgumentList $configuration
            $result.SafeModeAdminPassword = $SafeModeAdministratorPassword
            $result = $result | Select-PSFObject -KeepInputObject -ScriptProperty @{
                Password = {
                    [PSCredential]::new("Foo", $this.SafeModeAdminPassword).GetNetworkCredential().Password
                }
            } -ShowProperty Success, Message
            if (-not $NoResultCache) {
                $global:DCCreationResult = $result
            }
            $result
        } -EnableException $EnableException -PSCmdlet $PSCmdlet
        if (Test-PSFFunctionInterrupt) { return }

        if (-not $NoResultCache) {
            Write-PSFMessage -Level Host -String 'Install-DCDomainController.Results' -StringValues $DnsName
        }
    }
}