<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Indented! &#187; VbScript</title>
	<atom:link href="http://www.indented.co.uk/index.php/category/vbscript/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.indented.co.uk</link>
	<description></description>
	<lastBuildDate>Fri, 02 Jul 2010 10:45:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Building LDAP filters for date based attributes</title>
		<link>http://www.indented.co.uk/index.php/2009/08/27/building-ldap-filters-for-date-based-attributes/</link>
		<comments>http://www.indented.co.uk/index.php/2009/08/27/building-ldap-filters-for-date-based-attributes/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 10:33:34 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[LDAP]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=1154</guid>
		<description><![CDATA[Active Directory contains a number of attributes which hold date information. This article shows how to generate LDAP Filters for these attributes in both VbScript and PowerShell. Date attributes This LDAP Filter format can be used for the following attributes: createTimeStamp dsCorePropagationData expirationTime modifyTimeStamp whenChanged whenCreated VbScript ' The date the filter is supposed to [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Active Directory contains a number of attributes which hold date information. This article shows how to generate LDAP Filters for these attributes in both VbScript and PowerShell.<br />
<span id="more-1154"></span></p>
<h3>Date attributes</h3>
<p>This LDAP Filter format can be used for the following attributes:</p>
<ul>
<li>createTimeStamp</li>
<li>dsCorePropagationData</li>
<li>expirationTime</li>
<li>modifyTimeStamp</li>
<li>whenChanged</li>
<li>whenCreated</li>
</ul>
<h4>VbScript</h4>
<pre class="brush: vb;">
' The date the filter is supposed to find
dtmDate = Now() - 1

arrDateParts = Array(&quot;yyyy&quot;, &quot;m&quot;, &quot;d&quot;, &quot;h&quot;, &quot;n&quot;, &quot;s&quot;)

For Each strInterval in arrDateParts
  intDatePart = DatePart(strInterval, dtmDate)
  If intDatePart &lt; 10 Then
    strDateTime = strDateTime &amp; &quot;0&quot; &amp; intDatePart
  Else
    strDateTime = strDateTime &amp; intDatePart
  End If
Next
strDateTime = strDateTime &amp; &quot;.0Z&quot;

' WhenCreated is after strDateTime. i.e. objects created since strDateTime.
WScript.Echo &quot;(whenCreated&gt;=&quot; &amp; strDateTime &amp; &quot;)&quot;
</pre>
<p>This will produce a filter like &#8220;(whenCreated>=20090826110816.0Z)&#8221;. Accuracy is based on the source date, using Date() instead of Now() would result in accuracy to a day (e.g. &#8220;(whenCreated>=20090826000000.0Z)&#8221;).</p>
<h4>PowerShell</h4>
<pre class="brush: powershell;">
# Convert yesterday to a Universal date-time string
$DateString = (Get-Date).AddDays(-1).ToString(&quot;u&quot;) -Replace &quot;-|:|\s&quot;
$DateString = $DateString -Replace &quot;Z&quot;, &quot;.0Z&quot;

Write-Host &quot;(whenCreated&gt;=$DateString)&quot;
</pre>
<p>As with the VbScript version this returns a string accurate to seconds. Accuracy can be modified by using (Get-Date).Date.AddDays(-1).</p>
<h3>Interger8 attributes</h3>
<p>An Interger8 date is represented by the number of 100-nanosecond intervals since the Microsoft epoch (01/01/1601 00:00:00). This format applies to the following attributes:</p>
<ul>
<li>accountExpires</li>
<li>badPasswordTime</li>
<li>lastLogon</li>
<li>lastLogonTimeStamp</li>
<li>lockoutTime</li>
<li>pwdLastSet</li>
</ul>
<p>Note that lastLogoff also uses this format but the value for the attribute is not maintained by Active Directory.</p>
<h4>VbScript</h4>
<pre class="brush: vb;">
' The number of days to remove from the current date
Const DAYS_TO_REMOVE = 1

dblInt8 = CDbl(DateDiff(&quot;s&quot;, CDate(&quot;01/01/1601 00:00:00&quot;), Now - DAYS_TO_REMOVE))
' Earlier than the current date. i.e. Passwords set before the generated date
WScript.Echo &quot;(&amp;(pwdLastSet&lt;=&quot; &amp; CStr(dblInt8) &amp; &quot;0000000)(!pwdLastSet=0))&quot;
</pre>
<p>This produces a filter like &#8220;(&#038;(pwdLastSet<=128957595350000000)(!pwdLastSet=0))". As with the previous filter this is accurate to seconds, that can be modified by changing the source date in the same way as before.</p>
<h4>PowerShell</h4>
<pre class="brush: powershell;">
$DaysToRemove = 1
$Int8Date = [Math]::Round(( `
  New-TimeSpan $(Get-Date(&quot;01/01/1601 00:00:00&quot;)) `
  ((Get-Date).AddDays(-$DaysToRemove))).TotalSeconds, 0)

$Int8Date = &quot;$($Int8Date.ToString())0000000&quot;

$LdapFilter = &quot;(&amp;(pwdLastSet&lt;=$Int8Date)(!pwdLastSet=0))&quot;
</pre>
<h3>accountExpires</h3>
<p>Certain attributes, such as accountExpires, have default values that can make filtering using a date string difficult.</p>
<p>The following LDAP filter can be used to return all accounts that are set to expire.</p>
<pre class="brush: powershell;">
&quot;(accountExpires&lt;=9223372032559810000)(!accountExpires=0))&quot;
</pre>
<p>Where 9223372032559810000 is the default attribute value in most cases, and 0 is the default in the rest.</p>
<p>accountExpires exhibits inconsistent behaviour depending on how it is accessed. If using iADSUser.AccountExpirationDate an account that does not expire is denoted by the date &#8220;01/01/1970 00:00:00&#8243;. This epoch date differs from the epoch used with the underlying attribute, &#8220;01/01/1601 00:00:00&#8243;.</p>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2009/08/27/building-ldap-filters-for-date-based-attributes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Listing Trusts</title>
		<link>http://www.indented.co.uk/index.php/2009/08/27/listing-trusts/</link>
		<comments>http://www.indented.co.uk/index.php/2009/08/27/listing-trusts/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 10:01:11 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[Trust]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=1144</guid>
		<description><![CDATA[A script to enumerate trust information from an Active Directory forest. Const ADS_SCOPE_SUBTREE = 2 ' Trust Type ' http://msdn.microsoft.com/en-us/library/cc223771(PROT.10).aspx Dim objTrustTypes Set objTrustTypes = CreateObject(&#34;Scripting.Dictionary&#34;) objTrustTypes.Add 4, &#34;DCE&#34; objTrustTypes.Add 3, &#34;MIT&#34; objTrustTypes.Add 2, &#34;UpLevel&#34; objTrustTypes.Add 1, &#34;DownLevel&#34; ' Trust Attributes ' http://msdn.microsoft.com/en-us/library/cc223779(PROT.10).aspx Dim objTrustAttributes Set objTrustAttributes = CreateObject(&#34;Scripting.Dictionary&#34;) objTrustAttributes.Add 128, &#34;UsesRC4Encryption&#34; objTrustAttributes.Add 64, &#34;TreatAsExternal&#34; [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>A script to enumerate trust information from an Active Directory forest.<br />
<span id="more-1144"></span></p>
<pre class="brush: vb;">
Const ADS_SCOPE_SUBTREE = 2

' Trust Type
' http://msdn.microsoft.com/en-us/library/cc223771(PROT.10).aspx
Dim objTrustTypes
Set objTrustTypes = CreateObject(&quot;Scripting.Dictionary&quot;)
objTrustTypes.Add 4, &quot;DCE&quot;
objTrustTypes.Add 3, &quot;MIT&quot;
objTrustTypes.Add 2, &quot;UpLevel&quot;
objTrustTypes.Add 1, &quot;DownLevel&quot;

' Trust Attributes
' http://msdn.microsoft.com/en-us/library/cc223779(PROT.10).aspx
Dim objTrustAttributes
Set objTrustAttributes = CreateObject(&quot;Scripting.Dictionary&quot;)
objTrustAttributes.Add 128, &quot;UsesRC4Encryption&quot;
objTrustAttributes.Add 64, &quot;TreatAsExternal&quot;
objTrustAttributes.Add 32, &quot;WithinForest&quot;
objTrustAttributes.Add 16, &quot;CrossOrganisation&quot;
objTrustAttributes.Add 8, &quot;ForestTransitive&quot;
objTrustAttributes.Add 4, &quot;QuarantinedDomain&quot;
objTrustAttributes.Add 2, &quot;UpLevelOnly&quot;
objTrustAttributes.Add 1, &quot;NonTransitive&quot;

' Trust Direction
' http://msdn.microsoft.com/en-us/library/cc223768(PROT.10).aspx
Dim objTrustDirection
Set objTrustDirection = CreateObject(&quot;Scripting.Dictionary&quot;)
objTrustDirection.Add 3, &quot;BiDirectional&quot;
objTrustDirection.Add 2, &quot;Outbound&quot;
objTrustDirection.Add 1, &quot;Inbound&quot;
objTrustDirection.Add 0, &quot;Disabled&quot;

Dim objConnection : Set objConnection = CreateObject(&quot;ADODB.Connection&quot;)
objConnection.Provider = &quot;ADsDSOObject&quot;
objConnection.Open &quot;Active Directory Provider&quot;

Dim objCommand : Set objCommand = CreateObject(&quot;ADODB.Command&quot;)
objCommand.ActiveConnection = objConnection

Dim objRootDSE : Set objRootDSE = GetObject(&quot;LDAP://RootDSE&quot;)
objCommand.CommandText = &quot;SELECT distinguishedName, name, trustType, &quot; &amp; _
  &quot;trustAttributes, trustDirection, trustPartner, whenCreated &quot; &amp; _
  &quot;FROM 'GC://&quot; &amp; objRootDSE.Get(&quot;rootDomainNamingContext&quot;) &amp; _
  &quot;' WHERE objectClass='trustedDomain'&quot;

objCommand.Properties(&quot;Page Size&quot;) = 1000
objCommand.Properties(&quot;Timeout&quot;) = 600
objCommand.Properties(&quot;Searchscope&quot;) = ADS_SCOPE_SUBTREE
objCommand.Properties(&quot;Cache Results&quot;) = False

Dim objRecordSet : Set objRecordSet = objCommand.Execute

While Not objRecordSet.EOF
  WScript.Echo &quot;Trusted Domain: &quot; &amp; objRecordSet.Fields(&quot;name&quot;).Value
  WScript.Echo &quot;Trust Type: &quot; &amp; _
    objTrustTypes(objRecordSet.Fields(&quot;trustType&quot;).Value)

  Dim dblFlag
  Dim strFlags : strFlags = &quot;&quot;
  For Each dblFlag in objTrustAttributes
    If objRecordSet.Fields(&quot;trustAttributes&quot;).Value And dblFlag Then
      strFlags = strFlags &amp; objTrustAttributes(dblFlag) &amp; &quot; &quot;
    End If
  Next
  WScript.Echo &quot;Trust Attributes: &quot; &amp; strFlags

  WScript.Echo &quot;Trust Direction: &quot; &amp; _
    objTrustDirection(objRecordSet.Fields(&quot;trustDirection&quot;).Value)
  WScript.Echo &quot;Trust Partner: &quot; &amp; objRecordSet.Fields(&quot;trustPartner&quot;).Value
  WScript.Echo &quot;Distinguished Name: &quot; &amp; _
    objRecordSet.Fields(&quot;distinguishedName&quot;).Value
  WScript.Echo &quot;Created: &quot; &amp; objRecordSet.Fields(&quot;whenCreated&quot;).Value

  objRecordSet.MoveNext
Wend

objConnection.Close
</pre>
<h3>Usage example</h3>
<p>In the past I have used the script above to monitor trust settings across a forest. The following script uses the trust information to build a text file storing trust configuration sends an e-mail if that configuration changes.</p>
<pre class="brush: vb;">
Option Explicit

' Script to get trusts, compare with stored configuration and notify if changed

Sub ShowUsage
  Dim strUsage
  strUsage = &quot;Usage:&quot; &amp; vbCrLf &amp; vbCrLf &amp; _
    WScript.ScriptName &amp; _
    &quot; /Command:[Update | Notify] [/MailServer:&lt;serverName&gt;] &quot; &amp; _
    &quot;[/Recipient:&lt;address&gt;]&quot; &amp; vbCrLf &amp; vbCrLf &amp; _
    &quot;Arguments:&quot; &amp; vbCrLf &amp; vbCrLf &amp; _
    &quot;    Command      Update - Updates the contents of the text &quot; &amp; _
    &quot;file with data from the global catalog&quot; &amp; vbCrLf &amp; _
    &quot;                 Notify - Notifies the recipient using mailserver &quot; &amp; _
    &quot;if the trust data changes&quot; &amp; vbCrLf &amp; _
    &quot;    MailServer   Server used to send mail. Default: localhost&quot; &amp; vbCrLf &amp; _
    &quot;    Recipient    Email address of person or group to notify&quot; &amp; vbCrLf

  WScript.Echo strUsage
  WScript.Quit
End Sub

Function GetTrusts
  ' Returns a Scripting.Dictionary object containing details of the Trust
  ' Format:
  ' Key: DistinguishedName
  ' Data: Array(
  '           Trusted Domain,
  '           Type,
  '           Attributes,
  '           Direction,
  '           Partner,
  '           Created,
  '           Changed )

  Const ADS_SCOPE_SUBTREE = 2

  ' Trust Type
  ' http://msdn.microsoft.com/en-us/library/cc223771(PROT.10).aspx
  Dim objTrustTypes
  Set objTrustTypes = CreateObject(&quot;Scripting.Dictionary&quot;)
  objTrustTypes.Add 4, &quot;DCE&quot;
  objTrustTypes.Add 3, &quot;MIT&quot;
  objTrustTypes.Add 2, &quot;UpLevel&quot;
  objTrustTypes.Add 1, &quot;DownLevel&quot;

  ' Trust Attributes
  ' http://msdn.microsoft.com/en-us/library/cc223779(PROT.10).aspx
  Dim objTrustAttributes
  Set objTrustAttributes = CreateObject(&quot;Scripting.Dictionary&quot;)
  objTrustAttributes.Add 128, &quot;UsesRC4Encryption&quot;
  objTrustAttributes.Add 64, &quot;TreatAsExternal&quot;
  objTrustAttributes.Add 32, &quot;WithinForest&quot;
  objTrustAttributes.Add 16, &quot;CrossOrganisation&quot;
  objTrustAttributes.Add 8, &quot;ForestTransitive&quot;
  objTrustAttributes.Add 4, &quot;QuarantinedDomain&quot;
  objTrustAttributes.Add 2, &quot;UpLevelOnly&quot;
  objTrustAttributes.Add 1, &quot;NonTransitive&quot;

  ' Trust Direction
  ' http://msdn.microsoft.com/en-us/library/cc223768(PROT.10).aspx
  Dim objTrustDirection
  Set objTrustDirection = CreateObject(&quot;Scripting.Dictionary&quot;)
  objTrustDirection.Add 3, &quot;BiDirectional&quot;
  objTrustDirection.Add 2, &quot;Outbound&quot;
  objTrustDirection.Add 1, &quot;Inbound&quot;
  objTrustDirection.Add 0, &quot;Disabled&quot;

  Dim objConnection : Set objConnection = CreateObject(&quot;ADODB.Connection&quot;)
  objConnection.Provider = &quot;ADsDSOObject&quot;
  objConnection.Open &quot;Active Directory Provider&quot;

  Dim objCommand : Set objCommand = CreateObject(&quot;ADODB.Command&quot;)
  objCommand.ActiveConnection = objConnection

  Dim objRootDSE : Set objRootDSE = GetObject(&quot;LDAP://RootDSE&quot;)
  objCommand.CommandText = &quot;SELECT distinguishedName, name, &quot; &amp; _
    &quot;trustType, trustAttributes, trustDirection, trustPartner, &quot; &amp; _
    &quot;whenCreated, whenChanged &quot; &amp; _
    &quot;FROM 'GC://&quot; &amp; objRootDSE.Get(&quot;rootDomainNamingContext&quot;) &amp; _
    &quot;' WHERE objectClass='trustedDomain'&quot;

  objCommand.Properties(&quot;Page Size&quot;) = 1000
  objCommand.Properties(&quot;Timeout&quot;) = 600
  objCommand.Properties(&quot;Searchscope&quot;) = ADS_SCOPE_SUBTREE
  objCommand.Properties(&quot;Cache Results&quot;) = False

  Dim objRecordSet : Set objRecordSet = objCommand.Execute

  Dim objTrusts : Set objTrusts = CreateObject(&quot;Scripting.Dictionary&quot;)

  While Not objRecordSet.EOF
    Dim dblFlag
    Dim strAttributes : strAttributes = &quot;&quot;
    For Each dblFlag in objTrustAttributes
      If objRecordSet.Fields(&quot;trustAttributes&quot;).Value And dblFlag Then
        strAttributes = strAttributes &amp; objTrustAttributes(dblFlag) &amp; &quot; &quot;
      End If
    Next

    objTrusts.Add objRecordSet.Fields(&quot;distinguishedName&quot;).Valuem, Array( _
      objRecordSet.Fields(&quot;name&quot;).Value, _
      objTrustTypes(objRecordSet.Fields(&quot;trustType&quot;).Value), _
      strAttributes, _
      objTrustDirection(objRecordSet.Fields(&quot;trustDirection&quot;).Value), _
      objRecordSet.Fields(&quot;trustPartner&quot;).Value, _
      objRecordSet.Fields(&quot;whenCreated&quot;).Value, _
      objRecordSet.Fields(&quot;whenChanged&quot;).Value)

    objRecordSet.MoveNext
  Wend

  objConnection.Close

  Set objRecordSet = Nothing
  Set objCommand = Nothing
  Set objConnection = Nothing

  Set GetTrusts = objTrusts
End Function

Sub SendMail(strRecipient, strBody, strMailServer)

  Set objMail = CreateObject(&quot;CDO.Message&quot;)
  objMail.Subject = &quot;Trust monitor&quot;

  objMail.From = strRecipient
  objMail.To = strRecipient

  objMail.TextBody = strBody

  objMail.Configuration.Fields.Item _
    (&quot;http://schemas.microsoft.com/cdo/configuration/sendusing&quot;) = 2
  objMail.Configuration.Fields.Item _
    (&quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&quot;) = _
    strMailServer
  objMail.Configuration.Fields.Item _
    (&quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&quot;) = 25

  objMail.Configuration.Fields.Update
  objMail.Send
End Sub

'
' Main Code
'

Dim objFileSystem
Set objFileSystem = CreateObject(&quot;Scripting.FileSystemObject&quot;)
Dim objFile

Dim objTrusts : Set objTrusts = GetTrusts

If LCase(WScript.Arguments.Named(&quot;command&quot;)) = &quot;update&quot; Then
  Set objFile = objFileSystem.OpenTextFile(&quot;Trusts.txt&quot;, 2, True, 0)

  Dim strDN
  For Each strDN in objTrusts
    objFile.WriteLine strDN &amp; vbTab &amp; Join(objTrusts(strDN), vbTab)
  Next

ElseIf LCase(WScript.Arguments.Named(&quot;command&quot;)) = &quot;notify&quot; Then

  strRecipient = WScript.Arguments.Named(&quot;recipient&quot;)

  If strRecipient = &quot;&quot; Then
    WScript.Echo &quot;ERROR: No recipient defined&quot;
    ShowUsage
  End If

  strMailServer = WScript.Arguments.Named(&quot;mailserver&quot;)

  If strMailServer = &quot;&quot; Then
    strMailServer = &quot;localhost&quot;
  End If

  If objFileSystem.FileExists(&quot;Trusts.txt&quot;) Then
    Set objFile = objFileSystem.OpenTextFile(&quot;Trusts.txt&quot;, 1, False, 0)

    Dim objTrustsInFile
    Set objTrustsInFile = CreateObject(&quot;Scripting.Dictionary&quot;)

    Dim arrTrustData()
    Do While Not objFile.AtEndOfStream
      Dim arrTrustInFile : arrTrustInFile = Split(objFile.ReadLine, vbTab)

      ReDim arrTrustData(0)
      Dim i
      For i = 1 to UBound(arrTrustInFile)
        ReDim Preserve arrTrustData(i - 1)
        arrTrustData(i - 1) = arrTrustInFile(i)
      Next

      objTrustsInFile.Add arrTrustInFile(0), arrTrustData
    Loop
  End If

  Dim strTrust

  ' Comparison - Check for new Trusts

  Dim objNewTrusts : Set objNewTrusts = CreateObject(&quot;Scripting.Dictionary&quot;)

  For Each strTrust in objTrusts
    If Not objTrustsInFile.Exists(strTrust) Then
      objNewTrusts.Add strTrust, objTrusts(strTrust)
    End If
  Next

  ' Comparison - Check for removed Trusts

  Dim objRemovedTrusts
  Set objRemovedTrusts = CreateObject(&quot;Scripting.Dictionary&quot;)

  For Each strTrust in objTrustsInFile
    If Not objTrusts.Exists(strTrust) Then
      objRemovedTrusts.Add strTrust, objTrustsInFile(strTrust)
    End If
  Next

  ' Data: Array(
  '           Trusted Domain,
  '           Type,
  '           Attributes,
  '           Direction,
  '           Partner,
  '           Created,
  '           Changed )

  Dim strMessageBody
  Dim booNotify : booNotify = False
  If objNewTrusts.Count &gt; 0 Then
    booNotify = True
    strMessageBody = &quot;New Trusts:&quot; &amp; vbCrLf &amp; vbCrLf
    For Each strTrust in objNewTrusts
      strMessageBody = strMessageBody &amp; &quot;DN: &quot; &amp; strTrust &amp; vbCrLf &amp; _
        &quot;Trusted Domain: &quot; &amp; objNewTrusts(strTrust)(0) &amp; vbCrLf &amp; _
        &quot;Type: &quot; &amp; objNewTrusts(strTrust)(1) &amp; vbCrLf &amp; _
        &quot;Attributes: &quot; &amp; objNewTrusts(strTrust)(2) &amp; vbCrLf &amp; _
        &quot;Direction: &quot; &amp; objNewTrusts(strTrust)(3) &amp; vbCrLf &amp; _
        &quot;Partner: &quot; &amp; objNewTrusts(strTrust)(4) &amp; vbCrLf &amp; _
        &quot;Created: &quot; &amp; objNewTrusts(strTrust)(5) &amp; vbCrLf &amp; _
        &quot;Changed: &quot; &amp; objNewTrusts(strTrust)(6) &amp; vbCrLf &amp; vbCrLf
    Next
  End If
  If objRemovedTrusts.Count &gt; 0 Then
    booNotify = True
    For Each strTrust in objRemovedTrusts
      strMessageBody = strMessageBody &amp; &quot;DN: &quot; &amp; strTrust &amp; vbCrLf &amp; _
        &quot;Trusted Domain: &quot; &amp; objRemovedTrusts(strTrust)(0) &amp; vbCrLf &amp; _
        &quot;Type: &quot; &amp; objRemovedTrusts(strTrust)(1) &amp; vbCrLf &amp; _
        &quot;Attributes: &quot; &amp; objRemovedTrusts(strTrust)(2) &amp; vbCrLf &amp; _
        &quot;Direction: &quot; &amp; objRemovedTrusts(strTrust)(3) &amp; vbCrLf &amp; _
        &quot;Partner: &quot; &amp; objRemovedTrusts(strTrust)(4) &amp; vbCrLf &amp; _
        &quot;Created: &quot; &amp; objRemovedTrusts(strTrust)(5) &amp; vbCrLf &amp; _
        &quot;Changed: &quot; &amp; objRemovedTrusts(strTrust)(6) &amp; vbCrLf &amp; vbCrLf
    Next
  End If
  If booNotify = True Then
    strMessageBody = strMessageBody &amp; _
      &quot;If these trusts are correct please run &quot; &amp; _
      WScript.ScriptName &amp; &quot; /Command:Update&quot;

    SendMail strRecipient, strMessageBody, strMailServer
  End If
Else

  ShowUsage

End If
</pre>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2009/08/27/listing-trusts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reading NTFS and Share security with VbScript</title>
		<link>http://www.indented.co.uk/index.php/2009/02/19/reading-ntfs-and-share-security-with-vbscript/</link>
		<comments>http://www.indented.co.uk/index.php/2009/02/19/reading-ntfs-and-share-security-with-vbscript/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 17:25:25 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[VbScript]]></category>
		<category><![CDATA[acl]]></category>
		<category><![CDATA[ntfs]]></category>
		<category><![CDATA[permissions]]></category>
		<category><![CDATA[securitydescriptor]]></category>
		<category><![CDATA[vbs]]></category>
		<category><![CDATA[wmi]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=908</guid>
		<description><![CDATA[NTFS (File System) and Share security can be enumerated using the Win32_LogicalFileSecuritySetting and Win32_LogicalShareSecuritySetting WMI classes. This post demonstrates how to use each class to read the security descriptors. In each case the WMI class contains a GetSecurityDescriptor method used to retrieve the Security Descriptor (as a Win32_SecurityDescriptor). The references section at the bottom of [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>NTFS (File System) and Share security can be enumerated using the Win32_LogicalFileSecuritySetting and Win32_LogicalShareSecuritySetting WMI classes. This post demonstrates how to use each class to read the security descriptors.<br />
<span id="more-908"></span><br />
In each case the WMI class contains a GetSecurityDescriptor method used to retrieve the Security Descriptor (as a Win32_SecurityDescriptor).</p>
<p>The references section at the bottom of this article include details of sources for all constants. A little PowerShell creeps in to show how the numeric values were retrieved and checked.</p>
<h3>DACLs and SACLs</h3>
<p>A DACL or Discretionary Access Control List is the most heavily used, it contains Access Control Entries that define who can, and who cannot, access a resource or object. These are seen when viewing the Security tab of an object.</p>
<p>An SACL or System Access Control List defines which actions will be audited when accessing an a resource or object. Seen by accessing the Audit tab through Security and Advanced.</p>
<h3>NTFS security vs Share security</h3>
<p>Both the NTFS and the Share security descriptor can be read in exactly the same way. However, there are important differences between them.</p>
<h4>NTFS security descriptor</h4>
<ul>
<li>Supports inheritance on descriptor and on individual Access Control Entries</li>
<li>Can hold a Discretionary Access Control List and an System Access Control List</li>
</ul>
<h4>Share security descriptor</h4>
<ul>
<li>Has no owner or Primary Group</li>
<li>Control flags will be set (and usually limited) to SelfRelative and DiscretionaryACLPresent</li>
<li>Access Control Entry (ACE) Flags will not be set</li>
<li>Can hold a Discretionary Access Control List only</li>
<li>Supports a sub-set of Access Masks (rights) on each ACE</li>
</ul>
<h3>Getting the security descriptor</h3>
<h4>NTFS</h4>
<pre class="brush: vb;">
Dim strComputer : strComputer = &quot;.&quot;
' Connect to WMI on strComputer
Dim objWMI : Set objWMI = GetObject(&quot;winmgmts://&quot; &amp; strComputer &amp; &quot;/root/cimv2&quot;)
' Get an instance of LogicalFileSecuritySetting for C:\
Dim objSecuritySettings : Set objSecuritySettings = _
  objWMI.Get(&quot;Win32_LogicalFileSecuritySetting='C:\'&quot;)
Dim intReturnValue : Dim objSD
' Request the Security Descriptor as objSD
intReturnValue = objSecuritySettings.GetSecurityDescriptor objSD
</pre>
<h4>Share</h4>
<pre class="brush: vb;">
Dim strComputer : strComputer = &quot;.&quot;
' Connect to WMI on strComputer
Dim objWMI : Set objWMI = GetObject(&quot;winmgmts://&quot; &amp; strComputer &amp; &quot;/root/cimv2&quot;)
' Get an instance of LogicalShareSecuritySetting for ShareName
Dim objSecuritySettings : Set objSecuritySettings = _
  objWMI.Get(&quot;Win32_LogicalShareSecuritySetting='ShareName'&quot;)
Dim intReturnValue : Dim objSD
' Request the Security Descriptor as objSD
intReturnValue = objSecuritySettings.GetSecurityDescriptor objSD
</pre>
<h4>Error handling</h4>
<p>The GetSecurityDescriptor method of each WMI class (Win32_LogicalFileSecuritySetting and Win32_LogicalShareSecuritySetting) has a return value to allow errors to be handled. The return codes are represented by the constants below.</p>
<pre class="brush: vb;">
Const SUCCESS = 0
Const ACCESS_DENIED = 2
Const UNKNOWN_FAILURE = 8
Const PRIVILEGE_MISSING = 9
Const INVALID_PARAMETER = 21
</pre>
<h3>Values in the security descriptor</h3>
<p>The security descriptor contains three fields in addition to the DACL and SACL which are described later.</p>
<h4>Control flags</h4>
<p>Each security descriptor has a ControlFlags field which dictates how the descriptor behaves. This includes settings such as DACLProtected which indicates that the DACL cannot inherit values from a parent.</p>
<p>The script loads the values above into a Scripting.Dictionary object to simplify enumeration.</p>
<pre class="brush: vb;">
Dim objControlFlags : Set objControlFlags = CreateObject(&quot;Scripting.Dictionary&quot;)
objControlFlags.Add 32768, &quot;SelfRelative&quot;
objControlFlags.Add 16384, &quot;RMControlValid&quot;
objControlFlags.Add 8192, &quot;SystemAclProtected&quot;
objControlFlags.Add 4096, &quot;DiscretionaryAclProtected&quot;
objControlFlags.Add 2048, &quot;SystemAclAutoInherited&quot;
objControlFlags.Add 1024, &quot;DiscretionaryAclAutoInherited&quot;
objControlFlags.Add 512, &quot;SystemAclAutoInheritRequired&quot;
objControlFlags.Add 256, &quot;DiscretionaryAclAutoInheritRequired&quot;
objControlFlags.Add 32, &quot;SystemAclDefaulted&quot;
objControlFlags.Add 16, &quot;SystemAclPresent&quot;
objControlFlags.Add 8, &quot;DiscretionaryAclDefaulted&quot;
objControlFlags.Add 4, &quot;DiscretionaryAclPresent&quot;
objControlFlags.Add 2, &quot;GroupDefaulted&quot;
objControlFlags.Add 1, &quot;OwnerDefaulted&quot;
</pre>
<p>Note that they are intentionally entered in order from highest to lowest. A For Each loop will start with the highest value (because it was added first), then compare it to the ControlFlags value. In bitwise comparison, if the integer value can be there, then it must be there, that would all go wrong unless it starts with the highest possible value.</p>
<p>The values and names were taken from the .NET Framework, they can be displayed in PowerShell with the following command.</p>
<pre class="brush: powershell;">
[Enum]::GetValues([System.Security.AccessControl.ControlFlags]) | `
  Select-Object @{ n='Name';e={[String]$_} }, @{ n='Value';e={$_.value__} }
</pre>
<p>That logic is applied within the code as follows.</p>
<pre class="brush: vb;">
' Read the value of Control Flags from the descriptor
dblControlFlags = objSD.ControlFlags
WScript.Echo &quot;Control Flags:&quot;
' For each possible flag
For Each dblFlag in objControlFlags
  ' If it is possible for the flag to be there, then it must be there
  ' Something like bitwise AND
  If dblControlFlags &gt;= dblFlag Then
    ' Echo the flag, indicating it is present
    WScript.Echo &quot;  &quot; &amp; objControlFlags(dblFlag)
    ' Remove this value from the control flag value,
    ' already found this flag
    dblControlFlags = dblControlFlags - dblFlag
  End If
Next
</pre>
<h4>Primary group</h4>
<p>The Primary Group is not very interesting unless Services for Unix is in use. In many cases it will be blank.</p>
<p>If set, it can be enumerated as a Win32_Trustee, an object containing a Domain, Username, SID array, SID length and SIDString.</p>
<h4>Owner</h4>
<p>As with the Primary Group, the owner is stored as a Win32_Trustee object. It can be read from the descriptor as follows.</p>
<pre class="brush: vb;">
WScript.Echo &quot;Domain: &quot; &amp; objSD.Owner.Domain
WScript.Echo &quot;Username: &quot; &amp; objSD.Owner.Name
WScript.Echo &quot;SID: &quot; &amp; objSD.Owner.SIDString
</pre>
<h3>Access control entries in the DACL and SACL</h3>
<p>Both the DACL and SACL, if present, consist of one or more Access Control Entries (ACE). The ACE, like the security descriptor, breaks down into a number of different fields.</p>
<h4>Access Mask</h4>
<p>The access mask defines which rights should be used by the Access Control Entry. In the case of System ACL it defines which actions should be audited.</p>
<p>A number of the right names are omitted from the list below as they carry the same numeric value (mask the same bit), the meaning only changes in the context the right is applied.</p>
<pre class="brush: vb;">
Dim objAccessRights : Set objAccessRights = CreateObject(&quot;Scripting.Dictionary&quot;)
objAccessRights.Add 2032127, &quot;FullControl&quot;
objAccessRights.Add 1048576, &quot;Synchronize&quot;
objAccessRights.Add 524288, &quot;TakeOwnership&quot;
objAccessRights.Add 262144, &quot;ChangePermissions&quot;
objAccessRights.Add 197055, &quot;Modify&quot;
objAccessRights.Add 131241, &quot;ReadAndExecute&quot;
objAccessRights.Add 131209, &quot;Read&quot;
objAccessRights.Add 131072, &quot;ReadPermissions&quot;
objAccessRights.Add 65536, &quot;Delete&quot;
objAccessRights.Add 278, &quot;Write&quot;
objAccessRights.Add 256, &quot;WriteAttributes&quot;
objAccessRights.Add 128, &quot;ReadAttributes&quot;
objAccessRights.Add 64, &quot;DeleteSubdirectoriesAndFiles&quot;
objAccessRights.Add 32, &quot;ExecuteFile&quot;
objAccessRights.Add 16, &quot;WriteExtendedAttributes&quot;
objAccessRights.Add 8, &quot;ReadExtendedAttributes&quot;
objAccessRights.Add 4, &quot;AppendData&quot;
objAccessRights.Add 2, &quot;CreateFiles&quot;
objAccessRights.Add 1, &quot;ReadData&quot;
</pre>
<p>Note that a number of the rights in the list are composites of simpler rights, including Read, FullControl, Write and Modify.</p>
<p>The list can be retrieved, using PowerShell again, with the following command:</p>
<pre class="brush: powershell;">
[Enum]::GetValues([System.Security.AccessControl.FileSystemRights]) | `
  Select-Object @{n='Name';e={[String]$_} }, @{n='Value';e={$_.value__} }
</pre>
<p>Holding the flags in this fashion allows the Access Mask to be converted to a friendly form in the same way as the Control Flags were displayed.</p>
<pre class="brush: vb;">
' For each access control entry in the discretionary access control list
For Each objACE in objSD.DACL
  WScript.Echo &quot;Access Mask:&quot;
  ' Read the value of the access mask from the Access Control Entry
  dblAccessMask = objACE.AccessMask
  ' For each possible Right
  For Each dblAccess in objAccessRights
    ' If the right can be there then it must...
    If dblAccessMask &gt;= dblAccess Then
      ' Echo the right name
      WScript.Echo &quot;  &quot; &amp; objAccessRights(dblAccess)
      ' Remove the value from the access mask,
      ' already found this right.
      dblAccessMask = dblAccessMask - dblAccess
    End If
  Next
Next
</pre>
<h4>Flags</h4>
<p>The flags on an Access Control Entry defines whether the entry applies to Leaf or Container objects, how it behaves when inheritance is calculated, and whether or not the ACE is inherited or explicit.</p>
<pre class="brush: vb;">
Dim objAceFlags : Set objAceFlags = CreateObject(&quot;Scripting.Dictionary&quot;)
objAceFlags.Add 128, &quot;FailedAccess&quot;
objAceFlags.Add 64, &quot;SuccessfulAccess&quot;
objAceFlags.Add 16, &quot;Inherited&quot;
objAceFlags.Add 8, &quot;InheritOnly&quot;
objAceFlags.Add 4, &quot;NoPropagateInherit&quot;
objAceFlags.Add 2, &quot;ContainerInherit&quot;
objAceFlags.Add 1, &quot;ObjectInherit&quot;
</pre>
<p>Heading back to PowerShell again we can find the the names and values for these.</p>
<pre class="brush: powershell;">
[Enum]::GetValues([System.Security.AccessControl.AceFlags]) | `
  Select-Object @{n='Name';e={[String]$_} }, @{n='Value';e={$_.value__} }
</pre>
<p>A few are intentionally left out as they are composites of values more interesting to display separately.</p>
<p>Enumeration of the Access Control Entry flags is performed as follows.</p>
<pre class="brush: vb;">
' For each access control entry in the discretionary access control list
For Each objACE in objSD.DACL
  WScript.Echo &quot;ACE Flags:&quot;
    ' Read the value of ACE Flags from the Access Control Entry
  dblAceFlags = objAce.AceFlags
  ' For each possible flag
  For Each dblFlag in objAceFlags
    ' If the flag can be there then it must...
    If dblAceFlags &gt;= dblFlag Then
      ' Echo the name of the flag
      WScript.Echo &quot;  &quot; &amp; objAceFlags(dblFlag)
      ' Found it, remove it to note that it has been found.
      dblAceFlags = dblAceFlags - dblFlag
    End If
  Next
Next
</pre>
<h4>Trustee</h4>
<p>The value for the trustee (Win32_Trustee), the security principal (user, group, computer, etc) the right applies to is enumerated in the same way as the Owner above.</p>
<pre class="brush: vb;">
For Each objACE in objDACL
  WScript.Echo &quot;Domain: &quot; &amp; objACE.Trustee.Domain
  WScript.Echo &quot;User: &quot; &amp; objACE.Trustee.Name
  WScript.Echo &quot;SID: &quot; &amp; objACE.Trustee.SIDString
Next
</pre>
<h4>Type</h4>
<p>Finally, the ACEType consists of three values which define whether the ACE permits access, denies access or is an audit control.</p>
<pre class="brush: vb;">
Dim objAceTypes : Set objAceTypes = CreateObject(&quot;Scripting.Dictionary&quot;)
objAceTypes.Add 0, &quot;Allow&quot;
objAceTypes.Add 1, &quot;Deny&quot;
objAceTypes.Add 2, &quot;Audit&quot;
</pre>
<p>Once again, we can discover all of the possible values for AceFlags using PowerShell.</p>
<pre class="brush: powershell;">
[Enum]::GetValues([System.Security.AccessControl.AceType]) | `
  Select-Object @{n='Name';e={[String]$_} }, @{n='Value';e={$_.value__} }
</pre>
<p>However, this time the only values that are used in the script are 0 (Allow), 1 (Deny), and 2 (Audit).</p>
<pre class="brush: vb;">
' For each access control entry in the discretionary access control list
For Each objACE in objDACL
  ' Echo the type: Allow, Deny or Audit.
  WScript.Echo &quot;ACE Type: &quot; &amp; objAceTypes(objAce.AceType)
Next
</pre>
<h3>Listing permissions for all Shares</h3>
<p>Time to put all of that together. This sample lists the NTFS and Share permissions for each share configured on strComputer.</p>
<pre class="brush: vb;">
Option Explicit

' WMI Constants

Const WBEM_RETURN_IMMEDIATELY = &amp;h10
Const WBEM_FORWARD_ONLY = &amp;h20

' Constants and storage arrays for security settings

' GetSecurityDescriptor Return values

Dim objReturnCodes : Set objReturnCodes = CreateObject(&quot;Scripting.Dictionary&quot;)
Const SUCCESS = 0
Const ACCESS_DENIED = 2
Const UNKNOWN_FAILURE = 8
Const PRIVILEGE_MISSING = 9
Const INVALID_PARAMETER = 21

' Security Descriptor Control Flags

Dim objControlFlags : Set objControlFlags = CreateObject(&quot;Scripting.Dictionary&quot;)
objControlFlags.Add 32768, &quot;SelfRelative&quot;
objControlFlags.Add 16384, &quot;RMControlValid&quot;
objControlFlags.Add 8192, &quot;SystemAclProtected&quot;
objControlFlags.Add 4096, &quot;DiscretionaryAclProtected&quot;
objControlFlags.Add 2048, &quot;SystemAclAutoInherited&quot;
objControlFlags.Add 1024, &quot;DiscretionaryAclAutoInherited&quot;
objControlFlags.Add 512, &quot;SystemAclAutoInheritRequired&quot;
objControlFlags.Add 256, &quot;DiscretionaryAclAutoInheritRequired&quot;
objControlFlags.Add 32, &quot;SystemAclDefaulted&quot;
objControlFlags.Add 16, &quot;SystemAclPresent&quot;
objControlFlags.Add 8, &quot;DiscretionaryAclDefaulted&quot;
objControlFlags.Add 4, &quot;DiscretionaryAclPresent&quot;
objControlFlags.Add 2, &quot;GroupDefaulted&quot;
objControlFlags.Add 1, &quot;OwnerDefaulted&quot;

' ACE Access Right

Dim objAccessRights : Set objAccessRights = CreateObject(&quot;Scripting.Dictionary&quot;)
objAccessRights.Add 2032127, &quot;FullControl&quot;
objAccessRights.Add 1048576, &quot;Synchronize&quot;
objAccessRights.Add 524288, &quot;TakeOwnership&quot;
objAccessRights.Add 262144, &quot;ChangePermissions&quot;
objAccessRights.Add 197055, &quot;Modify&quot;
objAccessRights.Add 131241, &quot;ReadAndExecute&quot;
objAccessRights.Add 131209, &quot;Read&quot;
objAccessRights.Add 131072, &quot;ReadPermissions&quot;
objAccessRights.Add 65536, &quot;Delete&quot;
objAccessRights.Add 278, &quot;Write&quot;
objAccessRights.Add 256, &quot;WriteAttributes&quot;
objAccessRights.Add 128, &quot;ReadAttributes&quot;
objAccessRights.Add 64, &quot;DeleteSubdirectoriesAndFiles&quot;
objAccessRights.Add 32, &quot;ExecuteFile&quot;
objAccessRights.Add 16, &quot;WriteExtendedAttributes&quot;
objAccessRights.Add 8, &quot;ReadExtendedAttributes&quot;
objAccessRights.Add 4, &quot;AppendData&quot;
objAccessRights.Add 2, &quot;CreateFiles&quot;
objAccessRights.Add 1, &quot;ReadData&quot;

' ACE Types

Dim objAceTypes : Set objAceTypes = CreateObject(&quot;Scripting.Dictionary&quot;)
objAceTypes.Add 0, &quot;Allow&quot;
objAceTypes.Add 1, &quot;Deny&quot;
objAceTypes.Add 2, &quot;Audit&quot;

' ACE Flags

Dim objAceFlags : Set objAceFlags = CreateObject(&quot;Scripting.Dictionary&quot;)
objAceFlags.Add 128, &quot;FailedAccess&quot;
objAceFlags.Add 64, &quot;SuccessfulAccess&quot;
objAceFlags.Add 16, &quot;Inherited&quot;
objAceFlags.Add 8, &quot;InheritOnly&quot;
objAceFlags.Add 4, &quot;NoPropagateInherit&quot;
objAceFlags.Add 2, &quot;ContainerInherit&quot;
objAceFlags.Add 1, &quot;ObjectInherit&quot;

Sub ReadNTFSSecurity(objWMI, strPath)
  WScript.Echo &quot;  Displaying NTFS Security&quot;

  Dim objSecuritySettings : Set objSecuritySettings = _
    objWMI.Get(&quot;Win32_LogicalFileSecuritySetting='&quot; &amp; strPath &amp; &quot;'&quot;)
  Dim objSD : objSecuritySettings.GetSecurityDescriptor objSD

  Dim strDomain : strDomain = objSD.Owner.Domain
  If strDomain &lt;&gt; &quot;&quot; Then strDomain = strDomain &amp; &quot;\&quot;
  WScript.Echo &quot;  Owner: &quot; &amp; strDomain &amp; objSD.Owner.Name
  WScript.Echo &quot;  Owner SID: &quot; &amp; objSD.Owner.SIDString

  WScript.Echo &quot;  Basic Control Flags Value: &quot; &amp; objSD.ControlFlags
  WScript.Echo &quot;  Control Flags:&quot;

  DisplayValues objSD.ControlFlags, objControlFlags

  WScript.Echo

  Dim objACE

  ' Display the DACL

  WScript.Echo &quot;  Discretionary Access Control List:&quot;
  For Each objACE in objSD.DACL
    DisplayACE objACE
  Next

  ' Display the SACL (if there is one)

  If Not IsNull(objSD.SACL) Then
    WScript.Echo &quot;  System Access Control List:&quot;
    For Each objACE in objSD.SACL
      DisplayACE objACE
    Next
  End If
End Sub

Sub ReadShareSecurity(objWMI, strName)
  WScript.Echo &quot;  Displaying Share Security&quot;

  Dim objSecuritySettings : Set objSecuritySettings = _
    objWMI.Get(&quot;Win32_LogicalShareSecuritySetting='&quot; &amp; strName &amp; &quot;'&quot;)

  Dim objSD : objSecuritySettings.GetSecurityDescriptor objSD

  WScript.Echo &quot;  Basic Control Flags Value: &quot; &amp; objSD.ControlFlags
  WScript.Echo &quot;  Control Flags:&quot;

  DisplayValues objSD.ControlFlags, objControlFlags

  WScript.Echo

  Dim objACE

  ' Display the DACL

  WScript.Echo &quot;  Discretionary Access Control List:&quot;
  For Each objACE in objSD.DACL
    DisplayACE objACE
  Next
End Sub

Sub DisplayValues(dblValues, objSecurityEnumeration)

  Dim dblValue
  For Each dblValue in objSecurityEnumeration
    If dblValues &gt;= dblValue Then
      WScript.Echo &quot;      &quot; &amp; objSecurityEnumeration(dblValue)
      dblValues = dblValues - dblValue
    End If
  Next
End Sub

Sub DisplayACE(objACE)

  Dim strDomain : strDomain = objAce.Trustee.Domain
  If strDomain &lt;&gt; &quot;&quot; Then strDomain = strDomain &amp; &quot;\&quot;
  WScript.Echo &quot;    Trustee: &quot; &amp; UCase(strDomain &amp; objAce.Trustee.Name)
  WScript.Echo &quot;    SID: &quot; &amp; objAce.Trustee.SIDString

  WScript.Echo &quot;    Basic Access Mask Value: &quot; &amp; objACE.AccessMask

  WScript.Echo &quot;    Access Rights: &quot;
  DisplayValues objACE.AccessMask, objAccessRights

  WScript.Echo &quot;    Type: &quot; &amp; objAceTypes(objACE.AceType)

  WScript.Echo &quot;    Basic ACE Flags Value: &quot; &amp; objACE.AceFlags

  WScript.Echo &quot;    ACE Flags: &quot;
  DisplayValues objACE.AceFlags, objAceFlags
  WScript.Echo
End Sub

'
' Main Code
'

' The system to execute this script against
Dim strComputer : strComputer = &quot;.&quot;

' Connect to WMI
Dim objWMI : Set objWMI = GetObject(&quot;winmgmts:\\&quot; &amp; strComputer &amp; &quot;\root\CIMV2&quot;)

' Return all of the shares (Type = 0 means File Shares only, exclude
' are Administrative, Printer, etc)
Dim colItems : Set colItems = _
  objWMI.ExecQuery(&quot;SELECT * FROM Win32_Share WHERE Type='0'&quot;, &quot;WQL&quot;, _
  WBEM_RETURN_IMMEDIATELY + WBEM_FORWARD_ONLY)

Dim objItem
For Each objItem in colItems
  WScript.Echo
  WScript.Echo &quot;Security for &quot; &amp; objItem.Path &amp; _
    &quot; (Shared as &quot; &amp; objItem.Name &amp; &quot;)&quot;

  ReadNTFSSecurity objWMI, objItem.Path
  ReadShareSecurity objWMI, objItem.Name
Next
</pre>
<h4>References</h4>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/aa394180(VS.85).aspx">Win32_LogicalFileSecuritySetting</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa394188(VS.85).aspx">Win32_LogicalShareSecuritySetting</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa394402(VS.85).aspx">Win32_SecurityDescriptor</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa394063(VS.85).aspx">Win32_ACE</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa394501(VS.85).aspx">Win32_Trustee</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.controlflags.aspx">ControlFlags Enumeration</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx">FileSystemRights Enumeration</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.aceflags.aspx">AceFlags Enumeration</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.acetype.aspx">AceType Enumeration</a></li>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2009/02/19/reading-ntfs-and-share-security-with-vbscript/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Setting desktop wallpaper</title>
		<link>http://www.indented.co.uk/index.php/2008/12/23/setting-desktop-wallpaper/</link>
		<comments>http://www.indented.co.uk/index.php/2008/12/23/setting-desktop-wallpaper/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 13:27:50 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[group policy]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=671</guid>
		<description><![CDATA[Group Policy will, by default, only set the desktop wallpaper using Active Desktop. It is also possible to set the wallpaper using the logon script, or using a custom Group Policy template. Custom Group Policy Template The first thing to note about the custom policy is that it is an Unmanaged Policy. That means that [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Group Policy will, by default, only set the desktop wallpaper using Active Desktop. It is also possible to set the wallpaper using the logon script, or using a custom Group Policy template.<br />
<span id="more-671"></span></p>
<h3>Custom Group Policy Template</h3>
<p>The first thing to note about the custom policy is that it is an Unmanaged Policy. That means that any setting change will not revert if the policy is set to Disabled or Not Configured. The setting would have to be manually reversed or removed.</p>
<p>The second thing to note is that Unmanaged Policies are not displayed by default. After adding this template select the Administrative Templates folder under User Configuration, then View and Filtering. Remove the tick from &#8220;Show only policy settings that can be fully managed&#8221;. The policy will appear with a red icon instead of the regular blue icon.</p>
<p>This is a template that can be used to set the wallpaper on a client. It must be saved as a Administrative Template (.adm) file and manually added into a policy.</p>
<pre class="brush: plain;">
CLASS USER

CATEGORY &quot;Desktop&quot;
  CATEGORY &quot;Custom Policies&quot;

    KEYNAME &quot;Control Panel\Desktop&quot;

    POLICY &quot;Desktop Wallpaper&quot;

      EXPLAIN !!ExplainText

      PART !!WallpaperPathText EDITTEXT REQUIRED
        VALUENAME &quot;Wallpaper&quot;
      END PART

      PART !!WallpaperStyleText DROPDOWNLIST
        VALUENAME &quot;WallpaperStyle&quot;

        ITEMLIST
          NAME &quot;Centre&quot; VALUE NUMERIC 0 DEFAULT
          NAME &quot;Stretch&quot; VALUE NUMERIC 2
        END ITEMLIST
      END PART

      PART !!TileWallpaperText DROPDOWNLIST
        VALUENAME &quot;TileWallpaper&quot;

        ITEMLIST
          NAME &quot;No&quot; VALUE NUMERIC 0 DEFAULT
          NAME &quot;Yes&quot; VALUE NUMERIC 1
        END ITEMLIST
      END PART

    END POLICY

  END CATEGORY
END CATEGORY

[Strings]
ExplainText=&quot;Specifies the desktop background (wallpaper) displayed on all users' desktops.\n\nThe wallpaper image must be in bitmap (bmp) format.\n\nTo use this setting, type the fully qualified path and name of the file that stores the wallpaper image. You can type a local path, such as C:\Windows\web\wallpaper\home.bmp or a UNC path, such as \\Server\Share\Corp.bmp. If the specified file is not available when the user logs on, no wallpaper is displayed. You can also use this setting to specify that the wallpaper image be centered, tiled, or stretched.\n\nTo set wallpaper to Centre Tile must be disabled. To set wallpaper to Tiled both Centre and Tiled must be selected.&quot;
WallpaperPathText=&quot;Full UNC or path to Bitmap (bmp) file:&quot;
WallpaperStyleText=&quot;Centre or Stretch Wallpaper:&quot;
TileWallpaperText=&quot;Tile Wallpaper (if centre is selected):&quot;
</pre>
<h3>VbScript</h3>
<p>Alternatively, the same registry entries can be set using VbScript. This has the potential to be more flexible depending on the environment. It will run under a standard user, no need to grant extra rights on the PC.</p>
<pre class="brush: vb;">
Option Explicit

' Network and local locations for the wallpaper file.
' Must be BMP for the screen refresh to work
Const WALLPAPER_SOURCE = &quot;\\server01\netlogon\Wallpaper.bmp&quot;

Sub SetWallpaper
  ' Copies and sets the client wallpaper

  Const REG_HKCU = &amp;H80000001

  Dim objShell, objFileSystem, objFile, objRegistry
  Dim strWallpaperDestination, strKeyPath, strCommand

  ' Get the current user profile so we can copy the wallpaper there.
  Set objShell = CreateObject(&quot;WScript.Shell&quot;)
  strWallpaperDestination = objShell.ExpandEnvironmentStrings(&quot;%USERPROFILE%&quot;)

  ' Get the wallpaper file from the source
  Set objFileSystem = CreateObject(&quot;Scripting.FileSystemObject&quot;)
  Set objFile = objFileSystem.GetFile(WALLPAPER_SOURCE)

  ' Update the destination path to include the file name
  strWallpaperDestination = strWallpaperDestination &amp; &quot;\&quot; &amp; objFile.Name
  objFile.Copy strWallpaperDestination, True
  Set objFileSystem = Nothing

  ' Connect to the Registry on the local machine
  Set objRegistry = GetObject(&quot;winmgmts:\\.\root\default:StdRegProv&quot;)

  ' Set the values for the Wallpaper
  strKeyPath = &quot;Control Panel\Desktop&quot;
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;Wallpaper&quot;, _
    strWallpaperDestination

  ' Set the Position to Stretch
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;TileWallpaper&quot;, &quot;0&quot;
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;WallpaperStyle&quot;, &quot;2&quot;
  Set objRegistry = Nothing

  ' Update the system settings (refresh)
  strCommand = &quot;RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters&quot;
  objShell.Run strCommand, 1, True
  Set objShell = Nothing
End Sub

SetWallpaper
</pre>
<h3>Random wallpaper with VbScript</h3>
<p>I once had to deploy one of a selection of wallpapers to client computers on a network. It had to change (or at least attempt to change) each time the user logged on. This snippet uses the Randomize function in VbScript to generate a random number and pick a random file.</p>
<pre class="brush: vb;">
Option Explicit

Sub SetWallpaper
  ' Copies and sets the client wallpaper

  Const REG_HKCU = &amp;H80000001

  Dim objShell, objFileSystem, objFile, objRegistry
  Dim strWallpaperSource, strWallpaperDestination, strKeyPath, strCommand

  ' Get the current user profile so we can copy the wallpaper there.
  Set objShell = CreateObject(&quot;WScript.Shell&quot;)
  strWallpaperDestination = objShell.ExpandEnvironmentStrings(&quot;%USERPROFILE%&quot;)

  ' Get the source path
  strWallpaperSource = RandomizeWallpaper

  ' Get the wallpaper file from the source
  Set objFileSystem = CreateObject(&quot;Scripting.FileSystemObject&quot;)
  Set objFile = objFileSystem.GetFile(strWallpaperSource)

  ' Update the destination path to include the file name
  strWallpaperDestination = strWallpaperDestination &amp; &quot;\&quot; &amp; objFile.Name
  objFile.Copy strWallpaperDestination, True
  Set objFileSystem = Nothing

  ' Connect to the Registry on the local machine
  Set objRegistry = GetObject(&quot;winmgmts:\\.\root\default:StdRegProv&quot;)

  ' Set the values for the Wallpaper
  strKeyPath = &quot;Control Panel\Desktop&quot;
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;Wallpaper&quot;, strWallpaperDestination

  ' Set the Position to Stretch
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;TileWallpaper&quot;, &quot;0&quot;
  objRegistry.SetStringValue REG_HKCU, strKeyPath, &quot;WallpaperStyle&quot;, &quot;2&quot;
  Set objRegistry = Nothing

  ' Update the system settings (refresh)
  strCommand = &quot;RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters&quot;
  objShell.Run strCommand, 1, True
  Set objShell = Nothing
End Sub

Function RandomizeWallpaper
  Dim objShell, objFolder, objSubFolder, objFile
  Dim  strLogonServer
  Dim arrWallpaper()
  Dim i

  ' Get the current user profile so we can copy the wallpaper there.
  Set objShell = CreateObject(&quot;WScript.Shell&quot;)
  strLogonServer = objShell.ExpandEnvironmentStrings(&quot;%LOGONSERVER%&quot;)
  Set objShell = Nothing

  Set objFolder = objFileSystem.GetFolder(strLogonServer &amp; &quot;\NetLogon\Wallpaper&quot;)
  i = 0

  ' Get all the files beneath the folder
  For Each objFile in objFolder.Files
    ReDim Preserve arrWallpaper(i)
    arrWallpaper(i) = objFile.Path
    i = i + 1
  Next
  Randomize()

  ' Choose a random file
  i = Int(UBound(arrWallpaper) * Rnd())
  RandomizeWallpaper = arrWallpaper(i)
End Function

SetWallpaper
</pre>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/12/23/setting-desktop-wallpaper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Returning the OU for an object in AD</title>
		<link>http://www.indented.co.uk/index.php/2008/12/08/returning-the-ou-for-an-object/</link>
		<comments>http://www.indented.co.uk/index.php/2008/12/08/returning-the-ou-for-an-object/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 11:42:47 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=641</guid>
		<description><![CDATA[Occasionally it can be useful to know how to retrieve the parent, or OU holding an object, from Active Directory. Perhaps the easiest way to do this is using the Parent property. VbScript: Getting the OU for a user Set objUser = GetObject( _ &#34;LDAP://CN=Chris Dent,OU=Somewhere,DC=internal,DC=highorbit,DC=co,DC=uk&#34;) strParent = objUser.Parent WScript.Echo strParent In VbScript the value [...]


Related posts:<ol><li><a href='http://www.indented.co.uk/index.php/2010/01/22/changing-the-primary-group-with-powershell/' rel='bookmark' title='Permanent Link: Changing the Primary Group with PowerShell'>Changing the Primary Group with PowerShell</a> <small>Exactly as the title says, an example of how to...</small></li>
<li><a href='http://www.indented.co.uk/index.php/2009/10/02/get-dsacl/' rel='bookmark' title='Permanent Link: Get-DsAcl'>Get-DsAcl</a> <small>The goal of this PowerShell function is to create a...</small></li>
</ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Occasionally it can be useful to know how to retrieve the parent, or OU holding an object, from Active Directory.<br />
Perhaps the easiest way to do this is using the Parent property.<br />
<span id="more-641"></span></p>
<h3>VbScript: Getting the OU for a user</h3>
<pre class="brush: vb;">
Set objUser = GetObject( _
  &quot;LDAP://CN=Chris Dent,OU=Somewhere,DC=internal,DC=highorbit,DC=co,DC=uk&quot;)
strParent = objUser.Parent

WScript.Echo strParent
</pre>
<p>In VbScript the value returned is a string, to get the name of the OU either connect to the object then get the name attribute or parse the name out of the string (Split, or Mid, etc). The example below shows connecting to the parent object and echoing the name.</p>
<pre class="brush: vb;">
Set objParent = GetObject(strParent)
WScript.Echo objParent.Get(&quot;name&quot;)
</pre>
<h3>PowerShell: Getting the OU for a user</h3>
<pre class="brush: powershell;">
$DN = &quot;CN=Chris Dent,OU=Somewhere,DC=internal,DC=highorbit,DC=co,DC=uk&quot;
$User = [ADSI]&quot;LDAP://$DN&quot;
$Parent = $User.PSBase.Parent
</pre>
<p>PowerShell is a little different, the returned value is a DirectoryEntry, that means we can directly access any other property or attribute without connecting again.</p>
<pre class="brush: powershell;">
$DN = &quot;CN=Chris Dent,OU=Somewhere,DC=internal,DC=highorbit,DC=co,DC=uk&quot;
$User = [ADSI]&quot;LDAP://$DN&quot;
$Name = ($User.PSBase.Parent).Name
</pre>
<h3>Example: Getting the OU for all members of a group</h3>
<p>These examples assume that the group path is known, no searches are involved.</p>
<h4>VbScript</h4>
<pre class="brush: vb;">
Set objGroup = GetObject( _
  &quot;LDAP://CN=Domain Admins,CN=Users,DC=internal,DC=highorbit,DC=co,DC=uk&quot;)

Set objFileSystem = CreateObject(&quot;Scripting.FileSystemObject&quot;)
Set objFile = objFileSystem.OpenTextFile( _
  objGroup.Get(&quot;name&quot;) &amp; &quot; - Members.txt&quot;, 2, True, 0)

For Each objMember in objGroup.Members
  objFile.WriteLine objMember.Get(&quot;sAMAccountName&quot;) &amp; VbTab &amp; _
    objMember.Get(&quot;cn&quot;) &amp; VbTab &amp; _
    objMember.Parent
Next

Set objFile = Nothing
Set objFileSystem = Nothing

Set objGroup = Nothing
</pre>
<h4>PowerShell</h4>
<p>The note above about Parent returning a DirectoryEntry does not apply if using the Members method in PowerShell. The object returned is a COM Object and will not work in quite the same way. This is the equivalent of the VbScript above.</p>
<pre class="brush: powershell;">
$DN = &quot;CN=Domain Admins,CN=Users,DC=internal,DC=highorbit,DC=co,DC=uk&quot;
$Group = [ADSI]&quot;LDAP://$DN&quot;
$Group.PSBase.Invoke(&quot;Members&quot;) `
  | Select-Object `
    @{n=&quot;sAMAccountName&quot;;e={
      $_.GetType().InvokeMember(&quot;sAMAccountName&quot;, &quot;GetProperty&quot;, `
        $Null, $_, $Null)}}, `
    @{n=&quot;CN&quot;;e={
      $_.GetType().InvokeMember(&quot;cn&quot;, &quot;GetProperty&quot;, `
        $Null, $_, $Null)}}, `
    @{n=&quot;Parent&quot;;e={
      $_.GetType().InvokeMember(&quot;parent&quot;, &quot;GetProperty&quot;, `
        $Null, $_, $Null)}}
</pre>


<p>Related posts:<ol><li><a href='http://www.indented.co.uk/index.php/2010/01/22/changing-the-primary-group-with-powershell/' rel='bookmark' title='Permanent Link: Changing the Primary Group with PowerShell'>Changing the Primary Group with PowerShell</a> <small>Exactly as the title says, an example of how to...</small></li>
<li><a href='http://www.indented.co.uk/index.php/2009/10/02/get-dsacl/' rel='bookmark' title='Permanent Link: Get-DsAcl'>Get-DsAcl</a> <small>The goal of this PowerShell function is to create a...</small></li>
</ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/12/08/returning-the-ou-for-an-object/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exchange 2003: Returning mailbox sizes</title>
		<link>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-returning-mailbox-sizes/</link>
		<comments>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-returning-mailbox-sizes/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 12:13:20 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Exchange]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[information stores]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=604</guid>
		<description><![CDATA[This script uses WMI and Active Directory queries to return information about mailbox sizes from Exchange and the limits set in Active Directory. Download GetMailboxStatistics.vbs A number of people have been looking for Get-MailboxStatistics for Exchange 2003. I have a PowerShell version of this script for exactly that reason here. This script is only intended [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>This script uses WMI and Active Directory queries to return information about mailbox sizes from Exchange and the limits set in Active Directory.</p>
<p><a href='http://www.indented.co.uk/wp-content/uploads/2010/06/GetMailboxStatistics.txt'>Download GetMailboxStatistics.vbs</a></p>
<p>A number of people have been looking for Get-MailboxStatistics for Exchange 2003. I have a PowerShell version of this script for exactly that reason <a href="http://www.highorbit.co.uk/?p=871">here</a>.<br />
<span id="more-604"></span><br />
This script is only intended for use with Exchange 2003. Exchange 2000 must use MAPI, Exchange 2007 has a PowerShell cmdlet, Get-MailboxStatistics, which can much more easily return this information.</p>
<p>It requires access to WMI on each Exchange Server, but does not require any of the Exchange System Tools. legacyExchangeDN is used to match accounts between AD and Exchange.</p>
<p>The script performs a number of searches in Active Directory. The largest number if multiple Admin Groups are selected (/a:&#8221;Admin Group*&#8221;). It can be instructed to use a single DC by specifying a name with the /dc switch. For forest-wide searches that must be a Global Catalog. If no DC is specified the script executes a DNS query for Global Catalog service records on the current forest name to attempt to find a (responding) GC in the current site, failing back to any GC in the forest otherwise.</p>
<h4>Usage</h4>
<pre class="brush: plain;">
cscript GetMailboxStatistics.vbs [/o] [/s:&lt;exchangeServer&gt;]
        [/a:&quot;&lt;administrative Group Name&gt;&quot;] [/d:&lt;domainName&gt;]
        [/dc:&lt;domainControllerName&gt;] [/f:&lt;fileName&gt;]

One of the following parameters must be specified:

/o      Get statistics from all Exchange Servers in the organisation
        This option overrides all others
/s      Get statistics for this Exchange Server only
        This option overrides all except /o
/a      Get statistics from all Exchange Servers in the specified Administrative Group
/d      Get statistics from all Exchange Servers in the specified Domain

The following parameters are optional:

/dc     A Domain Controller to use for this process. Must be a Global Catalog
        for reporting that covers a Forest. The script will attempt to find a
        GC in the current site if not specified.
/f      File Name for the output. Default file name is MailboxReport.csv
</pre>
<p>The following details are returned by this script:</p>
<ul>
<li>Name</li>
<li>DN</li>
<li>AccountStatus (Enabled / Disabled)</li>
<li>UseDefaultQuotas (True / False)</li>
<li>Warn (in Mb, Warning Limit if specified on User Account)</li>
<li>ProhibitSend  (in Mb, if specified on User Account)</li>
<li>ProhibitSendAndReceive (in Mb, if specified on User Account)</li>
<li>Size (in Mb)</li>
<li>TotalItems</li>
<li>MailboxStatus (BelowLimit, IssueWarning, ProhibitSend, NoChecking, MailboxDisabled)</li>
<li>AssocContentCount (Total Number of messages associated with the mailbox folders)</li>
<li>DeletedMessageSize (in Mb)</li>
<li>LastLoggedOnUser</li>
<li>LastLogon</li>
<li>LastLogoff</li>
<li>DateDeleted (for mailboxes which have been disconnected, waiting to be purged)</li>
<li>MailboxDisplayName</li>
<li>MailboxGuid</li>
<li>ServerName (Exchange Server)</li>
<li>StorageGroup</li>
<li>Store</li>
<li>legacyExchangeDN</li>
</ul>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-returning-mailbox-sizes/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Finding a user in Exchange mailbox security</title>
		<link>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-finding-a-user-in-mailbox-security/</link>
		<comments>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-finding-a-user-in-mailbox-security/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 11:33:59 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Exchange]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[acl]]></category>
		<category><![CDATA[permissions]]></category>
		<category><![CDATA[securitydescriptor]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=575</guid>
		<description><![CDATA[A script to read the mailbox security descriptor from Active Directory with the intention of finding a particular user or security principal. It will not display the security descriptor, it simply displays whether or not the account is present in the access control list. The script works best when run with cscript as the script [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>A script to read the mailbox security descriptor from Active Directory with the intention of finding a particular user or security principal. It will not display the security descriptor, it simply displays whether or not the account is present in the access control list.<br />
<span id="more-575"></span><br />
The script works best when run with cscript as the script uses WScript.Echo to write back whether or not it finds a match.</p>
<p>It can be used against Exchange 2000 or Exchange 2003. Exchange 2007 can use Get-MailboxPermission to query the same information.</p>
<p>MailboxRights is used to retrieve the mailbox security descriptor. As part of CDOEXM (Collaboration Data Objects for Exchange Management) the Exchange System Tools must be installed on the system executing the script.</p>
<pre class="brush: vb;">
Option Explicit

' FindMailboxAccess.vbs
'
' Short Script to Find and Enumerate Mailbox Access for the specified
' security principal. Searches current domain, must be run as an Exchange Admin
' account to invoke MailboxRights method.
'
' This script is slow, it's speed is unavoidable as MailboxRights cannot be
' executed until connected to an individual user. That means we have to connect
' to every user account to determine whether or not the security principal is
' present within the ACL.
'
' Author: Chris Dent
' Modified: 04/01/2008

Sub UsageText
  Dim strMessage

  strMessage = &quot;Usage:&quot; &amp; VbCrLf &amp; VbCrLf
  strMessage = strMessage &amp; &quot;cscript &quot; &amp; WScript.ScriptName &amp; _
    &quot; &lt;search String&gt;&quot; &amp; VbCrLf
  strMessage = strmessage &amp; VbCrLf
  strMessage = strMessage &amp; &quot;Note: This script must be executed as Exchange &quot; &amp; _
    &quot;Administrator to enumerate&quot; &amp; VbCrLf
  strMessage = strMessage &amp; &quot;the Mailbox Security Descriptor&quot; &amp; VbCrLf
  WScript.Echo strMessage
  WScript.Quit
End Sub

Sub SortArgv
  Dim objArgv

  Set objArgv = WScript.Arguments
  If objArgv.Count &lt; 1 Then
    UsageText
  End If

  strSearchString = objArgv(0)

  Set objArgv = Nothing
End Sub

Sub SearchAD
  Const ADS_SCOPE_SUBTREE = 2

  Dim objConnection, objCommand, objRootDSE, objRecordSet, objUser
  Dim objMailboxSD, objDACL, objACE

  Set objConnection = CreateObject(&quot;ADODB.Connection&quot;)
  objConnection.Provider = &quot;ADsDSOObject&quot;
  objConnection.Open &quot;Active Directory Provider&quot;

  Set objCommand = CreateObject(&quot;ADODB.Command&quot;)
  objCommand.ActiveConnection = objConnection

  Set objRootDSE = GetObject(&quot;LDAP://RootDSE&quot;)
  objCommand.CommandText = &quot;SELECT distinguishedName, homeMDB &quot; &amp;_
    &quot;FROM 'LDAP://&quot; &amp; objRootDSE.Get(&quot;defaultNamingContext&quot;) &amp;_
    &quot;' WHERE objectClass='user' AND objectCategory='person'&quot;
  WScript.Echo &quot;Searching: &quot; &amp; objRootDSE.Get(&quot;defaultNamingContext&quot;)
  Set objRootDSE = Nothing

  objCommand.Properties(&quot;Page Size&quot;) = 1000
  objCommand.Properties(&quot;Timeout&quot;) = 600
  objCommand.Properties(&quot;Searchscope&quot;) = ADS_SCOPE_SUBTREE
  objCommand.Properties(&quot;Cache Results&quot;) = False

  Set objRecordSet = objCommand.Execute

  While Not objRecordSet.EOF
    On Error Resume Next
    If Not IsNull(objRecordSet.Fields(&quot;homeMDB&quot;)) Then
      ' Can't avoid connecting to the user, need to call the MailboxRights method

      Set objUser = _
        GetObject(&quot;LDAP://&quot; &amp; objRecordSet.Fields(&quot;distinguishedName&quot;).Value)

      Err.Clear
      Set objMailboxSD = objUser.MailboxRights
      Set objDACL = objMailboxSD.DiscretionaryAcl
      If Err.Number &lt;&gt; 0 Then
        ' Ignore It
      Else
        For Each objACE in objDACL
          If InStr(1, objACE.Trustee, strSearchString, VbTextCompare) Then
            WScript.Echo &quot;Found In Mailbox ACL: &quot; &amp; objUser.Name
          End If
        Next
      End If
      On Error Goto 0
    End If

    objRecordSet.MoveNext
  Wend
  objConnection.Close

  Set objRecordSet = Nothing
  Set objCommand = Nothing
  Set objConnection = Nothing
End Sub

'
' Main Code
'

Dim strSearchString

SortArgv

WScript.Echo &quot;Search String: &quot; &amp; strSearchString

SearchAD
</pre>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/10/28/exchange-2003-finding-a-user-in-mailbox-security/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VbScript: GetADSubnets</title>
		<link>http://www.indented.co.uk/index.php/2008/10/25/vbscript-active-directory-subnets/</link>
		<comments>http://www.indented.co.uk/index.php/2008/10/25/vbscript-active-directory-subnets/#comments</comments>
		<pubDate>Sat, 25 Oct 2008 10:46:37 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[subnet]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=543</guid>
		<description><![CDATA[The VbScript below demonstrates how subnet information might be retrieved from Active Directory. It is possible to use a search using to return this information (for objectClass=subnet). This method connects to the subnets container and loops through the contents returning the network address and mask length in a Dictionary object. Function GetADSubnets ' Return Type: [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>The VbScript below demonstrates how subnet information might be retrieved from Active Directory. It is possible to use a search using to return this information (for objectClass=subnet). This method connects to the subnets container and loops through the contents returning the network address and mask length in a Dictionary object.<br />
<span id="more-543"></span></p>
<pre class="brush: vb;">
Function GetADSubnets
  ' Return Type: Array

  Dim objRootDSE : Set objRootDSE = GetObject(&quot;LDAP://RootDSE&quot;)
  Dim objSubnets : Set objSubnets = GetObject(&quot;LDAP://CN=Subnets,CN=Sites,&quot; &amp; _
    objRootDSE.GEt(&quot;configurationNamingContext&quot;))

  Dim arrSubnets() : Dim i : i = 0
  For Each objSubnet in objSubnets
    ReDim Preserve arrSubnets(i)
    arrSubnets(i) = objSubnet.Get(&quot;name&quot;)
    i = i + 1
  Next

  GetADSubnets = arrSubnets
End Function
</pre>
<h3>Usage example</h3>
<pre class="brush: vb;">
WScript.Echo Join(GetADSubnets, vbCrlf)
</pre>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/10/25/vbscript-active-directory-subnets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modifying DNS records with WMI</title>
		<link>http://www.indented.co.uk/index.php/2008/10/23/modifying-dns-records-with-wmi/</link>
		<comments>http://www.indented.co.uk/index.php/2008/10/23/modifying-dns-records-with-wmi/#comments</comments>
		<pubDate>Thu, 23 Oct 2008 11:40:19 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Microsoft DNS]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[vbs]]></category>
		<category><![CDATA[wmi]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=252</guid>
		<description><![CDATA[Using WMI it is possible to modify any existing record hosted on a Microsoft DNS Server. The method used varies slightly depending on which record type we want to change. References for each version of the Modify method can be found in the DNS WMI Provider Reference. These are the most common: A Type CNAME [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Using WMI it is possible to modify any existing record hosted on a Microsoft DNS Server. The method used varies slightly depending on which record type we want to change.<br />
<span id="more-252"></span><br />
References for each version of the Modify method can be found in the <a href="http://msdn.microsoft.com/en-us/library/ms682128(VS.85).aspx">DNS WMI Provider Reference</a>. These are the most common:</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682181(VS.85).aspx">A Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682669(VS.85).aspx">CNAME Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682703(VS.85).aspx">MX Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682706(VS.85).aspx">NS Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682712(VS.85).aspx">PTR Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682738(VS.85).aspx">SRV Type</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms682744(VS.85).aspx">TXT Type</a></li>
</ul>
<p>The examples below show modification of Host or A records, but it is possible to extend the example to use any of the types above.</p>
<h3>Using VbScript to modify records</h3>
<p>This example demonstrates the use of WMI in VbScript to modify a record. The first value for Modify is the TTL, by using objItem.TTL we just reinsert the existing value, only changing the IP address.</p>
<pre class="brush: vb;">
' Connect to the WMI Service
Set objWMIService = GetObject(&quot;winmgmts:\\dc01\root\MicrosoftDNS&quot;)
' Run a query to get the record we want to change
Set colItems = objWMIService.ExecQuery(&quot;SELECT * FROM MicrosoftDNS_AType&quot; &amp; _
  &quot; WHERE ContainerName='thezone.net' AND OwnerName='test.thezone.net'&quot;,,48)

' Loop through the results
For Each objItem in colItems
  ' Modify the record
  objItem.Modify objItem.TTL, &quot;1.2.3.4&quot;
Next
</pre>
<p>If the TTL must be changed it is important to exclude the IP Address parameter, failure to do so will result in the record being deleted. Any attempt to use Modify without making any changes will result in a &#8220;SWbemObjectEx: Generic failure&#8221; exception.</p>
<h3>Using PowerShell to modify records</h3>
<p>The same failure reasons and restrictions apply with PowerShell (including the obscure deletion). Otherwise changing the record can be performed like this.</p>
<pre class="brush: powershell;">
$ServerName = &quot;dns01&quot;
$ContainerName = &quot;somedomain.example&quot;
$RecordName = &quot;test.somedomain.example&quot;

$Record = Get-WMIObject -Computer $ServerName `
  -Namespace &quot;root\MicrosoftDNS&quot; -Class &quot;MicrosoftDNS_AType&quot; `
  -Filter &quot;ContainerName='$ContainerName' AND OwnerName='$RecordName'&quot;
# Using the existing TTL value (in seconds)
$ModifiedRecord = $Record.Modify($Record.TTL, &quot;2.3.4.5&quot;)
</pre>
<p>In both VbScript and PowerShell the method call returns an object representing the updated record if further processing is required.</p>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/10/23/modifying-dns-records-with-wmi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Auditing userAccountControl with VbScript</title>
		<link>http://www.indented.co.uk/index.php/2008/10/22/auditing-useraccountcontrol/</link>
		<comments>http://www.indented.co.uk/index.php/2008/10/22/auditing-useraccountcontrol/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 19:23:51 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[VbScript]]></category>
		<category><![CDATA[userAccountControl]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://www.highorbit.co.uk/?p=444</guid>
		<description><![CDATA[This VbScript searches the current domain for all users with &#8220;User cannot change password&#8221;, &#8220;Password never expires&#8221;, or &#8220;Trusted for delegation&#8221; set, the results of the search are written to a tab delimited text file. ' UserAccountControl.vbs ' ' Script to report User Account Control Flag usage within the current domain. ' ' Author: Chris [...]


No related posts.

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>This VbScript searches the current domain for all users with &#8220;User cannot change password&#8221;, &#8220;Password never expires&#8221;, or &#8220;Trusted for delegation&#8221; set, the results of the search are written to a tab delimited text file.<br />
<span id="more-444"></span></p>
<pre class="brush: vb;">
' UserAccountControl.vbs
'
' Script to report User Account Control Flag usage within the current domain.
'
' Author: Chris Dent
' Modified: 06/03/2008

Option Explicit

Const REPORT_FILE = &quot;Users.txt&quot;

' userAccountControl flag values
Const ADS_UF_PASSWD_CANT_CHANGE = &amp;H40
Const ADS_UF_DONT_EXPIRE_PASSWD = &amp;H10000
Const ADS_UF_TRUSTED_FOR_DELEGATION = &amp;H80000
Const ADS_SCOPE_SUBTREE = 2

Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &amp;H6
Const CHANGE_PASSWORD_GUID  = &quot;{ab721a53-1e2f-11d0-9819-00aa0040529b}&quot;

'
' Main Code
'

Dim objFileSystem, objFile, objConnection, objCommand
Dim objRootDSE, objRecordSet, objUser
Dim objSD, objDACL, objACE
Dim strPwdCantChange, strPwdDontExpire, strTrustedForDelegation
Dim strDisplayName, strUsername, strDN
Dim intUAC
Dim booList

' Create report file
Set objFileSystem = CreateObject(&quot;Scripting.FileSystemObject&quot;)
Set objFile = objFileSystem.OpenTextFile(REPORT_FILE, 2, True, 0)

' Write header
objFile.WriteLine &quot;Display Name&quot; &amp; VbTab &amp; &quot;Username&quot; &amp; VbTab &amp;_
  &quot;Distinguished Name&quot; &amp; VbTab &amp; &quot;Password Cannot Change&quot; &amp;_
  VbTab &amp; &quot;Password Never Expires&quot; &amp; VbTab &amp; &quot;Trusted for Delegation&quot;

Set objConnection = CreateObject(&quot;ADODB.Connection&quot;)
objConnection.Provider = &quot;ADsDSOObject&quot;
objConnection.Open &quot;Active Directory Provider&quot;

Set objCommand = CreateObject(&quot;ADODB.Command&quot;)
objCommand.ActiveConnection = objConnection

' Configure search
Set objRootDSE = GetObject(&quot;LDAP://RootDSE&quot;)
objCommand.CommandText = &quot;SELECT displayName, distinguishedName, &quot; &amp;_
  &quot;sAMAccountName, userAccountControl, nTSecurityDescriptor FROM 'LDAP://&quot; &amp;_
  objRootDSE.Get(&quot;defaultNamingContext&quot;) &amp;_
  &quot;' WHERE objectClass='user' AND objectCategory='person'&quot;
Set objRootDSE = Nothing

objCommand.Properties(&quot;Page Size&quot;) = 1000
objCommand.Properties(&quot;Timeout&quot;) = 600
objCommand.Properties(&quot;Searchscope&quot;) = ADS_SCOPE_SUBTREE
objCommand.Properties(&quot;Cache Results&quot;) = False
Set objRecordSet = objCommand.Execute

While Not objRecordSet.EOF
  strPwdCantChange = &quot;False&quot; : strPwdDontExpire = &quot;False&quot;
  strTrustedForDelegation = &quot;False&quot;
  booList = False

  intUAC = objRecordSet.Fields(&quot;userAccountControl&quot;)

  ' Check for Password Cannot Change Flag

  Set objUser = GetObject(&quot;LDAP://&quot; &amp; objRecordSet.Fields(&quot;distinguishedName&quot;))
  Set objSD = objUser.Get(&quot;nTSecurityDescriptor&quot;)
  Set objDACL = objSD.DiscretionaryAcl

  For Each objACE in objDACL
    If objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT And _
        LCase(objACE.ObjectType) = CHANGE_PASSWORD_GUID Then

      strPwdCantChange = &quot;True&quot; : booList = True
      Exit For
    End If
  Next

  Set objDACL = Nothing
  Set objSD = Nothing
  Set objUser = Nothing

  ' Check for password never expires

  If intUAC And ADS_UF_DONT_EXPIRE_PASSWD Then
    strPWDDontExpire = &quot;True&quot; : booList = True
  End If

  ' Check for trusted for delegation

  If intUAC And ADS_UF_TRUSTED_FOR_DELEGATION Then
    strTrustedForDelegation = &quot;True&quot; : booList = True
  End If

  If booList = True Then
    strDisplayName = objRecordSet.Fields(&quot;displayName&quot;)
    strUsername = objRecordSet.Fields(&quot;sAMAccountName&quot;)
    strDN = objRecordSet.Fields(&quot;distinguishedName&quot;)

    objFile.WriteLine strDisplayName &amp; VbTab &amp; strUsername &amp; VbTab &amp;_
    strDN &amp; VbTab &amp; strPwdCantChange &amp; VbTab &amp; strPwdDontExpire &amp;_
    VbTab &amp; strTrustedForDelegation
  End If

  objRecordSet.MoveNext
Wend

objConnection.Close

Set objRecordSet = Nothing
Set objCommand = Nothing
Set objConnection = Nothing
</pre>


<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.indented.co.uk/index.php/2008/10/22/auditing-useraccountcontrol/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
