<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Posts on hearn.sh</title>
        <link>https://www.hearn.us/posts/</link>
        <description>Recent content in Posts on hearn.sh</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <copyright>Tom Hearn</copyright>
        <lastBuildDate>Tue, 17 Mar 2020 19:30:00 -0400</lastBuildDate>
        <atom:link href="https://www.hearn.us/posts/index.xml" rel="self" type="application/rss+xml" />
        
        <item>
            <title>Coronavirus Information Security Tips</title>
            <link>https://www.hearn.us/posts/coronavirus-information-security-tips/</link>
            <pubDate>Tue, 17 Mar 2020 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/coronavirus-information-security-tips/</guid>
            <description>It&amp;rsquo;s been an interesting couple of days for sure. We are all trying to figure out what this whole Coronavirus ordeal actually means to our families and our daily lives. Schools, restaurants, bars, movie theaters and basically everything else is closed and we all wish we had invested in toilet paper companies 2 weeks ago.
Thankfully we have the internet to keep us all up to date (maybe too up to date!</description>
            <content type="html"><![CDATA[<p>It&rsquo;s been an interesting couple of days for sure.  We are all trying to figure out what this whole Coronavirus ordeal actually means to our families and our daily lives.  Schools, restaurants, bars, movie theaters and basically everything else is closed and we all wish we had invested in toilet paper companies 2 weeks ago.</p>
<p>Thankfully we have the internet to keep us all up to date (maybe too up to date!)</p>
<p>Unfortunately many will take advantage of the increased internet usage and overall anxious feelings that many of us have.  I have received questions from family members, friends and colleagues over the past weeks about random emails, websites, programs, and weird messages.</p>
<p>I figured it was time to publish some of these for the world to see so I can share this link each time they come in.</p>
<h2 id="standard-best-practices-still-apply">Standard Best Practices Still Apply&hellip;</h2>
<ul>
<li>Enable Multi Factor anywhere you can.  Banks, utility websites, password managers, etc.  If a service you are using doesn&rsquo;t offer this then you should reconsider another option.</li>
<li>Do not share your username, password, social security number, or any other personal information with anyone over the phone, email or text message</li>
<li>Keep your antivirus software up to date</li>
<li>Use a firewall on your home internet router and your local computer</li>
<li>Keep your computer, router, IoT devices, smart devices, etc updated (automatically if possible)</li>
<li>Do not use the same password for any website.  Consider using something like LastPass to generate random, strong passwords for each unique website you have to use for logging in</li>
<li>Watch out for phishing attempts imitating services like Google, Microsoft and many others.  This may often come from a URL that looks legitimate but is not.  If you suspect it is not legitimate take a screenshot and send it to someone that is knowledgeable and can help you validate.  Do not ever forward an email you suspect is a phishing attempt, virus, trojan or malware.</li>
</ul>
<h2 id="be-weary-of-coronavirus-trackers">Be weary of Coronavirus trackers</h2>
<ul>
<li>There is a plethora of malware, trojans and viruses using the current epidemic as a method to create fake Coronavirus trackers to take advantage of anxious users.  Only get your information and/or downloads from validated, relevant sources such as the CDC, DHHS, or your local state and county health departments.</li>
</ul>
<h2 id="be-weary-of-vpn-service-claims">Be weary of VPN service claims</h2>
<ul>
<li>There has been a surge in users purchasing VPN services over the past few years to &ldquo;hide activity from ISPs&rdquo; and to &ldquo;block website tracking.&rdquo;  These promises have only increased with more users working from home.  They are often misleading as you move from your ISP tracking you to the VPN service tracking you.  Many of these services are operated by companies in foreign countries.</li>
<li>If you are using a paid VPN service make sure it is reputable</li>
<li>If you are using a free VPN service I would recommend you stop</li>
<li>Assume anything you are doing on a paid VPN service can be (and most likely is) tracked</li>
</ul>
<h2 id="be-careful-when-donating">Be careful when donating</h2>
<ul>
<li>If someone calls you asking for donations ask them for their business information and a number you can call them back.  Hang up, look up their information online and if it&rsquo;s legitimate give them a call back</li>
<li>Make sure you are checking the URL of any online donations and it is a validated, secure connection to provide any credit card information</li>
</ul>
<h2 id="a-good-opportunity-to-change-your-passwords">A good opportunity to change your passwords</h2>
<ul>
<li>Consider changing some of your important passwords in case anyone has your primary account passwords.  A reputable source to monitor this for free is <a href="https://haveibeenpwned.com/">Have I Been Pwned</a></li>
<li>Rotate your WiFi password in case any neighbors might have it.  This is good practice every 6 months even without Coronavirus.</li>
</ul>
<h2 id="dont-forget-to-protect-your-employer">Don&rsquo;t forget to protect your employer</h2>
<ul>
<li>With so many employees working from home we are at a significantly increased risk of breaches to business sytems and confidential information</li>
<li>Make sure you are keeping your work-related information on your work device</li>
<li>Shut your work laptop down, disconnect your VPN and logout when you are not working</li>
<li>Make sure you are familiar with your company&rsquo;s policies around VPN, systems access and what to do if you suspect your credentials were compromised</li>
<li>Be patient with your IT staff.  They are definitely stressed right now with so many users working remotely.</li>
</ul>
]]></content>
        </item>
        
        <item>
            <title>Cloning SVN to Git Repositories</title>
            <link>https://www.hearn.us/posts/cloning-svn-to-git/</link>
            <pubDate>Sun, 16 Feb 2020 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/cloning-svn-to-git/</guid>
            <description>I&amp;rsquo;m only about 2 years late to the show, but figured I would share how easy it was to migrate from my local Subversion repository to a local Git repository.
Make sure you have local filesystem access to the SVN repository and run the following commands:
git svn clone --username=yourgitusername file:///mnt/nfs/fs/svn/YourRepository/ YourRepository.git cd YourRepository.git git remote add origin http://x.x.x.x:3000/yourgitusername/YourRepository.git git push -u origin master At this point you are good to start using your git repository and destroy your old SVN repository.</description>
            <content type="html"><![CDATA[<p>I&rsquo;m only about 2 years late to the show, but figured I would share how easy it was to migrate from my local Subversion repository to a local Git repository.</p>
<p>Make sure you have local filesystem access to the SVN repository and run the following commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git svn clone --username<span style="color:#f92672">=</span>yourgitusername file:///mnt/nfs/fs/svn/YourRepository/ YourRepository.git
cd YourRepository.git
git remote add origin http://x.x.x.x:3000/yourgitusername/YourRepository.git
git push -u origin master
</code></pre></div><p>At this point you are good to start using your git repository and destroy your old SVN repository.</p>
]]></content>
        </item>
        
        <item>
            <title>Load Balancing via mod_proxy_balancer in Apache</title>
            <link>https://www.hearn.us/posts/load-balancing-via-mod-proxy/</link>
            <pubDate>Thu, 02 Jan 2020 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/load-balancing-via-mod-proxy/</guid>
            <description>Configuring load balancing in Apache was, at first pass, a little cumbersome largely because I couldn&amp;rsquo;t find any relevant examples to what I was trying to do that were inclusive inside a Virtual Host.
So without further ado, here is a configuraton with sticky session round robin load balancing in Apache within a Virtual Host:
&amp;lt;VirtualHost *:80&amp;gt; ServerName hearn.us ServerAlias hearn.us *.hearn.us DocumentRoot /var/www/html ErrorLog logs/error_hearn.us.log CustomLog logs/access_hearn.us.log combined ProxyPreserveHost On ProxyRequests Off Header add Set-Cookie &amp;#34;ROUTEID=.</description>
            <content type="html"><![CDATA[<p>Configuring load balancing in Apache was, at first pass, a little cumbersome largely because I couldn&rsquo;t find any relevant examples to what I was trying to do that were inclusive inside a Virtual Host.</p>
<p>So without further ado, here is a configuraton with sticky session round robin load balancing in Apache within a Virtual Host:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-apacheconf" data-lang="apacheconf"><span style="color:#f92672">&lt;VirtualHost</span> <span style="color:#e6db74">*:80</span><span style="color:#f92672">&gt;</span>
    ServerName hearn.us
    ServerAlias hearn.us *.hearn.us
    DocumentRoot <span style="color:#e6db74">/var/www/html</span>
    ErrorLog logs/error_hearn.us.log
    CustomLog logs/access_hearn.us.log combined

    ProxyPreserveHost <span style="color:#66d9ef">On</span>
    ProxyRequests <span style="color:#66d9ef">Off</span>
    Header add Set-Cookie <span style="color:#e6db74">&#34;ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/&#34;</span> env=BALANCER_ROUTE_CHANGED

    <span style="color:#f92672">&lt;Proxy</span> <span style="color:#e6db74">balancer://hearn.us_cluster</span><span style="color:#f92672">&gt;</span>
        BalancerMember http://vcosbackend1:80 route=1 # first node
        BalancerMember http://vcosbackend2:80 route=2 # second node
        Order Deny,Allow
        Allow from <span style="color:#66d9ef">all</span>
        ProxySet stickysession=ROUTEID
    <span style="color:#f92672">&lt;/Proxy&gt;</span>

    ProxyPass / balancer://hearn.us_cluster/
<span style="color:#f92672">&lt;/VirtualHost&gt;</span>
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Apache Error: no space left on device</title>
            <link>https://www.hearn.us/posts/apache-error-no-space-left-on-device/</link>
            <pubDate>Mon, 18 Nov 2019 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/apache-error-no-space-left-on-device/</guid>
            <description>I recently encountered an issue with Apache where I had plenty of disk space free, but after running sudo service httpd restart I received the error:
Error: No space left on device
Running ipcs -s showed that after Apache stopped I was still holding active semaphores.
To Clean the semaphores I simply fixed with:
for i in ``ipcs -s | awk &amp;#39;/httpd/ {print $2}&amp;#39;``; do (ipcrm -s $i); done Restart Apache and you should be good to go!</description>
            <content type="html"><![CDATA[<p>I recently encountered an issue with Apache where I had plenty of disk space free, but after running sudo service httpd restart I received the error:</p>
<p>Error: No space left on device</p>
<p>Running ipcs -s showed that after Apache stopped I was still holding active semaphores.</p>
<p>To Clean the semaphores I simply fixed with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">for</span> i in <span style="color:#e6db74">``</span>ipcs -s | awk <span style="color:#e6db74">&#39;/httpd/ {print $2}&#39;</span><span style="color:#e6db74">``</span>; <span style="color:#66d9ef">do</span> <span style="color:#f92672">(</span>ipcrm -s $i<span style="color:#f92672">)</span>; <span style="color:#66d9ef">done</span>
</code></pre></div><p>Restart Apache and you should be good to go!</p>
]]></content>
        </item>
        
        <item>
            <title>Disabling ipv6 in CentOS 7</title>
            <link>https://www.hearn.us/posts/disabling-ipv6-in-centos7/</link>
            <pubDate>Mon, 12 Aug 2019 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/disabling-ipv6-in-centos7/</guid>
            <description>IPv6 can certainly cause some unexpected results in Linux land. Disabling is super easy, depending on your preference of all interfaces or a specific interface:
Create a file /etc/sysctl.d/disableipv6.conf:
For all interfaces:
net.ipv6.conf.all.disable_ipv6 = 1 For an individual interface:
net.ipv6.conf.eth0.disable_ipv6 = 1 Rename eth0 to whatever interface you would like to disable.
Restart after to apply:
shutdown -r now </description>
            <content type="html"><![CDATA[<p>IPv6 can certainly cause some unexpected results in Linux land. Disabling is super easy, depending on your preference of all interfaces or a specific interface:</p>
<p>Create a file /etc/sysctl.d/disableipv6.conf:</p>
<p>For all interfaces:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext">net.ipv6.conf.all.disable_ipv6 = 1
</code></pre></div><p>For an individual interface:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext">net.ipv6.conf.eth0.disable_ipv6 = 1
</code></pre></div><p>Rename eth0 to whatever interface you would like to disable.</p>
<p>Restart after to apply:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">shutdown -r now
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Setup a Site to Site VPN with Ubiquiti</title>
            <link>https://www.hearn.us/posts/ubiquiti-site-to-site-vpn/</link>
            <pubDate>Wed, 14 Nov 2018 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/ubiquiti-site-to-site-vpn/</guid>
            <description>I use Ubiquiti heavily in my lab environments. I have a hosted site that I keep a number of virtualization servers and storage and recently setup a formal Site to Site VPN across two ERPro-8 Ubiquiti routers. This will most likely work for anything in the Edge line.
For the sake of this configuration we&amp;rsquo;ll say this is between Router A and Router B.
Router A has the external IP of X.</description>
            <content type="html"><![CDATA[<p>I use Ubiquiti heavily in my lab environments.  I have a hosted site that I keep a number of virtualization servers and storage and recently setup a formal Site to Site VPN across two ERPro-8 Ubiquiti routers.  This will most likely work for anything in the Edge line.</p>
<p>For the sake of this configuration we&rsquo;ll say this is between Router A and Router B.</p>
<p>Router A has the external IP of X.X.X.X and an internal subnet of 10.100.200.0/24</p>
<p>Router B has the external IP of Y.Y.Y.Y and an internal subnet of 10.200.200.0/24</p>
<p>Configuration is below:</p>
<p>Router A CLI:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">configure

set vpn ipsec ike-group FOO0 lifetime <span style="color:#ae81ff">28800</span>
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> dh-group <span style="color:#ae81ff">14</span>
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> encryption aes128
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> hash sha1

set vpn ipsec esp-group FOO0 lifetime <span style="color:#ae81ff">3600</span>
set vpn ipsec esp-group FOO0 pfs enable
set vpn ipsec esp-group FOO0 proposal <span style="color:#ae81ff">1</span> encryption aes128
set vpn ipsec esp-group FOO0 proposal <span style="color:#ae81ff">1</span> hash sha1

set vpn ipsec site-to-site peer Y.Y.Y.Y authentication mode pre-shared-secret
set vpn ipsec site-to-site peer Y.Y.Y.Y authentication pre-shared-secret YOURSUPERSECRETANDVERYUNIQUEPSK
set vpn ipsec site-to-site peer Y.Y.Y.Y description ipsec
set vpn ipsec site-to-site peer Y.Y.Y.Y local-address X.X.X.X

set vpn ipsec site-to-site peer Y.Y.Y.Y ike-group FOO0
set vpn ipsec site-to-site peer Y.Y.Y.Y vti bind vti0
set vpn ipsec site-to-site peer Y.Y.Y.Y vti esp-group FOO0

set interfaces vti vti0 address 10.255.255.1/30
set protocols static interface-route 10.200.200.0/24 next-hop-interface vti0

commit; save
</code></pre></div><p>Router B CLI:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">configure

set vpn ipsec ike-group FOO0 lifetime <span style="color:#ae81ff">28800</span>
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> dh-group <span style="color:#ae81ff">14</span>
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> encryption aes128
set vpn ipsec ike-group FOO0 proposal <span style="color:#ae81ff">1</span> hash sha1

set vpn ipsec esp-group FOO0 lifetime <span style="color:#ae81ff">3600</span>
set vpn ipsec esp-group FOO0 pfs enable
set vpn ipsec esp-group FOO0 proposal <span style="color:#ae81ff">1</span> encryption aes128
set vpn ipsec esp-group FOO0 proposal <span style="color:#ae81ff">1</span> hash sha1

set vpn ipsec site-to-site peer X.X.X.X authentication mode pre-shared-secret
set vpn ipsec site-to-site peer X.X.X.X authentication pre-shared-secret YOURSUPERSECRETANDVERYUNIQUEPSK
set vpn ipsec site-to-site peer X.X.X.X description ipsec
set vpn ipsec site-to-site peer X.X.X.X local-address Y.Y.Y.Y

set vpn ipsec site-to-site peer X.X.X.X ike-group FOO0
set vpn ipsec site-to-site peer X.X.X.X vti bind vti0
set vpn ipsec site-to-site peer X.X.X.X vti esp-group FOO0

set interfaces vti vti0 address 10.255.255.2/30
set protocols static interface-route 10.100.200.0/24 next-hop-interface vti0

commit; save
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Useful Powershell commands for Linux nerds</title>
            <link>https://www.hearn.us/posts/useful-powershell-commands-for-linux-nerds/</link>
            <pubDate>Tue, 23 Jun 2015 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/useful-powershell-commands-for-linux-nerds/</guid>
            <description>I often find myself looking for a few commands I drastically miss from linux in the Windows world. Pretty basic but here they are listed by their equal parts between Linux and Windows Powershell.
Note: Below I reference gc which is an alias for Get-Content. They can be interchanged.
active tail tail -f file.txt gc file.txt -Wait tail last 10 tail -n10 file.txt gc file.txt | Select -last 10 head first 10 head -n10 file.</description>
            <content type="html"><![CDATA[<p>I often find myself looking for a few commands I drastically miss from linux in the Windows world. Pretty basic but here they are listed by their equal parts between Linux and Windows Powershell.</p>
<p>Note: Below I reference gc which is an alias for Get-Content. They can be interchanged.</p>
<h4 id="active-tail">active tail</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">tail -f file.txt
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">gc file.txt -Wait
</code></pre></div><h4 id="tail-last-10">tail last 10</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">tail -n10 file.txt
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">gc file.txt | Select -last 10
</code></pre></div><h4 id="head-first-10">head first 10</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">head -n10 file.txt
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">gc file.txt | select -first 10
</code></pre></div><h4 id="grep">grep</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">grep my.pattern
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">Select-String -Pattern my.pattern
</code></pre></div><h4 id="word-count">word count</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">wc -l file.txt
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">gc file.txt | Measure-Object -Line
</code></pre></div><h4 id="process-listing">Process Listing</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">ps
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">get-process
</code></pre></div><h4 id="kill-process">Kill Process</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">kill app.exe
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">get-process app.exe | StopProcess
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Determine Forest and Domain Functional Levels in Powershell</title>
            <link>https://www.hearn.us/posts/determine-forest-and-domain-functional-levels-in-powershell/</link>
            <pubDate>Thu, 06 Nov 2014 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/determine-forest-and-domain-functional-levels-in-powershell/</guid>
            <description>A quick and easy post:
Import-Module ActiveDirectory # Get the forest functional level (Get-ADForest).ForestMode # Get the domain functional level (Get-ADDomain).DomainMode </description>
            <content type="html"><![CDATA[<p>A quick and easy post:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">Import-Module ActiveDirectory

<span style="color:#75715e"># Get the forest functional level</span>
(Get-ADForest).ForestMode

<span style="color:#75715e"># Get the domain functional level</span>
(Get-ADDomain).DomainMode
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Permission Denied Because Search Permissions Are Missing</title>
            <link>https://www.hearn.us/posts/permission-denied-search-permissions/</link>
            <pubDate>Mon, 12 May 2014 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/permission-denied-search-permissions/</guid>
            <description>I have been battling with an issue on Fedora Core 20 and Apache recently with an issue around receiving this error when trying to mount a virtual host in Apache and setting the DocumentRoot to a share under /mnt.
The error is:
[Mon May 12 21:42:02.632785 2014] [core:error] [pid 3974] (13)Permission denied: [client 192.168.1.200:50447] AH00035: access to / denied (filesystem path &amp;#39;/mnt/html&amp;#39;) because search permissions are missing on a component of the path I used chgrp to set the permissions on /mnt and /mnt/html and that didn&amp;rsquo;t help me at all, I was still receiving the same message.</description>
            <content type="html"><![CDATA[<p>I have been battling with an issue on Fedora Core 20 and Apache recently with an issue around receiving this error when trying to mount a virtual host in Apache and setting the DocumentRoot to a share under /mnt.</p>
<p>The error is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext">[Mon May 12 21:42:02.632785 2014] [core:error] [pid 3974] (13)Permission denied: [client 192.168.1.200:50447] AH00035: access to / denied (filesystem path &#39;/mnt/html&#39;) because search permissions are missing on a component of the path
</code></pre></div><p>I used chgrp to set the permissions on /mnt and /mnt/html and that didn&rsquo;t help me at all, I was still receiving the same message.</p>
<p>I even tried setting to a global 777 across the board for apache (this is a non-production server) and still no positive result.</p>
<p>The issue in the end was SELinux preventing access outside of it&rsquo;s defined default scope for Apache.</p>
<p>Running this fixed my issue:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">chcon -R -h -t httpd_sys_content_t /mnt
</code></pre></div><p>This could be applied to other directory roots outside of the default /var/www as well.</p>
]]></content>
        </item>
        
        <item>
            <title>Google Apps to Office 365: Duplicating the Google Apps Send Mail As Functionality</title>
            <link>https://www.hearn.us/posts/google-apps-to-0365-duplicating-sendas/</link>
            <pubDate>Fri, 01 Nov 2013 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/google-apps-to-0365-duplicating-sendas/</guid>
            <description>During our recent Google Apps to Office 365 migration we realized after the migration that there was a key feature that was missing in Office 365: the ability to send from email aliases from a single account (without having a shared mailbox)
In Google Apps this is a very simple feature and easily configured in the settings page.
In Office 365 that is not the case. Receiving from multiple aliases is easy by just added that email to the SMTP aliases for a user account.</description>
            <content type="html"><![CDATA[<p>During our recent Google Apps to Office 365 migration we realized after the migration that there was a key feature that was missing in Office 365: the ability to send from email aliases from a single account (without having a shared mailbox)</p>
<p>In Google Apps this is a very simple feature and easily configured in the settings page.</p>
<p>In Office 365 that is not the case. Receiving from multiple aliases is easy by just added that email to the SMTP aliases for a user account.</p>
<p>The problem occurs when you want to send from a single account, but as another user. We use aliases heavily, so we don&rsquo;t want to pay for the roughly 15 accounts that we send from (but distribute to multiple different users).</p>
<p>Googling (or Binging, ahem) led to have a ton of responses, but none that wouldn&rsquo;t yield the recipient seeing <a href="mailto:alias@domain.com">alias@domain.com</a> on behalf of <a href="mailto:realaccount@otherdomain.com">realaccount@otherdomain.com</a> (common behavior for those Exchange admins out there).</p>
<p>The other disclaimer here is that this is not an officially supported method by any Microsoft documentation that I found, rather some applied Exchange on-premise knowledge that came in handy.</p>
<p>Unfortunately, this also only works in the actual Outlook client, not in the Office 365 OWA mail client.</p>
<p>This solution requires you to fire up remote Powershell to connect to Exchange Online (by this point your execution policy should already be allowing connectivity remotely)</p>
<p>To create your Exchange Online Remote Powershell session do the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-powershell" data-lang="powershell">$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https<span style="color:#960050;background-color:#1e0010">:</span>//ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession $Session
</code></pre></div><p>Give it a minute to parse and load all required commandlets. while you are waiting you can complete the steps below</p>
<p>Now fire up the Exchange Online web page.</p>
<p>For each email address you want to send as:</p>
<ol>
<li>Ensure that your receiving account does <em>not</em> have an SMTP alias in the email addresses defined that you would like to send as</li>
<li>Go to the recipients tab</li>
<li>To to the contact sub-tab</li>
<li>Create an external contact with the email address you would like to send as. Please note that the Display Name cannot be the same as any other account (it will let you add it, but in the rule creation for routing it won&rsquo;t let you proceed)</li>
<li>Go to the mail flow tab</li>
<li>Create a new blank rule</li>
<li>Name the rule as you would like</li>
<li>Select: Apply this rule if the recipient is&hellip; and select the external contact you created</li>
<li>Select: Redirect the message to&hellip; and select your recipient account (what you login as)</li>
<li>Leave all other options as default and select save</li>
<li>Wait around 10 minutes to ensure the rule has propagated across all nodes</li>
<li>Now open your loaded powershell prompt back up</li>
<li>Run the following command: Add-RecipientPermission <a href="mailto:alias@anotherdomain.com">alias@anotherdomain.com</a> -AccessRights SendAs -Trustee <a href="mailto:loginaccount@domain.com">loginaccount@domain.com</a></li>
<li>Wait around 10 minutes to ensure the rule has propagated across all nodes</li>
<li>Open up Microsoft Outlook</li>
<li>Create a new message</li>
<li>Click the from button, and select Other E-mail addresses&hellip;</li>
<li>Click the from button in the dialog that opens and select the external contact you created in step 4</li>
</ol>
<p>Rinse and repeat this process for each alias you would like to send as.</p>
<p>It isn&rsquo;t pretty, but it gets the job done!</p>
]]></content>
        </item>
        
        <item>
            <title>Resolving CURLOPT_FOLLOWLOCATION cannot be activated with PHP and CURL</title>
            <link>https://www.hearn.us/posts/resolving-curlopt-followlocation-cannot-be-activated/</link>
            <pubDate>Thu, 06 Jun 2013 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/resolving-curlopt-followlocation-cannot-be-activated/</guid>
            <description>We were recently using a class we had created to access RETS/MLS in PHP which required that both cookies could be written locally and CURLOPT_FOLLOWLOCATION was enabled.
The actual error was:
CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /var/file/location We are running this particular site as a virtual host on Apache.
To both disable safe mode as well as remove the open_basedir issue follow these instructions.</description>
            <content type="html"><![CDATA[<p>We were recently using a class we had created to access RETS/MLS in PHP which required that both cookies could be written locally and CURLOPT_FOLLOWLOCATION was enabled.</p>
<p>The actual error was:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext"> CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /var/file/location
</code></pre></div><p>We are running this particular site as a virtual host on Apache.</p>
<p>To both disable safe mode as well as remove the open_basedir issue follow these instructions. Please note that safe mode is going away in future versions of PHP.</p>
<ol>
<li>Fire up your UNIX shell of choice, navigate to the location of your httpd.conf file for the virtual host (or your single httpd.conf file with multiple virtual hosts enabled):</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd /var/www/virtualhosts/domain.com/conf
</code></pre></div><ol start="2">
<li>Edit the file</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">vi httpd.conf
</code></pre></div><ol start="3">
<li>Add the following 2 lines to the required location in your httpd.conf file and save the edits:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext">php_admin_flag safe_mode off
php_admin_flag open_basedir none
</code></pre></div><ol start="4">
<li>Reload the apache service</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">service httpd reload
</code></pre></div><p>You&rsquo;re all set!</p>
<p>Optionally you could also change this configuration in the default php.ini file, but this is a much safer and restricted approach.</p>
]]></content>
        </item>
        
        <item>
            <title>Retrieving User Name and MetaData through WCF Web Services for SharePoint 2010</title>
            <link>https://www.hearn.us/posts/retrieving-username-and-metadata-sharepoint-2010/</link>
            <pubDate>Mon, 04 Mar 2013 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/retrieving-username-and-metadata-sharepoint-2010/</guid>
            <description>We have been writing some automated jobs at work to pull user data and compare against Active Directory using WCF services for SharePoint.
The important part of working with Active Directory, is of course, the dreaded username (aka sAMAccountName).
We noticed that when we pulled user information from a list the ModifiedBy, CreatedBy, etc were all blank. They did, however, have a ModifiedById and CreatedById which was a single integer.</description>
            <content type="html"><![CDATA[<p>We have been writing some automated jobs at work to pull user data and compare against Active Directory using WCF services for SharePoint.</p>
<p>The important part of working with Active Directory, is of course, the dreaded username (aka sAMAccountName).</p>
<p>We noticed that when we pulled user information from a list the ModifiedBy, CreatedBy, etc were all blank. They did, however, have a ModifiedById and CreatedById which was a single integer.</p>
<p>As it turns out, there is a list in the DataContext called UserInformationList which can be used to pull users based on their ID.</p>
<p>See the example below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp">MyNamespace.MyDataContext dc = <span style="color:#66d9ef">new</span> MyNamespace.SiteDataContext(<span style="color:#66d9ef">new</span> Uri(<span style="color:#e6db74">&#34;http://sharepoint.nerdyhearn.com/sites/departments/mydepartment/_vti_bin/ListData.svc/&#34;</span>));
dc.Credentials = System.Net.CredentialCache.DefaultCredentials;

<span style="color:#66d9ef">var</span> mylist = dc.MyList;

<span style="color:#75715e">// I like hard-typed lists for user information instead of var-based data
</span><span style="color:#75715e"></span>List&lt;MyNamespace.UserInformationListItem&gt; allSPUsers = dc.UserInformationList.ToList&lt;MyNamespace.UserInformationListItem&gt;();

<span style="color:#66d9ef">foreach</span> (<span style="color:#66d9ef">var</span> listItem <span style="color:#66d9ef">in</span> mylist) {
    <span style="color:#66d9ef">int</span> modifiedById = listItem.modifiedById;

    UserInformationListItem allUserData = (<span style="color:#66d9ef">from</span> usercheck <span style="color:#66d9ef">in</span> allSPUsers
        <span style="color:#66d9ef">where</span> usercheck.Id.Equals(modifiedById)
        <span style="color:#66d9ef">select</span> usercheck).FirstOrDefault&lt;UserInformationListItem&gt;();
        
    <span style="color:#66d9ef">string</span> username = allUserData.UserName;
    <span style="color:#66d9ef">string</span> name = allUserData.Name;
    <span style="color:#75715e">// more properties to be read here
</span><span style="color:#75715e"></span>}
</code></pre></div><p>Simple enough, but Googling didn&rsquo;t help me much on this, so figured I&rsquo;d share</p>
]]></content>
        </item>
        
        <item>
            <title>Up the creek without a paddle: Taking over a deserted SharePoint 2007 installation</title>
            <link>https://www.hearn.us/posts/taking-over-a-deserted-sharepoint-installation/</link>
            <pubDate>Thu, 27 Dec 2012 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/taking-over-a-deserted-sharepoint-installation/</guid>
            <description>I&amp;rsquo;ve been working on a client site for a few weeks and coming into the project they knew absolutely nothing about their current environment asides from the server name. This meant we didn&amp;rsquo;t have the Farm admin password, and didn&amp;rsquo;t have any current employees as farm or collection admins. To regain control of the environment I went through the following steps:
 Reset the service account passwords by following the Microsoft KB article here  Once we re-gained farm login after resetting credentials, we had another interesting caveat.</description>
            <content type="html"><![CDATA[<p>I&rsquo;ve been working on a client site for a few weeks and coming into the project they knew absolutely nothing about their current environment asides from the server name. This meant we didn&rsquo;t have the Farm admin password, and didn&rsquo;t have any current employees as farm or collection admins. To regain control of the environment I went through the following steps:</p>
<ol>
<li>Reset the service account passwords by following the Microsoft KB article here</li>
</ol>
<p>Once we re-gained farm login after resetting credentials, we had another interesting caveat. BUILTIN\Administrators and the farm admin account had been removed from the Farm Admins group so we still couldn&rsquo;t access content on any site collections.</p>
<p>They had also changed their theme, so in central admin the menus to add users were not working. Our only option from this point was to add our accounts using stsadm.</p>
<p>For both steps below also pay attention to if the site is using SSL or not (you&rsquo;ll need to change http:// or https:// depending on the site collection)</p>
<ol start="2">
<li>Add users to the Farm Administrators group using STSADM:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">stsadm -o adduser -url http://centraladminservername:port -userlogin DOMAIN<span style="color:#ae81ff">\u</span>ser -useremail user@email.com -group <span style="color:#e6db74">&#34;Farm Administrators&#34;</span> -username <span style="color:#e6db74">&#34;DOMAIN\user&#34;</span>
</code></pre></div><ol start="3">
<li>Set site collection ownership using STSADM:
You&rsquo;ll need to do this for each site collection you would like access to (My sites, Web Applications, etc)</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">stsadm -o siteowner -url http://site:port -ownerlogin DOMAIN<span style="color:#ae81ff">\u</span>ser -secondarylogin DOMAIN<span style="color:#ae81ff">\u</span>ser
</code></pre></div><p>Keep in mind that site collections can only have 2 owners, and resetting ownership may have adverse affects if the account you remove was being used as something other than an individual user.</p>
]]></content>
        </item>
        
        <item>
            <title>Search and Replace in MySQL</title>
            <link>https://www.hearn.us/posts/search-and-replace-in-mysql/</link>
            <pubDate>Sun, 09 Oct 2011 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/search-and-replace-in-mysql/</guid>
            <description>I often find myself looking for the proper syntax while attempting to do a search and replace in MySQL, and figured that I would help out by posting the syntax for someone else in the same situation:
UPDATE `schema`.`table` set column = replace(column, &amp;#34;find&amp;#34;, &amp;#34;replace&amp;#34;); That syntax will find any values &amp;ldquo;find&amp;rdquo; within the schema and table, and replace them with &amp;ldquo;replace&amp;rdquo;
A pretty short post but hopefully helpful to some of you out there.</description>
            <content type="html"><![CDATA[<p>I often find myself looking for the proper syntax while attempting to do a search and replace in MySQL, and figured that I would help out by posting the syntax for someone else in the same situation:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-mysql" data-lang="mysql"><span style="color:#66d9ef">UPDATE</span> <span style="color:#f92672">`</span><span style="color:#66d9ef">schema</span><span style="color:#f92672">`</span>.<span style="color:#f92672">`</span><span style="color:#66d9ef">table</span><span style="color:#f92672">`</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">column</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">replace</span>(<span style="color:#66d9ef">column</span>, <span style="color:#e6db74">&#34;find&#34;</span>, <span style="color:#e6db74">&#34;replace&#34;</span>);
</code></pre></div><p>That syntax will find any values &ldquo;find&rdquo; within the schema and table, and replace them with &ldquo;replace&rdquo;</p>
<p>A pretty short post but hopefully helpful to some of you out there.</p>
]]></content>
        </item>
        
        <item>
            <title>Web Form To Help Audit Permissions In SharePoint 2007/MOSS</title>
            <link>https://www.hearn.us/posts/web-form-to-audit-permissions-in-sharepoint/</link>
            <pubDate>Wed, 06 Oct 2010 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/web-form-to-audit-permissions-in-sharepoint/</guid>
            <description>Determining an overall view of SharePoint&amp;rsquo;s permissions can be quite a nasty task. Without the use of paid tools it becomes almost impossible to view the breakdown of an entire Site Collection&amp;rsquo;s permission structure.
We recently came across the need to determine permissions of a number of sites that are customer-facing as we are going to re-organize the site and I decided it was time to build a tool to help us in this process once and for all that we could use in the future (as this is not an un-common request).</description>
            <content type="html"><![CDATA[<p>Determining an overall view of SharePoint&rsquo;s permissions can be quite a nasty task. Without the use of paid tools it becomes almost impossible to view the breakdown of an entire Site Collection&rsquo;s permission structure.</p>
<p>We recently came across the need to determine permissions of a number of sites that are customer-facing as we are going to re-organize the site and I decided it was time to build a tool to help us in this process once and for all that we could use in the future (as this is not an un-common request).</p>
<p>I determined the easiest way would be to create an aspx page that could be loaded in the central admin realm.</p>
<p>This page is .NET 3.5-based and will iterate the entire farm, all site collections, and all sites, breaking down the permissions and roles for each site, where inheritance is broken, and when it is broken, what the updated permissions are. It even goes into list and list items permissions and inheritance. The amount of information it generates is quite overwhelming, so I ended up using this file to output directly to XML and then transformed the results as I needed via XSLT.</p>
<p>Without further ado, here is the code. You can simply place this entire code-integrated file in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\ADMIN. In my case I named the file auditor.aspx so it can be accessed directly from the farm&rsquo;s central admin site.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp">
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Page Language=<span style="color:#e6db74">&#34;C#&#34;</span> ContentType=<span style="color:#e6db74">&#34;application/xml&#34;</span>%&gt; 
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;Microsoft.SharePoint.Administration&#34;</span> %&gt; 
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;Microsoft.SharePoint&#34;</span> %&gt; 
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;System.Linq&#34;</span> %&gt;
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;System.Xml.Linq&#34;</span> %&gt;
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;System.Xml&#34;</span> %&gt; 
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Import Namespace=<span style="color:#e6db74">&#34;System.IO&#34;</span> %&gt;
&lt;%<span style="color:#960050;background-color:#1e0010">@</span> Register Tagprefix=<span style="color:#e6db74">&#34;SharePoint&#34;</span> Namespace=<span style="color:#e6db74">&#34;Microsoft.SharePoint.WebControls&#34;</span> Assembly=<span style="color:#e6db74">&#34;Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c&#34;</span> %&gt; 

&lt;script runat=<span style="color:#e6db74">&#34;server&#34;</span>&gt; 
    <span style="color:#66d9ef">protected</span> <span style="color:#66d9ef">override</span> <span style="color:#66d9ef">void</span> OnLoad(EventArgs e){ 
        <span style="color:#66d9ef">try</span>
        {
            SPFarm thisFarm = SPFarm.Local;
            SPWebService service = thisFarm.Services.GetValue&lt;SPWebService&gt;(<span style="color:#e6db74">&#34;&#34;</span>);
            XDocument doc = <span style="color:#66d9ef">new</span> XDocument();
            XElement root = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;webapplications&#34;</span>);

            <span style="color:#66d9ef">try</span>
            {                
                <span style="color:#66d9ef">foreach</span> (SPWebApplication webApp <span style="color:#66d9ef">in</span> service.WebApplications)
                {
                    XElement webappelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;webapplication&#34;</span>);
                    XAttribute attrname = <span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;name&#34;</span>, webApp.DisplayName);
                    webappelem.Add(attrname);

                    <span style="color:#66d9ef">try</span>
                    {
                        XElement sites = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;sites&#34;</span>);

                        <span style="color:#66d9ef">foreach</span> (SPSite siteCollection <span style="color:#66d9ef">in</span> webApp.Sites)
                        {
                            XElement site = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;site&#34;</span>);
                            site.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;url&#34;</span>, siteCollection.Url));
                            GetWebs(siteCollection.AllWebs, site);
                            sites.Add(site);
                        }

                        webappelem.Add(sites);
                    }
                    <span style="color:#66d9ef">catch</span> (Exception siteError)
                    {
                        webappelem.Add(<span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;error&#34;</span>, siteError.Message));
                    }
                    root.Add(webappelem);
                }
            }
            <span style="color:#66d9ef">catch</span> (Exception webAppError)
            {
                root.Add(<span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;error&#34;</span>, webAppError.Message));
            }

            doc.Add(root);
            XmlWriter writer = XmlWriter.Create(Response.OutputStream);
            doc.WriteTo(writer);
            writer.Close();
        }
        <span style="color:#66d9ef">catch</span> (Exception ex)
        {
            System.Web.HttpContext.Current.Response.Write(ex.Message);
        }
    }

    <span style="color:#66d9ef">public</span> XElement GetRoleAssignments(SPRoleAssignmentCollection racollection, SPWeb web)
    {
        XElement raelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;roleassignments&#34;</span>);

        <span style="color:#66d9ef">foreach</span> (SPRoleAssignment ra <span style="color:#66d9ef">in</span> racollection)
        {
            XElement tempra = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;roleassignment&#34;</span>);

            tempra.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;name&#34;</span>, ra.Member.Name));
            tempra.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;id&#34;</span>, ra.Member.ID));

            <span style="color:#66d9ef">try</span>
            {
                SPGroup <span style="color:#66d9ef">group</span> = web.Groups.GetByID(ra.Member.ID);
                tempra.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;isgroup&#34;</span>, <span style="color:#e6db74">&#34;True&#34;</span>));
            }
            <span style="color:#66d9ef">catch</span>
            {
                tempra.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;isgroup&#34;</span>, <span style="color:#e6db74">&#34;False&#34;</span>));
            }

            XElement rdtemp = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;roledefinitions&#34;</span>);

            <span style="color:#66d9ef">foreach</span> (SPRoleDefinition rd <span style="color:#66d9ef">in</span> ra.RoleDefinitionBindings)
            {
                XElement role = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;role&#34;</span>);
                role.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;name&#34;</span>, rd.Name));
                role.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;permissions&#34;</span>, rd.BasePermissions.ToString()));
                rdtemp.Add(role);
            }
            tempra.Add(rdtemp);
            raelem.Add(tempra);
        }
        <span style="color:#66d9ef">return</span> raelem;
    }

    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> GetWebs(SPWebCollection allWebs, XElement site)
    {
        XElement webs = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;webs&#34;</span>);

        <span style="color:#66d9ef">try</span>
        {
            <span style="color:#66d9ef">foreach</span> (SPWeb web <span style="color:#66d9ef">in</span> allWebs)
            {
                XElement webelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;web&#34;</span>);
                webelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;url&#34;</span>, web.Url));
                webelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;title&#34;</span>, web.Title));
                webelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;WebTemplateID&#34;</span>, web.WebTemplateId.ToString()));
                webelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;WebTemplateName&#34;</span>, web.WebTemplate));

                XElement grpelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;groups&#34;</span>);

                <span style="color:#66d9ef">foreach</span> (SPGroup <span style="color:#66d9ef">group</span> <span style="color:#66d9ef">in</span> web.Groups)
                {
                    XElement tempgrp = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;group&#34;</span>);

                    tempgrp.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;name&#34;</span>, <span style="color:#66d9ef">group</span>.Name));
                    tempgrp.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;id&#34;</span>, <span style="color:#66d9ef">group</span>.ID));

                    <span style="color:#66d9ef">string</span> owner = <span style="color:#66d9ef">group</span>.Owner.ID.ToString();

                    <span style="color:#66d9ef">try</span>
                    {
                        SPUser user = web.Users.GetByID(<span style="color:#66d9ef">group</span>.Owner.ID);
                        owner = user.Name;
                    }
                    <span style="color:#66d9ef">catch</span>
                    {
                        <span style="color:#66d9ef">try</span>
                        {

                            SPGroup groupcheck = web.Groups.GetByID(<span style="color:#66d9ef">group</span>.Owner.ID);
                            owner = groupcheck.Name;
                        }
                        <span style="color:#66d9ef">catch</span> { }
                    }

                    tempgrp.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;owner&#34;</span>, owner));

                    XElement members = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;members&#34;</span>);

                    <span style="color:#66d9ef">foreach</span> (SPUser user <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">group</span>.Users)
                    {
                        XElement tempmember = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;member&#34;</span>);
                        tempmember.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;name&#34;</span>, user.Name));
                        tempmember.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;id&#34;</span>, user.ID));
                        members.Add(tempmember);
                    }

                    tempgrp.Add(members);
                    grpelem.Add(tempgrp);
                }
                webelem.Add(grpelem);
                webelem.Add(GetRoleAssignments(web.RoleAssignments, web));

                XElement lists = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;lists&#34;</span>);

                <span style="color:#66d9ef">foreach</span> (SPList list <span style="color:#66d9ef">in</span> web.Lists)
                {
                    XElement listelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;list&#34;</span>);
                    listelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;title&#34;</span>, list.Title));
                    listelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;uniqueroleassignments&#34;</span>, list.HasUniqueRoleAssignments));

                    <span style="color:#66d9ef">if</span> (list.HasUniqueRoleAssignments)
                    {
                        listelem.Add(GetRoleAssignments(list.RoleAssignments, web));
                    }

                    XElement itemselem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;items&#34;</span>);

                    <span style="color:#66d9ef">foreach</span> (SPListItem item <span style="color:#66d9ef">in</span> list.Items)

                    {
                        XElement itemelem = <span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;item&#34;</span>);

                        <span style="color:#66d9ef">try</span>
                        {
                            itemelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;title&#34;</span>, item.Title));
                        }
                        <span style="color:#66d9ef">catch</span> {
                            <span style="color:#66d9ef">try</span>
                            {
                                itemelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;title&#34;</span>, item.DisplayName));
                            }
                            <span style="color:#66d9ef">catch</span> {
                                itemelem.Add(<span style="color:#66d9ef">new</span> XAttribute(<span style="color:#e6db74">&#34;title&#34;</span>, <span style="color:#e6db74">&#34;Not Available&#34;</span>));
                            }
                        }

                        <span style="color:#66d9ef">if</span> (item.HasUniqueRoleAssignments)
                        {
                            itemelem.Add(GetRoleAssignments(item.RoleAssignments, web));
                        }
                        itemselem.Add(itemelem);
                    }
                    listelem.Add(itemselem);
                    lists.Add(listelem);
                }
                webelem.Add(lists);
                webs.Add(webelem);
                web.Dispose();
            }
        }
        <span style="color:#66d9ef">catch</span> (Exception webError)
        {

            webs.Add(<span style="color:#66d9ef">new</span> XElement(<span style="color:#e6db74">&#34;error&#34;</span>, webError.Message));

        }

        site.Add(webs);

    }
&lt;/script&gt;
</code></pre></div>]]></content>
        </item>
        
        <item>
            <title>Creating an Organizational Chart Using C#: Part 2</title>
            <link>https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part2/</link>
            <pubDate>Thu, 18 Jun 2009 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part2/</guid>
            <description>In part 1 of this series, I went over how to actually establish the tree layout that would be used to create an organizational chart using C#.
Now that we have established we have a loaded tree structure, we simply need to build the chart itself.
To simplify the explanation of this process, I have broken the drawing out into two sections.
The first section, BuildBlock, simply builds the actual block which will have each Employee&amp;rsquo;s name and title information, with a background color and a small black border around the outside.</description>
            <content type="html"><![CDATA[<p>In <a href="https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part1/">part 1</a> of this series, I went over how to actually establish the tree layout that would be used to create an organizational chart using C#.</p>
<p>Now that we have established we have a loaded tree structure, we simply need to build the chart itself.</p>
<p>To simplify the explanation of this process, I have broken the drawing out into two sections.</p>
<p>The first section, BuildBlock, simply builds the actual block which will have each Employee&rsquo;s name and title information, with a background color and a small black border around the outside. By breaking this out of the process, it makes the code much easier to follow.</p>
<p>I will comment inline in the method, so here is the code for BuildBlock:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp"><span style="color:#75715e">// We want to return a bitmap of each Employee class
</span><span style="color:#75715e"></span><span style="color:#66d9ef">private</span> Bitmap BuildBlock(Employee employee)
{
  <span style="color:#66d9ef">int</span> width = <span style="color:#ae81ff">250</span>;
  <span style="color:#66d9ef">int</span> height = <span style="color:#ae81ff">80</span>;

  <span style="color:#75715e">// Create a new Bitmap which is is specified by the height and width above
</span><span style="color:#75715e"></span>  Bitmap canvas = <span style="color:#66d9ef">new</span> Bitmap(width, height);

  <span style="color:#75715e">// Create a drawable Graphics object from the bitmap
</span><span style="color:#75715e"></span>  Graphics gfx = Graphics.FromImage(canvas);

  <span style="color:#75715e">// Fill the rectangle with a background of gray
</span><span style="color:#75715e"></span>  gfx.FillRegion(Brushes.Gray, <span style="color:#66d9ef">new</span> Region(<span style="color:#66d9ef">new</span> Rectangle(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, width, height)));

  <span style="color:#75715e">// Draw the border around the outside
</span><span style="color:#75715e"></span>  gfx.DrawRectangle(<span style="color:#66d9ef">new</span> Pen(Brushes.Black, <span style="color:#ae81ff">1</span>), <span style="color:#66d9ef">new</span> Rectangle(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, width - <span style="color:#ae81ff">1</span>, height - <span style="color:#ae81ff">1</span>));

  <span style="color:#75715e">// Establish our two font objects, for the name and title respectively
</span><span style="color:#75715e"></span>  Font fontname = <span style="color:#66d9ef">new</span> Font(<span style="color:#e6db74">&#34;Helvetica&#34;</span>, <span style="color:#ae81ff">14</span>, FontStyle.Bold, GraphicsUnit.Pixel);
  Font fonttitle = <span style="color:#66d9ef">new</span> Font(<span style="color:#e6db74">&#34;Helvetica&#34;</span>, <span style="color:#ae81ff">10</span>, FontStyle.Italic, GraphicsUnit.Pixel);

  <span style="color:#66d9ef">int</span> namewidth = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> nameheight = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> titlewidth = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> titleheight = <span style="color:#ae81ff">0</span>;

  <span style="color:#75715e">// Get the height and widths of each text blob, with their fonts, so we can center them in the block
</span><span style="color:#75715e"></span>  namewidth = (<span style="color:#66d9ef">int</span>)gfx.MeasureString(employee.Name, fontname).Width;
  nameheight = (<span style="color:#66d9ef">int</span>)gfx.MeasureString(employee.Name, fontname).Height;
  titlewidth = (<span style="color:#66d9ef">int</span>)gfx.MeasureString(employee.Title, fonttitle).Width;
  titleheight = (<span style="color:#66d9ef">int</span>)gfx.MeasureString(employee.Title, fonttitle).Height;

  <span style="color:#66d9ef">int</span> namex = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> namey = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> titlex = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> titley = <span style="color:#ae81ff">0</span>;

  <span style="color:#75715e">// Now determine the center for names and titles with the widths and heights of the title and name font sections
</span><span style="color:#75715e"></span>  namex = (width / <span style="color:#ae81ff">2</span>) - (namewidth / <span style="color:#ae81ff">2</span>);
  namey = (height / <span style="color:#ae81ff">2</span>) - ((nameheight + titleheight) / <span style="color:#ae81ff">2</span>);
  titlex = (width / <span style="color:#ae81ff">2</span>) - (titlewidth / <span style="color:#ae81ff">2</span>);
  titley = (height / <span style="color:#ae81ff">2</span>) - ((nameheight + titleheight) / <span style="color:#ae81ff">2</span>) + nameheight;

  <span style="color:#75715e">// Draw the actual text
</span><span style="color:#75715e"></span>  gfx.DrawString(Name, fontname, Brushes.DarkBlue, namex, namey);
  gfx.DrawString(Title, fonttitle, Brushes.Black, titlex, titley);

  <span style="color:#75715e">// Flush the output to the bitmap
</span><span style="color:#75715e"></span>  gfx.Flush();

  <span style="color:#75715e">// Establish a padding bitmap, which will have 10 pixels around the entire image
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// Padding makes it look much better so they are not cramping and allows for easier drawing of lines
</span><span style="color:#75715e"></span>  Bitmap padding = <span style="color:#66d9ef">new</span> Bitmap(width + <span style="color:#ae81ff">20</span>, height + <span style="color:#ae81ff">20</span>);

  <span style="color:#75715e">// Make a graphics object from the padding bitmap
</span><span style="color:#75715e"></span>  Graphics padGfx = Graphics.FromImage(padding);

  <span style="color:#75715e">// Center the image in the padding canvas
</span><span style="color:#75715e"></span>  padGfx.DrawImage(canvas, <span style="color:#66d9ef">new</span> Point(<span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">10</span>));

  <span style="color:#75715e">// Flush the output to the bitmap
</span><span style="color:#75715e"></span>  padGfx.Flush();
  <span style="color:#66d9ef">return</span> padding;
}
</code></pre></div><p>The second aspect of drawing the tree, is drawing the entire tree itself. If you look at the structure of a tree, each tree is really a branch, even the tree itself, from the larger aspect.</p>
<p>To make the drawing logical and much easier to understand, if you break each grouping into a branch, you can then apply logic to each branch and traverse upwards until your tree is complete.</p>
<p>The aptly named BuildBranch is the real &ldquo;meat&rdquo; of our organizationl chart builder, so without further ado, here is the recursive code:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp"><span style="color:#66d9ef">private</span> Bitmap BuildBranch(Employee Manager)
{
  <span style="color:#75715e">// In each case of BuildBranch, Manager is really just the parent of all the children
</span><span style="color:#75715e"></span>
  <span style="color:#75715e">// Get the block of the manager
</span><span style="color:#75715e"></span>  Bitmap manager = BuildBlock(Manager);

  <span style="color:#75715e">// Now do the same for each child, obtaining a list of all Bitmap children
</span><span style="color:#75715e"></span>  List&lt;Bitmap&gt; children = <span style="color:#66d9ef">new</span> List&lt;Bitmap&gt;();
  <span style="color:#66d9ef">foreach</span> (Employee reportee <span style="color:#66d9ef">in</span> Manager.Children)
  {
  children.Add(BuildBlock(reportee));
  }

  <span style="color:#66d9ef">int</span> canvasWidth = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">int</span> canvasHeight = <span style="color:#ae81ff">0</span>;

  <span style="color:#75715e">// Figure out your final heights and widths
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// Do not forget that a branch could also just be a single employee without any children,
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// essentially rendering a branch the same as a block
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">if</span> (children.Count &gt; <span style="color:#ae81ff">0</span>)
  {
    <span style="color:#66d9ef">foreach</span> (Bitmap child <span style="color:#66d9ef">in</span> children)
    {
      canvasHeight += child.Height;
      canvasWidth = manager.Width;
    }

    <span style="color:#75715e">// Always increase the height by the manager
</span><span style="color:#75715e"></span>    canvasHeight += manager.Height;
  }
  <span style="color:#66d9ef">else</span>
  {
    canvasWidth = manager.Width;
    canvasHeight = manager.Height;
  }

  <span style="color:#75715e">// Create the bitmap to the correct size
</span><span style="color:#75715e"></span>  Bitmap result = <span style="color:#66d9ef">new</span> Bitmap(canvasWidth, canvasHeight);

  <span style="color:#75715e">// Now create a Graphics object from that bitmap
</span><span style="color:#75715e"></span>  Graphics gfx = Graphics.FromImage(result);

  <span style="color:#75715e">// Center the manager in the entire branch image
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> managerx = (canvasWidth / <span style="color:#ae81ff">2</span>) - (manager.Width / <span style="color:#ae81ff">2</span>);

  <span style="color:#75715e">// If the manager has children, then you want to draw a line down to connect the branches below
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">if</span> (children.Count &gt; <span style="color:#ae81ff">0</span>)
  {
    Graphics liner = Graphics.FromImage(manager);
    liner.DrawLine(<span style="color:#66d9ef">new</span> Pen(Brushes.Black, <span style="color:#ae81ff">2</span>), <span style="color:#66d9ef">new</span> Point(manager.Width / <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">90</span>), <span style="color:#66d9ef">new</span> Point(manager.Width / <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">100</span>));
    liner.Flush();
  }

  <span style="color:#75715e">// Draw a line from the center of the manager up (to connect to the next block)
</span><span style="color:#75715e"></span>  Graphics liner = Graphics.FromImage(manager);
  liner.DrawLine(<span style="color:#66d9ef">new</span> Pen(Brushes.Black, <span style="color:#ae81ff">2</span>), <span style="color:#66d9ef">new</span> Point(manager.Width / <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">0</span>), <span style="color:#66d9ef">new</span> Point(manager.Width / <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">10</span>));
  liner.Flush();

  gfx.DrawImage(manager, <span style="color:#66d9ef">new</span> Point(managerx, <span style="color:#ae81ff">0</span>));

  <span style="color:#75715e">// Draw lines in between org levels to connect each child to the manager
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> childx = <span style="color:#ae81ff">0</span>;
  <span style="color:#66d9ef">foreach</span> (Bitmap child <span style="color:#66d9ef">in</span> children)
  {
    gfx.DrawImage(child, <span style="color:#66d9ef">new</span> Point(childx, manager.Height));
    gfx.DrawLine(<span style="color:#66d9ef">new</span> Pen(Brushes.Black, <span style="color:#ae81ff">2</span>), <span style="color:#66d9ef">new</span> Point(childx + (child.Width / <span style="color:#ae81ff">2</span>), manager.Height), <span style="color:#66d9ef">new</span> Point(managerx + (manager.Width / <span style="color:#ae81ff">2</span>), manager.Height));
    childx += child.Width;
  }

  <span style="color:#75715e">// Dump the graphics object to the bitmap
</span><span style="color:#75715e"></span>  gfx.Flush();

  <span style="color:#75715e">// Give us the full Org Chart!
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">return</span> result;
}
</code></pre></div><p>That&rsquo;s it, now you have your organizational chart!</p>
]]></content>
        </item>
        
        <item>
            <title>Creating an Organizational Chart Using C#: Part 1</title>
            <link>https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part1/</link>
            <pubDate>Wed, 17 Jun 2009 19:30:00 -0400</pubDate>
            
            <guid>https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part1/</guid>
            <description>An organizational chart is something that many, well, organizations use. It is a very common request and often something that takes a long time for someone to create in something like Visio. Obviously the larger your company the more time-saving that is involved when these can be generated automatically.
This is the first part of a two-part series in which I would like to simply establish the basis, the technical layout, and the technologies that will be used to create the chart.</description>
            <content type="html"><![CDATA[<p>An organizational chart is something that many, well, organizations use. It is a very common request and often something that takes a long time for someone to create in something like Visio. Obviously the larger your company the more time-saving that is involved when these can be generated automatically.</p>
<p>This is the first part of a two-part series in which I would like to simply establish the basis, the technical layout, and the technologies that will be used to create the chart.</p>
<p>For the sake of this example, I will simply use a very simple Employee class, which will have their full name and their title. Each Employee instance can also hold any number of children Employees of the same type.</p>
<p>This class layout allows us to create the tree in concept, populate a tree-based Employee structure, and then populate the chart based on this layout.</p>
<p>The very simple code for the Employee class is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Employee</span>
{
  <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">string</span> m_Name = <span style="color:#66d9ef">string</span>.Empty;
  <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">string</span> m_Title = <span style="color:#66d9ef">string</span>.Empty;
  <span style="color:#66d9ef">private</span> List m_Children = <span style="color:#66d9ef">new</span> List();

  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> Name
  {
    <span style="color:#66d9ef">get</span>
    {
      <span style="color:#66d9ef">return</span> m_Name;
    }
    <span style="color:#66d9ef">set</span>
    {
      m_Name = <span style="color:#66d9ef">value</span>;
    }
  }

  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> Title
  {
    <span style="color:#66d9ef">get</span>
    {
      <span style="color:#66d9ef">return</span> m_Title;
    }
    <span style="color:#66d9ef">set</span>
    {
      m_Title = <span style="color:#66d9ef">value</span>;
    }
  }

  <span style="color:#66d9ef">public</span> List Children
  {
    <span style="color:#66d9ef">get</span>
    {
      <span style="color:#66d9ef">return</span> m_Children;
    }
    <span style="color:#66d9ef">set</span>
    {
      m_Children = <span style="color:#66d9ef">value</span>;
    }
  }
}
</code></pre></div><p>This class can then be populated through a recursive call by whatever means you find necessary. The data populating this tree is most-often Active Directory or LDAP, but could also be SQL, XML, a Web Service, or anything else that is data-accessible.</p>
<p>Let&rsquo;s use LDAP for our example, and the recursive call to populate our Employee tree would be something similiar to the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp"><span style="color:#66d9ef">public</span> Employee BuildTree(Employee Manager)
{
  <span style="color:#75715e">// LDAP is out of the scope of this article, so let&#39;s assume this works properly
</span><span style="color:#75715e"></span>  List reports = LdapSearcherClass.FindDirectReports(Manager);
  <span style="color:#66d9ef">foreach</span> (Employee child <span style="color:#66d9ef">in</span> reports)
  {
    Manager.Children.Add(BuildTree(child));
  }
  <span style="color:#66d9ef">return</span> Manager;
}
</code></pre></div><p>To get the entire tree, we would simply call this as follows:
Employee TopDog = BuildTree(new Employee(&ldquo;TopDog Name&rdquo;));</p>
<p>We now have the structure we need for the tree, and the method of populating this structure, which leaves us with an entirely populated tree of type Employee that we can use in <a href="https://www.hearn.us/posts/creating-an-org-chart-using-csharp-part2/">Part 2</a> to actually draw the chart.</p>
]]></content>
        </item>
        
    </channel>
</rss>
