diff --git a/api/composite_user.py b/api/composite_user.py
index 44fa8ca839136a3a37e6ff3e5420ff9020e62be5..c8f6eaebdb47f752748cf817a6fa7e7a32165e71 100644
--- a/api/composite_user.py
+++ b/api/composite_user.py
@@ -57,6 +57,12 @@ class CompositeUser:
                                    'GitlabEmail': gitlab_student.get_email()}
         return CompositeUser(student, {}, set())
 
+    def get_name(self) -> str:
+        return self.readable_name
+
+    def get_canvas_username(self) -> str:
+        return self.canvas_username
+
     def get_canvas_user(self) -> CanvasUser:
         if self.canvas_user is None:
             # self.canvas_user = CanvasUser(self.NUID)  # n.b., can retrieve own user but not arbitrary user
diff --git a/prep_assignment.py b/prep_assignment.py
index 8701a076d68390899638632b0720b2e62ea31bf5..ff4c53cacbb75637296d4377780f773365825056 100644
--- a/prep_assignment.py
+++ b/prep_assignment.py
@@ -23,6 +23,53 @@ def get_students() -> Set[CompositeUser]:
     return students
 
 
+def validate_roster_against_canvas(course_roster: Set[CompositeUser]) -> bool:
+    print('Validating course roster against Canvas.')
+    course = CanvasCourse(Course.canvas_course_id)
+    students_in_canvas = course.get_students()
+    roster_names: Set[str] = set(map(lambda s: s.get_canvas_username(), course_roster))
+    canvas_names: Set[str] = set(map(lambda s: s.get_username(), students_in_canvas))
+    roster_is_valid: bool = True
+    difference: Set[str] = roster_names - canvas_names
+    if len(difference) > 0:
+        roster_is_valid = False
+        print('\tStudent(s) are in roster but not in Canvas. The roster is invalid:')
+        extra_students: Set[CompositeUser] = set(filter(lambda s: s.get_canvas_username() in difference, course_roster))
+        for student in extra_students:
+            print(f'\t\t{student}')
+    difference = canvas_names - roster_names
+    if len(difference) > 0:
+        roster_is_valid = False
+        print('\tStudent(s) are in Canvas but not in roster. The roster is invalid:')
+        extra_students: Set[CanvasUser] = set(filter(lambda s: s.get_username() in difference, students_in_canvas))
+        for student in extra_students:
+            print(f'\t\t{student.get_name()} ({student})')
+    if roster_is_valid:
+        print(f'\t{len(roster_names)} names match. The roster is valid.')
+    return roster_is_valid
+
+
+def validate_roster_against_gitlab(course_roster: Set[CompositeUser]) -> bool:
+    print('Validating course roster against GitLab.')
+    roster_is_valid: bool = True
+    invalid_users: Set[CompositeUser] = set()
+    for student in course_roster:
+        username: str = student.gitlab_username
+        try:
+            print(f'\t{student.get_name()}'.ljust(30, '.'), end=' ')
+            GitlabUser(username)
+            print('✅')
+        except IndexError:
+            print('❌')
+            invalid_users.add(student)
+    if len(invalid_users) > 0:
+        roster_is_valid = False
+        print('\tStudent(s) have invalid GitLab usernames (may have changed usernames):')
+        for student in invalid_users:
+            print(f'\t\t{student}')
+    return roster_is_valid
+
+
 # TODO: assign_partners for arbitrarily-sized teams
 # TODO: break this up into bite-sized chunks
 # TODO: manage multiple sections
@@ -233,17 +280,20 @@ def create_groups(groupset_name: str,
 if __name__ == '__main__':
     groupset: str = input('Please provide the name of the student groupset: ')
     student_set: Set[CompositeUser] = get_students()
-    # TODO: check for changes to course roster
-    # TODO: check for changes to gitlab usernames
-    partners: List[Tuple[int, CompositeUser, CompositeUser, Optional[CompositeUser]]] = create_pairs(student_set,
-                                                                                                     groupset)
-    print()
-    save_student_roster(student_set)
-    create_contact_list(groupset, partners)
-    print()
-    create_repositories(groupset, partners)
-    print()
-    create_groups(groupset, partners)
-    print()
-    print('TODO:\tAdd issues')
-    print('\tCommit starter code')
+    course_roster_matches_canvas: bool = validate_roster_against_canvas(student_set)
+    course_roster_matches_gitlab: bool = validate_roster_against_gitlab(student_set)
+    if course_roster_matches_canvas and course_roster_matches_gitlab:
+        partners: List[Tuple[int, CompositeUser, CompositeUser, Optional[CompositeUser]]] = create_pairs(student_set,
+                                                                                                         groupset)
+        print()
+        save_student_roster(student_set)
+        create_contact_list(groupset, partners)
+        print()
+        create_repositories(groupset, partners)
+        print()
+        create_groups(groupset, partners)
+        print()
+        print('TODO:\tAdd issues')
+        print('\tCommit starter code')
+    else:
+        print('No partners assigned due to invalid roster. Please update student roster file.')