Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

@ -0,0 +1,58 @@
# A demo for the IDsObjectPicker interface.
import win32clipboard
import pythoncom
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
cf_objectpicker = win32clipboard.RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST)
def main():
hwnd = 0
# Create an instance of the object picker.
picker = pythoncom.CoCreateInstance(adsi.CLSID_DsObjectPicker,
None,
pythoncom.CLSCTX_INPROC_SERVER,
adsi.IID_IDsObjectPicker)
# Create our scope init info.
siis = adsi.DSOP_SCOPE_INIT_INFOs(1)
sii = siis[0]
# Combine multiple scope types in a single array entry.
sii.type = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | \
DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN
# Set uplevel and downlevel filters to include only computer objects.
# Uplevel filters apply to both mixed and native modes.
# Notice that the uplevel and downlevel flags are different.
sii.filterFlags.uplevel.bothModes = DSOP_FILTER_COMPUTERS
sii.filterFlags.downlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS
# Initialize the interface.
picker.Initialize(
None, # Target is the local computer.
siis, # scope infos
DSOP_FLAG_MULTISELECT, # options
('objectGUID','displayName') ) # attributes to fetch
do = picker.InvokeDialog(hwnd)
# Extract the data from the IDataObject.
format_etc = (cf_objectpicker, None,
pythoncom.DVASPECT_CONTENT, -1,
pythoncom.TYMED_HGLOBAL)
medium = do.GetData(format_etc)
data = adsi.StringAsDS_SELECTION_LIST(medium.data)
for item in data:
name, klass, adspath, upn, attrs, flags = item
print("Item", name)
print(" Class:", klass)
print(" AdsPath:", adspath)
print(" UPN:", upn)
print(" Attrs:", attrs)
print(" Flags:", flags)
if __name__=='__main__':
main()

View file

@ -0,0 +1,492 @@
"""A re-implementation of the MS DirectoryService samples related to services.
* Adds and removes an ActiveDirectory "Service Connection Point",
including managing the security on the object.
* Creates and registers Service Principal Names.
* Changes the username for a domain user.
Some of these functions are likely to become move to a module - but there
is also a little command-line-interface to try these functions out.
For example:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
--keyword=foo --keyword=bar --binding-string=bind_info \\
ScpCreate SpnCreate SpnRegister
would:
* Attempt to delete a Service Connection Point for the service class
'PythonScpTest'
* Attempt to create a Service Connection Point for that class, with 2
keywords and a binding string of 'bind_info'
* Create a Service Principal Name for the service and register it
to undo those changes, you could execute:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
SpnCreate SpnUnregister ScpDelete
which will:
* Create a SPN
* Unregister that SPN from the Active Directory.
* Delete the Service Connection Point
Executing with --test will create and remove one of everything.
"""
from win32com.adsi.adsicon import *
from win32com.adsi import adsi
import win32api, win32con, winerror
from win32com.client import Dispatch
import ntsecuritycon as dscon
import win32security
import optparse, textwrap
import traceback
verbose = 1
g_createdSCP = None
g_createdSPNs = []
g_createdSPNLast = None
import logging
logger = logging # use logging module global methods for now.
# still a bit confused about log(n, ...) vs logger.info/debug()
# Returns distinguished name of SCP.
def ScpCreate(
service_binding_info,
service_class_name, # Service class string to store in SCP.
account_name = None, # Logon account that needs access to SCP.
container_name = None,
keywords = None,
object_class = "serviceConnectionPoint",
dns_name_type = "A",
dn = None,
dns_name = None,
):
container_name = container_name or service_class_name
if not dns_name:
# Get the DNS name of the local computer
dns_name = win32api.GetComputerNameEx(win32con.ComputerNameDnsFullyQualified)
# Get the distinguished name of the computer object for the local computer
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
# Publish the SCP as a child of the computer object
keywords = keywords or []
# Fill in the attribute values to be stored in the SCP.
attrs = [
("cn", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (container_name,)),
("objectClass", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (object_class,)),
("keywords", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, keywords),
("serviceDnsName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (dns_name,)),
("serviceDnsNameType", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (dns_name_type,)),
("serviceClassName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (service_class_name,)),
("serviceBindingInformation", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (service_binding_info,)),
]
new = comp.CreateDSObject("cn=" + container_name, attrs)
logger.info("New connection point is at %s", container_name)
# Wrap in a usable IDispatch object.
new = Dispatch(new)
# And allow access to the SCP for the specified account name
AllowAccessToScpProperties(account_name, new)
return new
def ScpDelete(container_name, dn = None):
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("Removing connection point '%s' from %s", container_name, dn)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
comp.DeleteDSObject("cn=" + container_name)
logger.info("Deleted service connection point '%s'", container_name)
# This function is described in detail in the MSDN article titled
# "Enabling Service Account to Access SCP Properties"
# From that article:
# The following sample code sets a pair of ACEs on a service connection point
# (SCP) object. The ACEs grant read/write access to the user or computer account
# under which the service instance will be running. Your service installation
# program calls this code to ensure that the service will be allowed to update
# its properties at run time. If you don't set ACEs like these, your service
# will get access-denied errors if it tries to modify the SCP's properties.
#
# The code uses the IADsSecurityDescriptor, IADsAccessControlList, and
# IADsAccessControlEntry interfaces to do the following:
# * Get the SCP object's security descriptor.
# * Set ACEs in the DACL of the security descriptor.
# * Set the security descriptor back on the SCP object.
def AllowAccessToScpProperties(
accountSAM, #Service account to allow access.
scpObject, # The IADs SCP object.
schemaIDGUIDs = # Attributes to allow write-access to.
("{28630eb8-41d5-11d1-a9c1-0000f80367c1}", # serviceDNSName
"{b7b1311c-b82e-11d0-afee-0000f80367c1}", # serviceBindingInformation
)
):
# If no service account is specified, service runs under LocalSystem.
# So allow access to the computer account of the service's host.
if accountSAM:
trustee = accountSAM
else:
# Get the SAM account name of the computer object for the server.
trustee = win32api.GetComputerObjectName(win32con.NameSamCompatible)
# Get the nTSecurityDescriptor attribute
attribute = "nTSecurityDescriptor"
sd = getattr(scpObject, attribute)
acl = sd.DiscretionaryAcl
for sguid in schemaIDGUIDs:
ace = Dispatch(adsi.CLSID_AccessControlEntry)
# Set the properties of the ACE.
# Allow read and write access to the property.
ace.AccessMask = ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP
# Set the trustee, which is either the service account or the
# host computer account.
ace.Trustee = trustee
# Set the ACE type.
ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
# Set AceFlags to zero because ACE is not inheritable.
ace.AceFlags = 0
# Set Flags to indicate an ACE that protects a specified object.
ace.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
# Set ObjectType to the schemaIDGUID of the attribute.
ace.ObjectType = sguid
# Add the ACEs to the DACL.
acl.AddAce(ace)
# Write the modified DACL back to the security descriptor.
sd.DiscretionaryAcl = acl
# Write the ntSecurityDescriptor property to the property cache.
setattr(scpObject, attribute, sd)
# SetInfo updates the SCP object in the directory.
scpObject.SetInfo()
logger.info("Set security on object for account '%s'" % (trustee,))
# Service Principal Names functions from the same sample.
# The example calls the DsWriteAccountSpn function, which stores the SPNs in
# Microsoft Active Directory under the servicePrincipalName attribute of the
# account object specified by the serviceAcctDN parameter. The account object
# corresponds to the logon account specified in the CreateService call for this
# service instance. If the logon account is a domain user account,
# serviceAcctDN must be the distinguished name of the account object in
# Active Directory for that user account. If the service's logon account is the
# LocalSystem account, serviceAcctDN must be the distinguished name of the
# computer account object for the host computer on which the service is
# installed. win32api.TranslateNames and win32security.DsCrackNames can
# be used to convert a domain\account format name to a distinguished name.
def SpnRegister(
serviceAcctDN, # DN of the service's logon account
spns, # List of SPNs to register
operation, # Add, replace, or delete SPNs
):
assert type(spns) not in [str, str] and hasattr(spns, "__iter__"), \
"spns must be a sequence of strings (got %r)" % spns
# Bind to a domain controller.
# Get the domain for the current user.
samName = win32api.GetUserNameEx(win32api.NameSamCompatible)
samName = samName.split('\\', 1)[0]
if not serviceAcctDN:
# Get the SAM account name of the computer object for the server.
serviceAcctDN = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("SpnRegister using DN '%s'", serviceAcctDN)
# Get the name of a domain controller in that domain.
info = win32security.DsGetDcName(
domainName=samName,
flags=dscon.DS_IS_FLAT_NAME |
dscon.DS_RETURN_DNS_NAME |
dscon.DS_DIRECTORY_SERVICE_REQUIRED)
# Bind to the domain controller.
handle = win32security.DsBind( info['DomainControllerName'] )
# Write the SPNs to the service account or computer account.
logger.debug("DsWriteAccountSpn with spns %s")
win32security.DsWriteAccountSpn(
handle, # handle to the directory
operation, # Add or remove SPN from account's existing SPNs
serviceAcctDN, # DN of service account or computer account
spns) # names
# Unbind the DS in any case (but Python would do it anyway)
handle.Close()
def UserChangePassword(username_dn, new_password):
# set the password on the account.
# Use the distinguished name to bind to the account object.
accountPath = "LDAP://" + username_dn
user = adsi.ADsGetObject(accountPath, adsi.IID_IADsUser)
# Set the password on the account.
user.SetPassword(new_password)
# functions related to the command-line interface
def log(level, msg, *args):
if verbose >= level:
print(msg % args)
class _NoDefault: pass
def _get_option(po, opt_name, default = _NoDefault):
parser, options = po
ret = getattr(options, opt_name, default)
if not ret and default is _NoDefault:
parser.error("The '%s' option must be specified for this operation" % opt_name)
if not ret:
ret = default
return ret
def _option_error(po, why):
parser = po[0]
parser.error(why)
def do_ScpCreate(po):
"""Create a Service Connection Point"""
global g_createdSCP
scp = ScpCreate(_get_option(po, "binding_string"),
_get_option(po, "service_class"),
_get_option(po, "account_name_sam", None),
keywords=_get_option(po, "keywords", None))
g_createdSCP = scp
return scp.distinguishedName
def do_ScpDelete(po):
"""Delete a Service Connection Point"""
sc = _get_option(po, "service_class")
try:
ScpDelete(sc)
except adsi.error as details:
if details[0] != winerror.ERROR_DS_OBJ_NOT_FOUND:
raise
log(2, "ScpDelete ignoring ERROR_DS_OBJ_NOT_FOUND for service-class '%s'",
sc)
return sc
def do_SpnCreate(po):
"""Create a Service Principal Name"""
# The 'service name' is the dn of our scp.
if g_createdSCP is None:
# Could accept an arg to avoid this?
_option_error(po, "ScpCreate must have been specified before SpnCreate")
# Create a Service Principal Name"
spns = win32security.DsGetSpn(dscon.DS_SPN_SERVICE,
_get_option(po, "service_class"),
g_createdSCP.distinguishedName,
_get_option(po, "port", 0),
None, None)
spn = spns[0]
log(2, "Created SPN: %s", spn)
global g_createdSPNLast
g_createdSPNLast = spn
g_createdSPNs.append(spn)
return spn
def do_SpnRegister(po):
"""Register a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnRegister")
SpnRegister(_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_ADD_SPN_OP)
return g_createdSPNLast
def do_SpnUnregister(po):
"""Unregister a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnUnregister")
SpnRegister(_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_DELETE_SPN_OP)
return g_createdSPNLast
def do_UserChangePassword(po):
"""Change the password for a specified user"""
UserChangePassword(_get_option(po, "account_name_dn"),
_get_option(po, "password"))
return "Password changed OK"
handlers = (
('ScpCreate', do_ScpCreate),
('ScpDelete', do_ScpDelete),
('SpnCreate', do_SpnCreate),
('SpnRegister', do_SpnRegister),
('SpnUnregister', do_SpnUnregister),
('UserChangePassword', do_UserChangePassword),
)
class HelpFormatter(optparse.IndentedHelpFormatter):
def format_description(self, description):
return description
def main():
global verbose
_handlers_dict = {}
arg_descs = []
for arg, func in handlers:
this_desc = "\n".join(textwrap.wrap(func.__doc__,
subsequent_indent = " " * 8))
arg_descs.append(" %s: %s" % (arg, this_desc))
_handlers_dict[arg.lower()] = func
description = __doc__ + "\ncommands:\n" + "\n".join(arg_descs) + "\n"
parser = optparse.OptionParser(usage = "%prog [options] command ...",
description=description,
formatter=HelpFormatter())
parser.add_option("-v", action="count",
dest="verbose", default=1,
help="increase the verbosity of status messages")
parser.add_option("-q", "--quiet", action="store_true",
help="Don't print any status messages")
parser.add_option("-t", "--test", action="store_true",
help="Execute a mini-test suite, providing defaults for most options and args"),
parser.add_option("", "--show-tracebacks", action="store_true",
help="Show the tracebacks for any exceptions")
parser.add_option("", "--service-class",
help="The service class name to use")
parser.add_option("", "--port", default=0,
help="The port number to associate with the SPN")
parser.add_option("", "--binding-string",
help="The binding string to use for SCP creation")
parser.add_option("", "--account-name",
help="The account name to use (default is LocalSystem)")
parser.add_option("", "--password",
help="The password to set.")
parser.add_option("", "--keyword", action="append", dest="keywords",
help="""A keyword to add to the SCP. May be specified
multiple times""")
parser.add_option("", "--log-level",
help="""The log-level to use - may be a number or a logging
module constant""", default=str(logging.WARNING))
options, args = parser.parse_args()
po = (parser, options)
# fixup misc
try:
options.port = int(options.port)
except (TypeError, ValueError):
parser.error("--port must be numeric")
# fixup log-level
try:
log_level = int(options.log_level)
except (TypeError, ValueError):
try:
log_level = int(getattr(logging, options.log_level.upper()))
except (ValueError, TypeError, AttributeError):
parser.error("Invalid --log-level value")
try:
sl = logger.setLevel
# logger is a real logger
except AttributeError:
# logger is logging module
sl = logging.getLogger().setLevel
sl(log_level)
# Check -q/-v
if options.quiet and options.verbose:
parser.error("Can't specify --quiet and --verbose")
if options.quiet:
options.verbose -= 1
verbose = options.verbose
# --test
if options.test:
if args:
parser.error("Can't specify args with --test")
args = "ScpDelete ScpCreate SpnCreate SpnRegister SpnUnregister ScpDelete"
log(1, "--test - pretending args are:\n %s", args)
args = args.split()
if not options.service_class:
options.service_class = "PythonScpTest"
log(2, "--test: --service-class=%s", options.service_class)
if not options.keywords:
options.keywords = "Python Powered".split()
log(2, "--test: --keyword=%s", options.keywords)
if not options.binding_string:
options.binding_string = "test binding string"
log(2, "--test: --binding-string=%s", options.binding_string)
# check args
if not args:
parser.error("No command specified (use --help for valid commands)")
for arg in args:
if arg.lower() not in _handlers_dict:
parser.error("Invalid command '%s' (use --help for valid commands)" % arg)
# Patch up account-name.
if options.account_name:
log(2, "Translating account name '%s'", options.account_name)
options.account_name_sam = win32security.TranslateName(options.account_name,
win32api.NameUnknown,
win32api.NameSamCompatible)
log(2, "NameSamCompatible is '%s'",options.account_name_sam)
options.account_name_dn = win32security.TranslateName(options.account_name,
win32api.NameUnknown,
win32api.NameFullyQualifiedDN)
log(2, "NameFullyQualifiedDNis '%s'",options.account_name_dn)
# do it.
for arg in args:
handler = _handlers_dict[arg.lower()] # already been validated
if handler is None:
parser.error("Invalid command '%s'" % arg)
err_msg = None
try:
try:
log(2, "Executing '%s'...", arg)
result = handler(po)
log(1, "%s: %s", arg, result)
except:
if options.show_tracebacks:
print("--show-tracebacks specified - dumping exception")
traceback.print_exc()
raise
except adsi.error as xxx_todo_changeme:
(hr, desc, exc, argerr) = xxx_todo_changeme.args
if exc:
extra_desc = exc[2]
else:
extra_desc = ""
err_msg = desc
if extra_desc:
err_msg += "\n\t" + extra_desc
except win32api.error as xxx_todo_changeme1:
(hr, func, msg) = xxx_todo_changeme1.args
err_msg = msg
if err_msg:
log(1, "Command '%s' failed: %s", arg, err_msg)
if __name__=='__main__':
try:
main()
except KeyboardInterrupt:
print("*** Interrupted")

View file

@ -0,0 +1,132 @@
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
from win32com.adsi import adsicon
import pythoncom, pywintypes, win32security
options = None # set to optparse options object
ADsTypeNameMap = {}
def getADsTypeName(type_val):
# convert integer type to the 'typename' as known in the headerfiles.
if not ADsTypeNameMap:
for n, v in adsicon.__dict__.items():
if n.startswith("ADSTYPE_"):
ADsTypeNameMap[v] = n
return ADsTypeNameMap.get(type_val, hex(type_val))
def _guid_from_buffer(b):
return pywintypes.IID(b, True)
def _sid_from_buffer(b):
return str(pywintypes.SID(b))
_null_converter = lambda x: x
converters = {
'objectGUID' : _guid_from_buffer,
'objectSid' : _sid_from_buffer,
'instanceType' : getADsTypeName,
}
def log(level, msg, *args):
if options.verbose >= level:
print("log:", msg % args)
def getGC():
cont = adsi.ADsOpenObject("GC:", options.user, options.password, 0, adsi.IID_IADsContainer)
enum = adsi.ADsBuildEnumerator(cont)
# Only 1 child of the global catalog.
for e in enum:
gc = e.QueryInterface(adsi.IID_IDirectorySearch)
return gc
return None
def print_attribute(col_data):
prop_name, prop_type, values = col_data
if values is not None:
log(2, "property '%s' has type '%s'", prop_name, getADsTypeName(prop_type))
value = [converters.get(prop_name, _null_converter)(v[0]) for v in values]
if len(value) == 1:
value = value[0]
print(" %s=%r" % (prop_name, value))
else:
print(" %s is None" % (prop_name,))
def search():
gc = getGC()
if gc is None:
log(0, "Can't find the global catalog")
return
prefs = [(ADS_SEARCHPREF_SEARCH_SCOPE, (ADS_SCOPE_SUBTREE,))]
hr, statuses = gc.SetSearchPreference(prefs)
log(3, "SetSearchPreference returned %d/%r", hr, statuses)
if options.attributes:
attributes = options.attributes.split(",")
else:
attributes = None
h = gc.ExecuteSearch(options.filter, attributes)
hr = gc.GetNextRow(h)
while hr != S_ADS_NOMORE_ROWS:
print("-- new row --")
if attributes is None:
# Loop over all columns returned
while 1:
col_name = gc.GetNextColumnName(h)
if col_name is None:
break
data = gc.GetColumn(h, col_name)
print_attribute(data)
else:
# loop over attributes specified.
for a in attributes:
try:
data = gc.GetColumn(h, a)
print_attribute(data)
except adsi.error as details:
if details[0] != E_ADS_COLUMN_NOT_SET:
raise
print_attribute( (a, None, None) )
hr = gc.GetNextRow(h)
gc.CloseSearchHandle(h)
def main():
global options
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write report to FILE", metavar="FILE")
parser.add_option("-v", "--verbose",
action="count", default=1,
help="increase verbosity of output")
parser.add_option("-q", "--quiet",
action="store_true",
help="suppress output messages")
parser.add_option("-U", "--user",
help="specify the username used to connect")
parser.add_option("-P", "--password",
help="specify the password used to connect")
parser.add_option("", "--filter",
default = "(&(objectCategory=person)(objectClass=User))",
help="specify the search filter")
parser.add_option("", "--attributes",
help="comma sep'd list of attribute names to print")
options, args = parser.parse_args()
if options.quiet:
if options.verbose != 1:
parser.error("Can not use '--verbose' and '--quiet'")
options.verbose = 0
if args:
parser.error("You need not specify args")
search()
if __name__=='__main__':
main()

View file

@ -0,0 +1,247 @@
import sys, string
import pythoncom
import win32api
from win32com.adsi import *
verbose_level = 0
server = '' # Must have trailing /
local_name = win32api.GetComputerName()
def DumpRoot():
"Dumps the root DSE"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
for item in rootdse.Get("SupportedLDAPVersion"):
print("%s supports ldap version %s" % (path, item))
attributes = ["CurrentTime", "defaultNamingContext"]
for attr in attributes:
val = rootdse.Get(attr)
print(" %s=%s" % (attr, val))
###############################################
#
# Code taken from article titled:
# Reading attributeSchema and classSchema Objects
def _DumpClass(child):
attrs = "Abstract lDAPDisplayName schemaIDGUID schemaNamingContext attributeSyntax oMSyntax"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpAttribute(child):
attrs = "lDAPDisplayName schemaIDGUID adminDescription adminDisplayName rDNAttID defaultHidingValue defaultObjectCategory systemOnly defaultSecurityDescriptor"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpTheseAttributes(child, attrs):
for attr in attrs:
try:
val = child.Get(attr)
except pythoncom.com_error as details:
continue
# ###
(hr, msg, exc, arg) = details
if exc and exc[2]: msg = exc[2]
val = "<Error: %s>" % (msg,)
if verbose_level >= 2:
print(" %s: %s=%s" % (child.Class, attr, val))
def DumpSchema():
"Dumps the default DSE schema"
# Bind to rootDSE to get the schemaNamingContext property.
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("schemaNamingContext")
# Bind to the actual schema container.
path= "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
nclasses = nattr = nsub = nunk = 0
# Enumerate the attribute and class objects in the schema container.
for child in ob:
# Find out if this is a class, attribute, or subSchema object.
class_name = child.Class
if class_name == "classSchema":
_DumpClass(child)
nclasses = nclasses + 1
elif class_name == "attributeSchema":
_DumpAttribute(child)
nattr = nattr + 1
elif class_name == "subSchema":
nsub = nsub + 1
else:
print("Unknown class:", class_name)
nunk = nunk + 1
if verbose_level:
print("Processed", nclasses, "classes")
print("Processed", nattr, "attributes")
print("Processed", nsub, "sub-schema's")
print("Processed", nunk, "unknown types")
def _DumpObject(ob, level = 0):
prefix = " " * level
print("%s%s object: %s" % (prefix, ob.Class, ob.Name))
# Do the directory object thing
try:
dir_ob = ADsGetObject(ob.ADsPath, IID_IDirectoryObject)
except pythoncom.com_error:
dir_ob = None
if dir_ob is not None:
info = dir_ob.GetObjectInformation()
print("%s RDN='%s', ObjectDN='%s'" % (prefix, info.RDN, info.ObjectDN))
# Create a list of names to fetch
names = ["distinguishedName"]
attrs = dir_ob.GetObjectAttributes(names)
for attr in attrs:
for val, typ in attr.Values:
print("%s Attribute '%s' = %s" % (prefix, attr.AttrName, val))
for child in ob:
_DumpObject(child, level+1)
def DumpAllObjects():
"Recursively dump the entire directory!"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("defaultNamingContext")
# Bind to the actual schema container.
path= "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
# Enumerate the attribute and class objects in the schema container.
_DumpObject(ob)
##########################################################
#
# Code taken from article:
# Example Code for Enumerating Schema Classes, Attributes, and Syntaxes
# Fill a map with VT_ datatypes, to give us better names:
vt_map = {}
for name, val in pythoncom.__dict__.items():
if name[:3] == "VT_":
vt_map[val] = name
def DumpSchema2():
"Dumps the schema using an alternative technique"
path = "LDAP://%sschema" % (server,)
schema = ADsGetObject(path, IID_IADsContainer)
nclass = nprop = nsyntax = 0
for item in schema:
item_class = string.lower(item.Class)
if item_class == "class":
items = []
if item.Abstract: items.append("Abstract")
if item.Auxiliary: items.append("Auxiliary")
# if item.Structural: items.append("Structural")
desc = string.join(items, ", ")
import win32com.util
iid_name = win32com.util.IIDToInterfaceName(item.PrimaryInterface)
if verbose_level >= 2:
print("Class: Name=%s, Flags=%s, Primary Interface=%s" % (item.Name, desc, iid_name))
nclass = nclass + 1
elif item_class == "property":
if item.MultiValued:
val_type = "Multi-Valued"
else:
val_type = "Single-Valued"
if verbose_level >= 2:
print("Property: Name=%s, %s" % (item.Name, val_type))
nprop = nprop + 1
elif item_class == "syntax":
data_type = vt_map.get(item.OleAutoDataType, "<unknown type>")
if verbose_level >= 2:
print("Syntax: Name=%s, Datatype = %s" % (item.Name, data_type))
nsyntax = nsyntax + 1
if verbose_level >= 1:
print("Processed", nclass, "classes")
print("Processed", nprop, "properties")
print("Processed", nsyntax, "syntax items")
def DumpGC():
"Dumps the GC: object (whatever that is!)"
ob = ADsGetObject("GC:", IID_IADsContainer)
for sub_ob in ob:
print("GC ob: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalUsers():
"Dumps the local machine users"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["User", "Group"])
for sub_ob in ob:
print("User/Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalGroups():
"Dumps the local machine groups"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["Group"])
for sub_ob in ob:
print("Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
# get the members
members = sub_ob.Members()
for member in members:
print(" Group member: %s (%s)" % (member.Name, member.ADsPath))
def usage(tests):
import os
print("Usage: %s [-s server ] [-v] [Test ...]" % os.path.basename(sys.argv[0]))
print(" -v : Verbose - print more information")
print(" -s : server - execute the tests against the named server")
print("where Test is one of:")
for t in tests:
print(t.__name__,":", t.__doc__)
print()
print("If not tests are specified, all tests are run")
sys.exit(1)
def main():
import getopt, traceback
tests = []
for ob in globals().values():
if type(ob)==type(main) and ob.__doc__:
tests.append(ob)
opts, args = getopt.getopt(sys.argv[1:], "s:hv")
for opt, val in opts:
if opt=="-s":
if val[-1] not in "\\/":
val = val + "/"
global server
server = val
if opt=="-h":
usage(tests)
if opt=="-v":
global verbose_level
verbose_level = verbose_level + 1
if len(args)==0:
print("Running all tests - use '-h' to see command-line options...")
dotests = tests
else:
dotests = []
for arg in args:
for t in tests:
if t.__name__==arg:
dotests.append(t)
break
else:
print("Test '%s' unknown - skipping" % arg)
if not len(dotests):
print("Nothing to do!")
usage(tests)
for test in dotests:
try:
test()
except:
print("Test %s failed" % test.__name__)
traceback.print_exc()
if __name__=='__main__':
main()