diff --git a/lms/djangoapps/certificates/management/commands/find_unicode_certs.py b/lms/djangoapps/certificates/management/commands/find_unicode_certs.py
deleted file mode 100644
index 49497622c6651ecc7544ba61954d45748969f988..0000000000000000000000000000000000000000
--- a/lms/djangoapps/certificates/management/commands/find_unicode_certs.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from django.core.management.base import BaseCommand
-from certificates.models import certificate_status_for_student
-from certificates.queue import XQueueCertInterface
-from django.contrib.auth.models import User
-from student.models import UserProfile
-
-
-class Command(BaseCommand):
-
-    help = """
-    Looks for names that have unicode characters
-    and queues them up for a certificate request
-    """
-
-    def handle(self, *args, **options):
-
-        # TODO this is only temporary for CS169 certs
-
-        course_id = 'BerkeleyX/CS169.1x/2012_Fall'
-
-        enrolled_students = User.objects.filter(
-                courseenrollment__course_id=course_id).prefetch_related(
-                        "groups").order_by('username')
-        xq = XQueueCertInterface()
-        print "Looking for unusual names.."
-        for student in enrolled_students:
-            if certificate_status_for_student(
-                     student, course_id)['status'] == 'unavailable':
-                continue
-            name = UserProfile.objects.get(user=student).name
-            for c in name:
-                if ord(c) >= 0x200:
-                    ret = xq.add_cert(student, course_id)
-                    if ret == 'generating':
-                        print 'generating for {0}'.format(student)
-                    break
diff --git a/lms/djangoapps/certificates/management/commands/gen_cert_report.py b/lms/djangoapps/certificates/management/commands/gen_cert_report.py
new file mode 100644
index 0000000000000000000000000000000000000000..21e1775665c342f8891324e00e0e40a8721c956b
--- /dev/null
+++ b/lms/djangoapps/certificates/management/commands/gen_cert_report.py
@@ -0,0 +1,97 @@
+from django.core.management.base import BaseCommand
+from certificates.models import GeneratedCertificate
+from django.contrib.auth.models import User
+from optparse import make_option
+from django.conf import settings
+from xmodule.course_module import CourseDescriptor
+from xmodule.modulestore.django import modulestore
+from django.db.models import Count
+
+
+class Command(BaseCommand):
+
+    help = """
+
+    Generate a certificate status report for all courses that have ended.
+    This command does not do anything other than report the current
+    certificate status.
+
+    unavailable  - A student is not eligible for a certificate.
+    generating   - A request has been made to generate a certificate,
+                   but it has not been generated yet.
+    regenerating - A request has been made to regenerate a certificate,
+                   but it has not been generated yet.
+    deleting     - A request has been made to delete a certificate.
+
+    deleted      - The certificate has been deleted.
+    downloadable - The certificate is available for download.
+    notpassing   - The student was graded but is not passing
+
+    """
+
+    option_list = BaseCommand.option_list + (
+        make_option('-c', '--course',
+            metavar='COURSE_ID',
+            dest='course',
+            default=None,
+            help='Only generate for COURSE_ID'),
+        )
+
+    def _ended_courses(self):
+        for course_id in [course  # all courses in COURSE_LISTINGS
+                for sub in settings.COURSE_LISTINGS
+                    for course in settings.COURSE_LISTINGS[sub]]:
+            course_loc = CourseDescriptor.id_to_location(course_id)
+            course = modulestore().get_instance(course_id, course_loc)
+            if course.has_ended():
+                yield course_id
+
+    def handle(self, *args, **options):
+
+        # Find all courses that have ended
+
+        if options['course']:
+            ended_courses = [options['course']]
+        else:
+            ended_courses = self._ended_courses()
+
+        cert_data = {}
+
+        for course_id in ended_courses:
+
+            # find students who are enrolled
+            print "Looking up certificate states for {0}".format(course_id)
+            enrolled_students = User.objects.filter(
+                    courseenrollment__course_id=course_id).prefetch_related(
+                            "groups").order_by('username')
+            unavailable_count = enrolled_students.count() - \
+                    GeneratedCertificate.objects.filter(
+                            course_id__exact=course_id).count()
+            cert_data[course_id] = {'enrolled': enrolled_students.count()}
+            cert_data[course_id].update({'unavailable': unavailable_count})
+
+            tallies = GeneratedCertificate.objects.values(
+                    'status').annotate(dcount=Count('status'))
+            cert_data[course_id].update(
+                    {status['status']: status['dcount']
+                                        for status in tallies})
+
+        # all states we have seen far all courses
+        status_headings = set(
+                [status for course in cert_data
+                    for status in cert_data[course]])
+
+        # print the heading for the report
+        print "{:>20}".format("course ID"),
+        print ' '.join(["{:>12}".format(heading)
+                            for heading in status_headings])
+
+        # print the report
+        for course_id in cert_data:
+            print "{0:>20}".format(course_id[0:18]),
+            for heading in status_headings:
+                if heading in cert_data[course_id]:
+                    print "{:>12}".format(cert_data[course_id][heading]),
+                else:
+                    print " " * 12,
+            print
diff --git a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py
index 82e86c2097c16ccb3a1d2d5b57549540c2723526..080918c0ccd594bd64db6f1b7d77d95aaf138ac6 100644
--- a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py
+++ b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py
@@ -2,29 +2,92 @@ from django.core.management.base import BaseCommand
 from certificates.models import certificate_status_for_student
 from certificates.queue import XQueueCertInterface
 from django.contrib.auth.models import User
+from optparse import make_option
+from django.conf import settings
+from xmodule.course_module import CourseDescriptor
+from xmodule.modulestore.django import modulestore
+from certificates.models import CertificateStatuses
+import datetime
 
 
 class Command(BaseCommand):
 
     help = """
-    Find all students that have need certificates
-    and put certificate requests on the queue
+    Find all students that need certificates
+    for courses that have finished and
+    put their cert requests on the queue
 
-    This is only for BerkeleyX/CS169.1x/2012_Fall
+    Use the --noop option to test without actually
+    putting certificates on the queue to be generated.
     """
 
+    option_list = BaseCommand.option_list + (
+        make_option('-n', '--noop',
+            action='store_true',
+            dest='noop',
+            default=False,
+            help="Don't add certificate requests to the queue"),
+        make_option('-c', '--course',
+            metavar='COURSE_ID',
+            dest='course',
+            default=False,
+            help='Grade and generate certificates for a specific course'),
+
+        )
+
     def handle(self, *args, **options):
 
-        # TODO This is only temporary for CS169 certs
-
-        course_id = 'BerkeleyX/CS169.1x/2012_Fall'
-        enrolled_students = User.objects.filter(
-                courseenrollment__course_id=course_id).prefetch_related(
-                        "groups").order_by('username')
-        xq = XQueueCertInterface()
-        for student in enrolled_students:
-            if certificate_status_for_student(
-                     student, course_id)['status'] == 'unavailable':
-                ret = xq.add_cert(student, course_id)
-                if ret == 'generating':
-                    print 'generating for {0}'.format(student)
+        # Will only generate a certificate if the current
+        # status is in this state
+
+        VALID_STATUSES = [
+                 CertificateStatuses.unavailable
+        ]
+
+        # Print update after this many students
+
+        STATUS_INTERVAL = 500
+
+        if options['course']:
+            ended_courses = [options['course']]
+        else:
+            # Find all courses that have ended
+            ended_courses = []
+            for course_id in [course  # all courses in COURSE_LISTINGS
+                    for sub in settings.COURSE_LISTINGS
+                        for course in settings.COURSE_LISTINGS[sub]]:
+                course_loc = CourseDescriptor.id_to_location(course_id)
+                course = modulestore().get_instance(course_id, course_loc)
+                if course.has_ended():
+                    ended_courses.append(course_id)
+
+        for course_id in ended_courses:
+            print "Fetching enrolled students for {0}".format(course_id)
+            enrolled_students = User.objects.filter(
+                    courseenrollment__course_id=course_id).prefetch_related(
+                            "groups").order_by('username')
+            xq = XQueueCertInterface()
+            total = enrolled_students.count()
+            count = 0
+            start = datetime.datetime.now()
+            for student in enrolled_students:
+                count += 1
+                if count % STATUS_INTERVAL == 0:
+                    # Print a status update with an approximation of
+                    # how much time is left based on how long the last
+                    # interval took
+                    diff = datetime.datetime.now() - start
+                    timeleft = diff * (total - count) / STATUS_INTERVAL
+                    hours, remainder = divmod(timeleft.seconds, 3600)
+                    minutes, seconds = divmod(remainder, 60)
+                    print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format(
+                            count, total, hours, minutes)
+                    start = datetime.datetime.now()
+
+                if certificate_status_for_student(
+                     student, course_id)['status'] in VALID_STATUSES:
+                    if not options['noop']:
+                        # Add the certificate request to the queue
+                        ret = xq.add_cert(student, course_id)
+                        if ret == 'generating':
+                            print '{0} - {1}'.format(student, ret)