Joseph Michael Pesch
VP Programming

Windows Automation Service to Refresh Excel Workbook Data and Email PDF Export

by 12. December 2011 08:33

This was built to refresh an Excel file that has pivot tables built agains SSAS cube, format the spreadsheet, export it to PDF and email the PDF file. 

IMPORTANT NOTE: See this blog entry for potential issue when running Excel Automation code inside of a Windows Service:

using System;
using System.ComponentModel;
using System.Configuration;
using System.ServiceProcess;
using Microsoft.Office.Interop.Excel;

namespace AutomationService
  public partial class AutomationServiceInstance : ServiceBase

    string path = @"C:\ExcelAutomation";
    // Go back one day so we run on start...
    DateTime lastRun = DateTime.Now.AddDays(-1);
    Application excel = new ApplicationClass();

    public AutomationServiceInstance()

    protected override void OnStart(string[] args)
      System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
        , Char.ToString('\r') + Char.ToString('\n') 
        + "Starting service ... " + DateTime.Now.ToString());
      if(System.IO.File.Exists(path + @"\LastRun.txt"))
        // If last run time file exists load the date/time
        lastRun = Convert.ToDateTime(
          System.IO.File.ReadAllText(path + @"\LastRun.txt").Trim());
      BackgroundWorker wkr = new BackgroundWorker();
      wkr.DoWork += TimeCycle;

    protected override void OnStop()
      System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
        , Char.ToString('\r') + Char.ToString('\n')
        + "Stopping service ... " + DateTime.Now.ToString());

    protected void TimeCycle(object sender, DoWorkEventArgs e)
      excel.DisplayAlerts = false;
        if (!lastRun.DayOfYear.Equals(DateTime.Now.DayOfYear) 
          && DateTime.Now.TimeOfDay >= new TimeSpan(8,15,0)) ProcessIt();
        System.Threading.Thread.Sleep(60 * 1000);
      } while (true);

    protected void ProcessIt()
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "Begin processing ... " + DateTime.Now.ToString());
        string srcFile = path + @"\SourceFile.xlsx";
        string outFile = path + @"\OutputFile.pdf";
        Workbook wkb = excel.Workbooks.Open(srcFile, false, true);
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     workbook open: " + DateTime.Now.ToString());
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     connections enabled: " + DateTime.Now.ToString());
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     workbook refreshed: " + DateTime.Now.ToString());
        Worksheet sht = wkb.Worksheets["Pipeline Totals"] as Worksheet;
        // Format column A to a fixed width
        sht.get_Range("A1").EntireColumn.ColumnWidth = 20;
        // Format columns B through Z to auto fit width
        sht.get_Range("B1", "Z1").EntireColumn.AutoFit();
        // Navigate to first cell
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     formatting complete: " + DateTime.Now.ToString());
          , outFile, Microsoft.Office.Interop.Excel.XlFixedFormatQuality.xlQualityStandard
          , true, false, Type.Missing, Type.Missing, false, Type.Missing);
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     export complete: " + DateTime.Now.ToString());
        wkb.Close(false, Type.Missing, Type.Missing);
        MailUtil.SendMail("", "Sender Name"
          , ConfigurationManager.AppSettings["EmailDistributionListTo"]
          , ConfigurationManager.AppSettings["EmailDistributionListCC"]
          , ConfigurationManager.AppSettings["EmailDistributionListBCC"]
          , "Excel Automation Report", false, "", outFile);
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "     mail sent: " + DateTime.Now.ToString());
        sht = null;
        wkb = null;
        lastRun = DateTime.Now;
        System.IO.File.WriteAllText(path + @"\LastRun.txt", lastRun.ToString());
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "Processing complete ... " + DateTime.Now.ToString());
      catch (Exception ex)
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') 
          + "Exception occurred ... " + DateTime.Now.ToString());
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') + ex.Message);
        System.IO.File.AppendAllText(path + @"\AutomationServiceLog.txt"
          , Char.ToString('\r') + Char.ToString('\n') + ex.StackTrace);



C# | Excel

Excel Automation Issue Access File When Running as a Windows Service

by 12. December 2011 07:30

I wrote an Excel automation process that worked fine as a Console Application, then I converted it to a Windows Service and it would error out at the point of trying to open the file with the following file access error shown below. 

To see a copy of the complete Windows Service code view this blog entry:

SOURCE: Microsoft Office Excel
MESSAGE: Microsoft Office Excel cannot access the file 'C:\PathToFile\File.xlsx'.

There are several possible reasons:

• The file name or path does not exist.
• The file is being used by another program.
• The workbook you are trying to save has the same name as a currently open workbook.

This did not make sense as nothing changed between the Console Application code and the Windows Service code.  So, I assumed it was a permission issue.  Tried all sorts of permissions tests with folders/file, as well as the windows service login account, etc.  Still no luck.  Then found a post with a simple solution shown below:

For 64-bit (x64), create this folder:

For 32-bit (x86), create this folder:


C# | Excel

CMD Script Backup Folders to Alternate Location with Dated Folder Structure

by 9. December 2011 23:52

CMD script to backup file folder (with sub-folders) to an alternate location with dated folder structure:

set hour=%time:~0,2%
if "%hour:~0,1%" == " " set hour=0%hour:~1,1%
echo hour=%hour%
set min=%time:~3,2%
if "%min:~0,1%" == " " set min=0%min:~1,1%
echo min=%min%
set secs=%time:~6,2%
if "%secs:~0,1%" == " " set secs=0%secs:~1,1%
echo secs=%secs%

set year=%date:~-4%
echo year=%year%
set month=%date:~4,2%
if "%month:~0,1%" == " " set month=0%month:~1,1%
echo month=%month%
set day=%date:~7,2%
if "%day:~0,1%" == " " set day=0%day:~1,1%
echo day=%day%

set datetimef=%year%%month%%day%_%hour%%min%%secs%

echo datetimef=%datetimef%

mkdir d:\backup\d_inetpub_%datetimef%

xcopy d:\inetpub d:\backup\d_inetpub_%datetimef% /S /H /Y /C


HP Photosmart C6100 All In One Printer/Scanner/Fax

by 28. November 2011 06:51


SQL Date Manipulation

by 25. October 2011 09:35

Here is a query to get the previous quater:

  dateadd(qq, datediff(qq, 0, getdate())-1, 0) 
, dateadd(ms, -3, dateadd(qq, datediff(qq, 0, getdate()), 0))


SQL Server

ASP.Net .ASMX WebService Invocation Test Page Remote Access

by 18. October 2011 07:32

The ASP.Net .ASMX webservice page comes with an automatic invocation test page for each of the available operations defined in the service.  By default the invocation is limited to the service running on a local machine (e.g. if you are running the service on your local machine and browse to it you can invoke it;).  However, if the service is running on a server and you browse from your local machine you will probably see this message "The test form is only available for requests from the local machine" in the spot where the invocation button would normally be.  To enable remote invocation, make sure to add the web config section shown below.

        <add name="HttpGet"/>
        <add name="HttpPost"/>


ASP.Net | Web Service

MDX Query in C#

by 17. October 2011 08:46


Requires the AdomdClient, which is included in Microsoft SQL Server 2008 Feature Pack, October 2008, found here:

Download "Microsoft ADOMD.NET " from the link above and after running msi file you will get
Microsoft.AnalysisServices.AdomdClient.dll under folder
C:\Program Files\Microsoft.NET\ADOMD.NET\100.



ASP.Net Security Issue FormsAuthentication.Authenticate Always Returns false

by 14. October 2011 09:42

I was trying to create a custom authentication screen without using any of the standard ASP.Net security controls (i.e. Login control).  So, I created my custom form and was calling the System.Web.Security.FormsAuthentication.Authenticate(UserName, Password) method.  However, it was always returning false and in fact did not appear to even be hitting my SQL database (which contained the security) as the failed login attempts, etc. were all unaltered.  Furthermore, I changed my connection string to be a bogus reference and the Authenticate still simple returned false (I was expecting it to error).  I then found out that the System.Web.Security.FormsAuthentication.Authenticate(UserName, Password) method is for user information stored in the web.config file.  Instead, I used the System.Web.Security.Membership.ValidateUser(UserName, Password) method which is for the user information stored in the SQL database.

NOTE: When doing this I also then set the authorization cookie by calling:

System.Web.Security.FormsAuthentication.SetAuthCookie(UserName, true);

Here is some sample code:

static public string Login(string UserName, string Password)
  if (System.Web.Security.Membership.ValidateUser(UserName, Password))
    System.Web.Security.FormsAuthentication.SetAuthCookie(UserName, true);
    return "1|" + DateTime.Now.ToString();
    return "0|Login failed!";


ASP.Net | C#

Excel Number Format for Millions

by 12. October 2011 15:24

Here are a couple of custom number formats that allow formatting Excel for Millions.

Sample Number: 1,598,999

Use this format string: $#,##0.0,, ;[Red](#,##0.0,,);- ;

To display this: $1.6

Use this format string: $#,##0.0,,\M ;[Red](#,##0.0,,\M);- ;

To display this: $1.6M



Sharepoint 2010 Registry Entries

by 5. October 2011 12:38

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\LauncherSettings\LoadBalancerUrl
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\Gather\Portal_Content\ContentSources\0\StartPages\0\URL
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\Gather\Portal_Content\ContentSources\0\StartPages\1\URL
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\ResourceManager\ (several entries)
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Search\Applications\fd2e5092-25e3-46cf-8fc6-d62c85334b3d\Gather\Search\ContentSources\0\StartPages\0\URL
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Search\Applications\fd2e5092-25e3-46cf-8fc6-d62c85334b3d\ResourceManager\ (several entries)
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Secure\ConfigDB\dsn
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\WSS\CentralAdministrationURL


Restart Machine via Remote Desktop Connection

by 5. October 2011 12:36

From Commandline: "shutdown /r /t 0"

Alternatively, CTRL+ALT+END on the keyboard to get the Windows screen where you have shutdown/restart options.


Sharepoint 2010 Database Connection Strings in Registry

by 5. October 2011 08:28

I recently installed a new development environment on a virtual machine that was being used as the basis of a new virtual desktop pool for several developers.  My Sharepoint environment was broken once the virtual desktops were created because the installation put the machine name in the SQL connection strings and each of the virtual desktop instances has a unique machine name.  When I attempted to browse to the local sharepoint site I simply received the following error message: "Cannot connect to the configuration database.".  Researching the log file (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Logs\...) I saw the original machine name in the connection string of the failed connections.  Next I looked at the web.config of the root site as well as the C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Config\web.config and was unable to find any connection information.  Finally, I found the following registry entries and changed them from the specific machine name to the "localhost" alias.  NOTE: The first entry is the database connection and the other entries are various URL's.

My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Secure\ConfigDB\

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\LauncherSettings\LoadBalancerUrl

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\Gather\Portal_Content\ContentSources\0\StartPages\0\URL

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\Gather\Portal_Content\ContentSources\0\StartPages\1\URL

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Applications\c0e071e1-533e-457a-8a61-8a86a6b78dcd\ResourceManager\ (several urls are located in this section)

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Search\Applications\fd2e5092-25e3-46cf-8fc6-d62c85334b3d\Gather\Search\ContentSources\0\StartPages\0\URL

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Search\Applications\fd2e5092-25e3-46cf-8fc6-d62c85334b3d\ResourceManager\ (several urls are located in this section)

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\WSS\CentralAdministrationURL




SQL Out of Log Space

by 3. October 2011 15:39

To recover allocated but unused space run this command:

dbcc shrinkdatabase ('DBNAME_HERE', TRUNCATEONLY)


SQL Server

ASP.Net WCF Data Services Error Hosting on Multiple Environments

by 25. September 2011 16:25

I encountered an error when attempting to access a WCF Data Service from my hosted web site.  This error did not occur when running the service on my local development PC.  This is the error I received: "This collection already contains an address with scheme http.  There can be at most one address pr scheme in this collection. Parameter name: item"  To resolve this error my web.config required and additional entry to provide the host name as shown here.

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
        <add prefix="" />



Deploying SSAS Cube from Development to Test/Production

by 23. September 2011 08:47

The easiest way to deploy the cube is to generate a create database script from within SQL Management Studio.  When generating a database script of an Analysis Server database the resulting script file will be XMLA rather than SQL script (as when generating a normal SQL database script).  The resulting XMLA file will contain a DataSources section that contains connection information about the relational database (e.g. datawarehouse database) that the SSAS cube will be reading it's data from.  Below is an example of that section where I have put in variable placeholders to replace the original values of the following items:

  • $(DWServer) - Target database server where the relational data exists.
  • $(DWDatabase) - Target database where the relational data exists.
  • $(DwReaderAccount) - User account name that has read access to the relation database.
  • $(DwReaderPassword) - Password of the reader account.

Here is a sample section of the XMLA file with the above indicated replacements:

  <DataSource xsi:type="RelationalDataSource">
    <ConnectionString>Data Source=$(ImpacDWServer);Initial Catalog=$(ImpacDWDatabase);Integrated Security=True</ConnectionString>
        <ID>DataSourcePermission 1</ID>
        <Name>DataSourcePermission 1</Name>
        <RoleID>Role 1</RoleID>

In order to run the XMLA file through command line (rather than directly in SQL Management Studio) you will need the ASCMD.EXE utility from Microsoft.  You can download it from the SQL Server Analysis Samples page on (below are links to the SQL 2005 and 2008 pages).

SQL 2005

SQL 2008



SQL Script to Generate Table Inserts

by 23. September 2011 07:46

This script will accept a database name and comma delimited list of table names.  It will generate insert statements for all the records in the desired tables.  I will be adapting the script to include schema as well as table name.  The original script was provided by:

CREATE Procedure [dbo].[sp_CreateDataLoadScript]
@databaseName	varchar(128) ,
@TblNames varchar(max)
as begin

	set nocount on;

	create table #a (id int identity (1,1), ColType int, ColName varchar(128))
	create table #out (lnr int, statements varchar(max))
	declare @sql nvarchar(4000)
	declare @TblName as varchar(128)
	declare @idx as bigint
	declare @previdx as bigint
	declare @last as bit
	declare @hasIdentity as bit
	declare @lnr as int

	set @lnr=0

	set @idx=charindex(',',@TblNames)
	set @previdx=1

	if @idx>0 begin  /* many tables */
		set @TblName=ltrim(rtrim(substring(@TblNames,@previdx,@idx-@previdx)))
		set @previdx=@idx+1
		set @last=0
	else begin /* 1 table */
		set @TblName=ltrim(rtrim(@TblNames))
		set @last=1

	while len(@TblName)>0 begin

		select @sql = 'select case when DATA_TYPE like ''%char%'' or DATA_TYPE like ''%date%'' or DATA_TYPE like ''uniqueidentifier'' then 1 else 0 end , COLUMN_NAME
			from 	information_schema.columns
			where 	TABLE_NAME = ''' + @TblName + '''

		select 	@sql = 'exec ' +  @databaseName + '.dbo.sp_executesql N''' + replace(@sql, '''', '''''') + ''''
		insert 	#a (ColType, ColName)
		exec (@sql)

		select @hasIdentity=max(cast(clmns.is_identity as int))
		from sys.tables AS tbl
		INNER JOIN sys.all_columns AS clmns ON  clmns.object_id = tbl.object_id
		where = @TblName

		declare	@id int ,
		@maxid int ,
		@cmd1 varchar(7000) ,
		@cmd2 varchar(7000)

		insert into #out select @lnr, '/* ' + @TblName + ' */'
		set @lnr = @lnr+1
		insert into #out select @lnr, 'truncate table ' + @TblName
		set @lnr = @lnr+1

		if @hasIdentity=1 begin
			insert into #out select @lnr, 'set identity_insert ' + @TblName + ' ON'
			set @lnr = @lnr+1
		select 	@id = 0 , @maxid = max(id)
		from 	#a

		select	@cmd1 = 'insert into #out select ' + cast(@lnr as varchar) + ', '' insert ' + @TblName + ' ( '
		select	@cmd2 = ' + '' select '' + '
		while @id < @maxid
			select @id = min(id) from #a where id > @id

			select 	@cmd1 = @cmd1 + '[' + ColName + '],'
			from	#a
			where	id = @id

			select @cmd2 = 	@cmd2
					+ ' case when [' + ColName + '] is null '
					+	' then ''null'' '
					+	' else '
					+	  case when ColType = 1 then  ''''''''' + replace(convert(varchar(max),[' + ColName + ']),'''''''','''''''''''') + ''''''''' else 'convert(varchar(50),[' + ColName + '])' end
					+ ' end + '','' + '
			from	#a
			where	id = @id

		select @cmd1 = left(@cmd1,len(@cmd1)-1) + ' ) '' '
		select @cmd2 = left(@cmd2,len(@cmd2)-8) + ' from ' + @databaseName + '.dbo.' + @tblName

		exec (@cmd1 + @cmd2)
		truncate table #a

		if @hasIdentity=1 begin
			insert into #out select @lnr, 'set identity_insert ' + @TblName + ' OFF'
			set @lnr = @lnr+1

		insert into #out select @lnr, 'go'
		set @lnr = @lnr+1

		-- next table
		set @idx=charindex(',',@TblNames,@previdx)
		if @idx>0 begin  /* more tables */
			set @TblName=ltrim(rtrim(substring(@TblNames,@previdx,@idx-@previdx)))
			set @previdx=@idx+1
		else if @last=0 begin /* one more */
			set @TblName=ltrim(rtrim(substring(@TblNames,@previdx,8000)))
			set @last=1
		else  /* done */
			set @TblName=''

	drop table #a

	print 'use ' + @databaseName
	print 'go'
	print 'set nocount on'

	declare @statement varchar(max)
	declare @o int
	declare c_out cursor  LOCAL FAST_FORWARD for select statements from #out order by lnr
	open c_out

	declare @i int
	set @i=0
	fetch next from c_out into @statement

	while @@fetch_status=0 begin
		set @i=@i+1
		if @i=1000 begin
			print 'go'
			set @i=0

		print @statement

		fetch next from c_out into @statement

	close c_out
	deallocate c_out
	drop table #out


SQL Server

Sample jQuery - Reading oData Using XML and JSON

by 21. September 2011 13:50

Below are some sample jQuery script methods that illustrate reading data from an oData service.  One uses XML, while the other uses JSON.  The attached zip file contains the full source code, including the AdventureWorks sample database and the C# WCF Data Service that binds to it.  NOTE: That the jQuery JSON call will fail if the web site is compiled under .Net 3.5 framework; however, it will work correctly if compiled under the .Net 4.0 framework.  I saw some other posts indicating that this was a known issue in 3.5 where the JSON was not valid (the jQuery JSON call then errors out claiming the JSON is not valid).

ODataWeb.zipx (603.57 kb)

$.ajaxSetup({ "error": function (XMLHttpRequest, textStatus, errorThrown) {

$(document).ready(function () {

function TestAjax() {
  // setup sample url to find all product descriptions that contain the word "alloy"
  var url = "http://localhost:4241/adventureworks_wcfdataservice.svc/ProductDescriptions?$filter=indexof(Description, 'alloy') ne -1";
  $('#TestAjaxLink').click(function () {
      url: url,
      beforeSend: function (xhr) {
        xhr.overrideMimeType('text/plain; charset=x-user-defined');
      success: function (data) {
        var xml = $.parseXML(data);
        $(xml).find('entry').each(function () {
          var propXml = $(this).find('content').find('m\\:properties');
          var line = '
' + (propXml.find('d\\:ProductDescriptionID').text()) + ': ' + (propXml.find('d\\:Description').text()) + '
' $('#TestAjaxData').append(line); }); } }); }); } function TestJSON() { // setup sample url to find all product descriptions that contain the word "alloy" var url = "http://localhost:4241/adventureworks_wcfdataservice.svc/ProductDescriptions?$filter=indexof(Description, 'alloy') ne -1"; $('#TestJsonLink').click(function () { $.getJSON(url, function (results) { $.each(results.d, function (i, item) { var line = '
' + item.ProductDescriptionID + ': ' + item.Description + '
' $('#TestJsonData').append(line); }); }); }); }



C# Code to Get AD Members of a Security Group

by 15. September 2011 09:57

This method will accept a domain name and security group name and return all the AD members of that group.

using System.Collections.Generic;
using System.DirectoryServices;

namespace AdReader
  class Program
    static void Main(string[] args)
      List users = GetGroupMembers("", "security group name");
      foreach (DirectoryEntry user in users)
        System.Diagnostics.Debug.WriteLine(user.Name.Replace("CN=", ""));
    /// Gets a list of members in the specified group.        
    public static List GetGroupMembers(string domain, string groupName)
      List users = new List();
      string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))", "group", groupName); // principal);            
      string[] properties = new string[] { "fullname" };
      DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.Secure);
      DirectorySearcher searcher = new DirectorySearcher(adRoot);
      searcher.SearchScope = SearchScope.Subtree;
      searcher.ReferralChasing = ReferralChasingOption.All;
      searcher.Filter = filter;
      SearchResult result = searcher.FindOne();
      if (result != null)
        DirectoryEntry directoryEntry = result.GetDirectoryEntry();
        foreach (object dn in directoryEntry.Properties["member"])
          DirectoryEntry member = new DirectoryEntry("LDAP://" + dn);
          //Add users from other groups within this group (only go 1 level deep).      
          if (!IsGroup(member))
      return users;
    /// Determine whether the object is a group.        
    private static bool IsGroup(DirectoryEntry de)
      return de.Properties["objectClass"][1].ToString() == "group";



C# Code to Extract Binary Data from SQL and Save to Disk File

by 14. September 2011 14:24

This code will allow a simple SQL connection to select a single record with binary data in image column and save it as a file on the local disk.

string SQL = "select [FileData] from [MyTable] where [RecordID] = 1";
string cnString = @"Data Source=Server\Instance,Port;Initial Catalog=DB;Integrated Security=True;";
SqlConnection cn = new SqlConnection(cnString);
SqlCommand cmd = new SqlCommand(SQL, cn);
byte[] byt = (byte[])cmd.ExecuteScalar();
FileStream fs = new FileStream(@"c:\temp\tempfile.txt"
  , FileMode.CreateNew, FileAccess.Write);
fs.Write(byt, 0, byt.Length);





Microsoft SSAS OLAP Error: A duplicate attribute key has been found when processing table column value

by 9. September 2011 21:28

Here is the specific error I encountered:

"Errors in the OLAP storage engine: A duplicate attribute key has been found when processing: Table: 'MyTableHere', Column: 'MyColumnHere', Value: '0'. The attribute is 'MyAttributeHere'."

At first I was very confused because I didn't understand how having multiple values of 0 was an issue. It turns out the real issue is having both 0 values AND null values. The issue is manifest by the processing engine as it performs a select distinct which results in one row for the 0 values and another for the null values. However, the null value is then converted into a 0 by default (if you have the "NullProcessing" attribute of the Dimension set to "Automatic").  This is what causes the conflict.  In my case making the nulls 0 before processing the cube resolved the issue.

NOTE: With the default NULL processing for dimension attributes being set to 'Automatic' nulls will be converted to a Zero (for numerical values) or an empty string (for string values). The issue is that the engine first performs a "select distinct ..." on the raw values, so it will come up with one row for NULL and another row for ZERO/BLANK (depending on data type), then the conversion from NULL to the corresponding default occurs thus resulting in conflicting (or duplicate) keys.

Thanks to this post for helping me out: