Adds predefined AD Schema modifications related to RBAC
   Implements predefined schema mods like sshpublickey, sudoroles, and LAPS.
   Must be run from a Domain Controller with Schema admin rights
   Add-ADSchemaMod -name sshpublickey
     Adds 'sshPublicKey' attribute to user objects in AD. This allows you to define public key auth centrally and avoid trhe use of authorized_keys.
     This requires a correctly-configured sssd and sshd on the Linux clients, example below:
        services = nss, pam, sudo, ssh
        ldap_user_extra_attrs = sshPublicKey:sshPublicKey,phone:telephoneNumber,email:mail
        ldap_user_ssh_public_key = sshPublicKey
        AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
        AuthorizedKeysCommandUser nobody
   Add-ADSchemaMod -name SudoRoles
      Adds 'sudoRole' object definition to the schema, allowing Linux hosts using a correctly-configured sssd to pull sudoers definitions via LDAP.
      Examples of this config can be found under the `misc` folder, but the key elements are a correctly-configured nsswitch.conf and sssd.conf:
         sudoers: sss files
      sssd.conf: (replace variables)
         services = nss, pam, sudo, ssh
         ldap_netgroup_search_base = OU=Netgroups,OU=LinuxFeatures,DC=$DOMAIN?subtree?
         ldap_sudo_search_base = OU=SudoRoles,OU=LinuxFeatures,DC=$DOMAIN?subtree?
   Add-ADSchemaMod -name LAPS
   Requires Schema Admin, Enterprise Admin, and Domain Admin.
   This will briefly turn on the "Schema Updates Allowed" registry setting for NTDS

function add-ADSchemaMod {
        # The name of the schema modification. Tab-completion will show available options
        [ValidateScript({[bool](get-RBACSchemaMods -name $_)})]
        [ArgumentCompleter( {@((get-RBACSchemaMods).name)})]
    begin {
        $DomainProperties = get-ADDomain
        $domainDN = $domainProperties.distinguishedName
        $DomainDNS = $domainProperties.DNSRoot
        $DomainSID = $domainProperties.DomainSID
        $SID_DomainAdmin = "$DomainSID-512"
        $SID_EnterpriseAdmin = "$DomainSID-519"
        $SID_SchemaAdmin = "$DomainSID-518"
        $GroupInfo = get-currentUserGroups

        $PreChecks = @{
            IsDomainAdmin = $groupInfo.sid.contains($SID_DomainAdmin)
            IsEnterpriseAdmin = $groupInfo.sid.contains($SID_EnterpriseAdmin)
            IsSchemaAdmin = $groupInfo.sid.contains($SID_SchemaAdmin)
            OnDomainController = [bool](get-wmiObject -query "Select * from Win32_OperatingSystem where ProductType='2'")
        if ($PreChecks.values -contains $false) {
            Write-warning "Please run this from a domain controller with Domain-, Enterprise-, and Schema-Admin rights."
            Write-warning "See below for failing checks"
            foreach ($check in $PreChecks.getEnumerator()) {
                write-warning (" * {0,-24} : {1}" -f $, $check.value)
        $schemaBaseDirectory = "\\$DomainDNS\SYSVOL\$DomainDNS"
        $registryMod = @{
            path = "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\Parameters"
            Name = "Schema Update Allowed"
        if ($PSCmdlet.ShouldProcess("$($registryMod.path) : $($registryMod.Name)","Enabling Schema modifications in registry")) {
            New-ItemProperty @RegistryMod -propertyType DWord -value 1 -confirm:$false
    Process {
        $schemaDef = get-RBACSchemaMods -name $name
        $modName = $
        $LDIF_Document = $schemaDef.Value.LDIF_Document
        $SchemaCommand = $schemaDef.Value.Command
        $schemaFileName = "$modName.schema.activeDirectory"
        $schemaFilePath = "$schemaBaseDirectory\$SchemaFileName"
        if ($LDIF_Document) {
            if ($PSCmdlet.ShouldProcess($SchemaFilePath, "Importing Schema file")) {
                $LDIF_Document | out-file -filePath $SchemaFilePath
                ldifde -i -f $schemaFilePath -c "CN=Schema,CN=Configuration,DC=X" "CN=Schema,CN=Configuration,$DomainDN" -j "C:\"
        if ($SchemaCommand) {
            if ($PSCmdlet.ShouldProcess($schemaCommand,"Running Schema Command")) {
                invoke-Expression -command $schemaCommand

    End {
        if ($PSCmdlet.ShouldProcess("$($registryMod.path) : $($registryMod.Name)","Disabling Schema modifications in registry")) {
            Remove-ItemProperty @RegistryMod -confirm:$False