diff --git a/Canvas/CanvasApiMainScript.ps1 b/Canvas/CanvasApiMainScript.ps1 new file mode 100644 index 0000000..e0354ea --- /dev/null +++ b/Canvas/CanvasApiMainScript.ps1 @@ -0,0 +1,464 @@ +<# + Use at your own risk and stuff + This project contains the main methods for the Canvas APIs as well + as a number of test methods. See the method generator for more potential. + Based on https://canvas.instructure.com/doc/api/index.html +#> + +$logfile = ".\Canvaslog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" +$start = [system.datetime]::Now +#region Base Canvas API Methods +function Get-CanvasCredentials() +{ + if ($global:CanvasApiTokenInfo -eq $null) + { + + $ApiInfoPath = "$env:USERPROFILE\Documents\CanvasApiCreds.json" + + #TODO: Once this is a module, load it from the module path: $PSScriptRoot or whatever that is + if (-not (test-path $ApiInfoPath)) + { + $Token = Read-Host "Please enter your Canvas API API Access Token" + $BaseUri = Read-Host "Please enter your Canvas API Base URI (for example, https://domain.beta.instructure.com)" + + $ApiInfo = [ordered]@{ + Token = $Token + BaseUri = $BaseUri + } + + $ApiInfo | ConvertTo-Json | Out-File -FilePath $ApiInfoPath + } + + #load the file + $global:CanvasApiTokenInfo = Get-Content -Path $ApiInfoPath | ConvertFrom-Json + } + + return $global:CanvasApiTokenInfo +} + +function Get-CanvasAuthHeader($Token) { + return @{"Authorization"="Bearer "+$Token} +} + +function Get-CanvasApiResult(){ + + Param( + $Uri, + $RequestParameters, + [ValidateSet("GET", "POST", "PUT", "DELETE")] + $Method="GET" + ) + $AuthInfo = Get-CanvasCredentials + + if ($RequestParameters -eq $null) { $RequestParameters = @{} + + $RequestParameters["per_page"] = "10000" + + $Headers = (Get-CanvasAuthHeader $AuthInfo.Token) + + try + { + $Results = Invoke-WebRequest -Uri ($AuthInfo.BaseUri + $Uri) -ContentType "multipart/form-data" ` + -Headers $headers -Method $Method -Body $RequestParameters + } catch + { + throw $_.Exception.Message + } + + $Content = $Results.Content | ConvertFrom-Json + + #Either PSCustomObject or Object[] + if ($Content.GetType().Name -eq "PSCustomObject") { + return $Content + } + + $JsonResults = New-Object System.Collections.ArrayList + + $JsonResults.AddRange(($Results.Content | ConvertFrom-Json)) + + if ($Results.Headers.link -ne $null) { + $NextUriLine = $Results.Headers.link.Split(",") | where {$_.Contains("rel=`"next`"")} + + $PerPage = $NextUriLine.Substring($NextUriLine.IndexOf("per_page=")) -replace '(\D).*',"" + + if (-not [string]::IsNullOrWhiteSpace($NextUriLine)) + { + while ($Results.Headers.link.Contains("rel=`"next`"")) +{ + + $nextUri = $Results.Headers.link.Split(",") | ` + where {$_.Contains("rel=`"next`"")} | ` + % {$_ -replace ">; rel=`"next`""} | + % {$_ -replace "<"} + + #Write-Progress + Write-Host $nextUri + try{ + $Results = Invoke-WebRequest -Uri $nextUri -Headers $headers -Method Get -Body $RequestParameters -ContentType "multipart/form-data" ` + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $JsonResults.AddRange(($Results.Content | ConvertFrom-Json)) + } + } + } + + return $JsonResults +}} + +write-host "creating school.csv file" +#accounts +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv -path ".\Accounts.csv" -Append -NoTypeInformation + +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/sub_accounts" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv -path ".\Accounts.csv" -Append -NoTypeInformation +try{ +$acc = import-csv ".\Accounts.csv" + $xyz = $acc.id + $count = $acc.Count + foreach($x in $xyz) +{ + $uri0 = "/api/v1/accounts/"+ "$x" +"/sub_accounts" + $results = Get-CanvasApiResult -Uri $uri0 -Method GET + $results | convertto-Csv -NoTypeInformation + $results | Export-csv -path ".\Accounts.csv" -Append -NoTypeInformation +}} +Catch { + $_.Exception | Out-File $logfile -Append + } + +$tempCSV = Import-Csv .\Accounts.csv -Header "SIS ID","Name","workflow_state","parent_account_id","root_account_id","uuid","default_storage_quota_mb","default_user_storage_quota_mb","default_group_storage_quota_mb","default_time_zone" | select -skip 1 | sort 'SIS ID','Name' -Unique +$tempCSV | Export-CSV .\school.csv -NoTypeInformation + +write-host "creating Sync.csv file" +#courses details +try{ + $results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/courses" -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv ".\courses.csv" -NoTypeInformation + $courses = import-csv ".\courses.csv" + + #Check is Sync.csv is present - if not create else nothing + if (Test-Path .\Sync.csv) { + write-host "Sync.csv File already exists." +} + else{ + Set-Content ".\Sync.csv" -Value "id" + write-host "Provide course id in Sync.csv file" + } + +$proceed = Read-host " Press Y to continue " +if ($proceed -eq 'Y') +{ + $Sync = import-csv "Sync.csv" -Header id |select -skip 1 + +$id = $Sync.id +write-host "creating Section.csv file" +#Section Details +try{ +foreach($i in $id) +{ + $uri1 = "/api/v1/courses/" + "$i" + "/sections" + $results = Get-CanvasApiResult -Uri $uri1 -Method GET + $results | convertto-Csv -NoTypeInformation + $results | Export-csv ".\sectionTemp.csv" -Append -NoTypeInformation +}} +Catch { + $_.Exception | Out-File $logfile -Append + } + + try{ + $OrdersA = Import-CSV -Path .\sectionTemp.csv + $matchcounter = 0 + +foreach ($order1 in $OrdersA){ + $matched = $false + foreach ($order2 in $courses) + { + $obj = "" | select "SIS ID","course_id","Section Name","Term StartDate","Term EndDate","created_at","restrict_enrollments_to_section_dates","nonxlist_course_id","sis_section_id","sis_course_id","integration_id","sis_import_id","School SIS ID" + if(($order1.'course_id' -replace "A" ) -eq $order2.'id' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1. 'id' + $obj.'course_id' = $order1.'course_id' + $obj.'Section Name' = $order1.'name' + $obj.'Term StartDate' = $order1.'start_at' + $obj.'Term EndDate' = $order1.'end_at' + $obj.'created_at' = $order1.'created_at' + $obj.'restrict_enrollments_to_section_dates' = $order1.'restrict_enrollments_to_section_dates' + $obj.'nonxlist_course_id' = $order1.'nonxlist_course_id' + $obj.'sis_section_id' = $order1.'sis_section_id' + $obj.'sis_course_id' = $order1.'sis_course_id' + $obj.'integration_id' = $order1.'integration_id' + $obj.'sis_import_id' = $order1.'sis_import_id' + $obj.'School SIS ID' = $order2.'account_id' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\section.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +write-host "creating student.csv" + + $tempsection = import-csv .\sectionTemp.csv + $secid = $tempsection.id +#user Details +foreach($s in $secid) +{ + $uri2 = "/api/v1/sections/" + "$s" + "/enrollments" + $results = Get-CanvasApiResult -Uri $uri2 -Method GET + $results | convertto-Csv -NoTypeInformation + $results | Export-csv "users.csv" -Append -NoTypeInformation +} +#if you want user data with in section details run below code# +try{ +$matchcounter = 0 +$user= import-csv .\users.csv +$Section = import-csv .\section.csv +foreach ($order1 in $user){ + $matched = $false + foreach ($order2 in $Section) + { + $obj = "" | select "id","SIS ID","course_id","type","Username","FirstName","LastName","Password","Section SIS ID","School SIS ID","enrollment_state","role","sis_account_id","sis_course_id","sis_section_id","sis_user_id","html_url","user" + if(($order1.'course_id' -replace "A" ) -eq $order2.'course_id' ) + { + $matchCounter++ + $matched = $true + $obj.'id' = $order1.'id' + $obj.'SIS ID' = $order1.'user_id' + $obj.'course_id' = $order1.'course_id' + $obj.'type' = $order1.'type' + $obj.'Username' = '' + $obj.'FirstName' = '' + $obj.'LastName' = '' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order1.'course_section_id' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'enrollment_state' = $order1.'enrollment_state' + $obj.'role' = $order1.'role' + $obj.'sis_account_id' = $order1.'sis_account_id' + $obj.'sis_course_id' = $order1.'sis_course_id' + $obj.'sis_section_id' = $order1.'sis_section_id' + $obj.'sis_user_id' = $order1.'sis_user_id' + $obj.'html_url' = $order1.'html_url' + $obj.'user' = $order1.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\usernew.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +Import-Csv -Path .\usernew.csv | ? role -eq 'StudentEnrollment' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' | Export-Csv .\studentEnrollment.csv -NoTypeInformation + +Import-Csv -Path .\usernew.csv | ? role -eq 'TeacherEnrollment' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' | Export-Csv .\teacherroster.csv -NoTypeInformation + +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/users" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv .\Fulluser.csv -Append -NoTypeInformation + +$matchcounter = 0 +$Fulluser = import-csv .\Fulluser.csv +$user1= import-csv .\usernew.csv + +try{ +foreach ($order1 in $Fulluser){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + + if($order1.'id' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order2.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'name' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\usersall.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +try{ +Import-Csv -Path .\usersall.csv | ? role -eq 'StudentEnrollment' | sort 'SIS ID', 'School SIS ID' -Unique | Export-Csv .\student.csv -NoTypeInformation + +Import-Csv -Path .\usersall.csv | ? role -eq 'TeacherEnrollment' | sort 'SIS ID', 'School SIS ID' -Unique | Export-Csv .\teacher.csv -NoTypeInformation +} +Catch { + $_.Exception | Out-File $logfile -Append + } +<# +#if you want details with courses run below script +#Teacher details +foreach($i in $id) +{ + $uri3 = "/api/v1/courses/"+"$i"+"/users?enrollment_type[]=teacher&include[]=enrollments" + try{ + $results = Get-CanvasApiResult -Uri $uri3 -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv ".\Teacher1.csv" -Append -NoTypeInformation +} +#student details +foreach($i in $id) +{ +write-host "$i" + $uri4 = "/api/v1/courses/"+ "$i" +"/users?enrollment_type[]=student&include[]=enrollments" +$results = Get-CanvasApiResult -Uri $uri4 -Method GET +$results | convertto-Csv -NoTypeInformation +$results | Export-csv "Student1.csv" -Append -NoTypeInformation +} +import-csv Teacher1.csv | sort id -Unique | export-csv Teacher2.csv -NoTypeInformation +$tempCSV = Import-Csv Teacher2.csv -Header "SIS ID","Username","created_at","sortable_name","short_name","sis_user_id","integration_id","sis_import_id","login_id","enrollments","email","School SIS ID" | select -skip 1 +$tempCSV | Export-CSV Teacher2.csv -NoTypeInformation +import-csv Student1.csv | sort id -Unique | export-csv Student2.csv -NoTypeInformation +$tempCSV = Import-Csv Student2.csv -Header "SIS ID","Username","created_at","sortable_name","short_name","sis_user_id","integration_id","sis_import_id","login_id","enrollments","email","School SIS ID" | select -skip 1 +$tempCSV | Export-CSV Student2.csv -NoTypeInformation +$matchcounter = 0 +$student = import-csv Student2.csv +$teacher = import-csv Teacher2.csv +$user1= import-csv usernew.csv +foreach ($order1 in $student){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + + if($order1.'SIS ID' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'Username' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path Student0.csv -Append -NoTypeInformation + } + } +} +foreach ($order1 in $teacher){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + if($order1.'SIS ID' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'Username' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path Teacher0.csv -Append -NoTypeInformation + } + } +} +Import-Csv -Path 'Teacher0.csv'| sort 'SIS ID' -Unique | Export-Csv Teacher10.csv -NoTypeInformation +Import-Csv -Path 'student0.csv'| sort 'SIS ID' -Unique | Export-Csv Student10.csv -NoTypeInformation +Import-Csv -Path 'Teacher0.csv' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' -Unique | Export-Csv StudentEnrollment1.csv -NoTypeInformation +Import-Csv -Path 'student0.csv' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' -Unique | Export-Csv Teacherroster1.csv -NoTypeInformation +#> +try{ +remove-item Accounts.csv +remove-item sectionTemp.csv +remove-item Fulluser.csv +remove-item usersall.csv +remove-item usernew.csv +remove-item users.csv +remove-item courses.csv +} +Catch { + $_.Exception | Out-File $logfile -Append + } + +} +else { +write-host "You need to provide sync.csv in order to continue..." } + +$end = [system.datetime]::Now +$resultTime = $end - $start +Write-Host "Execution took : $($resultTime.TotalSeconds) seconds." + + +#endregion diff --git a/Canvas/CanvasSync.ps1 b/Canvas/CanvasSync.ps1 new file mode 100644 index 0000000..b16cf2b --- /dev/null +++ b/Canvas/CanvasSync.ps1 @@ -0,0 +1,486 @@ +<# +This script will download school data sync files from canvas + Use at your own risk and stuff + This project contains the main methods for the Canvas APIs as well + as a number of test methods. See the method generator for more potential. + Based on https://canvas.instructure.com/doc/api/index.html +#> + +$logfile = ".\CanvasSynclog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" +$start = [system.datetime]::Now +#region Base Canvas API Methods +function Get-CanvasCredentials() +{ + if ($global:CanvasApiTokenInfo -eq $null) + { + + $ApiInfoPath = "$env:USERPROFILE\Documents\CanvasApiCreds.json" + + #TODO: Once this is a module, load it from the module path: $PSScriptRoot or whatever that is + if (-not (test-path $ApiInfoPath)) + { + $Token = Read-Host "Please enter your Canvas API API Access Token" + $BaseUri = Read-Host "Please enter your Canvas API Base URI (for example, https://domain.beta.instructure.com)" + + $ApiInfo = [ordered]@{ + Token = $Token + BaseUri = $BaseUri + } + + $ApiInfo | ConvertTo-Json | Out-File -FilePath $ApiInfoPath + } + + #load the file + $global:CanvasApiTokenInfo = Get-Content -Path $ApiInfoPath | ConvertFrom-Json + } + + return $global:CanvasApiTokenInfo +} + +function Get-CanvasAuthHeader($Token) { + return @{"Authorization"="Bearer "+$Token} +} + +function Get-CanvasApiResult(){ + + Param( + $Uri, + + $RequestParameters, + + [ValidateSet("GET", "POST", "PUT", "DELETE")] + $Method="GET" + ) + + $AuthInfo = Get-CanvasCredentials + + if ($RequestParameters -eq $null) { $RequestParameters = @{} + + $RequestParameters["per_page"] = "10000" + + $Headers = (Get-CanvasAuthHeader $AuthInfo.Token) + + try + { + $Results = Invoke-WebRequest -Uri ($AuthInfo.BaseUri + $Uri) -ContentType "multipart/form-data" ` + -Headers $headers -Method $Method -Body $RequestParameters + } catch + { + throw $_.Exception.Message + } + + $Content = $Results.Content | ConvertFrom-Json + + #Either PSCustomObject or Object[] + if ($Content.GetType().Name -eq "PSCustomObject") { + return $Content + } + + $JsonResults = New-Object System.Collections.ArrayList + + $JsonResults.AddRange(($Results.Content | ConvertFrom-Json)) + + if ($Results.Headers.link -ne $null) { + $NextUriLine = $Results.Headers.link.Split(",") | where {$_.Contains("rel=`"next`"")} + + $PerPage = $NextUriLine.Substring($NextUriLine.IndexOf("per_page=")) -replace '(\D).*',"" + + if (-not [string]::IsNullOrWhiteSpace($NextUriLine)) + { + while ($Results.Headers.link.Contains("rel=`"next`"")) +{ + + $nextUri = $Results.Headers.link.Split(",") | ` + where {$_.Contains("rel=`"next`"")} | ` + % {$_ -replace ">; rel=`"next`""} | + % {$_ -replace "<"} + + #Write-Progress + Write-Host $nextUri + try{ + $Results = Invoke-WebRequest -Uri $nextUri -Headers $headers -Method Get -Body $RequestParameters -ContentType "multipart/form-data" ` + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $JsonResults.AddRange(($Results.Content | ConvertFrom-Json)) + } + } + } + + return $JsonResults +}} + +write-host "creating school.csv file" +#accounts +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv ".\Accounts.csv" -Append -NoTypeInformation + +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/sub_accounts" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv -path ".\Accounts.csv" -Append -NoTypeInformation + + $acc = import-csv -path .\Accounts.csv + $xyz = $acc.id + $count = $acc.Count +foreach($x in $xyz) +{ + $uri0 = "/api/v1/accounts/"+ "$x" +"/sub_accounts" + try{ + $results = Get-CanvasApiResult -Uri $uri0 -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv ".\Accounts.csv" -Append -NoTypeInformation +} + +$tempCSV = Import-Csv .\Accounts.csv -Header "SIS ID","Name","workflow_state","parent_account_id","root_account_id","uuid","default_storage_quota_mb","default_user_storage_quota_mb","default_group_storage_quota_mb","default_time_zone" | select -skip 1 | sort 'SIS ID','Name' -Unique +$tempCSV | Export-CSV .\school.csv -NoTypeInformation + + +#courses details + try{ + $results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/courses" -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv "courses.csv" -NoTypeInformation + $courses = import-csv "courses.csv" +if (Test-Path Sync.csv) +{ +$Sync = import-csv ".\Sync.csv" -Header id |select -skip 1 + +$id = $Sync.id +write-host "creating Section.csv file" +#Section Details +foreach($i in $id) +{ + $uri1 = "/api/v1/courses/" + "$i" + "/sections" + try{ + $results = Get-CanvasApiResult -Uri $uri1 -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv ".\sectionTemp.csv" -Append -NoTypeInformation +} + +try{ +$OrdersA = Import-CSV -Path .\sectionTemp.csv +$matchcounter = 0 + +foreach ($order1 in $OrdersA){ + $matched = $false + foreach ($order2 in $courses) + { + $obj = "" | select "SIS ID","course_id","Section Name","Term StartDate","Term EndDate","restrict_enrollments_to_section_dates","nonxlist_course_id","sis_section_id","sis_course_id","integration_id","sis_import_id","School SIS ID" + if(($order1.'course_id' -replace "A" ) -eq $order2.'id' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1. 'id' + $obj.'course_id' = $order1.'course_id' + $obj.'Section Name' = $order1.'name' + $obj.'Term StartDate' = $order1.'start_at' + $obj.'Term EndDate' = $order1.'end_at' + $obj.'created_at' = $order1.'created_at' + $obj.'restrict_enrollments_to_section_dates' = $order1.'restrict_enrollments_to_section_dates' + $obj.'nonxlist_course_id' = $order1.'nonxlist_course_id' + $obj.'sis_section_id' = $order1.'sis_section_id' + $obj.'sis_course_id' = $order1.'sis_course_id' + $obj.'integration_id' = $order1.'integration_id' + $obj.'sis_import_id' = $order1.'sis_import_id' + $obj.'School SIS ID' = $order2.'account_id' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\section.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +write-host "creating student.csv" + try{ + $tempsection = import-csv sectionTemp.csv + $secid = $tempsection.id +#user Details +foreach($s in $secid) +{ + $uri2 = "/api/v1/sections/" + "$s" + "/enrollments" + try{ + $results = Get-CanvasApiResult -Uri $uri2 -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv -path ".\users.csv" -Append -NoTypeInformation +}} +Catch { + $_.Exception | Out-File $logfile -Append + } +#if you want user data with in section details run below code# +try{ +$matchcounter = 0 +$user= import-csv .\users.csv +$Section = import-csv .\section.csv + +foreach ($order1 in $user){ + $matched = $false + foreach ($order2 in $Section) + { + $obj = "" | select "id","SIS ID","course_id","type","Username","FirstName","LastName","Password","Section SIS ID","School SIS ID","enrollment_state","role","sis_account_id","sis_course_id","sis_section_id","sis_user_id","html_url","user" + if(($order1.'course_id' -replace "A" ) -eq $order2.'course_id' ) + { + $matchCounter++ + $matched = $true + $obj.'id' = $order1.'id' + $obj.'SIS ID' = $order1.'user_id' + $obj.'course_id' = $order1.'course_id' + $obj.'type' = $order1.'type' + $obj.'Username' = '' + $obj.'FirstName' = '' + $obj.'LastName' = '' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order1.'course_section_id' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'enrollment_state' = $order1.'enrollment_state' + $obj.'role' = $order1.'role' + $obj.'sis_account_id' = $order1.'sis_account_id' + $obj.'sis_course_id' = $order1.'sis_course_id' + $obj.'sis_section_id' = $order1.'sis_section_id' + $obj.'sis_user_id' = $order1.'sis_user_id' + $obj.'html_url' = $order1.'html_url' + $obj.'user' = $order1.'user' + + + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path usernew.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +Import-Csv -Path .\usernew.csv | ? role -eq 'StudentEnrollment' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' | Export-Csv .\studentEnrollment.csv -NoTypeInformation + +Import-Csv -Path .\usernew.csv | ? role -eq 'TeacherEnrollment' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' | Export-Csv .\teacherroster.csv -NoTypeInformation + +try{ +$results = Get-CanvasApiResult -Uri "/api/v1/accounts/1/users" -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv -path .\Fulluser.csv -Append -NoTypeInformation + +try{ +$matchcounter = 0 +$Fulluser = import-csv .\Fulluser.csv +$user1= import-csv .\usernew.csv + +foreach ($order1 in $Fulluser){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + + if($order1.'id' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order2.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'name' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\usersall.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +try{ +Import-Csv -Path .\usersall.csv | ? role -eq 'StudentEnrollment' | sort 'SIS ID', 'School SIS ID' -Unique | Export-Csv .\student.csv -NoTypeInformation + +Import-Csv -Path .\usersall.csv | ? role -eq 'TeacherEnrollment' | sort 'SIS ID', 'School SIS ID' -Unique | Export-Csv .\teacher.csv -NoTypeInformation +} +Catch { + $_.Exception | Out-File $logfile -Append + } +<# +#if you want details with courses run below script +#Teacher details +foreach($i in $id) +{ + $uri3 = "/api/v1/courses/"+"$i"+"/users?enrollment_type[]=teacher&include[]=enrollments" + try{ + $results = Get-CanvasApiResult -Uri $uri3 -Method GET + } + Catch { + $_.Exception | Out-File $logfile -Append + } + $results | convertto-Csv -NoTypeInformation + $results | Export-csv .\Teacher1.csv -Append -NoTypeInformation +} +#student details +foreach($i in $id) +{ +write-host "$i" +$uri4 = "/api/v1/courses/"+ "$i" +"/users?enrollment_type[]=student&include[]=enrollments" +try{ +$results = Get-CanvasApiResult -Uri $uri4 -Method GET +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$results | convertto-Csv -NoTypeInformation +$results | Export-csv .\Student1.csv -Append -NoTypeInformation +} +import-csv .\Teacher1.csv | sort id -Unique | export-csv .\Teacher2.csv -NoTypeInformation +$tempCSV = Import-Csv .\Teacher2.csv -Header "SIS ID","Username","created_at","sortable_name","short_name","sis_user_id","integration_id","sis_import_id","login_id","enrollments","email","School SIS ID" | select -skip 1 +$tempCSV | Export-CSV .\Teacher2.csv -NoTypeInformation +import-csv .\Student1.csv | sort id -Unique | export-csv .\Student2.csv -NoTypeInformation +$tempCSV = Import-Csv .\Student2.csv -Header "SIS ID","Username","created_at","sortable_name","short_name","sis_user_id","integration_id","sis_import_id","login_id","enrollments","email","School SIS ID" | select -skip 1 +$tempCSV | Export-CSV .\Student2.csv -NoTypeInformation +$matchcounter = 0 +$student = import-csv .\Student2.csv +$teacher = import-csv .\Teacher2.csv +$user1= import-csv .\usernew.csv +try{ +foreach ($order1 in $student){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + + if($order1.'SIS ID' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'Username' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\Student0.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +try{ +foreach ($order1 in $teacher){ + $matched = $false + foreach ($order2 in $user1) + { + $obj = "" | select "SIS ID","course_id","Username","First Name","Last Name","Password","Section SIS ID","School SIS ID","role","login_id","Email","sis_course_id","sis_section_id","sis_user_id","html_url","User Details" + if($order1.'SIS ID' -eq $order2.'SIS ID' ) + { + $matchCounter++ + $matched = $true + $obj.'SIS ID' = $order1.'SIS ID' + $obj.'course_id' = $order2.'course_id' + $obj.'Username' = $order1.'Username' + $obj.'First Name' = $order1.'sortable_name' + $obj.'Last Name' = $order1.'short_name' + $obj.'Password' = 'P@ssword' + $obj.'Section SIS ID' = $order2.'Section SIS ID' + $obj.'School SIS ID' = $order2.'School SIS ID' + $obj.'role' = $order2.'role' + $obj.'login_id' = $order1.'login_id' + $obj.'Email' = $order1.'email' + $obj.'sis_course_id' = $order2.'sis_course_id' + $obj.'sis_section_id' = $order2.'sis_section_id' + $obj.'sis_user_id' = $order2.'sis_user_id' + $obj.'html_url' = $order2.'html_url' + $obj.'User Details' = $order2.'user' + + Write-Host "Match Found Orders " "$matchCounter" + $obj | Export-Csv -Path .\Teacher0.csv -Append -NoTypeInformation + } + } +} +} +Catch { + $_.Exception | Out-File $logfile -Append + } +Import-Csv -Path '.\Teacher0.csv'| sort 'SIS ID' -Unique | Export-Csv .\Teacher10.csv -NoTypeInformation +Import-Csv -Path '.\student0.csv'| sort 'SIS ID' -Unique | Export-Csv .\Student10.csv -NoTypeInformation +Import-Csv -Path '.\Teacher0.csv' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' -Unique | Export-Csv .\StudentEnrollment1.csv -NoTypeInformation +Import-Csv -Path '.\student0.csv' | select 'Section SIS ID', 'SIS ID' | sort 'Section SIS ID', 'SIS ID' -Unique | Export-Csv .\Teacherroster1.csv -NoTypeInformation +#> +try{ +remove-item .\Accounts.csv +remove-item .\sectionTemp.csv +remove-item .\Fulluser.csv +remove-item .\usersall.csv +remove-item .\usernew.csv +remove-item .\users.csv +remove-item .\courses.csv +} +Catch { + $_.Exception | Out-File $logfile -Append + } +} +else { +write-host "You need to provide sync.csv in order to continue..." +} + +$end = [system.datetime]::Now +$resultTime = $end - $start +Write-Host "Execution took : $($resultTime.TotalSeconds) seconds." -ForegroundColor Cyan + +#endregion + diff --git a/Canvas/Canvas_FileUpload.ps1 b/Canvas/Canvas_FileUpload.ps1 new file mode 100644 index 0000000..3829540 --- /dev/null +++ b/Canvas/Canvas_FileUpload.ps1 @@ -0,0 +1,249 @@ +#This script will create syncprofile and upload files to SchoolDataSync +#check configuration file is available or not + + +if (-not (test-path ".\conf.json")) +{ +param( + [Parameter(Mandatory=$true)][System.String]$Username, + [Parameter(Mandatory=$true)][System.String]$Password, + [Parameter(Mandatory=$true)][System.String]$SyncprofileName + ) + +$logfile = ".\CanvasFileUPloadlog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" +$start = [system.datetime]::Now + +#connect AzureAD +$secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force +$mycreds = New-Object System.Management.Automation.PSCredential ($Username, $secpasswd) +$res = Connect-AzureAD -Credential $mycreds + + +#create Azure application + $appName = 'connectsds' + $appHomePageUrl = 'http://sissync.microsoft.com' + $appURI = "http://sissync.microsoft.com/connectsds" + $appReplyURLs = "https://localhost:1234" + +##required resourceAccess +$svcprincipal = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -match "Microsoft Graph" } +$reqGraph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess" +$reqGraph.ResourceAppId = $svcprincipal.AppId + +##ResourceAccess- Delegated Permissions +$delPermission1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "0e263e50-5827-48a4-b97c-d940288653c7","Scope" #Access Directory as the signed in user +$appPermission1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList 63589852-04e3-46b4-bae9-15d5b1050748,"Scope" +$appPermission2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList 8523895c-6081-45bf-8a5d-f062a2f12c9f,"Scope" + +#apply permistions to app +$reqGraph.ResourceAccess = $delPermission1, $appPermission1, $appPermission2 + +if(!($myApp = Get-AzureADApplication -Filter "DisplayName eq '$($appName)'" -ErrorAction SilentlyContinue)) +{ + $myApp = New-AzureADApplication -DisplayName $appName -IdentifierUris $appURI -Homepage $appHomePageUrl -ReplyUrls $appReplyURLs -RequiredResourceAccess $reqGraph +} + +# Application (client) ID, tenant Name +$client_Id = (Get-AzureADApplication -Filter "DisplayName eq '$($appName)'" | select AppId).AppId +$ObjectId = (Get-AzureADApplication -Filter "DisplayName eq '$($appName)'" | select ObjectId).ObjectId +$resource = "https://graph.microsoft.com/" +$tenant = Get-AzureADTenantDetail +$tenantid = $tenant.ObjectId +$Domaininfo = $tenant.VerifiedDomains +$Domain = $Domaininfo.Name + +#Grant Adminconsent +$Grant= 'https://login.microsoftonline.com/common/adminconsent?client_id=' +$admin = '&state=12345&redirect_uri=https://localhost:1234' +$Grantadmin= $Grant + $client_Id + $admin + +start $Grantadmin + +#Getting SKuid +$skuid = Get-AzureADSubscribedSku | select +$studentskuIds = $skuid | where {($_.skuPartNumber -eq 'M365EDU_A5_STUDENT')} +$studentskuIds.skuId +$teacherskuIds = $skuid | where {($_.skuPartNumber -eq 'M365EDU_A5_FACULTY')} +$teacherskuIds.skuId +$studentlicense = $studentskuIds.skuId +$teacherlicense = $teacherskuIds.skuId + +#creating client secret +$startDate = Get-Date +$currentdate = get-date -format "ddmmyyyyhhmm" +$endDate = $startDate.AddYears(3) +$customkeyid = "secret" + "$currentdate" +$clientSecret = New-AzureADApplicationPasswordCredential -ObjectId $ObjectId -CustomKeyIdentifier $customkeyid -StartDate $startDate -EndDate $endDate +$Client_Secret = $clientSecret.Value + + + + $conf = [ordered]@{ + SyncprofileName= $SyncprofileName + client_Id = $client_Id + Client_Secret = $Client_Secret + Username = $Username + Password = $Password + Tenantid = $tenantid + Domain = $Domain + Teacherlicense= $teacherlicense + Studentlicense= $studentlicense + } + +$conf | ConvertTo-Json | Out-File -FilePath conf.json + +} + +else + { + + $logfile = ".\CanvasFileUPloadlog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" + $start = [system.datetime]::Now + $conffile = get-content ".\conf.json" | ConvertFrom-Json + + $SyncprofileName= $conffile.SyncprofileName + $client_Id = $conffile.client_Id + $Client_Secret = $conffile.Client_Secret + $Username = $conffile.Username + $Password = $conffile.Password + $tenantid = $conffile.Tenantid + $Domain = $conffile.Domain + $teacherlicense = $conffile.Teacherlicense + $studentlicense = $conffile.Studentlicense + } + ##Token generation + $loginurl = "https://login.microsoftonline.com/" + "$tenantid" + "/oauth2/v2.0/token" + + $ReqTokenBody = @{ + Grant_Type = "Password" + client_Id = $client_Id + Client_Secret = $Client_Secret + Username = $Username + Password = $Password + Scope = "https://graph.microsoft.com/.default" +} + +try{ +$Token = Invoke-RestMethod -Uri "$loginurl" -Method POST -Body $ReqTokenBody +} + +Catch { + $_.Exception | Out-File $logfile -Append + } + + +# Create header +$Header = @{ + Authorization = "$($token.token_type) $($token.access_token)" +} + + + +if($NewsyncID -eq $null){ +#####create synchronization profiles#### +write-host "creating new sync profile" +$body = '{ + "displayName": "'+$SyncprofileName+'", + "dataProvider": { + "@odata.type": "#Microsoft.Education.DataSync.educationCsvDataProvider", + "customizations": { + "student": { + "optionalPropertiesToSync": [ + "State ID", + "Middle Name" + ] + } + } + }, + "identitySynchronizationConfiguration": { + "@odata.type": "#Microsoft.Education.DataSync.educationIdentityCreationConfiguration", + "userDomains": [ + { + "appliesTo": "student", + "name": "'+$Domain+'" + }, + { + "appliesTo": "teacher", + "name": "'+$Domain+'" + } + ] + }, + "licensesToAssign": [ + { + "appliesTo": "teacher", + "skuIds": [ + "'+$teacherlicense+'" + ] + }, + { + "appliesTo": "student", + "skuIds": [ + "'+$studentlicense+'" + ] + } + ] +}' + + +try{ +$createdprofile = Invoke-RestMethod -Headers $Header -Uri 'https://graph.microsoft.com/beta/education/synchronizationProfiles' -Body $body -Method Post -ContentType 'application/json' +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$NewsyncID = $createdprofile.id + + +#create upload url +write-host "creating upload url" +$Uri1 = "https://graph.microsoft.com/beta/education/synchronizationProfiles/" + "$NewsyncID" + "/uploadurl" +try{ +$uploadurl = Invoke-RestMethod -Uri $Uri1 -Headers $Header -Method Get -ContentType "application/json" +} +Catch { + $_.Exception | Out-File $logfile -Append + } + +$b = $uploadurl.value + +$a = '\azcopy.exe azcopy cp "\*.csv" "' +$c = '" --recursive=true --check-length=false' + +$u = "$a" + "$b" + "$c" +if(test-path .\sastoken.cmd){ +remove-item .\sastoken.cmd +} + +$u >sastoken.cmd + +#run azcopy file and upload files using azcopy +start-process -FilePath ".\sastoken.cmd" + + +write-host "Starting sync" +#Run start sync profile +$UriStart = "https://graph.microsoft.com/beta/education/synchronizationProfiles/" + "$NewsyncID" + "/start" +try{ +$start = Invoke-RestMethod -Uri $UriStart -Headers $Header -Method Post -ContentType "application/json" +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$start +} + +else{ +write-host "getting sync status" +$Uri1 = "https://graph.microsoft.com/beta/education/synchronizationProfiles/" + "$NewsyncID" +try{ +$status = Invoke-RestMethod -Uri $Uri1 -Headers $Header -Method Get -ContentType "application/json" +} +Catch { + $_.Exception | Out-File $logfile -Append + } +$status +} +$end = [system.datetime]::Now +$resultTime = $end - $start +Write-Host "Execution took : $($resultTime.TotalSeconds) seconds." -ForegroundColor Cyan +#End of script diff --git a/Canvas/README.md b/Canvas/README.md new file mode 100644 index 0000000..b05ef26 --- /dev/null +++ b/Canvas/README.md @@ -0,0 +1,244 @@ +# Canvas + +# Description + +Downloading the synchronization files from data source Canvas and uploading the data to the school data synchronization tool + +# Index + +**System requirements** + +**Preparing the system** + +**Getting the Token ID** + +# Downloading Data from Canvas + + Without sync.csv file + + With sync.csv file + +# File Upload + +Canvas_FileUpload (Manual Script) + +Canvas_FileUpload (Automate) + +# System requirements + +A suitable version of Windows PowerShell is available for these operating systems: + +* Windows 10 + +* Windows 8.1 Pro + +* Windows 8.1 Enterprise + +* Windows 7 SP1 + +* Windows Server 2019 + +* Windows Server 2016 + +* Windows Server 2012 R2 + +* Windows Server 2008 R2 SP1 + +# Preparing the system + +Go to start button right click on the windows PowerShell Run as Administrator + +Check the ExecutionPolicy by running below command in the console + + Get-ExecutionPolicy + +Set the ExecutionPolicy to Unrestricted + + Set-ExecutionPolicy -ExecutionPolicy Unrestricted + +# Getting the Token ID + +Generate the new access token using the below process + +login into the Canvas website [uri](Ex:https://jlg.instructure.com) + +Go to Account → settings → Approved integrations → New Access Token + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasApproved%20Integrations.png) + +# Downloading Data from Canvas + +**Without sync.csv file** + +1. How to run the script? + + 1. Run the script by double-clicking “CanvasApiMainScript.ps1” + + 2. Script will ask for Uri - Pass login canvas [Uri](Ex: https://jlg.instructure.com) + + 3. Script will ask fir Token ID - Provide created Token id (Ex:4626~OhR7Arue1IhsaJnplrLYYeqj********) + +2. Where files will be created? + + Files will be created in the same directory where the script file is located + +Once you run the script, it downloads the all available courses data from canvas and creates courses.csv and looks for sync.csv file ( If location not having sync.csv file +Script will create sync.csv and ask you for the provide the details to move further) + +Script will ask the user to “keep course id in sync.csv file and press Y to proceed” + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasContinue.png) + +Hit “Y” and enter. The remaining script will run and create the below files for given input `sync.csv` course ids + +3. What files will be created? + + School.csv + + Section.csv + + Teacher.csv + + Student.csv + + StudentEnrollment.csv + + TeacherRoster.csv + +**With sync.csv file** + +1. How to run the script? + + * Run the script by double-clicking `CanvasApiMainScript.ps1` + + * Script will ask for Uri - Pass login [canvas Uri](https://jlg.instructure.com) + + * Script will ask fir Token ID - Provide created Token id (Ex:4626~OhR7Arue1IhsaJnplrLYYeqj********) + +2. Where files will be created? + + Files will be created in the same directory where the script file is located + +Once you run the script, it downloads the all available courses data from canvas and creates courses.csv + +Script will check sync.csv file. If the file is available runs the remaining script. If the file is not available script asks you to re-run the script by keeping the sync.csv file in the current location + +Script will create below files taking the input from sync.csv + + School.csv + + Section.csv + + Teacher.csv + + Student.csv + + StudentEnrollment.csv + + TeacherRoster.csv + +# Canvas Files Upload to SDS: + +**Canvas_FileUpload (Manual Script):** + +Uploading files to School Data Sync (Manual process): + +* [Link](https://sds.microsoft.com) + +* Login using your Global Admin account + +* Click on Add Profile + +* Enter sync profile Name + +* Choose Sync method → Upload CSV files + +* Choose Type for Csv files you are using → CSV files: SDS Format + +* Click start + +* Sync options: choose new users or Existing users + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasSyncOptions.png) + +* Upload files: Select created 6 csv files (School.csv, Section.csv, Teacher.csv, Student.csv, StudentEnrollment.csv, TeacherRoster.csv) + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/Canvasdatafile.png) + +* Select “Replace unsupported special characters” option + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasReplaceUnsupported.png) + +* When should we stop syncing this profile? + +Select the date + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasSelect%20the%20date.png) + +* Choose Teacher Options + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasChooseTeacher.png) + +Select licenses for Teachers + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasChooseTeacherLicense.png) + +* Choose Student Options + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasStudentption.png) + +Select licenses for Students + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasStudentLicense.png) + +* Review all data and select Create a profile + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasPleasewait.png) + +* Once Sync profile is submitted it will take some time to Create sync profile + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasSettingUp.png) + +Once it is created. It will show the status of sync + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasValidatingFiles.png) + +It will create new Teams in Teams Console + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasNewdataabove.png) + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasNew.png) + +Once it's done. It will create O365 groups as shown in below same will reflect in Teams + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasNew2.png) + +# Canvas File Upload to SDS (Automation): + +Keep the below files in the current folder where you are running the script + +azcopy.exe + +uploading .csv files (School.csv; section.csv; student.csv; studentEnrollment.csv; teacher.csv; teacherroster.csv) + +Navigate to current folder Run the script using run as admin rights + +ex: if I want to run the script in d: + +![](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/CanvasTochangethepath.png) + +Script will run in the current folder and create (conf. JSON) file and sastoken.cmd files + +Provide the username, password and syncprofileName for the first time running the script + +Second time onwards script will provide sync status + +# FAQs/Common Problems: + +Active Directory sync error + +If teachers or students are invited but they don’t enrol as teacher or student. They will not be available as a teacher or student in the created team + +If No Teachers – SDS won’t create teams for that section (if it has the students also) + +In tenant, Teacher will be assigned teacher license and the student will be student license diff --git a/Canvas/azcopy.exe b/Canvas/azcopy.exe new file mode 100644 index 0000000..8792970 Binary files /dev/null and b/Canvas/azcopy.exe differ diff --git a/DomainValidation/DomainValidation.ps1 b/DomainValidation/DomainValidation.ps1 new file mode 100644 index 0000000..dd65f79 --- /dev/null +++ b/DomainValidation/DomainValidation.ps1 @@ -0,0 +1,67 @@ +#Script do a DNS query, if all the domains are pointing to Webdir.online.lync.com script displays the Overall status is Ok, if not displays the overall status is not Ok message + +$logfile = ".\DomainValidationlog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" +$start = [system.datetime]::Now + + if(Get-Module -ListAvailable -Name MicrosoftTeams) + { + Write-Host "MicrosoftTeams module Already Installed" + } + else { + try { + Write-Host "Installing MicrosoftTeams" + Install-Module -Name MicrosoftTeams + } + catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + } +Connect-MicrosoftTeams +$Namelist=(Get-CsOnlineSipDomain -DomainStatus Enabled) +$FinalResult = @() +foreach ($Name in $NameList) +{ +if($Name.Name -match "onmicrosoft.com") +{ +Write-Host "Skipping"$Name.Name"since domain contain .onmicrosoft.com" -ForegroundColor Cyan +} +else{ +$RecordName="lyncdiscover."+$Name.Name +$tempObj = "" | Select-Object Name,Status,ErrorMessage +try { +if($dnsRecord = Resolve-DnsName $RecordName -ErrorAction Stop | Where-Object {$_.Type -eq 'A'}|Where-Object {$_.Name -eq 'webdir.online.lync.com'}) + { +$tempObj.Name = $Name.Name +$tempObj.Status = 'OK' +$tempObj.ErrorMessage = "Resolving to " + $dnsRecord.Name + } + elseif($dnsRecord = Resolve-DnsName $RecordName -ErrorAction Stop | Where-Object {$_.Type -eq 'A'}|Where-Object {$_.Name -ne 'webdir.online.lync.com'} +) +{ + $tempObj.Name = $Name.Name + $tempObj.Status = 'NOT_OK' + $tempObj.ErrorMessage = "Resolving to " + $dnsRecord.IPAddress +} +else{ +} + } +catch { +$tempObj.Name = $Name.Name +$tempObj.Status = 'NOT_OK' +$tempObj.ErrorMessage = $_.Exception.Message + } + $FinalResult += $tempObj + } + } + if($FinalResult.status -ccontains 'NOT_OK') + { + Write-Host "Overall status not Ok" -BackgroundColor DarkRed + } + else{ + Write-Host "Overall status Ok" -BackgroundColor DarkGreen + } +$end = [system.datetime]::Now +$resultTime = $end - $start +Write-Host "Execution took : $($resultTime.TotalSeconds) seconds." -ForegroundColor Cyan +return $FinalResult|ft +#End of script diff --git a/DomainValidation/README.md b/DomainValidation/README.md new file mode 100644 index 0000000..f93b1f1 --- /dev/null +++ b/DomainValidation/README.md @@ -0,0 +1,62 @@ +# DomainValidation +# Description +Script fetches the SIP enabled domains from Tenant, skips the DNS query for the domains contain .onmicrosoft.com, for domains which do not contain .onmicrosoft.com does a DNS name query resolution for **Lync discover** records and validate if they are pointing to webdir.online.lync.com + +If all the domains are pointing to Webdir.online.lync.com script displays the **Overall status is Ok**, even if one of the domain is pointing to outside webdir.online.lync.com then script displays the **Overall status is not Ok** message + +# Prerequisite + MicrosoftTeams module. Reference-[Microsoft Teams PowerShell Release Notes](https://docs.microsoft.com/en-us/microsoftteams/teams-powershell-release-notes) +# Input +Global Administrator or MicrosoftTeams administrator account user principal name and password, and then select OK +# Examples +##### Example 1 +If domain resolving to webdir.online.lync.com +###### Output +|Name | Status| ErrorMessage | +|---|----|-----| +|xyz.com | OK | Resolving to webdir.online.lync.com | +##### Example 2 +If domain resloving to other than webdir.online.lync.com +###### Output +|Name |Status |ErrorMessage | +|----|---|---| +|xyz.com |NOT_OK |Resolving to 52.xxx.12.xx4(IP Address)| +##### Example 3 +If the domain is not resolving +###### Output +|Name | Status |ErrorMessage | +|---|---|---| +|xyz.com |NOT_OK |lyncdiscover.xyz.com : DNS name does not exist| + +#### Parameters + +`-Type` + +Specifies the DNS query type that is to be issued. By default the type is A_AAAA, the A and AAAA types will both be queried. + +Type: RecordType +*** +Accepted values: UNKNOWN, A_AAAA, A, NS, MD, MF, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT, RP, AFSDB, X25, ISDN, RT, AAAA, SRV, DNAME, OPT, DS, RRSIG, NSEC, DNSKEY, DHCID, NSEC3, NSEC3PARAM, ANY, ALL, WINS| +*** +Position: 1 +*** +Default value: None +*** +Accept pipeline input: True +*** +Accept wildcard characters: False + +# Output +A log file will be generated with exceptions, errors along with script execution time + +Output contains + +Skip domains list + +Overall Tenant status - Ok/Not Ok + +|Domain Name |Status |ErrorMessage| +|---|---|---| + +#### Example +![Sample Output](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/DomainValidation.jpg) diff --git a/Send Notification to Selected Audience and Direct them to a Deep Link App/README.md b/Send Notification to Selected Audience and Direct them to a Deep Link App/README.md new file mode 100644 index 0000000..387810f --- /dev/null +++ b/Send Notification to Selected Audience and Direct them to a Deep Link App/README.md @@ -0,0 +1,118 @@ +# Send Notification to Selected Audience and Direct them to a Deep Link App + +# Description + +Script will accept the target audience from the user(CSV/Team Members/SG/DL), destination we need to point the users(App / Deep Link) to a specific entity and +send notification + +API's used in the script are under the `/beta` version in Microsoft Graph, the script will not support in the production environment + +# Prerequisites + + [Create new Azure App.](https://docs.microsoft.com/en-us/graph/auth-register-app-v2) + + [How to apply permissions](https://docs.microsoft.com/en-us/graph/notifications-integration-app-registration) to your newly created App. + + Please collect client id, client secret from created Azure app and tenant id from Azure portal + +##### Required Permissions + +|Permission type |Permissions (from least to most privileged)| +|-------------|----| +|Delegated (work or school account) |TeamsActivity.Send,Team.ReadBasic.All, TeamSettings.Read.All, TeamSettings.ReadWrite.All, Group.Read.All, Group.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All,GroupMember.Read.All, Group.Read.All| +|Application |TeamsActivity.Send,TeamSettings.Read.Group*, TeamSettings.ReadWrite.Group*, Team.ReadBasic.All, TeamSettings.Read.All, TeamSettings.ReadWrite.All, Group.Read.All, Group.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All,GroupMember.Read.All, Group.Read.All| + + # Example + Input 1 to send a notification to user chat + + Input 2 to send a notification to a specific Team + + Input 3 to send a notification to user-installed app + + Input 4 to send a notification to the Distribution list + + Input 5 to send a notification to Bulk users for the installed app(CSV) + + Input 6 to send a notification to a specific tab in the application + + # Parameters + +`-TeamId` + +Team identifier in Microsoft Teams + +Type: String +*** +Aliases: GroupId +*** +Position: Named +*** +Default value: None +*** +Accept pipeline input: True +*** +Accept wildcard characters: False + +`-AppId` + +Teams App identifier in Microsoft Teams + +Type: String +*** +Position: Named +*** +Default value: None +*** +Accept pipeline input: True +*** +Accept wildcard characters: False + +`-TenantId` + +Specifies the unique ID of the tenant on which to perform the operation. The default value is the tenant of the current user. This parameter applies only to partner users. + +Type: Guid +*** +Position: Named +*** +Default value: None +*** +Accept pipeline input: True +*** +Accept wildcard characters: False + +# Inputs + + Tenant_Id, Client_Id, Client_Secret + + [Find your tenant ID](https://docs.microsoft.com/en-us/onedrive/find-your-office-365-tenant-id#:~:text=In%20this%20article,your%20organization%20name%20or%20domain.) + + ChatId, UserId, Distribution list Id, TabId, TeamId, AppId, csv file full location(ex:d:\example.csv) + +# Procedure to run the script + + To execute `Send Notification to Selected Audience and Direct them to a Deep Link App` download/copy and paste the script into PowerShell + + Provide the input parameters Client_Id, Client_Secret, TenantId and hit enter to proceed further on the script + + Now the script will redirect to the web page for login + + ![Signin](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/Siginin.png) + + Provide admin credentials i.e user ID and password + + Press enter to continue + + Once you are login it will show the below image for grant permissions for the app to perform the operations + + ![GrantPermission](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/GrantPermissions.png) + + ![GrantPermission](https://github.com/Geetha63/MS-Teams-Scripts/blob/master/Images/GrantPermissions2.png) + + **Click Accept** + + If you have provided the correct credentials it will give success status `admin_consent = True` + + Now press Y to proceed further in the script + + Please choose the option 1 to 6 to send a notification to the targeted user diff --git a/Send Notification to Selected Audience and Direct them to a Deep Link App/SendNotificationForSelectedAudienceScript.ps1 b/Send Notification to Selected Audience and Direct them to a Deep Link App/SendNotificationForSelectedAudienceScript.ps1 new file mode 100644 index 0000000..5f33d4f --- /dev/null +++ b/Send Notification to Selected Audience and Direct them to a Deep Link App/SendNotificationForSelectedAudienceScript.ps1 @@ -0,0 +1,267 @@ +# This script will send notification to selected Audience using Graph api calling method. +param( + [Parameter(Mandatory=$true)][System.String]$client_Id, + [Parameter(Mandatory=$true)][System.String]$Client_Secret, + [Parameter(Mandatory=$true)][System.String]$Tenantid + ) +$logfile = ".\SendNotificationlog_$(get-date -format `"yyyyMMdd_hhmmsstt`").txt" +$start = [system.datetime]::Now + +#Grant Adminconsent +$Grant= 'https://login.microsoftonline.com/common/adminconsent?client_id=' +$admin = '&state=12345&redirect_uri=https://localhost:1234' +$Grantadmin = $Grant + $client_Id + $admin + +Start-Process $Grantadmin +write-host "login with your tenant login detials to proceed further" + +$proceed = Read-host " Press Y to continue " +if ($proceed -eq 'Y') +{ + write-host "Creating Access_Token" + $ReqTokenBody = @{ + Grant_Type = "client_credentials" + client_Id = "$client_Id" + Client_Secret = "$Client_Secret" + Scope = "https://graph.microsoft.com/.default" + } + + $loginurl = "https://login.microsoftonline.com/" + "$Tenantid" + "/oauth2/v2.0/token" + try{ + $Token = Invoke-RestMethod -Uri "$loginurl" -Method POST -Body $ReqTokenBody -ContentType "application/x-www-form-urlencoded" + } + catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + $Header = @{ + Authorization = "$($token.token_type) $($token.access_token)" + } + + $inputmethod = Read-host "Please choose target audience number + 1.send notification to user chat + 2.send notification to specific Team + 3.send notification to user installed app + 4.send notification to Distribution List + 5.send notification to Bulk users for installed app(csv) + 6.send notification to specific tab in application" + + if($inputmethod -eq 1){ + $chatid1 = read-host "please provide chatid" + $userid1 = read-host "please provide userid" + + $uri1 = "https://graph.microsoft.com/beta/chats/" +$chatid1 + "/sendActivityNotification" +$body1 = '{ + "topic": { + "source": "entityUrl", + "value": "https://graph.microsoft.com/beta/chats/'+$chatid1+'" + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "recipient": { + "@odata.type": "microsoft.graph.aadUserNotificationRecipient", + "userId": "'+$userid1+'" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "12322" + } + ] + }' + + try{ + $SendNotificationCall1 = Invoke-RestMethod -Uri $uri1 -Headers $Header -Body $body1 -Method Post -ContentType "application/json" + } + catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + } + +if($inputmethod -eq 2){ + +$Teamid2 = read-host "please provide teamid" + $userid2 = read-host "please provide userid" + +$uri2 = "https://graph.microsoft.com/beta/teams/" +$Teamid2 + "/sendActivityNotification" +$body2 =' +{ + "topic": { + "source": "entityUrl", + "value": "https://graph.microsoft.com/beta/teams/'+$Teamid2+'" + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "recipient": { + "@odata.type": "microsoft.graph.aadUserNotificationRecipient", + "userId": "'+$userid2+'" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "12322" + } + ] +}' +try{ +$SendNotificationCall2 = Invoke-RestMethod -Uri $uri2 -Headers $Header -Body $body2 -Method Post -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + +} + +if($inputmethod -eq 3){ +$userid3 = read-host "please provide userid" +$appid3 = read-host "Please provide application id" +$uri3 = "https://graph.microsoft.com/beta/users/"+"$userid3"+"/teamwork/sendActivityNotification" +$body3 =' +{ + "topic": { + "source": "entityUrl", + "value": "https://graph.microsoft.com/beta/users/'+"$userid3"+'/teamwork/installedApps/'+$appid3+'" + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "Task 12322" + } + ] +}' +try{ +$SendNotificationCall3 = Invoke-RestMethod -Uri $uri3 -Headers $Header -Body $body3 -Method Post -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + +} + +if($inputmethod -eq 4){ +$userid4 +$appid4 = read-host "Please provide application id" +$DL = read-host "please provide distribution list id" +$DLuri = "https://graph.microsoft.com/v1.0/groups/"+$DL+"/members" +#$DLuri = 'https://graph.microsoft.com/v1.0/groups/?$filter=mail'+ "eq" +'email@domain.onmicrosoft.com'+'&$expand=members$select=members/displayName' +try{ +$DLmembers = Invoke-RestMethod -Uri $DLuri -Headers $Header -Method Get -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } +$userdetails = $DLmembers.value +$userids = $userdetails.id +foreach($userid4 in $userids){ +$uri4 = "https://graph.microsoft.com/beta/users/"+"$userid4"+"/teamwork/sendActivityNotification" +$body4 =' +{ + "topic": { + "source": "entityUrl", + "value": "https://graph.microsoft.com/beta/users/'+"$userid4"+'/teamwork/installedApps/'+$appid4+'" + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "Task 12322" + } + ] +}' +try{ +$SendNotificationCall4 = Invoke-RestMethod -Uri $uri4 -Headers $Header -Body $body4 -Method Post -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } +} +} +if($inputmethod -eq 5){ +$appid5 = read-host "Please provide application id" + $file_List = Read-host "Please provide csv file full location(ex:d:\example.csv)" + Foreach ($file in $file_List){ + $userid5 = $file.user + $uri5 = "https://graph.microsoft.com/beta/users/"+"$userid3"+"/teamwork/sendActivityNotification" + $body5 =' +{ + "topic": { + "source": "entityUrl", + "value": "https://graph.microsoft.com/beta/users/'+"$userid5"+'/teamwork/installedApps/'+$appid5+'" + + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "Task 12322" + } + ] +}' +try{ +$SendNotificationCall5 = Invoke-RestMethod -Uri $uri5 -Headers $Header -Body $body5 -Method Post -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } + +} + +} + + if($inputmethod -eq 6){ + + $userid6 = read-host = "please provide user id" + $appid6 = read-host = "please provide app id for application" + $tabid6 = read-host = "please provide tab id " + + $uri6 = "https://graph.microsoft.com/beta/users/" + "$userid6" + "/teamwork/sendActivityNotification" +$body6 =' +{ + "topic": { + "source": "text", + "value": "Check Out Playlists!", + "webUrl": "https://teams.microsoft.com/l/entity/'+$appid6 + "/" + $tabid6+' + }, + "activityType": "taskCreated", + "previewText": { + "content": "New Task Created" + }, + "templateParameters": [ + { + "name": "taskId", + "value": "Task 12322" + } + ] +}' + + +try{ + $SendNotificationCall6 = Invoke-RestMethod -Uri $uri6 -Headers $Header -Body $body6 -Method Post -ContentType "application/json" +} +catch{ + $_.Exception.Message | out-file -Filepath $logfile -append + } +} + +} + +else{write-host "please rerun the script login with created graphapi application credentials"} + +$end = [system.datetime]::Now +$resultTime = $end - $start +Write-Host "Execution took : $($resultTime.TotalSeconds) seconds." -ForegroundColor Cyan + +#end of script