-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEPProcess.ps1
362 lines (306 loc) · 13.1 KB
/
EPProcess.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
<#
.Synopsis
Reformatter for your schools data export.
Will reformat your schools SMS export to 'students.csv' and 'teachers.csv' for upload to EPs SFTP server
.Description
v 2020.07.23
This tool will reformat your schools data export in to a format that can be automatically processed by EP.
The following file(s) are required:
-Config\config.ps1
This file contains configuration data required by the tool and is contained in a seperate file as this data will be particular to your school.
Please see https://github.com/EducationPerfect/class-list-formatter/ for more details
.PARAMETER rejectsFile
Override location and file name for rejects input file.
.PARAMETER classCodesFile
Override location and file name for classCodes input file.
.PARAMETER inputFile
Override location and file name for export input file.
.PARAMETER studentOutFile
Override location and file name for student output file. Use "" to suppress creation.
.PARAMETER teacherOutFile
Override location and file name for teacher output file. Use "" to suppress creation.
.PARAMETER rejectsOutFile
Override location and file name for rejects output file. Use "" to suppress creation.
.PARAMETER unknownOutFile
Override location and file name for unknown output file. Use "" to suppress creation.
#>
param(
[string]$rejectsFile,
[string]$classCodesFile,
[string]$inputFile,
[string]$studentOutFile,
[string]$teacherOutFile,
[string]$rejectsOutFile,
[string]$unknownOutFile
)
Set-PSDebug -Strict
#Load configuration parameters, not done before param() as it needs to run first
. Config\config.ps1
#Load defaults if not overridden
#Input files
if (!$PSBoundParameters.ContainsKey('rejectsFile')) {$rejectsFile = $global:config.files.rejectsFile}
if (!$PSBoundParameters.ContainsKey('classCodesFile')) {$classCodesFile = $global:config.files.classCodesFile}
if (!$PSBoundParameters.ContainsKey('inputFile')) {$inputFile = $global:config.files.inputFile}
#Output files
if (!$PSBoundParameters.ContainsKey('studentOutFile')) {$studentOutFile = $global:config.files.studentOutFile}
if (!$PSBoundParameters.ContainsKey('teacherOutFile')) {$teacherOutFile = $global:config.files.teacherOutFile}
if (!$PSBoundParameters.ContainsKey('rejectsOutFile')) {$rejectsOutFile = $global:config.files.rejectsOutFile}
if (!$PSBoundParameters.ContainsKey('unknownOutFile')) {$unknownOutFile = $global:config.files.unknownOutFile}
#Convert csv to utf8 due to bug in Import-CSV
$tempFile = "utf8" + $inputFile
Rename-Item -Path $inputFile -NewName $tempFile
Get-Content $tempFile | Set-Content -Encoding utf8 $inputFile
Remove-Item $tempFile
#Run any required PreProcess from config
if (Get-Command 'PreProcess' -ErrorAction SilentlyContinue){
PreProcess
}
#Import reject list and create regex to use on CLASS NAME column
try {
$rejectFile = Import-CSV $rejectsFile | select -ExpandProperty regex -ErrorAction Stop
} catch [System.IO.FileNotFoundException] {
"Error: $rejectsFile file not found"
exit
}
#Add key to account for empty file, or else everything gets rejected
$rejectRegex = if($rejectFile.Count -gt 0){ $rejectFile -join "|"} else { "abc1234" }
#Import class code data
try {
$classCodes = Import-Csv $classCodesFile | group -AsHashTable -Property Code -ErrorAction Stop
if ($classCodes.Count -eq 0) {
"Error: Class Codes file $classCodesFile empty"
exit
}
} catch [System.IO.FileNotFoundException] {
"Error: Class Codes File $classCodesFile not found"
exit
}
#Import spreadsheet data
try {
$spreadsheet = Import-Csv $inputFile -ErrorAction Stop
} catch [System.IO.FileNotFoundException] {
"Error: Input file $inputFile not found"
exit
}
#Extract teachers if requried/possible
if ($teacherOutFile -ne "" -and $global:config.teachers.surname -ne ""){
#Do teachers
$teachers = $spreadsheet | Select -Property `
@{label="Forename";expression={$_.($global:config.teachers.forename)}},
@{label="Surname";expression={$_.($global:config.teachers.surname)}},
@{label="Email";expression={$_.($global:config.teachers.email).ToLower()}},
@{label="SSO Identifier";expression={$_.($global:config.teachers.SSO).ToLower()}},
@{label="LTI Identifier";expression={$_.($global:config.teachers.LTI).ToLower()}},
@{label="Teacher Code";expression={$_.($global:config.teachers.code).ToUpper()}} `
| Sort "Email" -Unique `
| Where-Object{$_.Email -and $_.Forename -and $_.Surname}
#Do post processing that can't be done in the select
#SSO
if ($global:config.teachers.SSO -eq ""){
$teachers = $teachers | Select-Object -Property * -ExcludeProperty "SSO Identifier"
}
#LTI
if ($global:config.teachers.LTI -eq ""){
$teachers = $teachers | Select-Object -Property * -ExcludeProperty "LTI Identifier"
}
#Code
if ($global:config.teachers.code -eq ""){
$teachers = $teachers | Select-Object -Property * -ExcludeProperty "Teacher Code"
}
#Finally save it
$teachers | Export-Csv -Path $global:config.files.teacherOutFile -Force -NoTypeInformation -Encoding utf8
}
#Join teachers forename and surname together if required else assume entire name
if ($global:config.teachers.surname -ne ""){
$spreadsheet = $spreadsheet | Select-Object *, @{Name="Teacher/s";Expression={$_.($global:config.teachers.forename)+" "+$_.($global:config.teachers.surname)}}
} else {
$spreadsheet = $spreadsheet | Select-Object *, @{Name="Teacher/s";Expression={$_.($global:config.teachers.forename)}}
#TODO Split name up depending on comma or first space or capitals?
}
#Join staff name columns and group by student/classname for classes with more than one teacher
$spreadsheet = $spreadsheet | Group-Object -Property {$_.($global:config.students.UID) + $_.($global:config.classes.classCode)}
#Set up collections for output files: uploads, rejects and unknown codes
$upload = @()
$rejected = @()
$unknown = @()
#Generate a nicely formatted output row that should be able to be automatically proccessed.
#Assume that class code matches at this point
function Generate-OutputRow($matches, $row){
$campus = ""
$prepend = ""
$year = ""
$modifier = ""
$subject = ""
$code= ""
#Campus code
if($matches['Campus'].Length -gt 0){
$campus = $matches['Campus']+" ";
}
#Prepend field
if($global:config.classes.prepend.Length -gt 0){
$prepend = $row.Group[0].($global:config.classes.prepend)+" ";
}
#Year, look up code or convert to two digits
if($matches['Year'].Length -gt 0){
if($global:config.yearLevels.($matches['Year']).Length -gt 0) {
$yearLevel = $global:config.yearLevels.($matches['Year'])
#Check if we already have a word else, prepend Year
if ($yearLevel -like "* *"){
$year = $yearLevel
} else {
$year = "Year "+ $yearLevel
}
} else {
$year = "Year {0:d2}" -f [int32]($matches['Year'])
}
}
#Modifier
if ($year.Length -gt 0){
if ($matches['Modifier'].Length -gt 0){
$modifier ="." + $matches['Modifier'] + " "
} else {
$modifier = " "
}
}
#Subject
$subject = $classCodes[$matches['Code']].Description
#code
$code = $matches[0]
#Generate class name
$classname = $campus + $prepend + $year + $modifier + $subject + " (" + $code + ")"
#Generate student row
$outputrow = [PSCustomObject]@{
Forename = $row.Group[0].($global:config.students.forename)
Surname = $row.Group[0].($global:config.students.surname)
Class = $classname
"Class SMS ID" = $code
"Teacher/s" = $row.Group."Teacher/s" -Join ", "
"Student ID" = $row.Group[0].($global:config.students.studentID)
Email = $row.Group[0].($global:config.students.email)
"LTI Identifier" = $row.Group[0].($global:config.students.LTI)
"SSO Identifier" = $row.Group[0].($global:config.students.SSO)
#"Class Year"
#"Class Subject"
}
#Do post processing that can't be done in the custom object
#Student ID
if ($global:config.students.studentID -eq ""){
$outputrow = $outputrow | Select-Object -Property * -ExcludeProperty "Student ID"
}
#LTI
if ($global:config.students.LTI -eq ""){
$outputrow = $outputrow | Select-Object -Property * -ExcludeProperty "LTI Identifier"
}
#SSO
if ($global:config.students.SSO -eq ""){
$outputrow = $outputrow | Select-Object -Property * -ExcludeProperty "SSO Identifier"
}
return $outputrow
}
#Progress indicator
$currentCount = 1
$totalRows = $spreadsheet.Count
#Loop through all row data
Foreach ($row IN $spreadsheet)
{
Write-Progress -Activity "Processing" -Status "Progress: Row $currentCount of $totalRows" -PercentComplete ((($currentCount++)/$totalRows)*100)
#Cascading if statements here instead of a switch?
switch -regex ($row.Group.($global:config.classes.classCode))
{
#Ditch rejected class codes
$rejectRegex
{
$rejected += $row.Group
break
}
#Work on class codes that match expected format 1
$global:config.classes.regEx1
{
if ($global:config.classes.regEx1 -ne ""){
#Do we have a matching code?
If ($classCodes.ContainsKey($matches['Code'])) {
$upload += Generate-OutputRow $matches $row
} else {
$unknown += $row.Group
}
break
}
}
#Work on class codes that match expected format 2
$global:config.classes.regEx2
{
if ($global:config.classes.regEx2 -ne ""){
#Do we have a matching code?
If ($classCodes.ContainsKey($matches['Code'])) {
$upload += Generate-OutputRow $matches $row
} else {
$unknown += $row.Group
}
break
}
}
#Work on class codes that match expected format 3
$global:config.classes.regEx3
{
if ($global:config.classes.regEx3 -ne ""){
#Do we have a matching code?
If ($classCodes.ContainsKey($matches['Code'])) {
$upload += Generate-OutputRow $matches $row
} else {
$unknown += $row.Group
}
break
}
}
#Anything else: Didn't match any RegEx pattern provided
""
{
$unknown += $row.Group
break
}
}
}
#Export processed data
if ($studentOutFile -ne "") {$upload | Export-Csv -Path $studentOutFile -NoTypeInformation -Force -Encoding utf8}
#Export rejected data
if ($rejectsOutFile -ne "") {$rejected | Export-Csv -Path $rejectsOutFile -NoTypeInformation -Force -Encoding utf8}
#Export unknown class codes
if ($unknownOutFile -ne "") {$unknown | Export-Csv -Path $unknownOutFile -NoTypeInformation -Force -Encoding utf8}
if($global:config.showSummary){
Write-Output "Processing Report"
Write-Output "-----------------"
Write-Output "`nProcessed Rows:"
Write-Output "---------------"
$tmp_accepted = $upload.length
$tmp_rejected = $rejected.length
$tmp_unknown = $unknown.length
$tmp_total = ($tmp_accepted + $tmp_rejected + $tmp_unknown)
Write-Output "Accepted:`t $tmp_accepted"
Write-Output "Rejected:`t $tmp_rejected"
Write-Output "Unknown:`t $tmp_unknown"
Write-Output "Total:`t`t $tmp_total"
Write-Output "`nProcessed Classes:"
Write-Output "------------------"
$tmp_accepted = ($upload | sort-Object -Property "Class" -Unique).Count
$tmp_rejected = ($rejected | sort-Object -Property "CLASS NAME" -Unique).Count
$tmp_unknown = ($unknown | sort-Object -Property "CLASS NAME" -Unique).Count
$tmp_total = ($tmp_accepted + $tmp_rejected + $tmp_unknown)
Write-Output "Accepted:`t $tmp_accepted"
Write-Output "Rejected:`t $tmp_rejected"
Write-Output "Unknown:`t $tmp_unknown"
Write-Output "Total:`t`t $tmp_total"
Write-Output "`nProcessed Students:"
Write-Output "-------------------"
$tmp_accepted = ($upload | sort-Object -Property "Student ID" -Unique).Count
$tmp_rejected = ($rejected | sort-Object -Property "UPN Student" -Unique).Count
$tmp_unknown = ($unknown | sort-Object -Property "UPN Student" -Unique).Count
$tmp_total = ($spreadsheet.Group | sort-Object -Property "UPN Student" -Unique).Count
Write-Output "In accepted classes:`t $tmp_accepted"
Write-Output "In rejected classes:`t $tmp_rejected"
Write-Output "In unknown classes:`t`t $tmp_unknown"
Write-Output "In all classes:`t`t`t $tmp_total"
}
#Run any required PostProcess from config
if (Get-Command 'PostProcess' -ErrorAction SilentlyContinue){
PostProcess
}