--- title: "Concepts: Tasks & Task Forms" slug: "scripting-tutorials-tasks-and-task-forms" updated: 2024-09-18T16:20:16Z published: 2024-09-18T16:20:16Z canonical: "help.agilityblue.com/scripting-tutorials-tasks-and-task-forms" --- > ## Documentation Index > Fetch the complete documentation index at: https://help.agilityblue.com/llms.txt > Use this file to discover all available pages before exploring further. # Concepts: Tasks & Task Forms ## Get a Collection of Tasks To retrieve a collection of tasks, you use the `Get-Tasks` command. This command is like other collection commands where it can take `Top`, `Skip`, `Filter`, and `OrderBy` parameters. ```powershell # Retrieve tasks that are on hold and order them from newest to oldest $tasks = Get-Tasks `    -Filter "StatusDescription eq 'On Hold'" `    -OrderBy "CreatedOn desc"     Write-Output "Located $($tasks.TotalCount) tasks that are on hold:" # Do something with each task... $tasks.Collection | ForEach-Object {    # Retrieve the full task with forms (only if needed, otherwise this can slow down the script)...    $task = Get-Task -Id $_.TaskId -IncludeForms        # Do something with this task...    Write-Output "Task $($task.TaskId) has $($task.Forms.Count) form(s)" } ``` Output of this script: ```plaintext Located 4 tasks that are on hold: Task 1005 has 1 form(s) Task 1004 has 2 form(s) Task 1003 has 2 form(s) Task 120 has 1 form(s) ``` ## Getting a Collection of Task Form Fields If you’re interested in retrieving task form information based on specific fielded filters, then you should use the `Get-TaskFormFields` command. This command will retrieve a flat collection of task fields as individual records across all tasks allowing you to apply filters on the fields themself. ```powershell $taskFormFields = Get-TaskFormFields `    -Filter "TaskFormName eq 'Blowbacks' and Label eq 'Number of Sets'" # Add up all of the number fields... $sumOfBlowbackSets = $taskFormFields.Collection |    Where-Object { $_.ValueAsNumber -ne $null } |    Measure-Object -Property ValueAsNumber -Sum Write-Output "The total number of blowback sets is $($sumOfBlowbackSets.Sum.ToString('N0'))" ``` Output of this script: ```plaintext The total number of blowback sets is 5,630 ``` ## Get a Task Without Forms, Sections, and Fields In some cases, you may want to retrieve a task that doesn’t contain any of it’s forms, sections, and fields because it is much faster to work with less bulky data by simply reading task-based system properties. To do this, use the `Get-Task` command to retrieve a single task which requires the id of a task. ```powershell $task = Get-Task -Id 120 $task | ConvertTo-Json -Depth 10 ``` The output of this script: ```plaintext {  "Metadata": null,  "AssignedBy": null,  "AssignedTo": null,  "Client": null,  "CompletedBy": null,  "CreatedBy": null,  "Forms": [],  "Matter": null,  "Project": null,  "QualityCheckPerformedBy": null,  "Subscribers": [],  "TaskId": 120,  "ProjectId": 2016040000023,  "ProjectTypeId": 1,  "ProjectTypeName": "Normal",  "ProjectTypeDescription": "The normal project type where task work is performed.",  "ProjectSourceTypeId": 1,  "ProjectSourceTypeName": "Not Specified",  "ProjectDescription": "Process and Load Data",  "ProjectComputedTags": "Relativity; Technical",  "ProjectRequesterId": null,  "ProjectRequesterFirstName": null,  "ProjectRequesterLastName": null,  "ProjectRequesterFullName": null,  "ProjectRequesterEmail": null,  "MatterId": 42,  "MatterName": "Delta Bank SSB vs. Colorado Builders Construction CO.",  "MatterReference": "2016-3422",  "ClientId": 31,  "ClientName": "Delta Bank SSB",  "ClientReference": null,  "Name": "Relativity Processing Request",  "AssignedToId": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "AssignedToFullName": "Max Miller",  "AssignedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "AssignedByFullName": "Max Miller",  "EstimatedHours": null,  "ActualHours": null,  "StatusId": 4,  "StatusDescription": "Completed",  "QualityCheckStatusId": 1,  "QualityCheckStatusDescription": "Not Performed",  "QualityCheckPerformedById": null,  "QualityCheckPerformedByFullName": null,  "FormNames": "Relativity Processing Request",  "SortOrder": 0,  "DateDue": null,  "CompletedOn": "2016-04-28T13:51:48.379262-05:00",  "CompletedById": null,  "CompletedByFullName": null,  "AssignedOn": "2023-02-09T15:17:56.3981937+00:00",  "NumberOfComments": 2,  "NumberOfAttachments": 0,  "NumberOfMediaLogEntries": 0,  "NumberOfVolumes": 0,  "NumberOfBillingEntries": 0,  "NumberOfSubscribers": 0,  "NumberOfEmailMessages": 0,  "CreatedByFullName": "Max Miller",  "CreatedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "CreatedOn": "2016-04-28T13:43:45.5689454-05:00",  "LastUpdatedByFullName": "Max Miller",  "LastUpdatedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "LastUpdatedOn": "2023-02-09T15:17:56.3981937+00:00",  "LastUpdatedBy": null } ``` ## Get a Task that Includes Forms, Sections, and Fields In cases where you do need to retrieve a task’s forms, sections, and fields, you can add the `-InlcudeForms` switch to the `Get-Task` command. This command requires the id of the task. ```powershell $task = Get-Task -Id 120 -IncludeForms $task | ConvertTo-Json -Depth 10 ``` The output of this script: ```plaintext {  "Metadata": null,  "AssignedBy": null,  "AssignedTo": null,  "Client": null,  "CompletedBy": null,  "CreatedBy": null,  "Forms": [    {      "TaskFormId": 107,      "TaskId": 120,      "FormId": 0,      "Guid": 1461868991662,      "Name": "Relativity Processing Request",      "Sections": [        {          "TaskFormSectionId": 118,          "FormSectionId": null,          "TaskFormId": 107,          "Heading": "Processing Request",          "Position": 0,          "Guid": 1460996206057,          "Fields": [            {              "TaskFormFieldId": 226,              "FieldId": 0,              "TaskFormSectionId": 118,              "DataTypeId": 1,              "DataTypeName": "Basic Text",              "Label": "Processing Engine",              "ValueAsString": "Relativity",              "ValueAsBoolean": null,              "ValueAsNumber": null,              "ValueAsDecimal": null,              "ValueAsDate": null,              "DefaultValue": "Relativity",              "IsRequired": true,              "IsVisible": true,              "Position": 0,              "Guid": 1460996221915,              "ReferenceObject": null,              "AppliedProperties": []            },            {              "TaskFormFieldId": 227,              "FieldId": 0,              "TaskFormSectionId": 118,              "DataTypeId": 2,              "DataTypeName": "Rich Text",              "Label": "Processing Instructions",              "ValueAsString": "

Process and load PST files collected from custodians per the following instructions:

More details

",              "ValueAsBoolean": null,              "ValueAsNumber": null,              "ValueAsDecimal": null,              "ValueAsDate": null,              "DefaultValue": "

Process and load PST files collected from custodians per the following instructions:

",              "IsRequired": true,              "IsVisible": true,              "Position": 1,              "Guid": 1461176252114,              "ReferenceObject": null,              "AppliedProperties": []            }          ]        }      ]    }  ],  "Matter": null,  "Project": null,  "QualityCheckPerformedBy": null,  "Subscribers": [],  "TaskId": 120,  "ProjectId": 2016040000023,  "ProjectTypeId": 1,  "ProjectTypeName": "Normal",  "ProjectTypeDescription": "The normal project type where task work is performed.",  "ProjectSourceTypeId": 1,  "ProjectSourceTypeName": "Not Specified",  "ProjectDescription": "Process and Load Data",  "ProjectComputedTags": "Relativity; Technical",  "ProjectRequesterId": null,  "ProjectRequesterFirstName": null,  "ProjectRequesterLastName": null,  "ProjectRequesterFullName": null,  "ProjectRequesterEmail": null,  "MatterId": 42,  "MatterName": "Delta Bank SSB vs. Colorado Builders Construction CO.",  "MatterReference": "2016-3422",  "ClientId": 31,  "ClientName": "Delta Bank SSB",  "ClientReference": null,  "Name": "Relativity Processing Request",  "AssignedToId": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "AssignedToFullName": "Max Miller",  "AssignedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "AssignedByFullName": "Max Miller",  "EstimatedHours": null,  "ActualHours": null,  "StatusId": 4,  "StatusDescription": "Completed",  "QualityCheckStatusId": 1,  "QualityCheckStatusDescription": "Not Performed",  "QualityCheckPerformedById": null,  "QualityCheckPerformedByFullName": null,  "FormNames": "Relativity Processing Request",  "SortOrder": 0,  "DateDue": null,  "CompletedOn": "2016-04-28T13:51:48.379262-05:00",  "CompletedById": null,  "CompletedByFullName": null,  "AssignedOn": "2023-02-09T15:17:56.3981937+00:00",  "NumberOfComments": 2,  "NumberOfAttachments": 0,  "NumberOfMediaLogEntries": 0,  "NumberOfVolumes": 0,  "NumberOfBillingEntries": 0,  "NumberOfSubscribers": 0,  "NumberOfEmailMessages": 0,  "CreatedByFullName": "Max Miller",  "CreatedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "CreatedOn": "2016-04-28T13:43:45.5689454-05:00",  "LastUpdatedByFullName": "Max Miller",  "LastUpdatedById": "25a34a2f-e3d8-4690-88f5-6b399cf88c4c",  "LastUpdatedOn": "2023-02-09T15:17:56.3981937+00:00",  "LastUpdatedBy": null } ``` ## Anatomy of Task Forms All tasks contain a collection of forms that are referred to as task forms. These objects are created from workspace forms and maintain a snapshot as the form existed when the task was created. This allows users to modify or remove forms that were used on existing tasks without affecting those tasks. Task forms mirror the structure of forms where each task form contains a collection of sections and each section contains a collection of fields. The crucial difference between forms and task forms is that task forms contain the values of the fields in the forms. Below is an example of a task form that contains one section and two fields within that section. ```json {   "TaskFormId": 107,   "TaskId": 120,   "FormId": 0,   "Guid": 1461868991662,   "Name": "Relativity Processing Request",   "Sections": [     {       "TaskFormSectionId": 118,       "FormSectionId": null,       "TaskFormId": 107,       "Heading": "Processing Request",       "Position": 0,       "Guid": 1460996206057,       "Fields": [         {           "TaskFormFieldId": 226,           "FieldId": 0,           "TaskFormSectionId": 118,           "DataTypeId": 1,           "DataTypeName": "Basic Text",           "Label": "Processing Engine",           "ValueAsString": "Relativity",           "ValueAsBoolean": null,           "ValueAsNumber": null,           "ValueAsDecimal": null,           "ValueAsDate": null,           "DefaultValue": "Relativity",           "IsRequired": true,           "IsVisible": true,           "Position": 0,           "Guid": 1460996221915,           "ReferenceObject": null,           "AppliedProperties": []         },         {           "TaskFormFieldId": 227,           "FieldId": 0,           "TaskFormSectionId": 118,           "DataTypeId": 2,           "DataTypeName": "Rich Text",           "Label": "Processing Instructions",           "ValueAsString": "

Process and load PST files collected from custodians per the following instructions:

More details

",           "ValueAsBoolean": null,           "ValueAsNumber": null,           "ValueAsDecimal": null,           "ValueAsDate": null,           "DefaultValue": "

Process and load PST files collected from custodians per the following instructions:

",           "IsRequired": true,           "IsVisible": true,           "Position": 1,           "Guid": 1461176252114,           "ReferenceObject": null,           "AppliedProperties": []         }       ]     }   ] } ``` In the example above, you may notice properties that start with “ValueAs”. These fields hold the value for the field based on the data type. When creating, reading, or updating task fields, it’s important to use the correct `ValueAs*` field. Fields can be defined with 10 different data types: | Data Type Id | Data Type Name | Stored As | | --- | --- | --- | | 1 | Basic Text | ValueAsString | | 2 | Rich Text* | ValueAsString | | 3 | Whole Number | ValueAsNumber | | 4 | Decimal Number | ValueAsDecimal | | 5 | Yes or No Choice | ValueAsBoolean | | 6 | Date Only | ValueAsDate | | 7 | Date and Time | ValueAsDate | | 8 | Single Choice | ValueAsString | | 9 | Multiple Choice* | ValueAsString | | 10 | Reference | ReferenceObject | ## Finding Fields Tasks contain collections of forms, where each form contains collections of sections, and each section contains collections of fields. Below are a few methods you can use to help locate and pinpoint specific fields within task forms. ### Iterating through each field With this method, you use PowerShell’s `ForEach-Object` cmdlet to walk through each form, section, and field to locate the fields you’re interested in: ```powershell $task = Get-Task -Id 120 -IncludeForms # Iterate through each form in the task $task.Forms | ForEach-Object {    $form = $_        # Iterate through each section of the current form    $form.Sections | ForEach-Object {        $formSection = $_                # Iterate through each field of the current section        $formSection.Fields | ForEach-Object {            $formField = $_                        if ($formField.Label -eq "Processing Instructions") {                Write-Output "Encountered Form Field: $($formField.Label) (Data Type: $($formField.DataTypeName))"                return            }        }    } } ``` This script produces the following example output for our example task: ```plaintext Encountered Form Field: Processing Instructions (Data Type: Rich Text) ``` ### Piping and searching for a specific field by name With this method, you still walk through forms and sections by piping the `ForEach-Object` results into each cmdlet, but you use PowerShell’s `Where-Object` cmdlet at the end of the pipeline to pluck out the specific field. ```powershell $task = Get-Task -Id 120 -IncludeForms $processingInstructionsField = $task.Forms |    ForEach-Object { $_.Sections } |    ForEach-Object { $_.Fields } |    Where-Object { $_.Label -eq "Processing Instructions" } Write-Output "Encountered Form Field: $($processingInstructionsField.Label) (Data Type: $($processingInstructionsField.DataTypeName))" ``` This script produces the following example output for our example task: ```plaintext Encountered Form Field: Processing Instructions (Data Type: Rich Text) ``` ### Flattening the collection and searching for a specific field by name With this method, you use PowerShell’s `Select-Object` cmdlet to flatten the fields into a single collection where you then use the `Where-Object` cmdlet to retrieve the desired field. ```powershell $task = Get-Task -Id 120 -IncludeForms # Flatten the forms, sections, and fields into a single collection $fields = $task.Forms |    Select-Object -ExpandProperty Sections |    Select-Object -ExpandProperty Fields # Select the field based on the name of the field $processingInstructionsField = $fields | Where-Object { $_.Label -eq "Processing Instructions" } Write-Output "Encountered Form Field: $($processingInstructionsField.Label) (Data Type: $($processingInstructionsField.DataTypeName))" ``` This script produces the following example output for our example task: ```plaintext Encountered Form Field: Processing Instructions (Data Type: Rich Text) ``` > [!NOTE] > Fun Fact > > In PowerShell, when you retrieve an object from a collection (like a field from a list of fields), you're working with a **reference** to the original object, not a separate copy. This means that any changes you make to that object will automatically be reflected in the original data structure from which it was retrieved. ## Create a Task When creating a task, you will need some information from a form that exists within the workspace. Below is an example of creating a task that uses a “Processing QC” form: ```powershell # Which project to create the task under $projectId = 2024090000007 # Get the processing qc form $qcForm = Get-Form -Id 62 # Get the current date $currentDate = Get-Date # Get Central Time Zone information to set a due date on the task in the correct time zone $centralTimeZone = [TimeZoneInfo]::FindSystemTimeZoneById("Central Standard Time") # Get the offset for the Central Time Zone $offset = $centralTimeZone.GetUtcOffset($currentDate) # Create a DateTimeOffset directly with the date components and Central Time offset, otherwise # dates are saved in UTC, which is often not desiresd by end users. If you would like the # task to be ongoing, you can skip the date stuff and just use $null for DateDue. $dateDueWithOffset = [DateTimeOffset]::new(    $currentDate.Year,    $currentDate.Month,    $currentDate.Day,    17, # Hour    0,  # Minute    0,  # Second    $offset ) $qcTask = @{  ProjectId = $projectId  Name = "QC Processing Job"  DateDue = $dateDueWithOffset  Forms = @() } # To use a form for a task, we need to create a task form object that's # based on the form we want to use. We'll loop through each section and # field in the form and create a task form object that we can use to # create the task. # Forms contain sections, and sections contain fields. $qcTaskForm = @{  FormId   = $qcForm.FormId  Sections = @() } $qcForm.Sections | ForEach-Object {  $qcFormSection = $_  $qcTaskFormSection = @{    FormSectionId = $qcFormSection.SectionId    Fields        = @()  }  $qcTaskForm.Sections += $qcTaskFormSection  $qcFormSection.Fields | ForEach-Object {    $qcFormSectionField = $_    $qcTaskFormSectionField = @{      FieldId = $qcFormSectionField.FieldId    }    # Check if there is a default value on the field. If there is, apply the default    # to the appropriate ValueAs* field    if (-not [string]::IsNullOrWhiteSpace($qcFormSectionField.DefaultValue)) {      switch ($qcFormSectionField.DataTypeName) {        "Whole Number" {          # Convert the DefaultValue to an integer          $qcTaskFormSectionField['ValueAsNumber'] = `            [int]$qcFormSectionField.DefaultValue        }        "Decimal Number" {          # Convert the DefaultValue to a decimal          $qcTaskFormSectionField['ValueAsDecimal'] = `            [decimal]$qcFormSectionField.DefaultValue        }        "Yes or No Choice" {          # Convert the DefaultValue to a boolean          $qcTaskFormSectionField['ValueAsBoolean'] = `            [System.Convert]::ToBoolean($qcFormSectionField.DefaultValue)        }        { ($_ -eq "Date Only") -or ($_ -eq "Date and Time") } {          # Convert the DefaultValue to a date          $qcTaskFormSectionField['ValueAsDate'] = `            [DateTimeOffset]$qcFormSectionField.DefaultValue        }        { ($_ -eq "Single Choice") -or ($_ -eq "Multiple Choice") } {          # These fields don't have defaults, so they can be ignored unless you want          # to add selected options during the task creation.          break;        }        default {          $qcTaskFormSectionField['ValueAsString'] = `            $qcFormSectionField.DefaultValue        }      }    }    # Reference fields need to be handled in a different way. They exist as a    # separate "ReferenceObject" property on the field and contain a list of    # Values.    if (($qcFormSectionField.DataTypeName -eq "Reference") `        -and ($null -ne $qcFormSectionField.ReferenceObject -ne $null)) {      # Create the reference object property that requires the object id and      # the list of values.      $qcTaskFormSectionField['ReferenceObject'] = @{        ObjectId = $qcFormSectionField.ReferenceObject.ObjectId        Values   = @()      }      # If the form has default reference values, we'll add them here      $qcFormSectionField.ReferenceObject.DefaultValues | ForEach-Object {        $refVal = @{          KeyAsInteger = $_.KeyAsInteger          KeyAsLong    = $_.KeyAsLong        }        # Again, PowerShell will convert $null string properties to an empty string,        # so we'll handle objects that use a string as an ID separately here.        if (-not [string]::IsNullOrWhiteSpace($_.KeyAsString)) {          $refVal["KeyAsString"] = $_.KeyAsString        }        # Add the reference values to the reference object        $qcTaskFormSectionField.ReferenceObject.Values += $refVal      }    }    # Add the field to the section    $qcTaskFormSection.Fields += $qcTaskFormSectionField  } } # Finally, add the form to the task $qcTask.Forms += $qcTaskForm # Uncomment this line to view the task object that will be created before saving # $qcTask | ConvertTo-Json -Depth 10 # Use the Agility Blue `Add-Task` PowerShell command followed by the # task object to create the task $createdTask = Add-Task -Entry $qcTask Write-Output "Created QC task $($createdTask.TaskId) in project $($createdTask.ProjectId)" ``` The output of this script: ```plaintext Created QC task 1054 in project 2024090000007 ``` ## Update a Task After retrieving a task, you can update what you need to and save the same task back using the `Set-Task` command. ```powershell # This example will add a matter reference convention to the beginning of the task name if it doesn't already # exist. $task = Get-Task -Id 120 if ($task.Name.StartsWith("[$($task.MatterReference)]")) {    Write-Output "Task $($task.TaskId) already begins with the matter reference in the name: $($task.Name)"    exit } $task.Name = "[$($task.MatterReference)] $($task.Name)"     $updatedTask = Set-Task -Entry $task Write-Output "Task $($task.TaskId) has been updated to begin with the matter reference in the name: $($task.Name)" ``` The output of this script: ```plaintext Task 120 has been updated to begin with the matter reference in the name: [2016-3422] Relativity Processing Request ``` You can also update task form fields: ```powershell # Small helper function to retrieve fields from the task function Get-Field ($task, $fieldLabel) {    return $processingEngineField = $task.Forms |        ForEach-Object { $_.Sections } |        ForEach-Object { $_.Fields } |        Where-Object { $_.Label -eq $fieldLabel } } $task = Get-Task -Id 120 -IncludeForms # Retrieve the "Processing Engine" field $processingEngineField = Get-Field -task $task -fieldLabel "Processing Engine" if ($null -eq $processingEngineField) {    Write-Error "Unable to find a field named 'Processing Engine' on task $($task.TaskId)"    exit } # Update the field. This particular field is a Basic Text field, so we want to set the # ValueAsString property. $processingEngineField.ValueAsString = "Nuix" # Save the task. We don't need to update the forms or fields collection because any edits # we do to fields we located are automatically updated within their collections. Set-Task -Entry $task | Out-Null # Confirm our updated field $updatedTask = Get-Task $task.TaskId -IncludeForms $updatedProcessingEngineField = Get-Field -task $updatedTask -fieldLabel "Processing Engine" Write-Output "Updated the processing engine field on task $($updatedTask.TaskId) to `"$($updatedProcessingEngineField.ValueAsString)`"" ``` The output of this script: ```plaintext Updated the processing engine field on task 120 to "Nuix" ``` ## Assign a Task To assign a task, you use the `Set-AssignTask` command which requires a task id and a user’s id for the user (or team) that you would like to assign the task to. If you don’t know a user’s id, but you know their email address or full name, you can use that information to filter the `Get-WorkspaceUsers` command. ```powershell $taskId = 120 # Retrieve a workspace user based on their full name. We're interested in the document # reviewers team in this case $users = Get-WorkspaceUsers `    -Filter "FullName eq 'Document Reviewers' and IsTeamAccount eq true" `    -Top 1 # Teams in Agility Blue are just a special type of user account $documentReviewersTeam = $users.Collection | Select-Object -First 1 # Assign a task to a user/team using the UserId parameter $updatedTask = Set-AssignTask `    -TaskId $taskId `    -UserId $documentReviewersTeam.Id     Write-Output "Assigned $($updatedTask.AssignedToFullName) to task $($updatedTask.TaskId)" ``` The output of this script: ```plaintext Assigned Document Reviewers to task 120 ``` > [!NOTE] > Note > > Assigning a task to someone will automatically set the task status to “In Progress” (StatusId 2) ## Unassign a Task To unassign a task, you use the `Set-AssignTask` command with a task id, but set the user id parameter to `$null`. ```powershell $taskId = 120 $updatedTask = Set-AssignTask `    -TaskId $taskId `    -UserId $null if ($null -eq $updatedTask.AssignedToFullName) {    Write-Output "Task $($updatedTask.TaskId) is no longer assigned"    exit } # This shouldn't happen unless something went wrong Write-Output "Task is still assigned tp $($updatedTask.AssignedToFullName) on task $($updatedTask.TaskId)" ``` The output of this script: ```plaintext Task 120 is no longer assigned ``` > [!NOTE] > Note > > Unassigning a task will automatically set the task status to “New” (StatusId 1) ## Change the Status of a Task To change a task’s status, use the `Set-TaskStatus` command. ```powershell $taskId = 120 # Status Type ids are: # -------------------------------- # New = 1 # In Progress = 2 # In Quality Control = 3 # Completed = 4 # On Hold = 5 # Canceled = 6 # -------------------------------- # An example of placing a task on hold would be: $updatedTask = Set-TaskStatus `    -TaskId $taskId `    -StatusId 5 Write-Output "Task $($updatedTask.TaskId) status is now `"$($updatedTask.StatusDescription)`"" ``` The output of this script: ```plaintext Task 120 status is now "On Hold" ``` > [!NOTE] > Note > > Unlike within the UI, you can set the task status to any of the status types without requiring comments or assignments. For example, a task that is unassigned can be set to “In Progress” or tasks can be set to “On Hold” or “Canceled” without requiring a comment. These behaviors that require that information are purely UI driven and not a part of the core system. ## Change the Quality Check Status of a Task To set the quality check status of a task, use the `Set-TaskQualityCheckStatus` command. This command requires a task id, a quality check status type id, and an optional status id. ```powershell $taskId = 120 # Quality Check Status Type ids are: # -------------------------------- # Not Performed: 1 # Passed: 2 # Rejected: 3 # Providing the task status id is optional, but is a convenient way to complete a task at the same time # as updating the qc status. An example of changing the qc status to passed and also completing the task is: $updatedTask = Set-TaskQualityCheckStatus `    -TaskId $taskId `    -QualityCheckStatusTypeId 2 `    -StatusId 4 # This shouldn't happen unless something went wrong Write-Output "Task $($updatedTask.TaskId) QC status is `"$($updatedTask.QualityCheckStatusDescription)`" and the task status is set to `"$($updatedTask.StatusDescription)`"" ``` The output of this script: ```plaintext Task 120 QC status is "Passed" and the task status is set to "Completed" ``` ## Reopen a Previously Closed Task To reopen a task that was previously closed, use the `Set-ReopenTask` command that requires only a task id. ```powershell $taskId = 120 $updatedTask = Set-ReopenTask -TaskId $taskId Write-Output "Task $($updatedTask.TaskId) has been reopened and the status is now `"$($updatedTask.StatusDescription)`"" ``` The output of this script: ```plaintext Task 120 has been reopened and the status is now "In Progress" ``` > [!NOTE] > Note > > The same effect can be accomplished by using the `Set-TaskStatus` command by changing the status type to 1 or 2 depending on if the task was assigned or not. ## Delete a Task Deleting tasks can be achieved by using the `Remove-Task` command that requires a task id. Here is an example that shows how to delete a task: ```powershell $taskId = 120 Write-Output "Deleting task $taskId..." Remove-Task -Id $taskId # Try to retrieve the task to prove that it was deleted $task = Get-Task -Id $taskId if ($null -eq $task) {    Write-Output "A task with an id of $taskId doesn't exist"    exit } # The next line should not happen Write-Error "Uh-oh, task id $taskId still exists after attempting to delete it" ``` The output of this script: ```plaintext Deleting task 120... A task with an id of 120 doesn't exist ``` **Points of Interest:** - In the script above, we deleted the task first and then tried to retrieve it to prove that it was deleted. This isn’t a bad idea if you want to ensure something was deleted, but in optimized situations, you would only need to delete the entry because if something went wrong during the deletion process, the server would throw an exception that would be logged in the output. > [!WARNING] > Be Careful! > > Deleting data cannot be reversed, so make sure you thoroughly test your code to minimize mistakes! ## Tasks Attached to Event Triggers If you are interested in attaching an update event trigger to a task, there are additional considerations about the event that need to be addressed, particularly for `Before Save` actions. All update events also contain event actions that help describe the type of event that occurred. These can be thought of like “sub events”, and they are stored in a special variable named `$ABVAREventAction`. For most objects, this variable will be populated directly with the main event, such as `CREATE`, `UPDATE`, and `DELETE`. For tasks, though, there are a variety of update actions that a user can perform on a task that populate this event action variable with different information depending on the type of update they perform. This needs to be used within before-save event scripts to help identify the type of action they performed and is also important because the `Get-InboundObjectInstance` command will provide different data depending on these actions which dictates the return type needed. Below is a table of actions along with the type of data that the `Get-InboundObjectInstance` would provide. ```powershell Write-Output $ABVAREventAction ``` | $ABVAREventAction (Event Action/Sub-Event) | Model | Notes | | --- | --- | --- | | CREATE | AgilityBlue.ViewModels.TaskInternalModel | Occurs when a user creates a task. The task is provided when using `Get-InboundObjectInstance`. | | UPDATE | AgilityBlue.ViewModels.TaskInternalModel | Occurs when a user edits a task. The task is provided when using `Get-InboundObjectInstance`. | | DELETE | AgilityBlue.ViewModels.TaskInternalModel | Occurs when a user deletes a task. The task is provided when using `Get-InboundObjectInstance`. | | ASSIGN | AgilityBlue.ViewModels.KeyContainer | Occurs when a user assigns a task. The user id string is provided when using `Get-InboundObjectInstance`. | | ADD_FORMS | List | Occurs when a user adds forms to a task. A list of task forms is provided when using `Get-InboundObjectInstance`. | | QUALITY_CONTROL | Dictionary | Occurs when a user updates the quality control status of a task. A hash table (dictionary) of the quality control status id and task status id is provided when using `Get-InboundObjectInstance`. | | DONE | AgilityBlue.ViewModels.KeyContainer | Occurs when a user completes a task. The task id is provided when using `Get-InboundObjectInstance`. | Scripts that rely on the update action of a task should take this information into consideration for update events, otherwise the script may fail because it does not emit the correct return result for the action. For example, if you are interested in creating a script that only responds when the user completes a task, you need to filter out the other update actions by returning them back to the system and focus in on the “DONE” event action. ```powershell # Retrieve the incoming instance $inboundObj = Get-InboundObjectInstance # This script only cares about the update sub-event where it indicates that a task was marked commpleted if ($ABVAREventAction -ne "DONE") {    Write-Output "Ignoring task sub-event $ABVAREventAction"    if ($ABVAREventAction -eq "ADD_FORMS") {        # Adding Forms event special handling:        # Add a comma to force powershell into creating an array because it will convert single-item arrays to an object.        return ,$inboundObj    }    return $inboundObj } # Becausee the type of event is a "DONE" event, it only provides the task id as a "Key" # Retrieve the task ID from the inbound object $taskId = Get-InboundObjectId $task = Get-Task $taskId -IncludeForms # Continue on processing with the rest of the script... ``` **Points of interest**: - Before-Save scripts require the same return type as the input type, so you need to check the `$ABVAREventAction` variable and ensure you returning the correct type. - The ADD_FORMS event action needs to be returned as a list/array. PowerShell will auto-convert single-element lists into a single object, so use a comma before the variable to force the variable to be returned as a list. - For After-Save scripts, you could ignore the `$ABVAREventAction` variable by just using `Get-Task` that uses the `Get-InboundObjectId`, since that will always return the task id, and can help simplify the script.