lib/Datascripts.ps1

## TM Datascripts
Function Get-TMDatascript {
    [alias("Get-TMETLScript")]
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param(
        [Parameter(Mandatory = $false)]
        [String]$TMSession = "Default",

        [Parameter(Mandatory = $false)]
        [String]$Name,

        [Parameter(Mandatory = $false)]
        [String[]]$ProviderName,

        [Parameter(Mandatory = $false)]
        [String]$Server = $global:TMSessions[$TMSession].TMServer,

        [Parameter(Mandatory = $false)]
        [Bool]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,

        [Parameter(Mandatory = $false)]
        [Switch]$ResetIDs,

        [Parameter(Mandatory = $false, ParameterSetName = 'SaveCode')]
        [String]$SaveCodePath,

        [Parameter(Mandatory = $false, ParameterSetName = 'SaveCode')]
        [Switch]$Passthru
    )

    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    #Honor SSL Settings
    $TMCertSettings = $TMSessionConfig.AllowInsecureSSL ? @{SkipCertificateCheck = $true } : @{SkipCertificateCheck = $false }

    # Format the uri
    $instance = $Server.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')

    if ($TMSessionConfig.TMVersion -ge '6.1.0') {
        $uri = "https://$instance/tdstm/ws/dataScript/list"
    }
    else {
        $uri = "https://$instance/tdstm/ws/dataingestion/datascript/list"
    }


    try {
        $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
    }
    catch {
        return $_
    }

    if ($response.StatusCode -in @(200, 204)) {
        $Result = ($response.Content | ConvertFrom-Json).data
        if ($Result.Count -eq 0) { return $false }
    }
    else {
        return "Unable to collect Datascripts."
    }

    ## Get each Datascript's Source Code in the list
    for ($i = 0; $i -lt $Result.Count; $i++) {

        $uri = "https://"
        $uri += $instance
        if ($TMSessionConfig.TMVersion -ge '6.1.0') {
            $uri += '/tdstm/ws/dataScript/' + $Result[$i].id
        }
        else {
            $uri += '/tdstm/ws/dataingestion/datascript/' + $Result[$i].id
        }
        try {
            $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
        }
        catch {
            return $_
        }

        if ($response.StatusCode -eq 200) {
            $Result[$i] = ($response.Content | ConvertFrom-Json).data.datascript
        }
        else {
            return "Unable to collect Datascripts."
        }
    }

    if ($ResetIDs) {
        for ($i = 0; $i -lt $Result.Count; $i++) {
            $Result[$i].id = $null
            $Result[$i].provider.id = $null
        }
    }

    ## Return the details -- Filter based on passed parameters
    if ($ProviderName) {
        $Result = $Result | Where-Object { $_.provider.name -in $ProviderName }
    }
    elseif ($Name) {
        $Result = $Result | Where-Object { $_.name -eq $Name }
    }

    ## Save the Code Files to a folder
    if ($SaveCodePath) {

        ## Save Each of the Script Source Data
        foreach ($Item in $Result) {

            ## Get a FileName safe version of the Provider Name
            $SafeProviderName = Get-FilenameSafeString -String $Item.provider.name
            $SafeScriptName = Get-FilenameSafeString -String $Item.name

            ## Create the Provider Action Folder path
            $ProviderPath = Join-Path $SaveCodePath $SafeProviderName
            Test-FolderPath -FolderPath $ProviderPath

            ## Create a File ame for the Action
            $ProviderScriptConfig = Join-Path $ProviderPath ($SafeScriptName + '.json')
            $ProviderScriptPath = Join-Path $ProviderPath ($SafeScriptName + '.groovy')

            ## Copy the code from the Datascript
            $DatascriptCode = $Item.etlSourceCode ? $Item.etlSourceCode.toString() : ""

            ## Remove the ETL Code fro the Item, so it can be converted to Json
            $Item.PSObject.Properties.Remove('etlSourceCode')

            ## Start Writing the Content of the Script (Force to overwrite any existing files)
            Set-Content -Path $ProviderScriptConfig -Force -Value (ConvertTo-Json -InputObject $Item -Depth 5)
            Set-Content -Path $ProviderScriptPath -Force -Value $DatascriptCode
        }
    }

    if ($Passthru -or !$SaveCodePath) {
        return $Result
    }
}

Function New-TMDatascript {
    [alias("New-TMETLScript")]
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScript")]
        [Parameter(Mandatory = $true)][PSObject]$Datascript,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,
        [Parameter(Mandatory = $false)][switch]$Update

    )
    if ($global:TMSessions[$TMSession].TMVersion -like '4.6.*') {
        New-TMDatascript46 @PSBoundParameters
    }
    elseif ($global:TMSessions[$TMSession].TMVersion -ge '4.7.*' -and $global:TMSessions[$TMSession].TMVersion -lt '6.1.0') {
        New-TMDatascript47 @PSBoundParameters
    }
    else {
        New-TMDatascript61 @PSBoundParameters
    }
}
Function New-TMDatascript46 {
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScript")]
        [Parameter(Mandatory = $true)][PSObject]$Datascript,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL
    )

    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    #Honor SSL Settings
    if ($TMSessionConfig.AllowInsecureSSL) {
        $TMCertSettings = @{SkipCertificateCheck = $true }
    }
    else {
        $TMCertSettings = @{SkipCertificateCheck = $false }
    }

    $DatascriptName = $Datascript.name
    $ExistingDatascript = Get-TMDatascript -Name $DatascriptName -TMSession $TMSession
    if ($ExistingDatascript) {
        # Write-Host "Datascript Exists: "$DatascriptName
        if ($PassThru) { return $ExistingDatascript } else { return }
    }

    ## Action 0 (Renumber) - Confirm the name is unique
    $uri = "https://"
    $uri += $Server
    $uri += '/tdstm/ws/dataingestion/datascript/validateUnique'

    $PostBodyJSON = @{
        name       = $DatascriptName
        providerId = (Get-TMProvider -Name $Datascript.provider.name -TMSession $TMSession).id
    } | ConvertTo-Json -Depth 100

    try {
        $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {
                $isUnique = $responseContent.data.isUnique
                if ($isUnique -ne $true) {
                    $thisDatascript = Get-TMDatascript -Name $DatascriptName -TMSession $TMSession
                }
            }
        }
    }
    catch {
        Write-Host "Unable to determine if Datascript Name is unique."
        return $_
    }


    ## Action 2, Create the Datascript so the Script code can be saved into it.
    $uri = "https://"
    $uri += $Server
    $uri += '/tdstm/ws/dataingestion/datascript'

    ## If there is an existing Datascript, update it
    if ($thisDatascript) {
        $Datascript.id = $thisDatascript.id
        $uri += '/' + $Datascript.id
    }
    else {
        $Datascript.PSObject.properties.Remove('id')
    }

    ## Lookup Cross References
    $ProviderID = (Get-TMProvider -TMSession $TMSession | Where-Object { $_.name -eq $Datascript.provider.name }).id

    $PostBodyJSON = @{
        name        = $DatascriptName
        mode        = $Datascript.mode
        description = $Datascript.description
        providerId  = $ProviderID
        # etlSourceCode = $Datascript.etlSourceCode
    } | ConvertTo-Json -Depth 100

    try {
        $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {

                $NewDatascript = $responseContent.data.datascript
                $PostBodyJSON = @{
                    id     = $NewDatascript.id
                    script = $Datascript.etlSourceCode
                } | ConvertTo-Json -Depth 100

                $uri = "https://"
                $uri += $Server
                $uri += '/tdstm/ws/dataingestion/dataScript/saveScript'

                $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
                if ($response.StatusCode -eq 200) {
                    $responseContent = $response.Content | ConvertFrom-Json
                    if ($responseContent.status -eq 'success') {
                        if ($PassThru) { return $responseContent.data.dataScript } else { return }
                    }
                }
            }
        }
    }
    catch {
        Write-Host "Unable to create Datascript."
        return $_
    }

}
Function New-TMDatascript47 {
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScript")]
        [Parameter(Mandatory = $true)][PSObject]$Datascript,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,
        [Parameter(Mandatory = $false)][switch]$Update

    )
    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    #Honor SSL Settings
    if ($TMSessionConfig.AllowInsecureSSL) {
        $TMCertSettings = @{SkipCertificateCheck = $true }
    }
    else {
        $TMCertSettings = @{SkipCertificateCheck = $false }
    }

    ## Look for an existing Script
    $DatascriptName = $Datascript.name
    $ExistingDatascript = Get-TMDatascript -Name $DatascriptName -TMSession $TMSession

    ## If the Script should not be updated, return it
    if ($ExistingDatascript) {

        ## End the function if there is not an update to be made
        if ($Update) {

            ## Record the DatascriptId for the update
            $DatascriptID = $ExistingDatascript.id

        }
        else {

            ## If $PassThru is present, return the Existing Datascript script.
            if ($PassThru) {
                return $ExistingDatascript
            }
            else {
                return
            }

        }
    }
    else {

        ## Lookup Provider ID
        if ([String]::IsNullOrWhiteSpace($Datascript.provider.name)) {
            Write-Error -Message "Provider name is blank for Datascript: $($Datascript.name)"
            return
        }
        $ProviderID = (Get-TMProvider -Name $Datascript.provider.name -TMSession $TMSession).id
        if (!$ProviderID) {
            # Create the provider if it doesn't exist
            $NowFormatted = (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ' -AsUTC).ToString()
            $Provider = [PSCustomObject]@{
                id          = $null
                name        = $Datascript.provider.name
                description = ""
                comment     = ""
                dateCreated = $NowFormatted
                lastUpdated = $NowFormatted
            }
            $ProviderID = (New-TMProvider -Provider $Provider -PassThru -TMSession $TMSession).id
        }

        try {

            ## There is not an existing Datascript, Create the basic
            ## Create the shell Datascript object, which must be created first
            $PostBodyJSON = @{
                description = $Datascript.description
                mode        = $Datascript.mode
                name        = $Datascript.name
                providerId  = $ProviderID
            } | ConvertTo-Json -Compress

            $uri = "https://"
            $uri += $Server
            $uri += '/tdstm/ws/dataingestion/datascript'

            ## Post the Datascript Object to the server
            Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession
            $response = Invoke-WebRequest -Method 'POST' -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
            if ($response.StatusCode -eq 200) {
                $responseContent = $response.Content | ConvertFrom-Json
                if ($responseContent.status -eq "success") {

                    ## Now that the shell exists, get it's ID
                    $DatascriptID = $responseContent.data.datascript.id
                }
            }
        }
        catch {
            Write-Host "Unable to create Datascript."
            return $_
        }

    }

    ## Now that we have an ID for the Datascript, send the source code content
    $PostBodyJSON = @{
        id     = $DatascriptID
        script = $Datascript.etlSourceCode.ToString()
    } | ConvertTo-Json -Depth 100

    try {

        ## Post the Source to be saved for this script.
        $uri = "https://"
        $uri += $Server
        $uri += '/tdstm/ws/dataScript/saveScript'
        $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq 'success') {
                if ($PassThru) {
                    return $responseContent.data.dataScript
                }
            }
        }
        elseif ($response.StatusCode -eq 204) {
            return
        }
    }
 catch {
        Write-Host "Unable to save Datascript Source to server"
        return $_
    }

}

Function New-TMDatascript61 {
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScript")]
        [Parameter(Mandatory = $true)][PSObject]$Datascript,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,
        [Parameter(Mandatory = $false)][switch]$Update

    )
    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    #Honor SSL Settings
    if ($TMSessionConfig.AllowInsecureSSL) {
        $TMCertSettings = @{SkipCertificateCheck = $true }
    }
    else {
        $TMCertSettings = @{SkipCertificateCheck = $false }
    }

    ## Look for an existing Script
    $DatascriptName = $Datascript.name
    $ExistingDatascript = Get-TMDatascript -Name $DatascriptName -TMSession $TMSession

    ## If the Script should not be updated, return it
    if ($ExistingDatascript) {

        ## End the function if there is not an update to be made
        if ($Update) {

            ## Record the DatascriptId for the update
            $DatascriptID = $ExistingDatascript.id

        }
        else {

            ## If $PassThru is present, return the Existing Datascript script.
            if ($PassThru) {
                return $ExistingDatascript
            }
            else {
                return
            }

        }
    }
    else {

        ## Lookup Provider ID
        if ([String]::IsNullOrWhiteSpace($Datascript.provider.name)) {
            Write-Error -Message "Provider name is blank for Datascript: $($Datascript.name)"
            return
        }
        $ProviderID = (Get-TMProvider -Name $Datascript.provider.name -TMSession $TMSession).id
        if (!$ProviderID) {
            # Create the provider if it doesn't exist
            $NowFormatted = (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ' -AsUTC).ToString()
            $Provider = [PSCustomObject]@{
                id          = $null
                name        = $Datascript.provider.name
                description = ""
                comment     = ""
                dateCreated = $NowFormatted
                lastUpdated = $NowFormatted
            }
            $ProviderID = (New-TMProvider -Provider $Provider -PassThru -TMSession $TMSession).id
        }

        try {

            ## There is not an existing Datascript, Create the basic
            ## Create the shell Datascript object, which must be created first
            $PostBodyJSON = @{
                description = $Datascript.description
                mode        = $Datascript.mode
                name        = $Datascript.name
                provider    = $ProviderID
            } | ConvertTo-Json -Compress

            $uri = "https://"
            $uri += $Server
            $uri += '/tdstm/ws/dataScript'

            ## Post the Datascript Object to the server
            Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession
            $response = Invoke-WebRequest -Method 'POST' -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
            if ($response.StatusCode -eq 200) {
                $responseContent = $response.Content | ConvertFrom-Json
                if ($responseContent.status -eq "success") {

                    ## Now that the shell exists, get it's ID
                    $DatascriptID = $responseContent.data.datascript.id
                }
            }
        }
        catch {
            Write-Host "Unable to create Datascript."
            return $_
        }

    }

    ## Now that we have an ID for the Datascript, send the source code content
    $PostBodyJSON = @{
        id     = $DatascriptID
        script = $Datascript.etlSourceCode
    } | ConvertTo-Json -Depth 100

    try {

        ## Post the Source to be saved for this script.
        $uri = "https://"
        $uri += $Server
        $uri += '/tdstm/ws/dataScript/saveScript'
        $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq 'success') {
                if ($PassThru) {
                    return $responseContent.data.dataScript
                }
            }
        }
        elseif ($response.StatusCode -eq 204) {
            return
        }
    }
 catch {
        Write-Host "Unable to save Datascript Source to server"
        return $_
    }

}

Function Invoke-TMDatascript {
    [alias("Invoke-TMETLScript")]
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScriptName")]
        [Parameter(Mandatory = $true)][String]$DatascriptName,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,
        [Parameter(Mandatory = $false)][bool]$QueueBatches = $false,
        [Parameter(Mandatory = $false)][bool]$MonitorBatches = $false,
        [Parameter(Mandatory = $true)][String]$DataType,
        [Parameter(Mandatory = $false)]$Data,
        [Parameter(Mandatory = $false)][String]$FilePath,
        [Parameter(Mandatory = $false)][String]$FileName,
        [Parameter(Mandatory = $false)][Int16]$ActivityId,
        [Parameter(Mandatory = $false)][Int16]$ParentActivityId = -1,
        [Parameter(Mandatory = $false)][switch]$isAutoPost,
        [Switch]$SendNotification
    )
    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    ## If a File Path was passed and there is no data, Read the file
    if ($FilePath -and -not $Data) {
        $Data = Get-Content $FilePath -Raw
        $FileName = (Get-Item $FilePath).Name
    }

    ## If a File Path was passed and there is no File Name, get the file name
    if ($FilePath -and -not $FileName) {
        $FileName = (Get-Item $FilePath).Name
    }

    #Honor SSL Settings
    if ($TMSessionConfig.AllowInsecureSSL) {
        $TMCertSettings = @{SkipCertificateCheck = $true }
    }
    else {
        $TMCertSettings = @{SkipCertificateCheck = $false }
    }

    if ($ActivityId) {
        ## Parent ID is only used on the root 'TransitionManager Data Import' Activity
        ## ParentID + 1 = Transform Data
        ## ParentID + 2 = Import Batches
        ## ParentID + 3 + n for each batch

        ## Add the Datascript Processing Progress Indicators
        $ProgressIndicators = @()
        $ProgressIndicators += @{ Id = $ActivityId; Activity = 'TransitionManager Data Import'; ParentId = $ParentActivityId }
        $ProgressIndicators += @{ Id = ($ActivityId + 1); Activity = 'Datascript Data Transformation'; ParentId = $ActivityId }
        $ProgressIndicators += @{ Id = ($ActivityId + 2); Activity = 'Import Batches'; ParentId = $ActivityId }
        $ProgressIndicators += @{ Id = ($ActivityId + 3); Activity = 'Monitor Batches'; ParentId = $ActivityId }

        #Write Progress Indicators for each in the Array
        $ProgressIndicators | ForEach-Object {
            Write-Progress @_ -CurrentOperation 'Queued' -PercentComplete 0
        }
    }

    ## Fix the Server URL
    $instance = $Server.Replace('/tdstm', '')
    $instance = $instance.Replace('https://', '')
    $instance = $instance.Replace('http://', '')

    $Boundary = '----------------------------540299933173025267350719'

    ## First Test to see if the Datascript Script exists or not
    if ($ActivityId) {

        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Datascript Data Transformation' -CurrentOperation 'Validating Datascript Script' -Status 'Confirming Datascript Script exists in TransitionManager' -PercentComplete 5
    }
    Write-Host 'Validating Datascript Script: ' -NoNewline
    Write-Host $DatascriptName -ForegroundColor Yellow

    $Datascript = Get-TMDatascript -TMSession $TMSession -Name $DatascriptName
    if (-Not $Datascript) { Throw  'The Datascript [' + $DatascriptName + '] does not exist' }

    ## Build the Data Post
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/fileSystem/uploadFileETLAssetImport"

    ## FileName
    if (-not $FileName) {
        $FileName = ('DataForETL_' + (Get-Date -Format FileDateTime ) + '.' + $DataType)
    }

    ## Construct the PostBody and Form Data for the request
    $CRLF = "`r`n";
    $PostBody = ("-----------------------------$boundary",
        'Content-Disposition: form-data; name="uploadType"',
        '',
        'assetImport',
        "-----------------------------$boundary",
        ''
    ) -join $CRLF
    $FileUpload = @{
        Form = @{
            uploadType = 'assetImport'
            file       = Get-Item -Path $FilePath
            fileName   = $FileName
        }
    }

    ## Upload the Data File
    if ($ActivityId) {
        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Datascript Data Transformation' -CurrentOperation 'Uploading Data' -Status ('Uploading ' + $FileName) -PercentComplete 5
    }
    Write-Host "Uploading File: " -NoNewline
    Write-Host $FileName -ForegroundColor Yellow

    try {
        ## If the file is being uploaded, append the fileupload to the command
        if ($FileUpload) {
            $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -ContentType ('multipart/form-data; boundary=---------------------------' + $boundary) @TMCertSettings @FileUpload

        }
        else {

            $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -ContentType ('multipart/form-data; boundary=---------------------------' + $boundary) @TMCertSettings
        }

    }
    catch {
        throw $_
    }
    if ($response.StatusCode -eq 200) {
        $responseContent = $response.Content | ConvertFrom-Json
        if ($responseContent.status -eq "success") {
            $DatascriptdataFileName = $responseContent.data.filename
        }
        else {
            Throw "Unable to upload data to TM Datascript pre-transform storage."
        }
    }

    ## With the file uploaded, Initiate the Datascript script on the server
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/assetImport/initiateTransformData"
    $uri += "?dataScriptId=" + $Datascript.id
    $uri += "&filename=" + $DatascriptdataFileName

    ## Deal with Version specific items
    $TMVersion = [System.Version]::Parse($TMSessionConfig.TMVersion)
    if (($TMVersion.Major -eq 6) -and ($TMVersion.ToString() -ge '6.0.2.1')) {
        $uri += "&originalFilename=" + $FileName
        $uri += "&sendNotification=" + $SendNotification.IsPresent.toString().ToLower()
    }
    if ($TMVersion.ToString() -ge '6.1.0' -and $isAutoPost.IsPresent) {
        $uri += '&isAutoPost=true'
    }

    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript script
    if ($ActivityId) {
        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Datascript Data Transformation' -CurrentOperation 'Starting Datascript Transformation' -PercentComplete 5
    }
    Write-Host 'TransitionManager Data Import: ' -NoNewline
    Write-Host 'Starting Datascript Transformation' -ForegroundColor Yellow

    $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
    if ($response.StatusCode -eq 200) {
        $responseContent = $response.Content | ConvertFrom-Json
        if ($responseContent.status -eq "success") {
            $DatascriptProgressKey = $responseContent.data.progressKey
        }
        else {
            throw $responseContent.errors
        }
    }
    else {
        Throw $response
    }


    ## Supply Progress from Datascript Transformation Progress
    if ($ActivityId) {
        Write-Progress -Id $($ActivityId + 1) -Activity 'Datascript Data Transformation' -CurrentOperation 'Running Datascript Transformation' -PercentComplete 0 -ParentId $ActivityId
    }

    ## The Datascript is underway, Setup a progress URL
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/progress/" + $DatascriptProgressKey
    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Poll for the status of the Datascript engine
    ## TODO: This should be converted to a function for polling the job engine. It's nearly dupilcated now in the Import Batch watching.
    $Completed = $false
    ## $ReportedLogItems = [System.Collections.ArrayList]@()
    while ($Completed -eq $false) {

        ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript script
        $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {
                $DatascriptProgress = $responseContent.data

                switch ($DatascriptProgress.status) {
                    "Queued" {

                        $CurrentOperation = 'Datascript Queued'
                        $Status = 'Queued'
                        $ProgressString = 'Status - Queued: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break

                    }
                    "Pending" {
                        $CurrentOperation = 'Datascript Pending'
                        $Status = 'Pending'
                        $ProgressString = 'Status - Pending: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "RUNNING" {
                        $CurrentOperation = 'Datascript Running'
                        $Status = 'Transforming Data'
                        $ProgressString = 'Status - Running: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp -gt 99 ? 99 : $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "COMPLETED" {
                        $DatascriptOutputKey = $DatascriptProgress.detail
                        $CurrentOperation = 'Datascript Processing Complete'
                        $Status = 'Creating Import Batches'
                        $Completed = $true
                        $SleepSeconds = 0
                        $PercentComplete = 99
                        $ProgressString = "Status - Datascript Processing Complete, Creating Import Batches."
                        Break
                    }
                    "Failed" {
                        $CurrentOperation = 'Failed'
                        $Status = $DatascriptProgress.status
                        Write-Host "Datascript Processing Failed "$DatascriptProgress.detail
                        Throw $DatascriptProgress.detail
                    }
                    Default {
                        $CurrentOperation = 'State Unknown'
                        $Status = 'Unknown. Sleeping to try again.'
                        $ProgressString = "Unknown Status: " + $DatascriptProgress.status
                        $PercentComplete = 99
                        $SleepSeconds = 2
                        Break
                    }
                }

                ## Notify the user of the Datascript Progress
                if ($ActivityId) {
                    Write-Progress -Id ($ActivityId + 1) `
                        -ParentId $ActivityId `
                        -Activity 'Datascript Data Transformation' `
                        -CurrentOperation $CurrentOperation `
                        -Status $Status `
                        -PercentComplete ($PercentComplete ?? 0)
                }
                else {
                    Write-Host $ProgressString
                }
                Start-Sleep -Seconds $SleepSeconds
            }
        }
    }

    ## Update Progress and transition to Activity + 2
    Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Datascript Data Transformation' -CurrentOperation 'Transformation Complete' -PercentComplete 100 -Completed
    Write-Progress -Id ($ActivityId + 2) -ParentId $ActivityId -Activity 'Importing Batches' -CurrentOperation 'Beginning Import' -PercentComplete 5

    Write-Host "Datascript Transformation is complete, Loading to Batch Import"

    ## TODO, this is where a Job Log could be pulled. With the DatascriptOutputKey now provided, the API like this could be used:
    ## https://tmad60.transitionmanager.net/tdstm/ws/assetImport/viewData?filename=DatascriptOutputData_BSItLiP036AOsI0cr8e1g2WmipbdtN0c.json and
    ## https://tmad60.transitionmanager.net/tdstm/ws/assetImport/viewData?filename=DatascriptOutputData_BSItLiP036AOsI0cr8e1g2WmipbdtN0c_Application.json
    ## Check the Datascript Script Editor Web Dev tools to see more

    # TM version 6.0 and lower seperate transforming and posting the Datascript. Version 6.1 does not. If 6.1 runs both the transform and the post steps we will get each import batch in TM twice.
    if ($TMSessionConfig.TMVersion -lt '6.1.0') {
        ## With the Datascript converted, Use it to create Import Batches
        $uri = "https://"
        $uri += $instance
        $uri += "/tdstm/ws/assetImport/loadData?filename="
        $uri += $DatascriptOutputKey
        $uri += "&dataScriptId="
        $uri += $Datascript.id

        Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

        ## Post the Transformed data filename to the Datascript engine to Import the Batches.
        $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {
                $ImportJob = $responseContent.data
                $DatascriptProgressKey = $ImportJob.progressKey
            }
            else {
                throw 'Failed to Load Import Batch'
            }
        }
        else {
            Throw 'Failed to Load Import Batch.'
        }
    }

    ## Ensure the Batches loaded and the job is finished
    ## The Datascript is underway, Setup a progress URL
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/progress/" + $DatascriptProgressKey
    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Poll for the status of the Datascript engine
    ## TODO: This should be converted to a function for polling the job engine. It's nearly dupilcated now in the Import Batch watching.
    $Completed = $false
    while ($Completed -eq $false) {

        ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript script
        $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {
                $DatascriptProgress = $responseContent.data

                switch ($DatascriptProgress.status) {
                    "Queued" {
                        $CurrentOperation = 'Loading Batches Queued'
                        $Status = 'Queued'
                        $ProgressString = 'Status - Queued: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "Pending" {
                        $CurrentOperation = 'Loading Batches Pending'
                        $Status = 'Pending Batch Loading'
                        $ProgressString = 'Status - Pending: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "RUNNING" {
                        $CurrentOperation = 'Loading Batches'
                        $Status = 'Loading Batches'
                        $ProgressString = 'Status - Running: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "COMPLETED" {
                        $BatchGroupGuid = $DatascriptProgress.data.groupGuid
                        $CurrentOperation = 'Batch Loading Complete'
                        $Status = 'Loaded Import Batches'
                        $Completed = $true
                        $SleepSeconds = 0
                        $PercentComplete = 99
                        $ProgressString = "Status - Completed Loading Import Batches."
                        Break
                    }
                    "Failed" {
                        $CurrentOperation = 'Failed'
                        $Status = $DatascriptProgress.status
                        Write-Host "Batch Loading Processing Failed "$DatascriptProgress.detail
                        Throw $DatascriptProgress.detail
                    }
                    Default {
                        $CurrentOperation = 'State Unknown'
                        $Status = 'Unknown. Sleeping to try again.'
                        $ProgressString = "Unknown Status: " + $DatascriptProgress.status
                        $PercentComplete = 99
                        $SleepSeconds = 2
                        Break
                    }
                }

                ## Notify the user of the Datascript Progress
                if ($ActivityId) {
                    $ProgressOptions = @{
                        Id               = ($ActivityId + 2)
                        ParentId         = $ActivityId
                        Activity         = 'Import Batch Loading'
                        CurrentOperation = $CurrentOperation
                        Status           = $Status
                        PercentComplete  = $PercentComplete
                    }
                    if ($Completed) {
                        $ProgressOptions.Completed = $True
                    }
                    Write-Progress @ProgressOptions
                }
                else {
                    Write-Host $ProgressString
                }
                if (-Not $Completed) {
                    Start-Sleep -Seconds $SleepSeconds
                }
            }
        }
    }

    ## Assemble the batch list object. Dependencies are deliberately moved to the end
    $BatchesToProcess = [System.Collections.ArrayList]@()

    ## Get the Batches that were created during the import
    ## With the Datascript converted, Use it to create Import Batches
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/import/batches?groupGuid="
    $uri += $BatchGroupGuid

    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Post the Transformed data filename to the Datascript engine to Import the Batches.
    $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
    if ($response.StatusCode -eq 200) {
        $responseContent = $response.Content | ConvertFrom-Json
        if ($responseContent.status -eq "success") {
            $Batches = $responseContent.data
        }
        else {

        }
    }
    else {

    }

    Write-Host $Batches.Length -ForegroundColor Yellow -NoNewline
    Write-Host ' Batches have been created'

    ## Update Progress and transition to Activity + 3
    Write-Progress -Id ($ActivityId + 2) -ParentId $ActivityId -Activity 'Batches Imported' -CurrentOperation 'Importing Batches Complete' -PercentComplete 100 -Completed
    Write-Progress -Id ($ActivityId + 3) -ParentId $ActivityId -Activity 'Monitoring Batches' -CurrentOperation 'Monitoring Batches' -PercentComplete 5

    ## OPTIONAL - If the switch was set to Queue the batches
    if ($QueueBatches) {

        ## Sort the batches to a desired order
        $Batches | Where-Object { $_.domainClass -ne 'Dependency' } | ForEach-Object { $BatchesToProcess.Add($_) | Out-Null }
        $Batches | Where-Object { $_.domainClass -eq 'Dependency' } | ForEach-Object { $BatchesToProcess.Add($_) | Out-Null }

        ## Write Progress to the Monitor Import Batches
        if ($ActivityId) {
            Write-Progress -Id ($ActivityId + 3) `
                -ParentId $ActivityId `
                -Activity 'Manage Batches' `
                -CurrentOperation 'Queueing Batches' `
                -Status ('Queueing ' + [string]$Batches.Length + ' batches.') `
                -PercentComplete 5
        }
        Write-Host "Queueing Batches:" -NoNewline
        Write-Host $Batches.Length -ForegroundColor Yellow

        ## Add a Progress Activity for each of the Import Batches
        for ($i = 0; $i -lt $BatchesToProcess.Count; $i++) {

            ## Set Variable for Batch
            $Batch = $BatchesToProcess[$i]

            ## Create Progress Results for the batches that were created
            if ($ActivityId) {

                ## Activity Explained: The $ActivityId is considered the (Root) + 2 (to move to Monitoring Batches) + I for the looping + 1 to add a new layer
                Write-Progress -Id ($ActivityId + 3 + $i + 1) `
                    -ParentId ($ActivityId + 3) `
                    -Activity ($Batch.domainClassName + ' batch: ' + $Batch.id + ' | Total: ' + $Batch.recordsSummary.count) `
                    -CurrentOperation 'Queueing Batch' `
                    -Status ([String]$Batch.recordsSummary.count + ' ' + $Batch.domainClassName + ' records') `
                    -PercentComplete 10
            }
            Write-Host "Batch (id $($Batch.id)) Created with $([String]$Batch.recordsSummary.count) $($Batch.domainClassName) records"
        }

        ## Queue each Batch
        for ($i = 0; $i -lt $BatchesToProcess.Count; $i++) {

            ## Set Variable for Batch
            $Batch = $BatchesToProcess[$i]
            if ($Batch.autoProcess -eq 0) {

                ## With the file uploaded, Initiate the Datascript script on the server
                $uri = "https://"
                $uri += $instance
                $uri += "/tdstm/ws/import/batches"

                Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

                $PostBody = @{
                    action = 'QUEUE'
                    ids    = $Batch.id
                } | ConvertTo-Json -Depth 100


                ## Post this batch to begin it's Queueing
                $response = Invoke-WebRequest -Method Patch -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBody @TMCertSettings
                if ($response.StatusCode -eq 200) {
                    $responseContent = $response.Content | ConvertFrom-Json
                    if ($responseContent.status -eq "success") {

                        ## Create Progress Results for the batches that were created
                        if ($ActivityId) {

                            ## Notify the Manage Batches Activity of a queued batch
                            Write-Progress -Id ($ActivityId + 3) `
                                -ParentId $ActivityId `
                                -Activity 'Monitor Batches' `
                                -CurrentOperation 'Queueing Batches' `
                                -Status ('Queued ' + $Batch.domainClass + ' Batch') `
                                -PercentComplete 5

                            ## Activity (Root) + 2 (to move to Monitoring Batches) + I for the looping + 1 to add a new layer
                            Write-Progress -Id ($ActivityId + 3 + $i + 1) `
                                -ParentId ($ActivityId + 3) `
                                -Activity ($Batch.domainClassName + ' batch: ' + $Batch.id + ' | Total: ' + $Batch.recordsSummary.count) `
                                -CurrentOperation 'Batch Queued'  `
                                -Status 'Queued' `
                                -PercentComplete 0
                        }
                        Write-Host "Batch Queued: " -NoNewline
                        Write-Host $Batch.domainClassName -ForegroundColor Yellow
                    }
                    else {
                        Throw 'Failed to Queue Batch'
                    }
                }
                else {
                    Throw 'Failed to Queue Batch.'
                }
            }
        }

        ## If Monitoring isn't going to occur, status should be complete here
        if ($MonitorBatches -ne $true) {
            Write-Progress -Id ($ActivityId + 3) -ParentId $ActivityId -Activity 'Batches Queued' -CurrentOperation 'Batches have been queued' -PercentComplete 100 -Completed
        }
    }

    ## Allow the batch to be monitored and reported on in the UI
    if ($MonitorBatches) {
        $BatchStatus = @{
            CompletedBatches = 0
            TotalBatches     = $BatchesToProcess.Count
        }

        ## Monitor the batches to completion
        for ($i = 0; $i -lt $BatchesToProcess.Count; $i++) {

            ## Set Variable for Batch
            $Batch = $BatchesToProcess[$i]
            if ($Batch.recordsSummary.count -gt 0) {
                ## Build the URL
                $uri = "https://"
                $uri += $instance
                $uri += "/tdstm/ws/import/batch/"
                $uri += $Batch.id
                $uri += "/progress"

                Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

                ## Poll for the status of the Import Batch
                if ($ActivityId) {

                    ## Activity (Root) + 3 (to move to Monitoring Batches) + I for the looping + 1 to add a new layer
                    Write-Progress -Id ($ActivityId + 3 + $i + 1) `
                        -ParentId ($ActivityId + 3) `
                        -Activity ($Batch.domainClassName + ' batch: ' + $Batch.id + ' | Total: ' + $Batch.recordsSummary.count) `
                        -CurrentOperation 'Monitoring Progress'  `
                        -Status 'Importing' `
                        -PercentComplete 1
                }
                Write-Host 'Monitoring Batch Status for ' -NoNewline
                Write-Host $Batch.domainClassName -ForegroundColor Yellow

                ## Start a loop to run while the batch is not complete.
                $Completed = $false
                while ($Completed -eq $false) {

                    ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript script
                    $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
                    if ($response.StatusCode -eq 200) {
                        $responseContent = $response.Content | ConvertFrom-Json
                        if ($responseContent.status -eq "success") {

                            $BatchProgress = $responseContent.data

                            switch ($BatchProgress.status.code) {
                                "RUNNING" {
                                    $CurrentOperation = 'Import Running'
                                    $Status = 'Importing Batch Data'
                                    $ProgressString = $DomainClass + ' Status: Running - ' + $BatchProgress.progress + "%"
                                    $PercentComplete = $BatchProgress.progress
                                    $SleepSeconds = 2
                                    break
                                }
                                "QUEUED" {
                                    $CurrentOperation = 'Batch Queued'
                                    $Status = 'Batch Queued'
                                    $ProgressString = $DomainClass + ' Status: Queued'
                                    $PercentComplete = $BatchProgress.progress
                                    $SleepSeconds = 2
                                    break

                                }
                                "PENDING" {
                                    $CurrentOperation = 'Batch Pending'
                                    $Status = 'Batch Pending'
                                    $ProgressString = $DomainClass + ' Status: Pending'
                                    $PercentComplete = $BatchProgress.progress
                                    $SleepSeconds = 2
                                    break

                                }
                                "COMPLETED" {
                                    $Completed = $true
                                    $CurrentOperation = 'Complete'
                                    $Status = 'Complete'
                                    $ProgressString = ($batch.domainClassName + " Status: Complete")
                                    $PercentComplete = 100
                                    $SleepSeconds = 0
                                    break

                                }
                                Default {
                                    $CurrentOperation = 'Status Unknown. Retrying'
                                    $Status = 'Retrying'
                                    $ProgressString = ($batch.domainClassName + "Status Unkown. Retrying")
                                    $PercentComplete = 1
                                    $SleepSeconds = 2
                                    break
                                }
                            }

                            ## Display the Status of this loop
                            if ($ActivityId) {

                                $ProgressOptions = @{
                                    Id               = ($ActivityId + 3 + $i + 1)
                                    ParentId         = ($ActivityId + 3)
                                    Activity         = ($Batch.domainClassName + ' batch: ' + $Batch.id + ' | Total: ' + $Batch.recordsSummary.count)
                                    CurrentOperation = $CurrentOperation
                                    Status           = $Status
                                    PercentComplete  = ($PercentComplete ?? 0)
                                }
                                ## Activity (Root) + 3 (to move to Monitoring Batches) + I for the looping + 1 to add a new layer
                                if ($Completed) {
                                    $ProgressOptions.Completed = $true
                                }
                                Write-Progress @ProgressOptions

                            }
                            else {
                                Write-Host $ProgressString
                            }

                            ## Sleep the expected duration
                            Start-Sleep -Seconds $SleepSeconds
                        }
                    }
                }
            }
            ## Now that this batch is done, increment the Completed Batches counter
            $BatchStatus.CompletedBatches++
            Write-Host 'Batch Import Complete for ' -NoNewline
            Write-Host $Batch.domainClassName -ForegroundColor Yellow
        }

        ## Mark the Manage Batches Activity Complete
        if ($ActivityId) {
            Write-Progress -Id ($ActivityId + 3) `
                -ParentId $ActivityId `
                -Activity 'Batches Posted' `
                -CurrentOperation 'Complete'  `
                -Status 'All Batches Imported' `
                -PercentComplete 100 `
                -Completed
        }
    }


    ## Mark the TM Import Activity complete
    if ($ActivityId) {
        Write-Progress -Id $ActivityId `
            -ParentId $ParentActivityId `
            -Activity 'TransitionManager Data Import' `
            -CurrentOperation 'Complete'  `
            -Status 'All Data Imported' `
            -PercentComplete 100 `
            -Complete
    }
    Write-Host 'All Batches have Imported successfully'
}

Function Test-TMDatascript {
    [alias("Test-TMETLScript")]
    param(
        [Parameter(Mandatory = $false)][String]$TMSession = "Default",
        [Alias("ETLScriptName")]
        [Parameter(Mandatory = $true)][String]$DatascriptName,
        [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer,
        [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,
        [Parameter(Mandatory = $false)][bool]$QueueBatches = $false,
        [Parameter(Mandatory = $false)][bool]$MonitorBatches = $false,
        [Parameter(Mandatory = $true)][String]$DataType,
        [Parameter(Mandatory = $false)]$Data,
        [Parameter(Mandatory = $false)][String]$FilePath,
        [Parameter(Mandatory = $false)][String]$FileName,
        [Parameter(Mandatory = $false)][Int16]$ActivityId,
        [Parameter(Mandatory = $false)][Int16]$ParentActivityId = -1
    )

    ## Get Session Configuration
    $TMSessionConfig = $global:TMSessions[$TMSession]
    if (-not $TMSessionConfig) {
        Write-Host 'TMSession: [' -NoNewline
        Write-Host $TMSession -ForegroundColor Cyan
        Write-Host '] was not Found. Please use the New-TMSession command.'
        Throw "TM Session Not Found. Use New-TMSession command before using features."
    }

    ## If a File Path was passed and there is no data, Read the file
    if ($FilePath -and -not $Data) {
        $Data = Get-Content $FilePath -Raw
        $FileName = (Get-Item $FilePath).Name
    }

    ## If a File Path was passed and there is no File Name, get the file name
    if ($FilePath -and -not $FileName) {
        $FileName = (Get-Item $FilePath).Name
    }

    #Honor SSL Settings
    if ($TMSessionConfig.AllowInsecureSSL) {
        $TMCertSettings = @{SkipCertificateCheck = $true }
    }
    else {
        $TMCertSettings = @{SkipCertificateCheck = $false }
    }

    if ($ActivityId) {
        ## Parent ID is only used on the root 'TransitionManager Data Import' Activity
        ## ParentID + 1 = Transform Data
        ## ParentID + 2 = Import Batches
        ## ParentID + 3 + n for each batch

        ## Add the Datascript Processing Progress Indicators
        $ProgressIndicators = @()
        $ProgressIndicators += @{ Id = $ActivityId; Activity = 'Test Datascript Data Transformation'; ParentId = $ParentActivityId }

    }

    ## Fix the Server URL
    $instance = $Server.Replace('/tdstm', '')
    $instance = $instance.Replace('https://', '')
    $instance = $instance.Replace('http://', '')

    $Boundary = '----------------------------540299933173025267350719'

    ## First Test to see if the Datascript exists or not
    if ($ActivityId) {

        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Datascript Data Transformation' -CurrentOperation 'Validating Datascript' -Status 'Confirming Datascript exists in TransitionManager' -PercentComplete 5
    }
    $Datascript = Get-TMDatascript -TMSession $TMSession -Name $DatascriptName
    if (-Not $Datascript) { Throw  'The Datascript [' + $DatascriptName + '] does not exist' }

    ## Build the Data Post
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/fileSystem/uploadFileETLAssetImport"

    ## FileName
    if (-not $FileName) {
        $FileName = ('DataForETL_' + (Get-Date -Format FileDateTime ) + '.' + $DataType)
    }

    ## Construct the PostBody and Form Data for the request
    $CRLF = "`r`n";
    $PostBody = ("-----------------------------$boundary",
        'Content-Disposition: form-data; name="uploadType"',
        '',
        'assetImport',
        "-----------------------------$boundary",
        ''
    ) -join $CRLF
    $FileUpload = @{
        Form = @{
            uploadType = 'assetImport'
            file       = Get-Item -Path $FilePath
            fileName   = $FileName
        }
    }
    ## Upload the Data File
    if ($ActivityId) {
        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Testing Datascript Data Transformation' -CurrentOperation 'Uploading Data' -Status ('Uploading ' + $FileName) -PercentComplete 5
    }

    try {
        ## If the file is being uploaded, append the fileupload to the command
        if ($FileUpload) {
            $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -ContentType ('multipart/form-data; boundary=---------------------------' + $boundary) @TMCertSettings @FileUpload
        }
        else {
            $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -ContentType ('multipart/form-data; boundary=---------------------------' + $boundary) @TMCertSettings
        }

    }
    catch {
        throw $_
    }
    if ($response.StatusCode -eq 200) {
        $responseContent = $response.Content | ConvertFrom-Json
        if ($responseContent.status -eq "success") {
            $DatascriptdataFileName = $responseContent.data.filename
        }
        else {
            Throw "Unable to upload data to TM Datascript pre-transform storage."
        }
    }

    ## With the file uploaded, Initiate the Datascript script on the server
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/dataScript/initiateTestScript"

    ## Create a post body
    $PostBody = [PSCustomObject]@{
        dataScriptId = $Datascript.id
        filename     = $DatascriptdataFileName
        script       = ($Datascript.etlSourceCode -replace $CRLF, '\n')
    } | ConvertTo-Json -Compress

    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript
    if ($ActivityId) {
        Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Testing Datascript Data Transformation' -CurrentOperation 'Starting Datascript Testing' -PercentComplete 5
    }
    else {
        Write-Host 'TransitionManager Data Import: Starting Datascript Test'
    }

    $response = Invoke-WebRequest -Method Post -Uri $uri -Body $PostBody -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
    if ($response.StatusCode -eq 200) {
        $responseContent = $response.Content | ConvertFrom-Json
        if ($responseContent.status -eq "success") {
            $DatascriptProgressKey = $responseContent.data.progressKey
        }
        else {
            throw $responseContent.errors
        }
    }
    else {
        Throw $response
    }


    ## Supply Progress from Datascript Transformation Progress
    if ($ActivityId) {
        Write-Progress -Id $($ActivityId + 1) -Activity 'Testing Datascript Data Transformation' -CurrentOperation 'Running Datascript Transformation' -PercentComplete 0 -ParentId $ActivityId
    }
    else {
        Write-Host 'Testing Datascript Data Transformation: Starting Datascript Processing'
    }

    ## The Datascript is underway, Setup a progress URL
    $uri = "https://"
    $uri += $instance
    $uri += "/tdstm/ws/progress/" + $DatascriptProgressKey
    Set-TMHeaderContentType -ContentType JSON -TMSession $TMSession

    ## Poll for the status of the Datascript engine
    ## TODO: This should be converted to a function for polling the job engine. It's nearly dupilcated now in the Import Batch watching.
    $Completed = $false
    while ($Completed -eq $false) {

        ## Post the data starting the Datascript process. A progress key is provided. This progress key is what can be used to poll for the status of the Datascript script
        $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings
        if ($response.StatusCode -eq 200) {
            $responseContent = $response.Content | ConvertFrom-Json
            if ($responseContent.status -eq "success") {
                $DatascriptProgress = $responseContent.data

                switch ($DatascriptProgress.status) {
                    "Queued" {

                        $CurrentOperation = 'Datascript Queued'
                        $Status = 'Queued'
                        $ProgressString = 'Status - Queued: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break

                    }
                    "Pending" {
                        $CurrentOperation = 'Datascript Pending'
                        $Status = 'Pending'
                        $ProgressString = 'Status - Pending: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "RUNNING" {
                        $CurrentOperation = 'Datascript Running'
                        $Status = 'Transforming Data'
                        $ProgressString = 'Status - Running: ' + $DatascriptProgress.percentComp + '%'
                        $PercentComplete = $DatascriptProgress.percentComp
                        $SleepSeconds = 2
                        Break
                    }
                    "COMPLETED" {
                        $CurrentOperation = 'Datascript Testing Complete'
                        $Status = 'Creating Import Batches'
                        $Completed = $true
                        $SleepSeconds = 0
                        $PercentComplete = 99
                        $ProgressString = "Status - Datascript Testing Complete"
                        Break
                    }
                    "Failed" {
                        $CurrentOperation = 'Failed'
                        $Status = $DatascriptProgress.status
                        Write-Host "Datascript Testing Failed "$DatascriptProgress.detail
                        Throw $DatascriptProgress.detail
                    }
                    Default {
                        $CurrentOperation = 'State Unknown'
                        $Status = 'Unknown. Sleeping to try again.'
                        $ProgressString = "Unknown Status: " + $DatascriptProgress.status
                        $PercentComplete = 99
                        $SleepSeconds = 2
                        Break
                    }
                }

                ## Notify the user of the Datascript Progress
                if ($ActivityId) {
                    Write-Progress -Id ($ActivityId + 1) `
                        -ParentId $ActivityId `
                        -Activity 'Testing Datascript Data Transformation' `
                        -CurrentOperation $CurrentOperation `
                        -Status $Status `
                        -PercentComplete $PercentComplete
                }
                else {
                    Write-Host $ProgressString
                }
                Start-Sleep -Seconds $SleepSeconds
            }
        }
    }

    ## Update Progress and transition to Activity + 2
    Write-Progress -Id ($ActivityId + 1) -ParentId $ActivityId -Activity 'Tested Datascript Data Transformation' -CurrentOperation 'Testing Complete' -PercentComplete 100 -Completed

    ## Mark the TM Import Activity complete
    if ($ActivityId) {
        Write-Progress -Id $ActivityId `
            -ParentId $ParentActivityId `
            -Activity 'TransitionManager Data Import' `
            -CurrentOperation 'Complete'  `
            -Status 'All Data Imported' `
            -PercentComplete 100 `
            -Complete
    }
}

Function Read-TMDatascriptFile {
    param(
        [Parameter(Mandatory = $true)]$Path
    )

    ## First order of business is to determine if this Script file has a counterpart Json file
    $DatascriptConfigJsonPath = $Path -Replace '.groovy', '.json'
    $DatascriptConfigFile = Get-Item -Path $DatascriptConfigJsonPath -ErrorAction 'SilentlyContinue'

    ## Check if there is a config JSON file, if so, get the Action from the 2 files
    if ($DatascriptConfigFile) {

        ## Get the Recipe Object that doesn't have the source code
        $TMDatascript = Get-Content -Path $DatascriptConfigFile | ConvertFrom-Json
        Add-Member -InputObject $TMDatascript -NotePropertyName etlSourceCode -NotePropertyValue (Get-Content -Path $Path -Raw)
    }

    ## Read the ReferenceDesign (Combined) file
    else {

        ## Name the Input File
        $Content = Get-Content -Path $Path -Raw

        ## Ignore Empty Files
        if (-Not $Content) {
            return
        }

        $ContentLines = Get-Content -Path $Path

        ## Create Automation Token Variables Parse the Script File
        New-Variable astTokens -Force
        New-Variable astErr -Force
        $ast = [System.Management.Automation.Language.Parser]::ParseInput($Content, [ref]$astTokens, [ref]$astErr)

        ##
        ## Assess the Script Parts to get delineating line numbers
        ##

        ## Locate the Delimiting line
        $ConfigBlockStartLine = $astTokens | `
            Where-Object { $_.Text -like '/*********TransitionManager-ETL-Script*********' } |`
            Select-Object -First 1 | `
            Select-Object -ExpandProperty Extent | `
            Select-Object -ExpandProperty StartLineNumber

        ## Test if the file has been written with MetaData
        if (-Not $ConfigBlockStartLine) {

            ## This file does not have metadata. Create the minimum data for the constructor below
            $DatascriptConfig = @{
                DatascriptName = (Get-Item -Path $Path).BaseName
                Description    = ""
                ProviderName   = (Get-Item -Path $Path).Directory.BaseName
                IsAutoProcess  = $false
                Target         = $null
                Mode           = 'Import'
            }

            ## Add Variables that will be used in the construction
            $DatascriptCode = $ContentLines
            $ConfigBlockEndLine = -1
        }
        else {

            ## This File has metadata - Work to parse it

            $ConfigBlockEndLine = $astTokens | `
                Where-Object { $_.Text -like '*********TransitionManager-ETL-Script*********/' } |`
                Select-Object -First 1 | `
                Select-Object -ExpandProperty Extent | `
                Select-Object -ExpandProperty StartLineNumber

            ## Adjust the Line Numbers to capture just the JSON
            $JsonConfigBlockStartLine = $ConfigBlockStartLine + 1
            $JsonConfigBlockEndLine = $ConfigBlockEndLine - 1


            ##
            ## Read the Script Header to gather the configurations
            ##

            ## Get all of the lines in the header comment
            $DatascriptConfigJson = $JsonConfigBlockStartLine..$JSONConfigBlockEndLine | ForEach-Object {

                ## Return the line for collection
                $ContentLines[$_ - 1]

            } | Out-String

            ## Convert the JSON string to an Object
            if ($DatascriptConfigJson) {
                $DatascriptConfig = $DatascriptConfigJson | ConvertFrom-Json
            }
            else {
                $DatascriptConfig = @{
                    DatascriptName = (Get-Item -Path $Path).BaseName
                    Description    = ""
                    ProviderName   = (Get-Item -Path $Path).Directory.Parent.Parent.BaseName
                    IsAutoProcess  = $false
                    Target         = $null
                    Mode           = 'Import'
                }
            }
        }

        ##
        ## Read the Script Block
        ##

        ## Note where the Configuration Code is located
        $StartCodeBlockLine = $ConfigBlockEndLine + 1
        $EndCodeBlockLine = $ast[-1].Extent.EndLineNumber

        ## Create a Text StrinBuilder to collect the Script into
        $DatascriptStringBuilder = New-Object System.Text.StringBuilder

        ## For each line in the Code Block, add it to the Datascript Script Code StringBuilder
        $StartCodeBlockLine..$EndCodeBlockLine | ForEach-Object {
            $DatascriptStringBuilder.AppendLine($ContentLines[$_]) | Out-Null
        }

        ## Convert the StringBuilder to a Multi-Line String
        $DatascriptCode = $DatascriptStringBuilder.ToString()

        ## Assemble the Action Object
        $TMDatascript = [pscustomobject]@{

            ## Primary Information
            id            = $null
            name          = $DatascriptConfig.DatascriptName
            description   = $DatascriptConfig.Description

            ## Source Code
            etlSourceCode = $DatascriptCode

            ## Provider
            provider      = @{
                id   = $null
                name = $DatascriptConfig.ProviderName
            }

            ## Other details for the Datascript Script
            dateCreated   = Get-Date
            lastUpdated   = Get-Date
        }
    }

    ## Return the Action Object
    return $TMDatascript
}