Jump to content

Recommended Posts

Posted

Introductory Notes;

This script is intended as an add-on for the “Managing Google Classroom with SIMS data in Powershell (In a MAT environment) V9” script (though you could run this happily on it's own). Whilst syncing your Google Classrooms with SIMS is incredibly useful, sometimes you might need additional classrooms that automatically sync with a group of people (e.g. for Staff Training).

 

The aim of this script is to treat an AD OU containing Groups as an authoritative source for additional Google Classrooms. AD Group names will be converted to match the Google Classroom Alias names agreed by the Trust, and students and the class teacher will be determined by the AD Group membership and other Group attributes.

 

Google Classrooms will remain in place as long as the AD Group exists, has students, and has a valid Teacher.

 

Requirements;

  • A tested and operational GAMADV (4.83.04+) installation.
  • Your Teachers and Students gmail addresses to be stored in AD.
  • A dedicated AD OU, containing only Groups to be used for this script.
  • A Group attribute pointing at the Class Teacher’s AD User (I like to use the “ManagedBy” group attribute).

 

AD Group Setup;

Our Custom Classes Group OU looks like this;

Screenshot 2019-06-05 at 13.03.25.png

Each class group can contain users and/or other groups. Our GDPR class contains our All-Staff group;

Screenshot 2019-06-05 at 13.04.55.png

I use the “Managed By” attribute to determine the class teacher;

Screenshot 2019-06-05 at 13.09.09.png

And that’s it - Additional teachers can of course be invited by the Class Owner.

 

What The Script Does;

  • Lines 3-5 set the AD variables, including the AD User attribute you use to store your gmail addresses, the AD Group attribute where you store your Class Teacher, and the OU where you’re storing your classes.
  • Lines 7-11 set the paths required to run the script.
  • Lines 13-16 set your School Prefix and your email settings.
  • Lines 19-50 setup some counters, check/create the file paths and create a Log file.
  • Lines 52-58 clear the data from the last time the script ran.
  • Lines 60-63 download a list of current Google Classrooms.
  • Lines 69-76 searches the specified AD OU for groups that have the Teacher attribute set and have members. The Google class Alias is then determined by adding the School Prefix and “Custom_” to the Group Name and replacing any spaces with underscores. This Alias is then set as the AD Group description attribute. The email address of the class teacher is grabbed.
  • Lines 77-102 determine if the custom class has already been created. If so, then the script check whether the existing Google Class owner matches the AD Group teacher, and updates this if required. If the class does not exist, then it is created.
  • Lines 104-120 grab all members of the AD Group and add their email addresses to a CSV file.
  • Lines 122-126 sync the members of the Google Classroom with the CSV file created in lines 104-120.
  • Lines 137-155 check the Google Classroom data collected in lines 60-63 for classes matching the name “Custom_”. If a matching AD Group Description cannot be found, then the Google Classroom is archived.
  • Lines 159-189 email the results of the script and the logfile.

Posted
##Set preferences
#AD Settings (Used if you're using  AD to store/verify your Staff/Student addresses)
   $MailVariable = "gmail" ##AD option used to store email address.
   $OwnerVariable = "ManagedBy" ##AD option used to store Class Owner.
   $ClassGroupOU = "OU=CustomClasses,OU=Classes,OU=School Groups,DC=myschool,DC=com"
#File Paths and Misc Settings
   $LogfilePath = ".\Logs\" ##Path where log files are created.
   $Classfilepath = ".\ClassData\" ##Path where data file is created.
   $GAMPath = "C:\GAM\GAMADV\gam.exe" ##Path where GAMADV is installed.
   $GAMData = ".\GAMData\" ##Path where GAM data is recorded.
   $GAMDataSize = "10KB" ##Minimum expected size for successfully exported GAM Data
#School and Email Settings
   $SchoolPrefix = "MySchool" ##Prefix to add to Class Alias to prevent MAT conflicts.
   $SMTPServer = "aspmx.l.google.com" ##SMTP server for emailing log files.
   $SMTPTo = "Alerts " ##Recipient address for log files.
   $SMTPFrom = "DC001 " ##Sender address for log files.
##/Set preferences

Import-Module ActiveDirectory
$dnsroot = '@' + (Get-ADDomain).dnsroot

##Determine Start Time
$StartTime = Get-Date

##Setup Counters
$ClassCreated = 0
$ClassModified = 0
$ClassRemoved = 0
$InvalidClass = 0

##Check paths
if (Test-Path -Path $LogfilePath) {
   #"Log folder exists"
} else {
   New-Item $LogfilePath -type directory #Creates log folder.
}
if (Test-Path -Path $Classfilepath) {
   #"Class Data folder exists"
} else {
   New-Item $Classfilepath -type directory #Creates log folder.
}
if (Test-Path -Path $GAMData) {
   #"GAM Data folder exists"
} else {
   New-Item $GAMData -type directory #Creates log folder.
}

##Set Logfile Name
$Logfilename = Get-Date -UFormat "%Y%m%d"
$Logfile = $Logfilepath + $Logfilename + ".txt"

##Clear old GAM data
Write-Host "Clearing old GAM data files...." -ForegroundColor Green
Get-ChildItem -Path $GAMData -Recurse -Force | Remove-Item -Force

##Clear old Class data
Write-Host "Clearing old Class data files...." -ForegroundColor Green
Get-ChildItem -Path $Classfilepath -Recurse -Force | Remove-Item -Force

##Export Current Google Classes
Write-Host "Grabbing list of existing Google Classrooms....." -ForegroundColor Green
$GAMCurrent = $GAMData + 'GAMCurrent.csv'
& $GAMPath print courses state provisioned state active state declined alias fields id fields name fields courseState owneremail > $GAMCurrent 2> $null

## Check that GAM data exists
if ((Test-Path -Path $GAMCurrent) -And (Get-Item $GAMCurrent).Length -gt $GAMDataSize) {
   Write-Host "Grabbing list of existing Google Classrooms - Success!" -ForegroundColor Green
   Write-Host "Searching for Custom Class Groups in $ClassGroupOU" -ForegroundColor Green
   $ClassGroups = Get-ADGroup -Filter * -Properties * -SearchBase $ClassGroupOU | Where {($_.$OwnerVariable -ne $null)} | Where {$_.members} ##Grab groups with members and Owner set.
   foreach ($ClassGroup in $ClassGroups) {
       $ClassName = $ClassGroup.Name
       $ClassAlias = $SchoolPrefix + "Custom_" + $Classname -replace ' ','_'
       $ClassDN = $ClassGroup.DistinguishedName
       $ClassOwner = $ClassGroup.$OwnerVariable
       $ClassOwnerEmail = Get-ADUser -Identity $ClassOwner -Properties * | Select-Object -ExpandProperty $MailVariable
       Set-ADGroup $ClassDN -Description $ClassAlias ##Sets Group description to $ClassAlias for valid class matching.
       if ($ClassOwnerEmail) {
           $ExistingCourseList = Import-Csv -Path $GAMCurrent | Where {$_.Aliases -eq $ClassAlias }
           if ($ExistingCourseList) {
               foreach ($Item in $ExistingCourseList){
                   $CurrentOwner = $Item.ownerEmail
               }
               if (($CurrentOwner -eq $ClassOwnerEmail)) {
                   Write-Host "Owner for class $ClassAlias already set" -ForegroundColor Blue
               } else {
                   Write-Host "Google Classroom $ClassAlias already exists - changing owner to $ClassOwnerEmail and reset course to provisioned." -ForegroundColor Green
                   $Loginfo = 'Google Classroom ' + $ClassAlias + ' already exists - changing owner to ' + $ClassOwnerEmail + ' and reset course to provisioned.'
                   "$Loginfo" | Out-File $Logfile -append
                   $ClassModified = $ClassModified + 1
                   & $GAMPath update course $ClassAlias status PROVISIONED 2> $null
                   & $GAMPath course $ClassAlias add teacher $ClassOwnerEmail 2> $null
                   & $GAMPath update course $ClassAlias owner $ClassOwnerEmail 2> $null
               }
           } else {
               Write-Host "Creating Google Classroom $ClassAlias with teacher $ClassOwnerEmail" -ForegroundColor Green
               ##Write to log file##
               $Loginfo = 'Created Google Classroom ' + $ClassAlias + ' with ' + $ClassOwnerEmail
               "$Loginfo" | Out-File $Logfile -append
               $ClassCreated = $ClassCreated + 1
               & $GAMPath create course alias $ClassAlias name $ClassName teacher $ClassOwnerEmail 2> $null
               & $GAMPath course $ClassAlias add teacher $ClassOwnerEmail 2> $null
           }

           $Students = Get-ADGroupMember $ClassDN -Recursive | Where {$_.objectclass -eq 'user'} | Get-ADUSer -Properties * | Where {$_.$MailVariable -ne $null}
           $StudCount = @($Students).count
           Write-Host "Generating CSV for class $ClassAlias with $StudCount students." -ForegroundColor Green 
           foreach ($Student in $Students) {
               $UserInfo = Get-ADUser -Identity $Student -Properties *
               $StudName = $UserInfo.displayname
               $StudEmail = $UserInfo.$MailVariable
               $Classfile = $Classfilepath + $ClassAlias + ".csv"
               if((Test-Path -Path $Classfile )){ #Check to see if file has already been created
                   #"Class file already exists"
               } else {
                   $Classhead = 'Email'
                   "$Classhead" | Out-File $Classfile -append #Create Blank class file
               }
   
               "$StudEmail" | Out-File $Classfile -append #Add student's email address to class file.
           }

           Write-Host "Syncing $StudCount students with Google Classroom $ClassAlias" -ForegroundColor Green
           $RawCourseCSV = $Classfilepath + "Raw_" + $ClassAlias + ".csv"
           Get-Content $Classfile -Raw | Set-Content $RawCourseCSV #Reencode course CSV to RAw so that it can be read by GAM.
           $CSVFile = $RawCourseCSV + ":Email" #Set the source CSV file and data field for the sync.
           & $GAMPath course "$ClassAlias" sync students csvfile $CSVFile 2> $null

       } else {
           Write-Host "Teacher for group $ClassAlias does not have $MailVariable set." -ForegroundColor Red
           $Loginfo = 'Teacher for group ' + $ClassAlias + ' does not have ' + $MailVariable + " set."
           "$Loginfo" | Out-File $Logfile -append
           $InvalidClass = $InvalidClass + 1
       }

   }

   ##Archive old Custom Classes
   $ClassPrefix = $SchoolPrefix + "Custom_*"
   $ExistingCourseList = Import-Csv -Path $GAMCurrent | Where-Object {$_.Aliases -like $ClassPrefix}
   if ($ExistingCourseList) {
       foreach ($Item in $ExistingCourseList){
           $ClassName = $Item.Aliases
           $ADClassGroup = Get-ADGroup -Filter {Description -eq $ClassName} -SearchBase $ClassGroupOU ##Grab groups with members and Owner set.
           if ($ADClassGroup) {
               Write-Host "Matching group found for $ClassName" -ForegroundColor Green
           } else {
               Write-Host "No matching group found for $ClassName" -ForegroundColor Red
               $Loginfo = $ClassAlias + ' does not match any existing AD Group.  Setting status to ARCHIVED.'
               "$Loginfo" | Out-File $Logfile -append
               $ClassRemoved = $ClassRemoved + 1
               & $GAMPath update course $ClassName status ARCHIVED 2> $null
           }
           
       }
   }

}

##Determine End Time
$TotalTime = $("{0:hh\:mm\:ss}" -f (New-TimeSpan -Start $StartTime -End $(Get-Date)))

Write-Host "Script completed in $TotalTime" -ForegroundColor Green

##Script completes successfully - Email log file##
if((Test-Path -Path $Logfile)){ #Test to see if anything has been logged
   $EmailOptions = @{
       'SMTPServer' = $SMTPServer
       'To' = $SMTPTo
       'From' = $SMTPFrom
       'Subject' = "Results from Google Custom Classes Script"
       'Body' = "Script completed in $TotalTime
Classes Created:  $ClassCreated
Classes Modified: $ClassModified
Classes Removed:  $ClassRemoved
Invalid Classes:  $InvalidClass"
       'Attachments' = $Logfile
   }
   Send-MailMessage @emailOptions
} else {
   $EmailOptions = @{
       'SMTPServer' = $SMTPServer
       'To' = $SMTPTo
       'From' = $SMTPFrom
       'Subject' = "Results from Google Custom Classes Script"
       'Body' = "No changes today.
Script completed in $TotalTime minutes."
   }
   Send-MailMessage @emailOptions
}

  • 2 weeks later...
Posted

Google very kindly introduced a "feature" this week, where the API now returns a list of all your classes including the deleted ones. As there's currently no way to identify the deleted classes (there's no "DELETED" status), Ross over at GAMADV has very quickly worked his magic, and updated GAM to compensate for classes that are listed, but not actually there.......

 

So, in a nutshell, update to at least GAMADV 4.86.07

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...