Category Archives: Reference - Page 4

List AD users in a group using powershell

This is not a rocket science thing since there are apparently multiple ways to do this but I had a specific requirement to quickly get a list of users for a group but only list specific properties which include the “Title” property that is not available using the AccountManagement namespace.

So without mush further ado… here is a simple script that works for me.

# Read the input parameters $GroupName
param([string] $GroupName = $(throw write-host "Please specify the group name." -Foregroundcolor Red))

$Recurse = $true

$OutputFile = "GroupUsers.csv"
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$group=[System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($ct, $GroupName)
$members = $group.GetMembers($Recurse)

$columnNames = "Name,Title,Description"
$columnNames | Out-File -FilePath $OutputFile -Encoding 'UTF8'
foreach($user in $members){
    $DE = $user.GetUnderlyingObject()
    $output = $user.name + "," + $DE.title + "," + $user.description

    Write-Host $output
    $output | Out-File -FilePath $OutputFile -Encoding 'UTF8' -append
    $output = ""
}

In order to get to the ‘Title’ property I use the ‘GetUnderlyingObject’ method to get the DirectoryEntry object which do have the ‘Title’ property. This way it makes it possible to access any/all the ‘forgotten’ properties which they never implemented in the new namespace.
Additionally it also save the output to a CSV file.

Creating a Multi-instance self registering service

This is one of those things I’ve been wanting to do for a long time for my Event Scavenger pet project. Basically the requirement is this:

“Being able to have one executable (.exe) file that can be used multiple times for different service instances.”

It turns out it is not too hard to achieve this using C# and .Net 4.0 (might even work with older frameworks but haven’t tried it). It is an extension of my already improved self registering Windows Service extensions which make it possible to simply run the Service exe with a ‘-install’ command line parameter. With the latest additions a ‘named’ instance can also be specified. This means, in the Service Manager of Windows you can see the Service executable plus a command line parameter that makes it unique. It allows you to stop/start/manage it separately as an entity. This is exactly the same as how Microsoft BizTalk Server implements ‘Host Instances’.

Now lets get dirty with some code samples. The first code snippet shows (an example) part of main program.cs that handles the command like parameters.

string collectorName = "Default";		

if (args.Length > 0)
{                
  if (args[0].ToUpper() == "-INSTALL")
  {
              string serviceParameters = "";
    if (args.Length > 1)
    {
      collectorName = args[1];
                  serviceName = "Event Reaper - " + collectorName;
      displayName = "Event Reaper - " + collectorName;
                  serviceParameters = "\"-Collector:" + collectorName + "\"";
    }
    if (args.Length > 2)
      displayName = args[2];
    if (args.Length > 3)
      description = args[3];

    HenIT.Services.ServiceRegister.InstallService(
      System.Reflection.Assembly.GetExecutingAssembly().Location,
      serviceName,
      displayName,
      description,
                  serviceParameters);
    return;
  }
  else if (args[0].ToUpper() == "-UNINSTALL")
  {
    if (args.Length > 1)
    {
      collectorName = args[1];
                  serviceName = "Event Reaper - " + collectorName;
    }
    HenIT.Services.ServiceRegister.UnInstallService(
       System.Reflection.Assembly.GetExecutingAssembly().Location,
                 serviceName);
    return;
  }
  collectorName = HenIT.CommandLineUtils.GetCommand(args, "", "-Collector:");
}
if (collectorName.Length == 0)
  collectorName = Properties.Settings.Default.CollectorName;

ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[] 
{ 
  new EventReaperService() { CollectorName = collectorName }
};
ServiceBase.Run(servicesToRun);

All this section does is to check for the “-INSTALL” or “-UNINSTALL” parameters and then call the helper class that does the registration/unregistration. The Display name of the service instance is always prefixed with “Event Reaper – ” to grouped all instances visually together in Service manager.

InstallService

The ServiceRegister class only has two methods. InstallService is the first one and handles all the bits to gather login details, set properties and then register the service.

public static bool InstallService(string serviceExePath,
        string serviceName,
        string displayName,
        string description,
        string serviceParameters)
{
    bool success = false;
    try
    {
        string workingPath = System.IO.Path.GetDirectoryName(serviceExePath);
        string logPath = System.IO.Path.Combine(workingPath, "Install.log");
        ServiceStartMode startmode = ServiceStartMode.Automatic;
        ServiceAccount account = ServiceAccount.LocalService;
        string username = "";
        string password = "";
        bool delayedStart = true;

        InstallerForm installerForm = new InstallerForm();
        installerForm.StartType = ServiceStartMode.Automatic;
        installerForm.AccountType = ServiceAccount.User;
        installerForm.BringToFront();
        installerForm.TopMost = true;
        if (installerForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            startmode = installerForm.StartType;
            account = installerForm.AccountType;
            delayedStart = installerForm.DelayedStart;
            if (installerForm.AccountType == ServiceAccount.User)
            {
                username = installerForm.UserName;
                password = installerForm.Password;
            }


            Hashtable savedState = new Hashtable();
            ProjectInstallerForHelper myProjectInstaller = new ProjectInstallerForHelper(delayedStart);
            InstallContext myInstallContext = new InstallContext(logPath, new string[] { });
            myProjectInstaller.Context = myInstallContext;
            myProjectInstaller.ServiceName = serviceName;
            myProjectInstaller.DisplayName = displayName;
            myProjectInstaller.Description = description;
            myProjectInstaller.StartType = startmode;
            myProjectInstaller.Account = account;
            if (account == ServiceAccount.User)
            {
                myProjectInstaller.ServiceUsername = username;
                myProjectInstaller.ServicePassword = password;
            }
            myProjectInstaller.Context.Parameters["AssemblyPath"] = serviceExePath + " " + serviceParameters;

            myProjectInstaller.Install(savedState);
            success = true;
        }
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, "Install service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    }
    return success;
}

The class InstallerForm is simply a plain Windows Form to capture service properties like the username/password etc. I’m not showing its code here now. AssemblyPath is the actual property that Service manager use to launch the executable plus its parameters.

ProjectInstallerForHelper is an utility class that simply inherits from System.Configuration.Install.Installer. It looks like this:

internal class ProjectInstallerForHelper : System.Configuration.Install.Installer
{
    private ServiceProcessInstaller processInstaller;
    private System.ServiceProcess.ServiceInstaller serviceInstaller;

    public ProjectInstallerForHelper(bool delayedAutoStart = true)
    {
        processInstaller = new ServiceProcessInstaller();
        serviceInstaller = new System.ServiceProcess.ServiceInstaller();
        serviceInstaller.DelayedAutoStart = delayedAutoStart;

        Installers.AddRange(new Installer[] {
                processInstaller,
                serviceInstaller});
    }

    #region Added properties
    public string ServiceName
    {
        get { return serviceInstaller.ServiceName; }
        set { serviceInstaller.ServiceName = value; }
    }
    public string DisplayName
    {
        get { return serviceInstaller.DisplayName; }
        set { serviceInstaller.DisplayName = value; }
    }
    public string Description
    {
        get { return serviceInstaller.Description; }
        set { serviceInstaller.Description = value; }
    }
    public ServiceStartMode StartType
    {
        get { return serviceInstaller.StartType; }
        set { serviceInstaller.StartType = value; }
    }
    public ServiceAccount Account
    {
        get { return processInstaller.Account; }
        set { processInstaller.Account = value; }
    }
    public string ServiceUsername
    {
        get { return processInstaller.Username; }
        set { processInstaller.Username = value; }
    }
    public string ServicePassword
    {
        get { return processInstaller.Password; }
        set { processInstaller.Password = value; }
    }
    #endregion
}

UnInstallService

This is essentially just the reverse of InstallService.

public static bool UnInstallService(string serviceExePath, string serviceName)
{
    bool success = false;
    try
    {
        ServiceController sc = new ServiceController(serviceName);
        if (sc == null)
        {
            System.Windows.Forms.MessageBox.Show("Service not installed or accessible!", "Stopping service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
            return true;
        }
        if (sc.Status == ServiceControllerStatus.Running || sc.Status == ServiceControllerStatus.Paused)
        {
            sc.Stop();
        }
    }
    catch (Exception ex)
    {
        if (!ex.Message.Contains("was not found on computer"))
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, "Stopping service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
        }
        else
            return true;
    }
    try
    {
        string workingPath = System.IO.Path.GetDirectoryName(serviceExePath);
        string logPath = System.IO.Path.Combine(workingPath, "Install.log");

        ServiceInstaller myServiceInstaller = new ServiceInstaller();
        InstallContext Context = new InstallContext(logPath, null);
        myServiceInstaller.Context = Context;
        myServiceInstaller.ServiceName = serviceName;
        myServiceInstaller.Uninstall(null);
        success = true;
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, "Uninstall service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    }
    return success;
}

Summary

And this is basically the whole thing that allows you to create a Windows Service in C# that can handle multiple instances. There are a few things to keep in mind like the fact that all instances share the same config file unless you make a physical copy of the exe and config file to another directory and register it from there. Using this you can multiple services using different config all running side by side not affecting each other (hopefully hehe)

Creating custom BizTalk Event View

This is not exactly ‘new’ technology but someone might find it useful. In recent Windows versions Microsoft enhanced the way the Event log work and function plus the way you can access it. The default Event Viewer inside Windows support creating ‘Views’ with which you can filter events based on your needs. If you know your XML syntax you can create some nice views for yourself. I created one for filtering all BizTalk related events that can simply be imported and then used as is. The XML looks like this:

<ViewerConfig>
<QueryConfig>
<QueryParams>
  <UserQuery /> 
  </QueryParams>
<QueryNode>
  <Name>BizTalk Server</Name> 
<QueryList>
<Query Id="0" Path="Application">
  <Select Path="Application">*[System[Provider[@Name='BizTalk Server']]]</Select> 
  <Select Path="Application">*[System[Provider[@Name='BizTalk Server Deployment']]]</Select> 
  <Select Path="Application">*[System[Provider[@Name='ENTSSO']]]</Select> 
  </Query>
  </QueryList>
  </QueryNode>
  </QueryConfig>
<ResultsConfig>
<Columns>
  <Column Name="Level" Type="System.String" Path="Event/System/Level" Visible="">120</Column> 
  <Column Name="Keywords" Type="System.String" Path="Event/System/Keywords">70</Column> 
  <Column Name="Date and Time" Type="System.DateTime" Path="Event/System/TimeCreated/@SystemTime" Visible="">170</Column> 
  <Column Name="Source" Type="System.String" Path="Event/System/Provider/@Name" Visible="">99</Column> 
  <Column Name="Event ID" Type="System.UInt32" Path="Event/System/EventID" Visible="">80</Column> 
  <Column Name="Task Category" Type="System.String" Path="Event/System/Task" Visible="">80</Column> 
  <Column Name="User" Type="System.String" Path="Event/System/Security/@UserID">50</Column> 
  <Column Name="Operational Code" Type="System.String" Path="Event/System/Opcode">110</Column> 
  <Column Name="Log" Type="System.String" Path="Event/System/Channel">80</Column> 
  <Column Name="Computer" Type="System.String" Path="Event/System/Computer">170</Column> 
  <Column Name="Process ID" Type="System.UInt32" Path="Event/System/Execution/@ProcessID">70</Column> 
  <Column Name="Thread ID" Type="System.UInt32" Path="Event/System/Execution/@ThreadID">70</Column> 
  <Column Name="Processor ID" Type="System.UInt32" Path="Event/System/Execution/@ProcessorID">90</Column> 
  <Column Name="Session ID" Type="System.UInt32" Path="Event/System/Execution/@SessionID">70</Column> 
  <Column Name="Kernel Time" Type="System.UInt32" Path="Event/System/Execution/@KernelTime">80</Column> 
  <Column Name="User Time" Type="System.UInt32" Path="Event/System/Execution/@UserTime">70</Column> 
  <Column Name="Processor Time" Type="System.UInt32" Path="Event/System/Execution/@ProcessorTime">100</Column> 
  <Column Name="Correlation Id" Type="System.Guid" Path="Event/System/Correlation/@ActivityID">85</Column> 
  <Column Name="Relative Correlation Id" Type="System.Guid" Path="Event/System/Correlation/@RelatedActivityID">140</Column> 
  <Column Name="Event Source Name" Type="System.String" Path="Event/System/Provider/@EventSourceName">140</Column> 
  </Columns>
  </ResultsConfig>
  </ViewerConfig>

To use simply copy/past into an XML file and use the ‘Import Custom View…’ context menu option in the standard Event Log Viewer of Windows.

Of course, if you want a proper Event View solution over a whole group of servers use my Event Scavenger tool 😉

BizTalk and MSDTC

This is a quick post to summarize my frustrations about the process of setting up and configuring a BizTalk (2010) environment  on a multiple server environment.

If you encounter any/all of the following errors while doing the initial configuration:

  • Exception of type System.EnterpriseServices.TransactionProxyException was thrown
  • [WARN] AdminLib GetBTSMessage: hrErr=80070002; Msg=The system cannot find the file specified.;
  • [WARN] AdminLib GetBTSMessage: hrErr=c0c02560; Msg=Failed to read “KeepDbDebugKey” from the registry.

then start troubleshooting by looking at the following things:

  1. Check that MSDtc is installed, running and configured properly – especially the security settings. This apply to BOTH the SQL Server and all BizTalk servers! See the following screenshot:
    BizTalk MSDtc Security settings

    BizTalk MSDtc Security settings

    The Type of communication can be changed to Mutual or Incoming Caller but it HAS to be the same on all the machines (SQL and BizTalk servers)

  2. Check that MSDtc has been allowed access through the firewall – again on ALL machines including the SQL server!

    BizTalk/SQL MSDtc Firewall access

    BizTalk/SQL MSDtc Firewall access

  3. Check that the SQL Server Browser service is running on the SQL server machine.

I really hope that Microsoft will one day fix this issue where the Configuration Wizard does not check these things BEFORE you start trying to apply settings. It is really frustrating that you have to ‘stumble’ across this every time you set up a new environment – Yes you should check these things beforehand I know…

Getting list of disabled users in AD

Having to quickly help some colleagues find a list of all the currently disabled users on a domain I created a quick Powershell script (with some help from Google of course).

I suspect other people might also like to know how to do it so here is a copy of the script.

This script is easily modifiable to search for all kind of other ‘stuff’ in AD as well.

How to run application after VS MSI installer finish

Sometimes you need to do something that is not provided ‘out-of-the-box’ – as provided by the default tools you use. Take Visual Studio’s built in ‘Set-up’ and installation projects as an example.

I wanted to simply add the option to launch the executable that was installed during the install process once the installer ends. Sounds simple and there are ways of doing this with and without Visual Studio using custom installer classes plus ‘Custom Actions’ is possible but it has its drawbacks – like it suspend the installer or you have to write extra code inside your app just to cater for that.

Interestingly enough, MSI installers actually supports this functionality ‘natively’ i.e. it is a built-in feature of MSI technology to have the option for ‘Run my app after the installer ends’. The problem is just that Visual Studio doesn’t expose this functionality itself. The only way to ‘enable’ this feature is to modify the MSI package afterwards – through a ‘Post build action’ or manually (or you can use msbuild or any other build process tool).

To do this you can use a JavaScript script that simply makes the required changes to the MSI package (its internal database). See Aaron Stebner’s blog for more details. The example script to do this is located here.

I initially had trouble getting the working paths correct for my specific project but it turned out the normal ‘build’ command in VS does not always rebuild the solution. Instead you have to explicitly use the ‘Rebuild’ command on the Set-up project to make sure it recreate the MSI using the post build action script.

To summarize how to do it:

  1. First download a copy of the ‘EnableLaunchApplication.js’ script to the set-up projects directory – the directory where the .vdproj file is located.
  2. Then edit the js file to specify the actual exe name of your application you want to ‘launch’ after the MSI finish. You can of course customize it further.
  3. In the Visual Studio set up project’s project properties specify the following ‘PostBuildEvent’: cscript.exe “$(ProjectDir)EnableLaunchApplication.js” “$(BuiltOuputPath)”
  4. Take not that the spelling mistake (BuiltOuputPath) is deliberate since that is how the VS team implemented it (was probably a typo which they never fixed)
  5. Now you can use the ‘Rebuild’ command for the (set-up) project.

and thats how it works. Have fun!

Java pie

A useful JavaScript library I came across recently is the one created by Balamurugan that is based on the wz_jsgraphics library from walterzorn.

I made some modifications to the Pie library so more ‘properties’ can be specified by the calling script/code which makes it easier to use.

An example:

JavaScript Pie graph

<script type="text/javascript" src="wz_jsgraphics.js"></script>
<script type="text/javascript" src="pie.js"></script>
<div id="pieCanvas" style="overflow: auto; position:relative;height:300px;width:400px;"></div>
<script type="text/javascript">

 

var p = new pie();
p.radius = 100;
p.labelDistance = 120;
p.xCenter = 200;
p.yCenter = 150;
p.add("Jan",49);
p.add("Feb",51);
p.add("Mar", 87);
p.add("Apr",120);
p.add("May",56);
p.add("Jun",41);
p.add("Jul",31);
p.add("Aug",65);
p.fontName = "Tahoma";
p.labelFontSize = 14;
p.render("pieCanvas", "This is a test");

With this you will get a plain (but nice) pie graph that can use customize a bit if you like.

Here is a link to my modified version: JavaScriptPie

Javascript tip: innerText or textContent

Just a quick tip how to handle using an UI object’s innerText property properly. Even today there are differences on how web browsers give you access to the ‘Text’ content of an HTML element. Let say you have the following html:

<p id=”mine”>This is some text</p>

To get the ‘content you must use the following:

IE and Chrome

mine.innerText

but in Firefox

mine.textContent

To make a ‘universal function to get this text you can use the following function:

function getInnerText(obj){
  if (obj){
    if (obj.innerText)
      return obj.innerText;
    else
      return obj.textContent
    }
  else
    return "";
}

Formatting C# code in WordPress post

If you are like me working with C# a lot and trying to post articles on your WordPress site you might like this: Alex Gorbatchev’s SyntaxHighlighter

Example source code listing

[ sourcecode language=”csharp” ]
void Stuff
{

int moreStuff = 0;

}
[ /sourcecode ]

Would look like this:

void Stuff
{
    int moreStuff = 0;
}

I haven’t tested it with all possible language features but at least it is a start!

Getting month names with tsql

A quick tip using tsql to get a list of the month names.

SELECT Number + 1 as [Number],
DateName(mm,DateAdd(mm,Number,0)) as [Name]
FROM master..spt_values
WHERE Type = ‘P’ and Number < 12

Shamelessly copied from somewhere on the Internet… 😉