Assignments Scripts - Export

Exports - EDU assignments

<#
   .Synopsis
    Export the Edu Assignments data of a user in a set of classes specified in csv file.
    .DESCRIPTION
    The script reads the class details of user from input csv file. Get the assignments and submissions of each assignment and generates the assignment file(assignment.json) and report file(GetAssignmentsReport.csv). when extracting of submissions is done it updates the GetSubmissionsProcessed column to true for that specific class. If the script fails in between we can rerun the script with the same input file, because the file will be updated for last deletion of submission.
   .Example
    .\Export-EduAssignments.ps1 -userClassDetailsFile <full path of user class details csv file>
   .Parameter userClassDetailsFile
   This is the csv file(userClassDetails.csv) which is the output of Get-UserClasses.ps1 script. This file have information about the user classes and whether the deletion and get submissions are processed. This value should be full path of the file(drive:\GDPR\userClassDetails.csv)
   .Notes
   We need to have the Microsoft.IdentityModel.Clients.ActiveDirectory.dll and Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll are required
#>
param(
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({
        if(-Not ($_ | Test-Path)) {
            throw "The userClassDetailsFile does not exist."
        }
        if(-Not ($_ | Test-Path -PathType Leaf) ){
            throw "The userClassDetailsFile argument must be a file. Folder paths are not allowed."
        }
        if($_ -notmatch "(\.csv)"){
            throw "The userClassDetailsFile should be a comma-separated file, generated using Get-UserClasses.ps1"
        }
        return $true
    })]
    [string] $userClassDetailsFile
)

# Load ADAL
Add-Type -Path ".\ADAL\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$educationEndpoint = "https://graph.microsoft.com/beta/education/"
$script:userClassDetails = @()
$script:getAssignmentsReport = @()
$script:maxRetryAttempt = 3
$script:authHeaders = $null
$script:authenticationResult = $null
$graphEndpoint = "https://graph.microsoft.com"
$authString = "https://login.windows.net/common"

#Get the authheaders
function Get-AuthHeaders
{
    Param(
        [Parameter(Mandatory=$false)]
        [bool] $useRefreshToken = $false
    )
    $clientId = "eb2298a1-a6bb-4f16-a27a-b582815db47b"
    $redirectURI = New-Object System.Uri("urn:ietf:wg:oauth:2.0:oob")
    $promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
    $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authString
    if($useRefreshToken -eq $false)
    {
        $script:authenticationResult = $authContext.AcquireToken($graphEndpoint, $clientID, $redirectURI, $promptBehavior)
    }
    else
    {
        $script:authenticationResult = $authContext.AcquireTokenByRefreshToken($script:authenticationResult.RefreshToken, $clientId)
    }
    $authHeader = $script:authenticationResult.AccessTokenType + " " + $script:authenticationResult.AccessToken
    $headers = @{"Authorization" = $authHeader; "Content-Type" = "Application/json"}
    return $headers
}

#Retry logic and logging of errors for script
function Invoke-RequestWithRetry
{
    param(
        [Parameter(Mandatory=$true)]$url,
        [Parameter(Mandatory=$false)]$classId,
        [Parameter(Mandatory=$false)]$className,
        [Parameter(Mandatory=$true)]$OperationName
    )

    for($i=1; $i -le $script:maxRetryAttempt; $i++)
    {
        try
        {
            $APIResult = Invoke-WebRequest -Method Get -Uri $url -Headers $script:authHeaders
            $resultCount = 0
            if($OperationName -eq "GetAssignments")
            {
                $valueStartIndex = ($APIResult.content.indexof('"value":') + 8)
                $valueEndIndex = $APIResult.content.Length
                $valueString = $APIResult.content.substring($valueStartIndex, $valueEndIndex-$valueStartIndex -1)
                $resultCount = (($valuestring | select-string '"classId":' -AllMatches ).Matches.Count)
            }
            else
            {
                $submissionsJson = $APIResult.content | ConvertFrom-Json
                $resultCount = $submissionsJson.value.count
            }

            $script:getAssignmentsReport += [PSCustomObject]@{
                RequestUrl = $url
                Method = "Get"
                ResponseCode = $APIResult.StatusCode
                ClassName = $className
                ClassId = $classId
                RequestId = $APIResult.Headers["request-id"]
                StatusDescription = $APIResult.StatusDescription
                NumberOfAttempts = $i
                OperationName = $OperationName
                ResultCount = $resultCount
            }
            return $APIResult
        }
        catch
        {
            if($_.Exception.Response -ne $null)
            {
                $responseCode = $_.Exception.Response.StatusCode.Value__
                $requestId = $_.Exception.Response.Headers["request-id"]
            }
           
            $script:getAssignmentsReport += [PSCustomObject]@{
                RequestUrl = $url
                Method = "Get"
                ResponseCode = $responseCode
                ClassName = $className
                ClassId = $classId
                RequestId = $requestId
                StatusDescription = $_.Exception.Message
                NumberOfAttempts = $i
                OperationName = $OperationName
                ResultCount = $resultCount
            }

            if($i -eq $script:maxRetryAttempt)
            {
                throw $_
            }

            if($responseCode -eq 401)
            {
                $script:authHeaders = Get-AuthHeaders -useRefreshToken $true
            }
        }
    }
}

#get assignments
function Get-Assignments
{
    param(
        [Parameter(Mandatory=$true)]$classDetails
    )
    try
    {
        $classId = $classDetails.ClassId
        $userId = $classDetails.UserId
        $role = $classDetails.Role
        $className = $classId
        if($classDetails.ClassName -ne $null -and $classDetail.ClassName.Length -ne 0)
        {
            $className = $classDetails.ClassName
        }
        $getAssignmentsUri = ("{0}/classes('{1}')/assignments?TargetUserId={2}&UserClassRole={3}" -f $educationEndpoint, $classId, $userId, $role)
        $assignments = $null
        $assignments = Invoke-RequestWithRetry -url $getAssignmentsUri -classId $classId -className $className -OperationName "GetAssignments"
        $outputstring = ""
        if($assignments -ne $null)
        {
            $valueStartIndex = ($assignments.content.indexof('"value":') + 8)
            $valueEndIndex = $assignments.content.Length
            $valueString = $assignments.content.substring($valueStartIndex, $valueEndIndex-$valueStartIndex -1)
          
            $valueString = $valueString.TrimEnd("]")
            $valueString = $valueString.TrimStart("[")
            $indexValues = (($valuestring | select-string '"classId":' -AllMatches ).Matches.Index)
            Write-Host "Retrieved $($indexValues.count) Assignments for $className class"
            $assignmentsStrings = @()
            for($i=0; $i -lt $indexValues.count; $i++)
            {
                if($i -ne $indexValues.count -1)
                {
                    $assignmentsStrings += $valueString.substring(($indexValues[$i]-1),($indexValues[$i+1] - $indexValues[$i] -1))
                }
                else
                {
                    $assignmentsStrings += $valueString.substring(($indexValues[$i]-1), ($valueString.Length - $indexValues[$i] +1))
                }
               
                if($role -eq "Student")
                {
                    $submissionsIndex = $assignmentsStrings[$i].indexof('"submissions":[')
                    $assignmentsStrings[$i] = $assignmentsStrings[$i].substring(0, $submissionsIndex+15)
                    $assignmentsStrings[$i] = $assignmentsStrings[$i] + "]}"
                }
            }
            for($i=0; $i -lt $assignmentsStrings.Length ; $i++)
            {
                $assignmentString = $assignmentsStrings[$i]
                $assignmentJson = $assignmentString | ConvertFrom-Json
                $assignmentId = $assignmentJson.id
                Write-Host "Getting submissions for $($assignmentJson.displayName) assignment"
                $sumbmissionsEndpoint = ("{0}/classes('{1}')/assignments('{2}')/submissions?TargetUserId={3}&UserClassRole={4}" -f $educationEndpoint, $classId, $assignmentId, $userId, $role)
                $submissions = Invoke-RequestWithRetry -classId $classId -url $sumbmissionsEndpoint -classname $className -OperationName "GetSubmissions"
                if($submissions -ne $null -and $submissions.Content.Length -ne 0 )
                {
                    $submissionsJson = $submissions.content | ConvertFrom-Json
                    Write-Host "Retrieved $($submissionsJson.value.count) submissions for $($assignmentJson.displayName) assignment"
                    $valueStartIndex = ($submissions.content.indexof('"value":') + 9)
                    $valueEndIndex = $submissions.content.lastindexof("}")
                    $submissionsString = $submissions.content.substring($valueStartIndex, $valueEndIndex-$valueStartIndex -1)
                    $assignmentsStrings[$i] = $assignmentsStrings[$i].TrimEnd("]}")
                    $assignmentsStrings[$i] = $assignmentsStrings[$i] + $submissionsString + "]}"
                }
            }
           
            $completeAssigmentsString = "["
            if($assignmentsStrings.Length -eq 0)
            {
                $completeAssigmentsString = $completeAssigmentsString + "]"
            }
            else
            {
                for($i=0; $i -lt $assignmentsStrings.Length; $i++)
                {
                    if($i -eq $assignmentsStrings.Length -1)
                    {
                        $completeAssigmentsString = $completeAssigmentsString + $assignmentsStrings[$i] + "]"
                    }
                    else
                    {
                        $completeAssigmentsString = $completeAssigmentsString + $assignmentsStrings[$i] + ","
                    }
                }
            }
            $outputstring = '{"ClassId":"' + $classId + '","ClassName":"' + $className +'","assignments":' + $completeAssigmentsString + '}'
            $dateTimeStamp = $(get-date -f yyyy-MM-dd)
            $fileName = $directoryPath + "\" + $className + "_" + $userId + "_" + $dateTimeStamp + ".json"
            $outputstring | Out-File $fileName
            Write-Host("Assignments file for $className is generated at $fileName")
            $classDetails.GetSubmissionsProcessed = "True"
            $script:userClassDetails | Export-Csv -Path $($directoryPathOfFile) -NoTypeInformation -Force
        }
    }
    catch
    {
        write-Error $_.Exception.Message
    }
   
}

$directoryPathOfFile = (Get-Item -path $($userClassDetailsFile)).FullName
$directoryPath = (Get-Item -Path ".\" -Verbose).FullName
$script:authHeaders = Get-AuthHeaders
$script:userClassDetails = import-csv $userClassDetailsFile

$progressTracker = 1;
#loop through each line and get submissions if the getsubmissionsprocessed column is false
foreach($classDetail in $script:userClassDetails)
{
    Write-Progress -Activity "Getting Assignments for user" -Status "Processing for class: $($classDetail.classId)" -PercentComplete ($progressTracker/$($script:userClassDetails | Measure-object).count * 100)
    if($classDetail.GetSubmissionsProcessed -eq "False")
    {
        Write-host "Getting Assignments for $($classDetail.ClassName)"
        Get-Assignments -classDetails $classDetail
    }
    $progressTracker++
}

$script:getAssignmentsReport | Export-Csv -Path .\GetAssignmentsReport.csv -NoTypeInformation
Write-Host "Report file(GetAssignmentsReport.csv) is generated at $directoryPath\GetAssignmentsReport.csv"
Write-Host "Updated Class details file($($directoryPathOfFile)) and generated updated file is at $($directoryPathOfFile)"

Expand your Office skills
Explore training
Get new features first
Join Office Insiders

Was this information helpful?

Thank you for your feedback!

Thank you for your feedback! It sounds like it might be helpful to connect you to one of our Office support agents.

×