DSCResources/MSFT_xOfflineDomainJoin/MSFT_xOfflineDomainJoin.psm1

$moduleRoot = Split-Path `
    -Path $MyInvocation.MyCommand.Path `
    -Parent

#region LocalizedData
$Culture = 'en-us'
if (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath $PSUICulture))
{
    $Culture = $PSUICulture
}
Import-LocalizedData `
    -BindingVariable LocalizedData `
    -Filename MSFT_xOfflineDomainJoin.psd1 `
    -BaseDirectory $moduleRoot `
    -UICulture $Culture
#endregion


function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [System.String]
        $IsSingleInstance,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $RequestFile
    )

    Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): "
        $($LocalizedData.GettingOfflineDomainJoinMessage)
        ) -join '')

    # It is not possible to read the ODJ file that was used to join a domain
    # So it has to always be returned as blank.
    $returnValue = @{
        IsSingleInstance = 'Yes'
        RequestFile = ''
    }

    #Output the target resource
    $returnValue
} # Get-TargetResource


function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [System.String]
        $IsSingleInstance,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $RequestFile
    )

    Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): "
        $($LocalizedData.ApplyingOfflineDomainJoinMessage)
        ) -join '')

    # Check the ODJ Request file exists
    if (-not (Test-Path -Path $RequestFile))
    {
        $errorId = 'RequestFileNotFoundError'
        $errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound
        $errorMessage = $($LocalizedData.RequestFileNotFoundError) `
            -f $RequestFile
        $exception = New-Object -TypeName System.ArgumentException `
            -ArgumentList $errorMessage
        $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
            -ArgumentList $exception, $errorId, $errorCategory, $null

        $PSCmdlet.ThrowTerminatingError($errorRecord)
    } # if

    # Don't need to check if the domain is already joined because
    # Set-TargetResource wouldn't fire unless it wasn't.
    Join-Domain -RequestFile $RequestFile
} # Set-TargetResource


function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [System.String]
        $IsSingleInstance, 

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $RequestFile
    )

    # Flag to signal whether settings are correct
    [Boolean] $desiredConfigurationMatch = $true

    Write-Verbose -Message ( @("$($MyInvocation.MyCommand): "
        $($LocalizedData.CheckingOfflineDomainJoinMessage)
        ) -join '')

    # Check the ODJ Request file exists
    if (-not (Test-Path -Path $RequestFile))
    {
        $errorId = 'RequestFileNotFoundError'
        $errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound
        $errorMessage = $($LocalizedData.RequestFileNotFoundError) `
            -f $RequestFile
        $exception = New-Object -TypeName System.ArgumentException `
            -ArgumentList $errorMessage
        $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
            -ArgumentList $exception, $errorId, $errorCategory, $null

        $PSCmdlet.ThrowTerminatingError($errorRecord)
    } # if

    $CurrentDomainName = Get-DomainName

    if($CurrentDomainName)
    {
        # Domain is already joined.
        Write-Verbose -Message ( @(
            "$($MyInvocation.MyCommand): "
            $($LocalizedData.DomainAlreadyJoinedMessage) `
                -f $CurrentDomainName `
            ) -join '' )
    }
    else
    {
        # Domain is not joined, so change is required.
        Write-Verbose -Message ( @("$($MyInvocation.MyCommand): "
            $($LocalizedData.DomainNotJoinedMessage)
            ) -join '')

        $desiredConfigurationMatch = $false
    } # if
    return $desiredConfigurationMatch
} # Test-TargetResource


<#
.SYNOPSIS
Uses DJoin.exe to join a Domain using a ODJ Request File.
#>

function Join-Domain {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [System.String]
        $RequestFile
    )

    Write-Verbose -Message ( @(
        "$($MyInvocation.MyCommand): "
        $($LocalizedData.AttemptingDomainJoinMessage) `
            -f $RequestFile `
        ) -join '' )

    $Result = & djoin.exe @(
        '/REQUESTODJ'
        '/LOADFILE'
        $RequestFile
        '/WINDOWSPATH'
        $ENV:SystemRoot
        '/LOCALOS')
    if ($LASTEXITCODE -eq 0)
    {
       # Notify DSC that a reboot is required.
        $global:DSCMachineStatus = 1
    }
    else
    {
        Write-Verbose -Message $Result

        $errorId = 'DjoinError'
        $errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound
        $errorMessage = $($LocalizedData.DjoinError) `
            -f $LASTEXITCODE
        $exception = New-Object -TypeName System.ArgumentException `
            -ArgumentList $errorMessage
        $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
            -ArgumentList $exception, $errorId, $errorCategory, $null

        $PSCmdlet.ThrowTerminatingError($errorRecord)
    } # if

    Write-Verbose -Message ( @(
        "$($MyInvocation.MyCommand): "
        $($LocalizedData.DomainJoinedMessage) `
            -f $RequestFile `
        ) -join '' )
} # function Join-Domain


<#
.SYNOPSIS
Returns the name of the Domain the computer is joined to or
$null if not domain joined.
#>

function Get-DomainName
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param()

    # Use CIM to detect the domain name so that this will work on Nano Server.
    $ComputerSystem = Get-CimInstance -ClassName win32_computersystem -Namespace root\cimv2
    if ($ComputerSystem.Workgroup)
    {
        return $null
    }
    else
    {
        $ComputerSystem.Domain
    }
} # function Get-DomainName


Export-ModuleMember -Function *-TargetResource