我正在尝试运行LDAP查询,以获取过去30天内具有whenchanged
属性的已停用用户列表。查询
SELECT Name, description, profilePath, homeDrive, whenChanged, distinguishedName,userAccountControl
FROM 'LDAP://wusrcpsakc07.abc.com:3268/dc=SAK,dc=com'
WHERE objectCategory='user' and userAccountcontrol = '514'
运行正常。当我添加whenchanged
属性时,出现错误
SELECT Name, description, profilePath, homeDrive, whenChanged, distinguishedName,userAccountControl
FROM 'LDAP://wusrcpsakc07.abc.com:3268/dc=SAK,dc=com'
WHERE objectCategory='user' and userAccountcontrol = '514'
and whenChanged > getDate() - 30
答案 0 :(得分:2)
由于我熟悉SSIS / LDAP集成,我认为我将以Pavel的方向为基础。
我假设您正在使用ADO.NET源来处理数据流。使用过滤器使您的包正常工作,不包括日期逻辑。
您需要做的第一件事是创建一些SSIS变量。我喜欢变量,并且至少看到需要创建的4个变量。
DATEADD( "d",-30, @[System::StartTime] )
(DT_WSTR, 4)YEAR(@[User::SourceDate]) + RIGHT("0" + (DT_WSTR, 2)MONTH(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2) DAY(@[User::SourceDate]), 2) + "000000.0Z"
(DT_WSTR, 4)YEAR(@[User::SourceDate]) + RIGHT("0" + (DT_WSTR, 2)MONTH(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2) DAY(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2)DATEPART("hour", @[User::SourceDate] ), 2) + RIGHT("0" + (DT_WSTR, 2)DATEPART("minute", @[User::SourceDate] ), 2) + RIGHT("0" + (DT_WSTR, 2)DATEPART("second", @[User::SourceDate] ), 2) +".0Z"
SELECT Name, description, profilePath, homeDrive, whenChanged, distinguishedName, userAccountControl FROM 'LDAP://DC=home,DC=billfellows,DC=net' WHERE objectCategory='user' and userAccountcontrol = '514' AND whenChanged >= '
@[User::QueryBase] + @[User::ADTime] + "'"
看起来很多,但事实并非如此。让我们分解吧。
- SourceDate将在包裹开始时间前30天计算。
- ADTime - 这会构建一个YYYYMMDDHHMMSS.0Z字符串(日期后跟那些批评Ms的模糊用法的时间部分)这些将是0填充值,以确保像May这样的月表示为05而不是5
- QueryBase - 这提供了查询的基本框架,AND whenChanged >= '
这是一个不完整的查询,不解析但是它是静态的一块
- Query - 这使用QueryBase和ADTime将“dynamic”元素添加到查询中。由于AD无法处理动态部分,因此我们将如何欺骗它。我们通过交换日期和时间部分来构建每次执行的查询字符串。
ADO.NET查询编辑器可以与您定期使用的大多数脾气暴躁的SSIS项目相关联(是的,这是一个奖项)。与OLE DB Source组件不同,您无法在编辑器本身中指定您希望由Variable驱动它。 相反,您需要右键单击“数据流任务”并选择“属性”。
在结果窗口中,您将找到Expressions椭圆并单击它。
选择看起来像[ADO.NET源组件名称]的那个。[SqlCommand]并为其赋值@[User::Query]
。在下图中,您可以看到我调用了我的源组件“ADO AD”
支持和可维护性是我这样做的主要原因。通过单独构建变量,我可以通过在包中放置断点并检查元素或添加触发的脚本任务以及包含相关信息的信息消息来解决任何出错的问题。虽然我可以将所有可变逻辑放入源组件的SqlCommand属性,但调试是不可能的,因为SSIS没有为您提供检查Object上表达式的机制。
514未禁用。我的意思是,是,但userAccountControl
还有其他值可能表示已禁用。这是一个关于userAccountControl是否与2进行按位AND运算的问题2.看到最后的第一个链接是为了我悲伤的悲惨故事。
对于userAccountControl,值512是活动的AD帐户,514是禁用的帐户。我在其他团队的文档中有这个。不幸的是,这不太准确。该字段实际上是一个位掩码。在我们实施我的软件包后的一两年,我们了解到非活动人员出现在Feed中,这是不可能的,我们将其过滤掉(514s)。然后我了解到514实际上只是512(NORMAL_ACCOUNT)ORed与2(ACCOUNTDISABLE)。实施了一个自动化流程,创建了密码过期的帐户或一些无意义的帐户,其净结果为546(常规变为544 - 帐户已启用 - 要求用户在首次登录时更改密码)。
我非常喜欢将Biml与SSIS结合使用,因为它允许我与其他人“分享我的工作”,而无需邮寄包裹。以下代码基于我的Biml Active Directory SSIS Data Source帖子,并针对此特定情况进行了一些调整。请注意,我必须双击ADO.NET源组件,单击列,然后我收到警告
“ADO AD不支持在列”“上找到的数据类型”System.Object“。此列将转换为DT_NTEXT”
我确信有一种方法可以让Biml生成确切的包,但是,我只需点击几下即可获得这么少的“工作”。
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<AdoNetConnection Name="AD" ConnectionString="Data Source=HOME.BILLFELLOWS.NET;Provider=ADsDSOObject;Integrated Security=SSPI;" Provider="System.Data.OleDb.OleDbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</Connections>
<Packages>
<Package Name="so_23741312" DelayValidation="true" ForcedExecutionValueDataType="Empty" Language="None" ConstraintMode="Parallel" VersionBuild="5" CreatorName="bfellows" CreatorComputerName="WESTMARCH" CreationDate="2014-05-19T22:28:49">
<Variables>
<Variable Name="ADTime" DataType="String" IncludeInDebugDump="Exclude" EvaluateAsExpression="true">(DT_WSTR, 4)YEAR(@[User::SourceDate]) + RIGHT("0" + (DT_WSTR, 2)MONTH(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2) DAY(@[User::SourceDate]), 2) + "000000.0Z"</Variable>
<Variable Name="ADTimePedantic" DataType="String" IncludeInDebugDump="Exclude" EvaluateAsExpression="true">(DT_WSTR, 4)YEAR(@[User::SourceDate]) + RIGHT("0" + (DT_WSTR, 2)MONTH(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2) DAY(@[User::SourceDate]), 2) + RIGHT("0" + (DT_WSTR, 2)DATEPART("hour", @[User::SourceDate] ), 2)+ RIGHT("0" + (DT_WSTR, 2)DATEPART("minute", @[User::SourceDate] ), 2)+ RIGHT("0" + (DT_WSTR, 2)DATEPART("second", @[User::SourceDate] ), 2)+".0Z"</Variable>
<Variable Name="Query" DataType="String" IncludeInDebugDump="Exclude" EvaluateAsExpression="true">@[User::QueryBase] + @[User::ADTime] + "'"</Variable>
<Variable Name="QueryBase" DataType="String" IncludeInDebugDump="Exclude">SELECT Name, description, profilePath, homeDrive, whenChanged, distinguishedName, userAccountControl FROM 'LDAP://DC=home,DC=billfellows,DC=net' WHERE objectCategory='user' and userAccountcontrol = '514' AND whenChanged >= '</Variable>
<Variable Name="RowCountSource" DataType="Int32" IncludeInDebugDump="Include">0</Variable>
<Variable Name="SourceDate" DataType="DateTime" IncludeInDebugDump="Exclude" EvaluateAsExpression="true">DATEADD( "d",-30, @[System::StartTime] )</Variable>
</Variables>
<Tasks>
<Dataflow Name="DFT AD Extract" DelayValidation="true" ForcedExecutionValueDataType="Empty">
<Expressions>
<Expression ExternalProperty="[ADO AD].[SqlCommand]">@[User::Query]</Expression>
</Expressions>
<Transformations>
<AdoNetSource Name="ADO AD" LocaleId="None" ConnectionName="AD">
<DirectInput>SELECT Name, description, profilePath, homeDrive, whenChanged, distinguishedName, userAccountControl FROM 'LDAP://DC=home,DC=billfellows,DC=net' WHERE objectCategory='user' and userAccountcontrol = '514' AND whenChanged >= '20140419000000.0Z'</DirectInput>
</AdoNetSource>
<DerivedColumns Name="bit bucket Active" LocaleId="None">
<InputPath OutputPathName="CSPL Filter Inactive Accounts.ActiveAccounts" SsisName="CSPL Filter Inactive Accounts_ActiveAccounts_bit bucket Active" />
</DerivedColumns>
<DerivedColumns Name="bit bucket InActive" LocaleId="None">
<InputPath OutputPathName="CSPL Filter Inactive Accounts.Default" SsisName="CSPL Filter Inactive Accounts_Default_bit bucket InActive" />
</DerivedColumns>
<ConditionalSplit Name="CSPL Filter Inactive Accounts" LocaleId="None">
<InputPath OutputPathName="DER Check Account Status.Output" SsisName="DER Check Account Status_Output_CSPL Filter Inactive Accounts" />
<OutputPaths>
<OutputPath Name="ActiveAccounts">
<Expression>IsActive</Expression>
</OutputPath>
</OutputPaths>
</ConditionalSplit>
<DataConversion Name="DC NTEXT to DT_WSTR" LocaleId="None">
<InputPath OutputPathName="RC Source.Output" SsisName="RC Source_Output_DC NTEXT to DT_WSTR" />
<Columns>
<Column SourceColumn="distinguishedName" TargetColumn="distinguishedName" DataType="String" Length="500" />
<Column SourceColumn="description" TargetColumn="description" DataType="String" Length="500" />
<Column SourceColumn="Name" TargetColumn="Name" DataType="String" Length="500" />
<Column SourceColumn="userAccountControl" TargetColumn="userAccountControl" DataType="Int32" />
<Column SourceColumn="profilePath" TargetColumn="profilePath" DataType="String" Length="500" />
<Column SourceColumn="homeDrive" TargetColumn="homeDrive" DataType="String" Length="500" />
</Columns>
</DataConversion>
<DerivedColumns Name="DER Check Account Status" LocaleId="None">
<InputPath OutputPathName="DC NTEXT to DT_WSTR.Output" SsisName="DC NTEXT to DT_WSTR_Output_DER Check Account Status" />
<Columns>
<Column Name="IsActive" DataType="Boolean">(([userAccountControl] & 2) == 2) ? false : true</Column>
</Columns>
</DerivedColumns>
<RowCount Name="RC Source" LocaleId="None" VariableName="User.RowCountSource">
<InputPath OutputPathName="ADO AD.Output" SsisName="ADO AD_Output_RC Source" />
</RowCount>
</Transformations>
</Dataflow>
</Tasks>
<Connections>
<Connection ConnectionName="AD" />
</Connections>
</Package>
</Packages>
</Biml>
由于我在过去30天内没有禁用任何帐户,因此这里没有什么可看的。