Tuesday, March 27, 2012

AD : Enumerating UserAccountControl

 

There doesn’t seem to anything built into the .NET framework to do this and it’s a lot easier to read actual names rather than hex boolean manipulation so I rolled my own:

[Flags]
enum UserAccountControl
{
ADS_UF_SCRIPT = 1, // 0x1
ADS_UF_ACCOUNTDISABLE = 2, // 0x2
ADS_UF_HOMEDIR_REQUIRED = 8, // 0x8
ADS_UF_LOCKOUT = 16, // 0x10
ADS_UF_PASSWD_NOTREQD = 32, // 0x20
ADS_UF_PASSWD_CANT_CHANGE = 64, // 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128, // 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256, // 0x100
ADS_UF_NORMAL_ACCOUNT = 512, // 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048, // 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096, // 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 8192, // 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 65536, // 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 131072, // 0x20000
ADS_UF_SMARTCARD_REQUIRED = 262144, // 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 524288, // 0x80000
ADS_UF_NOT_DELEGATED = 1048576, // 0x100000
ADS_UF_USE_DES_KEY_ONLY = 2097152, // 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 4194304, // 0x400000
ADS_UF_PASSWORD_EXPIRED = 8388608, // 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216 // 0x1000000
} 

With this you can write code like:


val = val | (int) UserAccountControl.ADS_UF_DONT_EXPIRE_PASSWD;


Far more readable, I think you’ll agree.


And remember:


To clear a value, use:


val = val & (int) ~UserAccountControl.ADS_UF_ACCOUNTDISABLE;


The ~ is a boolean complement ~ Operator.


Enjoy!

Friday, March 23, 2012

C# : Logging the variables in a class

 

Imagine you have a web site with a bunch of global variables. You want to display them in a debug page. So you could use intellisense and manually traverse through the class but if it’s a big class it’s a right royal pain and you have to keep updating the code as you add new variables.

Enter stage right Reflection.

Type objectType = typeof (GlobalVar);
GlobalVar gv = new GlobalVar();
System.Reflection.FieldInfo[] fieldInfo = objectType.GetFields();

foreach (System.Reflection.FieldInfo info in fieldInfo)
{
xxx.Text = info.Name;

object oText = info.GetValue(null);
if (oText is string)
yyy.Text = (String)oText;
else if (oText is int)
yyy.Text = oText.ToString();
else if (oText is bool)
yyy.Text = oText.ToString();
else if (oText is long)
yyy.Text = oText.ToString();
}


Note the “GetValue(null); “. This is because all the variables in the class are static.



For a non-static class, see C# Tutorial - Using Reflection to Get Object Information.



Enjoy!

Thursday, March 22, 2012

ASP.NET : At least one check box must be checked

 

The ASP.NET Validation Controls are a really neat way of doing user validation. However, they are pretty basic. What about more complicated stuff? For that you need a CustomValidator.

e.g. I have a number of check boxes on the page and one of the validation rules is that at least one of the check boxes must be checked. Mr Google to the rescue and (roll of drums) the answer is:

Put this script at the top of the page:

<script runat="server">

void CustomValidator_CBValidate(Object source, ServerValidateEventArgs args)
{
args.IsValid = (chkBox1.Checked == true) || (chkBox2.Checked == true) || ...;
}

</script>



And then in your page:



<asp:CheckBox ID="chkBox1" Text="xxx" runat="server" />

<asp:CheckBox ID="chkBox2" Text="yyy" runat="server" />

...

<asp:CustomValidator id="CustomValidator1"
runat="server" ErrorMessage="Please select an option"
OnServerValidate="CustomValidator_CBValidate">
</asp:CustomValidator>


Enjoy!



C# : Active Directory Resources

 

Being doing a bit of work in this space and I found the following links to be really useful:

Howto: (Almost) Everything In Active Directory via C#

Everything in Active Directory via C#.NET 3.5

Active Directory and .NET

Active Directory Objects and C#

Active Directory With C#

So if you want to create users, work with their passwords, update their details, add them to groups etc. you’ll find something above to help you.

Enjoy!

Wednesday, March 14, 2012

C# : The server is unwilling to process the request

 

Busy doing some AD work with C#.

I’m creating the user, changing some of the attributes (e.g. setting “DONT_EXPIRE_PASSWORD”) and then setting the password.

Got the exception:

DirectoryServicesCOMException (0x80072035): The server is unwilling to process the request

Mr. Google to the rescue. After sorting through the huge pile of crap, found the answer.

You need to do it in the following order:

  • Create the user
  • Commit changes
  • Set the password
  • Commit changes
  • Change the attributes
  • Commit changes

i.e. Set the password BEFORE doing any attribute CRUD stuff.

Enjoy!

Thursday, March 08, 2012

WCF : Message logging


The best developer tool is Google. 99 % of the time you can find an answer or sample code to your problem.

On the other hand, the worst developer tool is Google. At least half the links are rubbish. There should be some kind of peer review like stackoverflow has to delete crap articles from the Web.

This came about because I was looking for a way to log the actual messages being sent over WCF.

Came across loads of articles, none of which worked 100%. Some were misleading and some were absolute rubbish.

The worst aspect was that they include some small XML snippet which you cut and paste into the web.config without any context i.e. just where are you supposed to insert it?

Anyway, here’s the solution I came up with:

<configuration>
...
  </system.serviceModel>
    <diagnostics>
         <messageLogging 
         logEntireMessage="true" 
         logMalformedMessages="false"
         logMessagesAtServiceLevel="true" 
         logMessagesAtTransportLevel="true"
         maxMessagesToLog="3000"
         maxSizeOfMessageToLog="2000"/>
     </diagnostics>    
  </system.serviceModel>
...
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue=
"Information,ActivityTracing"
        propagateActivity="true">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="messages"
                 type="System.Diagnostics.XmlWriterTraceListener"
                 initializeData="c:\...\messages.svclog" />
        </listeners>
      </source>  
    </sources>
       <sharedListeners>
      <add initializeData="C:\...\Trace.svclog"  
type="System.Diagnostics.XmlWriterTraceListener"
        name="xml" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
...
<configuration>

Enjoy!