<?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>Slipsec</title>
	<atom:link href="http://slipsec.com/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://slipsec.com/blog</link>
	<description>Blogging about Powershell</description>
	<lastBuildDate>Tue, 08 May 2012 12:49:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Oracle + XML + Xpath = bug?</title>
		<link>http://slipsec.com/blog/?p=368</link>
		<comments>http://slipsec.com/blog/?p=368#comments</comments>
		<pubDate>Sun, 06 May 2012 17:24:59 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[PLSQL]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=368</guid>
		<description><![CDATA[I was faced with a catch-all logging database table.  It was used to save off some transactions with other systems that are passed via XML, saved to a directory with some other files for processing.  The database saved time-stamps and some other &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=368">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>I was faced with a catch-all logging database table.  It was used to save off some transactions with other systems that are passed via XML, saved to a directory with some other files for processing.  The database saved time-stamps and some other metadata, but I needed to search it by looking for some specific values saved within the XML to do some bug-hunting during some specific transactions.  As I got to looking at the different ways I could do this, I discovered that oracle has some great options for XML parsing, exposing the power of <a href="http://en.wikipedia.org/wiki/XPath">Xpath </a>for use within queries.</p>
<p>The problem was, I kept running into some errors.  Specifically this one:</p>
<pre class="brush: text; gutter: false">ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00230: invalid character 0 (U+0000) found in a Name or Nmtoken
Error at line 2
ORA-06512: at &quot;SYS.XMLTYPE&quot;, line 254 
ORA-06512: at line 1</pre>
<p>&nbsp;</p>
<p>Doesn&#8217;t look too complicated, it&#8217;s finding a NULL character somewhere in the XML where I attempt to create <a href="http://docs.oracle.com/cd/B19306_01/appdev.102/b14259/xdb04cre.htm">XMLType </a><a href="http://docs.oracle.com/cd/B10500_01/appdev.920/a96616/arxml24.htm#1014689">from the</a> <a href="http://www.orafaq.com/wiki/CLOB">CLOB </a>to in order to use my xpath query.  So, I tried replace(myxmlcolumn,CHR(0),&#8221;) to simply remove the NULL.  I still got the error&#8211; strange indeed!  So, I tried replacing it with an &#8216;H&#8217;, just in case Oracle was being non-<a href="http://en.wikipedia.org/wiki/SQL#Standardization">ANSI </a>by treating (in my replace) the <a href="http://stackoverflow.com/questions/203493/why-does-oracle-9i-treat-an-empty-string-as-null">empty string as a NULL</a>.</p>
<p>At this point, I&#8217;m lost.  Research reveals a few vague hints at what could be going wrong, but interestingly there are a few hints out there about this being a bug.  I gave up and turned to trusty <a href="http://stackoverflow.com/">Stack Overflow</a> and <a href="http://stackoverflow.com/questions/10322612/lpx-00230-invalid-character-0-u0000-found-in-a-name-or-nmtoken">posted my situation</a>.  After a few days, and no answer&#8211; I posted a bounty on the question to up the incentive factor.  These guys would help me out for sure.</p>
<p>But no.  The bounty expired, and the closest I got was instructions to go search <a href="https://support.oracle.com/CSP/ui/flash.html">Oracle Support</a> for a bug.  No here&#8217;s where I have a problem&#8211; you must FIRST PAY to use the support site.  I understand and respect this business model if I required resources from Oracle.  However, I&#8217;m simply looking for verification that I&#8217;m dealing with a _known bug_ in the software, and if I am I should be able get some more details what exactly the bug is, so that I can be sure to avoid it.  I&#8217;m sure the fortune 50 company I work for has the 5-figure support contract, but I&#8217;m also sure it would take me weeks to go through the bureaucracy to get what I need.</p>
<p>So let&#8217;s get this straight, the software has been paid for, the license has been purchased, and my company even has a support contract, all to the tune of millions of dolars.  But for a simple contractor I still cannot use the product as the available documentation says I can because of a known bug.  I cannot even work around the bug with any certainty without first paying.  Worse yet, nobody can even tell me the details for fear of retribution from the company.</p>
<p>I hope someone will look at the business strategy here, because I&#8217;m at a bit of a loss.  As a developer just starting to experiment with Oracle databases, I have been given roadblocks.  I respect the model of paid support, but when there is a know bug, or a configuration that should be avoided, that crosses the line from support to documentation.</p>
<p>To the problem at hand, I simply gave up.  <a href="http://www.orafaq.com/node/895">CLOB</a>s offer some nice text proccessing, but it is exposed via the Oracle supplied package <a href="http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lob.htm">DBMS_LOB</a>.  The answer for me was to avoid any chance of the bug and sacrifice the gains from using a true xml language tool and just treat it as unstructured text.  This is a pretty fragile fix that Oracle has forced me into, but I have work to do.  I got lucky and the XML doesn&#8217;t change too much, and I can grab the first of the elements with the value I&#8217;m looking to use later in my query:</p>
<pre>Select dbms_lob.substr(myxmlcolumn, 10, dbms_lob.instr(myxmlcolumn,&#039;&lt;data&gt;&#039;) + 6)</pre>
<p>Ended up looking something like this (I&#8217;m taking out the \n to make it look better in a report)</p>
<pre class="brush: sql; gutter: true">Select * from(
  select dbms_lob.substr(message, 10, dbms_lob.instr(message,&#039;&lt;ASDFNumber&gt;&#039;) + 12)   AS ASDF_NUM,
  PROCESSIND,CREATEDT,LASTUPDATEDT,
  replace(replace(ERRORDES,CHR(10),&#039;--&#039;), CHR(13), &#039;&#039;) as Error_Description,
  replace(replace(MESSAGE,CHR(10),&#039;--&#039;), CHR(13), &#039;&#039;) as Message
from myschema.mytable
  WHERE internalserviceid= &#039;some stuff I wanted to query for&#039;
 and CREATEDT &gt; TO_DATE( sysdate -3) -- to_date(&#039;4/25/2012 04:30:00 pM&#039;, &#039;mm/dd/yyyy HH:MI:SS AM&#039;)
) WHERE ASDF_NUM in(
&#039;1234123410&#039;,
&#039;1234123411&#039;,
&#039;1234123412&#039;)
order by ASDF_NUM,CreateDT;</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=368</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DO NOT MESS WITH ORACLE CLIENT INSTALLS</title>
		<link>http://slipsec.com/blog/?p=364</link>
		<comments>http://slipsec.com/blog/?p=364#comments</comments>
		<pubDate>Sun, 06 May 2012 15:18:02 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=364</guid>
		<description><![CDATA[Honestly I have not encountered a mess of convolution and misery like this since trying to upgrade multiple Oracle clients on a single workstation. Week two at the new job, I tracked down a &#8220;Token too big&#8221; issue (a bit &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=364">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Honestly I have not encountered a mess of convolution and misery like this since trying to upgrade multiple Oracle clients on a single workstation. Week two at the new job, I tracked down a &#8220;Token too big&#8221; <a href="http://blogs.technet.com/b/surama/archive/2009/04/06/kerberos-authentication-problem-with-active-directory.aspx">issue</a> (a bit like catching a <a href="http://en.wikipedia.org/wiki/Snipe_hunt">snipe</a>, <a href="http://en.wikipedia.org/wiki/Brownie_(folklore)">brownie</a>, or <a href="http://en.wikipedia.org/wiki/Chupacabra">Chupacabra</a>&#8211; I thought these things were legend!)  Weeks 3-4 I fought with the Oracle client.</p>
<p>From what I am able to gather from versions 8 through 11 of Oracle, the client was <a href="http://blogs.msdn.com/b/adonet/archive/2009/06/15/system-data-oracleclient-update.aspx">deprecated </a>by the MS ADO.NET team, some of they design decisions are, well surprising.  From what I can gather, in the name of configurability, and portability some interesting decisions have been made.  Among the most interesting I have found are the storing and setting of: <a href="http://docs.oracle.com/cd/B28359_01/network.111/b28317/tnsnames.htm#NETRF007">connections to servers</a>, <a href="http://docs.oracle.com/cd/B12037_01/em.101/b12140/3_oui_oracle_homes.htm">switching between clients</a> the <a href="http://docs.oracle.com/cd/B12037_01/em.101/b12140/3_oui_oracle_homes.htm#i1005615">setting of the install and configuration roots</a><a href="http://www.youtube.com/watch?v=P_i1xk07o4g">,</a> or even the <a href="http://docs.oracle.com/cd/B12037_01/em.101/b12140/3_oui_oracle_homes.htm#i1005634">tracking of inventory</a>.  Take a look at the number of competing configuration stores in the <a href="http://docs.oracle.com/cd/B28359_01/install.111/b32007/deinstall.htm">uninstall instructions</a>, and you should get a good idea.  They include the Registry, Environmental variables, text files, the %path%, and even alternate settings just to allow for the overriding of these.</p>
<p>After furiously googling for 5 days straight, I still had no luck figuring why my powershell script stopped working.  Such a shame, it&#8217;s so HEAVY to start Toad when all I really want is to knock out a simple query with a single clause or two.  Unsupprisingly my computer almost always has Powershell open.  This is what happens when you have too much complexity.  I think myself pretty good with issues like this, but even with an offered bounty on <a href="http://stackoverflow.com/questions/9873501/error-when-trying-to-call-oracle-dataaccess-client-oracledataadapter-fill">StackOverflow</a>, there is no answer&#8230; well I think that speaks for itself.  What a mess.</p>
<p>So here is my advice.  If you have a working install I recommend two things: 1) do *NOT* mess with it.  and 2) do *NOT* install other versions.  This is great until you have multiple home-grown tools to run that require the different versions be installed at the same time.  Hence my mess <img src='http://slipsec.com/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=364</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AD Schema, Indexed Attributes</title>
		<link>http://slipsec.com/blog/?p=296</link>
		<comments>http://slipsec.com/blog/?p=296#comments</comments>
		<pubDate>Fri, 09 Jul 2010 22:34:44 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[AD]]></category>
		<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[powershell]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=296</guid>
		<description><![CDATA[I needed to optimize a query and make sure that I was only hitting indexed attributes. So I&#8217;d better find out what&#8217;s being indexed. Each piece of the schema is stored as an LDAP object, and each of those has &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=296">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>I needed to optimize a query and make sure that I was only hitting indexed attributes.</p>
<p>So I&#8217;d better find out what&#8217;s being indexed.  Each piece of the schema is stored as an LDAP object, and each of those has a bitwise property named <a href="http://msdn.microsoft.com/en-us/library/ms679765(VS.85).aspx">SearchFlags</a> where 1=Index.  </p>
<pre class="brush: powershell">

#Connect to the rootDSE
$dse = [adsi]"LDAP://rootDSE"
#Look up the schema naming context
$schema = [adsi]"LDAP://$($dse.schemaNamingContext)"
#Build a directory searcher
$ds = new-ojbect DirectoryServices.DirectorySearcher
#LDAP queries can have a built-in bitwise AND
$bAND1 = "1.2.840.113556.1.4.803:=1"
$ds.SearchRoot = $schema
$ds.Filter = "(&#038;(objectclass=attributeSchema)(searchFlags:$bAND1))"
$indexed = $ds.FindAll()
$indexed | ft {$_.properties.cn}
</pre>
<p>Of note here is the handy <a href="http://support.microsoft.com/kb/269181">bitwise flags</a> I can put in my filter.   It looks like &#8220;attributename:ruleOID:=value&#8221; where ruleOID for Bitwise AND is 1.2.840.113556.1.4.803.  The last line I&#8217;m not dealing with a DirectoryServices.DirectoryEntry object, but with a DirectoryServices.SearchResult, so I have to drill through the properties attribute to get the cn.</p>
<p>When I&#8217;m working with scripts interactively like this, I often chop up an array on the fly using a range operator so I don&#8217;t send thousands of objects down the pipeline like so: $array[0..4] | %{#do stuff}.  This is fine most of the time but does get a bit funky when dealing with children.  Initially, I had been working with $schema.children.  Trying to specify an index or range objects with &#8220;Unable to index into an object of type System.DirectoryServices.DirectoryEntries&#8221;.  Not something that inherits the full collection interface, but no matter- it&#8217;s easy enough to just force it to an array.  Found this gem from <a href="http://mow001.blogspot.com/2006/06/powershel-and-active-directory-part-1.html">//o//</a>.</p>
<pre class="brush: powershell">
$children = $schema.children

#fails:
$children[0..4]
#forcing to an array: win
(@($children))[0..4] | Format-List
</pre>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=296</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AD password expiration, and powershell</title>
		<link>http://slipsec.com/blog/?p=284</link>
		<comments>http://slipsec.com/blog/?p=284#comments</comments>
		<pubDate>Wed, 28 Apr 2010 03:53:50 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[AD]]></category>
		<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Every Day Powershell]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[Quick Tip]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=284</guid>
		<description><![CDATA[Yes, I&#8217;m a bit spoiled by having exchange cmdlets on the majority of servers I run. A client wanted a password expiration date check, and ANR is a way for me to be lazy. get-mailbox *@example.com &#124; %{ $ds = &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=284">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Yes, I&#8217;m a bit spoiled by having exchange cmdlets on the majority of servers I run.  A client wanted a password expiration date check, and <a href="http://www.informit.com/articles/article.aspx?p=30117&#038;seqNum=5">ANR</a> is a way for me to be lazy. </p>
<pre class="brush: powershell">
get-mailbox *@example.com | %{
  $ds = New-Object DirectoryServices.DirectorySearcher
  $ds.Filter = "(UserPrincipalName=$($_.UserPrincipalName))"
  $res = $ds.findall()
  "$($_.UserPrincipalName)`n"  + [datetime]::FromFileTime( $($res[0].Properties.pwdlastset))
}
</pre>
<p>This being a very fast answer to the problem has a few touches needed if I want to consider this ready to reuse:</p>
<ul>
<li>I should not be using Exchange cmdlets when I&#8217;m building a new DirectorySearcher anyway.</li>
<li>I need to add checks for the bitwise parameter to catch &#8220;password never expires&#8221; where set.</li>
</ul>
<p>But it&#8217;s the week of 2010 scripting games.  I&#8217;ll add these to the list of things I need to revisit.</p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=284</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Take some Powershell Exchange inbox!</title>
		<link>http://slipsec.com/blog/?p=268</link>
		<comments>http://slipsec.com/blog/?p=268#comments</comments>
		<pubDate>Tue, 27 Apr 2010 03:48:41 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Exchange2007]]></category>
		<category><![CDATA[powershell]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=268</guid>
		<description><![CDATA[Raw snippet, but very cool. Will need to do a lot of cleanup and turn into a module, but just playing around I&#8217;m pretty excited about being able to get my email from Powershell&#8230; and without Outlook. More to come. &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=268">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Raw snippet, but very cool.  Will need to do a lot of cleanup and turn into a module, but just playing around I&#8217;m pretty excited about being able to get my email from Powershell&#8230; and without Outlook.  More to come.  </p>
<p>Install EWS managed API from here http://www.microsoft.com/downloads/details.aspx?displaylang=en&#038;FamilyID=c3342fb3-fbcc-4127-becf-872c746840e1</p>
<pre class="brush: powershell">
#default install path:
$dllpath = "C:Program FilesMicrosoftExchangeWeb Services1.0Microsoft.Exchange.WebServices.dll"
[Reflection.Assembly]::LoadFile($dllpath)
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = Net.NetworkCredential('myUserName', 'MyPassw0rd', 'netBIOSdomainName')
$s.AutodiscoverUrl("myEmail@example.com")

$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(25)

#show folders in inbox, with some interesting properties
$inbox.FindFolders($folderView) |ft DisplayName,TotalCount,ChildFolderCount -AutoSize

#load the rest of the items to use for the MAPI propertySet
$pSubject = [Microsoft.Exchange.WebServices.Data.ItemSchema]::subject
$pAttachments = [Microsoft.Exchange.WebServices.Data.ItemSchema]::HasAttachments
$pReceived = [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived

#make a view (25 deep, no offset)
$ItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(25)
$ItemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow
$ItemView.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly, $pSubject, $pAttachments, $pBody, $pReceived)

#find, show!
$res = $inbox.FindItems($itemView)
$res | ft DateTimeReceived,HasAttachments,Subject -AutoSize
</pre>
<p>And that&#8217;s all there was to it.  Can&#8217;t wait to do more.</p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=268</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exchange mailbox move/export progress tracking.</title>
		<link>http://slipsec.com/blog/?p=270</link>
		<comments>http://slipsec.com/blog/?p=270#comments</comments>
		<pubDate>Sat, 24 Apr 2010 00:09:16 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[Exchange2007]]></category>
		<category><![CDATA[powershell]]></category>
		<category><![CDATA[Quick Tip]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=270</guid>
		<description><![CDATA[While an export is running I have found that I often wish I knew how much or what mailboxes have not successfully processed so I can get a head start on repairing corruption or other problems. This poses a few &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=270">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>While an export is running I have found that I often wish I knew how much or what mailboxes have not successfully processed so I can get a head start on repairing corruption or other problems.  This poses a few problems: 1 the xml report file does not yet have the correct closing tags.  This can be fixed by using he following:</p>
<pre class="brush: powershell">
$foo = [xml]((gc 'C:Program FilesMicrosoftExchange ServerLoggingMigrationLogsexport-Mailbox20100423-160215-9382781.xml') + "  </TaskDetails></export-Mailbox>")
</pre>
<p>This is from a quick copy-past of the host display seen as individual mailboxes are exported.  I could have set the export-mailbox or move-mailbox to an explicit file, but this is DIRTY scripting, so I don&#8217;t care that much and just copied the name from the output in another shell window after using the default.</p>
<p>The two tags that are left open vary a tiny bit between <export-mailbox> and <move-mailbox>, but no matter- sub the correct closers.  Some quick powershell XML hacking gets the unsuccessfull mailboxes, and I&#8217;ll revisit this post in a bit to add some details for success.</p>
<pre class="brush: powershell">
 $foo.'export-Mailbox'.TaskDetails.Item | ?{$_.result.ErrorCode -ne 0} | %{write-host -for Cyan "$($_.source.Identity)"; $_.result.'#text'}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=270</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Logon Scripting with .vbs, Deleting the Outlook Profile, Registry and AD with .vbs.</title>
		<link>http://slipsec.com/blog/?p=200</link>
		<comments>http://slipsec.com/blog/?p=200#comments</comments>
		<pubDate>Sun, 21 Feb 2010 22:24:36 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[AD]]></category>
		<category><![CDATA[Exchange]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[vbs]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=200</guid>
		<description><![CDATA[I can&#8217;t wait for the day that every client in my domain has powershell installed on it. Then everyone can be set to the following .vbs set objShell = CreateObject( “Wscript.Shell” ) objShell.run( “powershell.exe -noexit c:scriptslogon.ps1” ) So I have &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=200">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>I can&#8217;t wait for the day that every client in my domain has powershell installed on it.  Then everyone can be set to the following .vbs</p>
<pre class="brush: vb">
set objShell = CreateObject( “Wscript.Shell” )
objShell.run( “powershell.exe -noexit c:scriptslogon.ps1” )
</pre>
<p>So I have no choice, I must do something I&#8217;ve avoided for a long time.  I must wade into the quirks, oddities, and idiosyncrasies of VB Script.  Among them I had to brush up on:</p>
<ul>
<li>The use of &#8221; to escape &#8221; as in: &#8220;look a &#8220;&#8221;quotation&#8221;"!&#8221; &#8211; good luck trying to figure the right keywords to google this.</li>
<li>The <a href="http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx">syntactical overloading of parentheses</a> for FOUR different language elements, and the fuzzy rules on how this is decided.</li>
<li>Foreign (to me) structuring of <a href="http://www.tizag.com/vbscriptTutorial/vbscriptelseif.php">If, Else, ElseIf, and End If</a></li>
<li>Error Handling (<a href="http://www.vbdotnetheaven.com/UploadFile/ecabral/ADandNETInVB11112005020216AM/ADandNETInVB.aspx">example</a>) (<a href="http://msdn.microsoft.com/en-us/library/53f3k80h(VS.85).aspx">MSDN</a>).  On Error goto 0?  How dirty I feel! goto #fail.</li>
</ul>
<p>But while I wait for the ubiquity of windows 7 (thus powershell 2.0) being installed on all client machines; migrations must be done so I&#8217;m faced the following requirements:</p>
<ol>
<li>Allow for &#8220;click-style admins&#8221; &#8211; those who  to control the execution of a logon script</li>
<li>Script must execute once, and only once</li>
<li>Script must delete the MAPI profile so that users may use Autodiscover to setup their new Outlook Anywhere profiles on our multitenancy system.</li>
<li>(bonus) Lock out user access to the user&#8217;s current Exchange mailbox on their own system</li>
</ol>
<p>First: allowing for execution (or not) of the script though an easy to administer way to control the execution of the script.  I chose to use group membership.  This lets the helpdesk personnel to simply add the users to be migrated to an AD group.  Easy schmeezy for them.  On the backend, it means that the logon script must check for membership in the group so:</p>
<pre class="brush: vb">
groupDN = "CN=lescript,OU=lescript,OU=Department,DC=FABRICAM,DC=DOM"
  Set objSysInfo = CreateObject("ADSystemInfo")
  Set user = getObject("LDAP://" &#038; objSysInfo.UserName)
  on error resume next
  memberOf = user.getex("memberOf")
  If (Err.Number <> 0) then
    'you are here if the user is a member of no groups.
    'msgbox("you are member of no groups")
    On Error GoTo 0
  else
    For Each objGroup in memberOf
      'msgbox("objgroup,groupDN is: " &#038; vbcr &#038; objGroup &#038; vbcr &#038;groupDN)
      If objGroup = groupDN Then
        'Checks completed.  "Work" code goes here.
      End If
    Next
  End If
</pre>
<p>On line 0 I hard code the DN of the group I want to test membership in.  Lines 1-2 create the LDAP object for connecting to AD.  Line 3 changes the error handling so I can capture errors and handle them.  This is needed because if the user is a member of no groups, an error will be thrown and needs to be handled.  Because I&#8217;m only enabling error handling here, any _other_ ADSI problems should cause execution to stop due to the default error handling.  The use of <a href="http://msdn.microsoft.com/en-us/library/aa746500(VS.85).aspx">getex()</a> over <a href="http://msdn.microsoft.com/en-us/library/aa746502(VS.85).aspx">get()</a> is important here because it is <a href="http://msdn.microsoft.com/en-us/library/aa746500(VS.85).aspx">guaranteed to return an array</a>, which can then be iterated through with For Each.  Finally on line 12 we pass the last If statement and have completed this requirement.</p>
<p><a href="http://technet.microsoft.com/en-us/library/cc784088(WS.10).aspx">Assigning a logon script to a user or group</a>.<br />
<a href="http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/usersgroups/groups/ ">Using AD groups from VBScript</a>.<br />
<a href="http://www.codeproject.com/KB/vbscript/userinfo.aspx">Getting the current AD user information from a logon script</a>.<br />
<a href="http://www.computerperformance.co.uk/vbscript/vbscript_group_enumerate_members.htm">Enumerating AD Group membership from vbs</a>.<br />
<a href="http://www.vbdotnetheaven.com/UploadFile/ecabral/ADandNETInVB11112005020216AM/ADandNETInVB.aspx">A more familiar way to .NET programmers</a> using DirectoryServices.DirectoryEntry (I found this after I had a working script <img src='http://slipsec.com/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  )</p>
<p>Next: Execution should be once, and only once.  We don&#8217;t want to be deleting the Outlook profile every time a user logs on.</p>
<pre class="brush: vb">
Set wmiLocator = CreateObject("WbemScripting.SWbemLocator") 'to get to stdRegProv
Set wshNetwork = CreateObject("WScript.Network") 'used to determine local machine name
'msgbox("name: " &#038; WshNetwork.ComputerName"
set wmiNS = wmiLocator.ConnectServer(wshNetwork.ComputerName,"rootdefault") 'WMI namespace
set objReg = wmiNS.Get("StdRegProv")
</pre>
<p>In this snippet, I go through the steps required to get a connection to the local registry.  More on <a href="http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/registry/">working with the registry and keys</a> from vbs.  The comments are pretty self-explanatory, and the good news is that because I&#8217;m only looking at the HKCU hive, I&#8217;m do not need to use impersonation.  </p>
<pre class="brush: vb">
if objGroup = groupDN then
  set wsh = createobject("wscript.shell")
  on error resume next
  key = wsh.RegRead("HKCUProfileDeleted")
  'when err = (hex)80070002, key does not exist
  if err.number <> 0 then
    if hex(err.number) = 80070002 then
      'msgBox("Script set to run: deleting profile and adding reg. key")
      'wsh.sleep 14000
      'old way: lRC = DeleteRegEntry(HKEY_CURRENT_USER, profile)
      wsh.RegWrite"HKCUProfileDeleted", "True", "REG_SZ"
      wsh.run("regDelete.bat")
    End If
  Else
    if key = "True" then
      'msgBox("Profile has already been deleted, nothing will be done.")
    ElseIf key = "False" then
      'external editing of the key is the only way to get here.
      'Either the key does not exist, or it's set to true by the script.
    msgBox("Please report this message to support" &#038; vbcr &#038; _
      """Profile deletion key was set to False, no action was taken.""" &#038; vbcr &#038; _
      "HKCUProfileDeleted")
    Else
      msgbox("Please report this error to support" &#038; vbcr &#038; _
        """Key set to something other than True or False""" &#038; _
        vbcr &#038; "HKCUProfileDeleted" &#038; vbcr &#038; "Key value: " &#038; key)
    End If
  End If
</pre>
<p>In this section (executed after the group membership tests above) I check for registry key named &#8220;HKCUProfileDeleted&#8221;.  If it does NOT exist (Line 6 checks for this read error), then I add it, set it to &#8220;True&#8221;, and run the batch file &#8220;regDelete.bat&#8221;.  The rest of the snippet contains a do-nothing check if they key has already been set (lines 14-15) and error handling should the key be set to &#8220;False&#8221; (16-21) or some other value (22-25).  Since these states should never happen, I&#8217;m only kicking an error to a message box, and asking the user to report it.  </p>
<p>Now the &#8220;meat&#8221;: Deleting the MAPI profile.  Because the profile is nothing more than a stack of registry keys, it should be simple to delete right?  Wrong.  VBS apparently has no way to recursively delete a registry key without writing the recursion yourself.  If that wasn&#8217;t enough, for some reason I&#8217;ve been unable to completely isolate, when I tried to recursively delete keys (line 9) with the sample function (recursion handled via vbs logic) found here <a href="http://support.microsoft.com/kb/279847">kb279847</a>, some keys remain.  I tried the standard programmer &#8220;wait 10&#8243; solution in case something was accessing the MAPI profile and adding keys as I tried to delete them (line 8 ) but that yielded only slightly better results.  Less subkeys remained, but full recursive deletion still failed. </p>
<p>So what to do?  Well there&#8217;s <a href="http://technet.microsoft.com/en-us/library/ee692837.aspx">Wscript.shell.Run(foo.exe)</a> and that gives us the ability to run a file.  So why not take the easy way out and just do a &#8220;reg /delete&#8221;?</p>
<pre class="brush: text">
rem reg delete /va /f "HKCUSoftwareMicrosoftWIndows NTCurrentVersionWindows Messaging Subsystem"
regedit.exe /s \FABRICAM.DOMSYSVOLLCS.CORPscriptsprofileDelete.reg
</pre>
<p>Line 0 fails.  So I&#8217;m just moving on, I&#8217;m really tired of jumping through hoops at this point, but trial and error proves that line 1 (using regedit to load a .reg file) works out just fine.  I saved the &#8220;profileDelete.reg&#8221; to the System Volume and tested successfully.  </p>
<p>Yes, it seems like this should have been easier, but soon enough it won&#8217;t matter and I&#8217;ll be able to use powershell</p>
<pre class="brush: powershell">
remove-item -path "HKCUSoftwareMicrosoftWIndows NTCurrentVersionWindows Messaging Subsystem"
</pre>
<p>Until then the .reg file looks like this:</p>
<p><code lang="dos">Windows Registry Editor Version 5.00<br />
[-HKEY_CURRENT_USERSoftwareMicrosoftWindows NTCurrentVersionWindows Messaging Subsystem]</code></p>
<p><a href="http://support.microsoft.com/kb/310516">Forget it, I&#8217;ll use a .reg file</a><br />
<a href="http://support.microsoft.com/kb/252304#LetMeFixItMyselfAlways">Removing the Outlook profile registry keys using regedit</a><br />
<a href="http://www.mvps.org/serenitymacros/help.html">More recursive registry vbs (.reg too)</a></p>
<p>The &#8220;bonus&#8221; requirement of locking users out of their mailboxes I&#8217;ll handle in my next post.  Until then, you need an updated token&#8211; any ACL changes won&#8217;t take effect until you log out/in.  Remember mailbox ACLs are held in the LDAP property &#8220;msExchMailboxSecurityDescriptor&#8221;, and you&#8217;d need to go through the painful process of <a href="http://slipsec.com/blog/?p=179">decrypting</a> that.</p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=200</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Powershell text processing</title>
		<link>http://slipsec.com/blog/?p=190</link>
		<comments>http://slipsec.com/blog/?p=190#comments</comments>
		<pubDate>Thu, 08 Oct 2009 01:58:47 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[Every Day Powershell]]></category>
		<category><![CDATA[powershell]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=190</guid>
		<description><![CDATA[How I used powershell today. I&#8217;ve seen some of these &#8220;real life examples&#8221; of how people have dealt with real-world applications. Here is mine. I received a list of users I needed to migrate on my Exchange platform, but it &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=190">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>How I used powershell today.  I&#8217;ve seen some of these &#8220;real life examples&#8221; of how people have dealt with real-world applications.  Here is mine.  I received a list of users I needed to migrate on my Exchange platform, but it was in the wrong form because it was just a paste of the junky output of another script.  Long story short, I had a lot of crap around what I wanted from this file.  Sure, I could just paste this into excel &#038; figure out how to import it so they line up in a column &#038; I could just copy them out but… that wouldn’t be usefull in the future if I wanted to automate it so I wound up finding a few ways of doing it for next time.</p>
<p>Load up a “here-string” named $foo with some of the text I received (you can see the formatting &#038; junk I don&#8217;t want).  Since I&#8217;m doing this interactive, the >> prompts are there when I paste.</p>
<pre class="brush: powershell">

[PS] $foo = @"
>>                                      18                                      11 an@example.com                Third Storage Group
>>                                     144                                      67 hr@example.com                      Third Storage Group
>>                                     348                                     204 ce@example.com              Third Storage Group
>>                                     415                                      27 sr@example.com                     Fourth Storage Group
>>                                     439                                       7 uc@example.com                 Third Storage Group
>>                                    1305                                     237 al@example.com              Fourth Storage Group
--REMOVED FOR READABILITY--
@”
</pre>
<p>Check to see what element 1 is (I just find it easier to type than the first element [0]), it’s not a whole line so split the string on the newline character &#038; save it back into the same variable.  Strange that the here-string didn&#8217;t understand the newlines when I pasted the text in, but I&#8217;ll look more into that later.</p>
<pre class="brush: powershell">

[PS] $foo[1]

[PS] $foo = $foo.split("`n")
[PS] $foo[1]
                                    144                                      67 hr@example.com                      Third Storage Group
</pre>
<p>Now it’s a line, but I don’t want anything but the email address… so I came up with this mess:</p>
<pre class="brush: powershell">

[PS] $foo[1].split(" ", [StringSplitOptions]::RemoveEmptyEntries)
144
67
hr@example.com
Third
Storage
Group
</pre>
<p>Right, so that’s a PITA to use the messy ENUM from some namespace google told me about called [stringsplitoptions].  So let’s um… do it simpler.  Just splitting on a space (“ “) and using the “?” (Where-Object) to filter what comes down the pipeline.  </p>
<pre class="brush: powershell">

[PS] $foo[1].split(" ") | ?{$_ -like "*example.com"}
hr@example.com
</pre>
<p>Since that’s what I wanted (the email address only), I don’t need to just run it on one element of the array of strings $foo, I can do it on the whole thing by wrapping it inside it’s own scriptblock:</p>
<pre class="brush: powershell">

[PS] $foo | %{$_.split(" ") | ?{$_ -like "*example.com"}}
</pre>
<p>So it’s a pipeline inside of another pipeline.  I’d dare bash to pull this one off… but it’s just string processing so it’s pretty much what it was made for.</p>
<p>And with that, it’s on to my migration script:</p>
<pre class="brush: powershell">

[PS] $foo | %{$_.split(" ") | ?{$_ -like "*example.com"}} | Out-File example.com.1
[PS] ./init.ps1 -source example.com.1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=190</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Move-Mailbox -AllowMerge selects the wrong target</title>
		<link>http://slipsec.com/blog/?p=184</link>
		<comments>http://slipsec.com/blog/?p=184#comments</comments>
		<pubDate>Tue, 29 Sep 2009 20:12:56 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[AD]]></category>
		<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[Exchange2007]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[powershell]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=184</guid>
		<description><![CDATA[Never a good situation to find yourself in. Fist things first, I&#8217;m looking for clues on how the lookup is done on the target account.  Loading up the move-mailbox log &#38; casting it to XML makes it easy to work &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=184">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Never a good situation to find yourself in.</p>
<p>Fist things first, I&#8217;m looking for clues on how the lookup is done on the target account.  Loading up the move-mailbox log &amp; casting it to XML makes it easy to work with.</p>
<pre class="brush: powershell">

$log = [xml](gc C:logdirlogfile)
</pre>
<p>With that I can select the 2 mailboxes with the failed targets and see if there&#8217;s anything suspicious.  Looking at the &#8220;Target&#8221; node, it has little of interest, basically target forest GC and some other migration settings that have little if anything to do with the target account lookup.</p>
<pre class="brush: powershell">

$log."move-Mailbox".TaskDetails.Item | ?{$_.MailboxName -like "*foo*" -or $_.MailboxName -like "*bar*"} | %{$_.Source}
SourceDatabase
Identity
IsResourceMailbox
SourceDomainController
SourceDirectReports
SourcePublicDelegatesBL
SourceDeliverAndRedirect
SIDUsedInMatch
MatchedContactsDNList
Alias
SourceGlobalCatalog
SourceServer
SourceAltRecipientBL
SourcePublicDelegates
IsMatchedNTAccountMailboxEnabled
DistinguishName
DisplayName
PrimarySmtpAddress
LegacyExchangeDN
SourceManager
SMTPProxies
MatchedTargetNTAccountDN
SourceAltRecipient
</pre>
<p>Of interest, MatchedTargetNTAccountDN is incorrect, proving that the cmdlet lookup had the wrong account selected.  But why?  Looking at the SIDUsedInMatch I figured I should check the SID.</p>
<pre class="brush: powershell">

get-mailbox foo | %{[adsi]"LDAP://$($_.DistinguishedName)"} | %{
  $sid = New-Object System.Security.Principal.SecurityIdentifier $($_.objectSid),0
  $sid
  $sid.Translate([System.Security.Principal.NTAccount])
}
</pre>
<p>Good news, nothing matched.  So the confusion must be coming from somewhere else.  I know that the &#8216;sn&#8217; is used in ANR so this could be a possibility, but I doubt it since it would cause problems with all the &#8220;Smith&#8221; surnames on the system.</p>
<p>After checking all this&#8230; I&#8217;m waiting on a response from PSS, I&#8217;ll update when I have it <img src='http://slipsec.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=184</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exchange 2003 mailbox permissions.</title>
		<link>http://slipsec.com/blog/?p=179</link>
		<comments>http://slipsec.com/blog/?p=179#comments</comments>
		<pubDate>Mon, 14 Sep 2009 21:53:52 +0000</pubDate>
		<dc:creator>jstimmel</dc:creator>
				<category><![CDATA[AD]]></category>
		<category><![CDATA[cmdlet]]></category>
		<category><![CDATA[Exchange]]></category>
		<category><![CDATA[powershell]]></category>

		<guid isPermaLink="false">http://slipsec.com/blog/?p=179</guid>
		<description><![CDATA[WARNING!!! This is a 1/2 baked script that among other evil things: Doesn&#8217;t return objects Uses `t tab formatting as standard output Uses Write-Host BUT&#8230; it works.  Exchange 2007 provides different methods for these tasks, so I&#8217;m mainly preserving this &#8230;<p class="read-more"><a href="http://slipsec.com/blog/?p=179">Continue reading &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>WARNING!!! This is a 1/2 baked script that among other evil things:</p>
<ul>
<li>Doesn&#8217;t return objects</li>
<li>Uses `t tab formatting as standard output</li>
<li>Uses Write-Host</li>
</ul>
<p>BUT&#8230; it works.  Exchange 2007 provides different methods for these tasks, so I&#8217;m mainly preserving this for postarity as I close in on decomissioning my remaining 03 servers.  At some point I might need some of the functions or casts in here so I&#8217;m publishing something I&#8217;m not proud of.  If you like feel free to fix the issues, it&#8217;s bare minimum functionality at the moment, but like I said&#8211; it gets the job done.  After running the script as an audit, it was clear that the number of permissions I had to deal with in this migration made it not worth my time to automate the migration of them across forests.</p>
<p>So here is my pile of hackery:</p>
<pre class="brush: powershell">

param(
  [string]$OU = $(throw "Sorry, you must supply an OU.  Bye!")
)

#TODO don't pass the OU in a asinine way.
$SearchRoot = [adsi]"LDAP://OU=$OU"
$filter = "(&#038;(&#038;(&#038;(&#038;(mailnickname=*)(objectCategory=person)(objectClass=user)(msExchMailboxSecurityDescriptor=*)))))"
#$filter = "(&#038;(&#038;(&#038;(&#038;(mailnickname=cs)(objectCategory=person)(objectClass=user)(msExchMailboxSecurityDescriptor=*)))))"
$ds = New-Object DirectoryServices.DirectorySearcher($SearchRoot,$filter)
$ds.PageSize = 5000
$ds.PropertiesToLoad.Addrange(@("msExchMailboxSecurityDescriptor","userPrincipalName","objectSid"))

$ds.FindAll() | %{
  $user = $_.GetDirectoryEntry()
  Write-host -for Red "$($user.userPrincipalName)"

  #here the DaclByte is a byte[] that is the secuirtydescriptor
  [byte[]]$byteDACL = ($_.properties)["msexchmailboxsecuritydescriptor"][0]

  ###########################################################################
  #using an activeDirectorySecurity to manipulate the securityDescriptor
  #GetAccessRule is actually inherited from System.Security.AccessControl.DirectoryObjectSecurity, what's the point of using the child class?
  #http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.directoryobjectsecurity.getaccessrules.aspx
  #AuthorizationRuleCollection GetAccessRules(bool includeExplicit,bool includeInherited,Type targetType)
  ###########################################################################

  $adDACL = new-object System.DirectoryServices.ActiveDirectorySecurity
    #setSecurity...() takes a byte[] and will let us translate.
  $adDACL.SetSecurityDescriptorBinaryForm($byteDACL)
  $ACLs = $adDACL.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier])
  $ACLs | %{
    if(($_.IdentityReference).IsAccountSid()){
      #translate will barf if the account does not exist (say from an old Domain trust).  So I'm checking $? and not bothering to list permissions for missing accounts.
      #and hiding errors by changing EAP
      $oldEAP  = $ErrorActionPreference; $ErrorActionPreference = "SilentlyContinue"
      $name = ([System.Security.Principal.SecurityIdentifier]$_.IdentityReference).translate([System.Security.Principal.NTAccount])
      $exist = $?
      $ErrorActionPreference = $oldEAP

      if($exist){
        $permissions = @()
	    write-host -for CYAN "`t$name"
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::CreateChild){
          $ar = "FullAccess"
	  "`t`t$ar"
          $permissions += ,$ar
        }
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::WriteOwner -ne 0){
	  $ar = "ChangeOwner"
	  "`t`t$ar"
          $permissions += ,$ar
        }
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::WriteDacl){
          $ar = "Modify User Attributes"
	  "`t`t$ar"
          $permissions += ,$ar
        }
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::ListChildren){
          $ar = "Is mailbox primary owner of this object"
	  "`t`t$ar"
          $permissions += ,$ar
        }
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::Delete){
          $ar = "DeleteItem"
	  "`t`t$ar"
          $permissions += ,$ar
        }
        If ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::ReadControl){
          $ar = "ReadPermission"
	  "`t`t$ar"
          $permissions += ,$ar
        }
      }
    }
  }
  #TODO fix checks on invalid SIDs
  $sendAs = $user.psbase.get_objectSecurity().getAccessRules($true,$false, [System.Security.Principal.SecurityIdentifier]) | ?{$_.ObjectType -eq "ab721a54-1e2f-11d0-9819-00aa0040529b"}
  $sendAs | %{
    if(($_.IdentityReference).IsAccountSid()){

      #translate will barf if the account does not exist (say from an old Domain trust).  So I'm checking $? and not bothering to list permissions for missing accounts.
      #$oldEAP  = $ErrorActionPreference; $ErrorActionPreference = "SilentlyContinue"
      $name = ([System.Security.Principal.SecurityIdentifier]$_.IdentityReference).translate([System.Security.Principal.NTAccount])
      #$ErrorActionPreference =$oldEAP
      "`t`tSEND AS: $name"
      $permissions += ,$ar
    }
  }
  $recvAs = $user.psbase.get_objectSecurity().getAccessRules($true,$false, [System.Security.Principal.SecurityIdentifier])| ?{$_.ObjectType -eq "ab721a56-1e2f-11d0-9819-00aa0040529b"}
  $recvAs | %{
    if(($_.IdentityReference).IsAccountSid()){
      #translate will barf if the account does not exist (say from an old Domain trust).  So I check $? and not bothering to list permissions for missing accounts.
      #$oldEAP  = $ErrorActionPreference; $ErrorActionPreference = "SilentlyContinue"
      ([System.Security.Principal.SecurityIdentifier]$_.IdentityReference).translate([System.Security.Principal.NTAccount])
      #$ErrorActionPreference = $oldEAP
      $permissions += ,$ar
      "`t`tRECEIVE AS: $name"
    }
  }
  #TODO return objects instead of tab formatted strings.
  #Write-host -for Red "$($user.userPrincipalName)"
  #"`t`t$permissions"
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://slipsec.com/blog/?feed=rss2&#038;p=179</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

