Google
 

Friday, December 5, 2008

Handling errors when calling PowerShell using C#

In a previous post, I explained how to call PowerShell Commands from C# code in an easy way. But what about error handling?
First, we should know about the types of errors that need to be handled:
  • Exceptions due to error in syntax of the command or script.
  • Errors generated from commands themselves due to logical errors or invalid parameters.
Handling Exceptions:
Several exceptions can be thrown. The base for PowerShell exceptions is the System.Management.Automation.RuntimeException class. Exceptions can originate from bad syntax or calling invalid commands.
Handling this kind of errors follows the common exception handling in .net as this example shows:


try
{
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "c:\\" + " -recurse -Filter *.exe");
}
}
catch (System.Management.Automation.RuntimeException ex)
{
Console.WriteLine(ex.Message);
//Specific handling for PowerShell errors
}
catch (Exception ex)
{
//general handling and logging
}

Command Errors:
These errors that commands return. For example, when you run this command in PowerShell while you don't have a Q drive:
dir Q:
You'll get this error:
Get-ChildItem : Cannot find drive. A drive with name 'q' does not exist.
At line:1 char:4
Which makes sense. But how to check for this kind of errors?
The Invoke method of the RunspaceInvoke class has an overload that accepts an IList as the 3rd parameter. This out parameter will contain a list of errors that has occurred.


IList errors;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "Q:\\" + " -recurse -Filter *.exe", null, out errors);
}

if (errors.Count > 0)
{
PSObject error = errors[0] as PSObject;
if (error != null)
{
ErrorRecord record = error.BaseObject as ErrorRecord;
Console.WriteLine(record.Exception.Message);
Console.WriteLine(record.FullyQualifiedErrorId);
}

return;
}

In the above code, I cast the error to PSObject and get its BaseObject and cast it to ErrorRecord which contains the error information.

An interesting part here, is that you can check the FullyQualifiedErrorId property which is a string to distinguish errors and create logic to handle specific errors. ErrorDetails property can also be checked. But be careful because it can be null.

I hope this post can make your programming with PowerShell easier.

Thursday, November 27, 2008

Live webinar: Accelerate the deployment and provisioning of your SharePoint e-learning platform

Challenges faced by today’s educational institutions typically lie in three main areas: efficiency, security, and accuracy. When it comes to building a Microsoft based e-learning platform, thousands of students, teachers, and parents’ accounts should be provisioned for tens or hundreds of your schools on an interrelated set of Microsoft application servers such as Active directory, SharePoint, Exchange, and Office Communication Server (OCS). In reality, these activities are painful. In such large-scale deployments of Microsoft Learning Gateway (MLG) or other connected e-learning solutions, manual provisioning becomes practically impossible. Consider data incompleteness and inconsistency. And add the fact that mass provisioning is needed every new academic year and ongoing re-provisioning is needed through the year.


Build your Microsoft e-learning platform. Automate your most mission-critical provisioning and ongoing management activities. Rely on a secure, reliable, and scalable provisioning solution; ITWorx Education Catalyst Provisioning Suite.

ITWorx introduces Catalyst 2.0, the second release of its market- sweeping provisioning product, with a richer set of functions and capabilities to further expedite and facilitate your provisioning processes.

In this webinar you will learn how Catalyst can:

  • Decrease the provisioning time from weeks to hours.
  • Meet the real education business challenges.
  • Automate the synchronization with Schools’ Management Information Systems.
  • Guarantee data consistency and accuracy across the board.
  • Tailor to administrator needs for reduced complexity.

Thursday, November 20, 2008

Storing Arabic (or Unicode) data in MySQL using Connector/Net 5.2

Storing Unicode data in varchar columns in MySQL can be tricky. I spent some time to use MySQL Connector/Net 5.2 to store Arabic data.
Once you know it, it's simple:

  • The varchar column Charset should be utf8
  • The varchar column Collate property should be utf8_general_ci. I tried utf8_bin and worked too. This is a screen shot from MySQL Administrator table editor:


  • In the .net application, the connection string must include charset=utf8. For example:

"server=localhost;uid=root;password=123;database=test;port=3306;charset=utf8"

Friday, November 14, 2008

Scripting SQL Server database objects using SMO

Scripting a database objects from development environment is a necessary step before deployment to production or test environments and to add the script to source control. Doing this manually is error prone and time consuming.
Also If you practice continuous integration, it's a must to automate the script generation process.

I used Database Publishing Wizard which is hosted on codeplex. It's good but the command line options lack the ability to determine which objects to script. That caused a problem because it scripted users as well. Which I did not want it to do.

Although it's hosted on codeplex, I could not download the source code to make the necessary modifications.

So, I had to go the hard way. And I did it myself. Using SQL Server Management Objects (SMO), I built a small command line utility to script: Tables, Indexes, UDFs, Veiws, SPs, Defaults, Checks, Foreign keys.
There are limitations ofcourse, But at least it's under control as long as the code is available.

The application depends on the core class ScriptingEngine, which in turn depends on Microsoft.SqlServer.Management.Smo.Scripter class.

Points of interest:
  • Order of scripting is important for the script to be used to regenerate objects.
  • Determining object dependencies is an important trick. Using DiscoverDependencies method, it's possible to order objects bu


public void ScriptViews()
{
List<urn> urns=new List<urn>();

foreach (View view in _database.Views)
{
if (view.IsSystemObject)
continue;
urns.Add(view.Urn);

}

DependencyTree tree = _scripter.DiscoverDependencies(urns.ToArray(), true);
DependencyCollection dc = _scripter.WalkDependencies(tree);

RemoveUrnType(dc,"Table");
RemoveUrnType(dc, "UserDefinedFunction");

_scripter.ScriptWithList(dc);

}

  • Note the RemoveUrnType method, it's used to filter unwanted object types from the DependencyCollection:


private void RemoveUrnType(DependencyCollection dc,string type)
{
for (int counter = 0; counter < dc.Count; counter++)
{
if (dc[counter].Urn.Type==type)
{
dc.RemoveAt(counter);
counter--;
}
}
}

  • Usage:
SqlScripter.exe -server:server\instance -database:dbname -login:login -password:pwd -filename:pathtoscriptfile

You can download the source from skydrive:

Saturday, November 1, 2008

New .NET logos and poster

Microsoft announced new logos for the .net platform. Also a new poster for .NET 4.0 is available.
The reason for the new logo seems to be it's more suitable for the new Azure Services Platform.




A big goodbye to the old logo:



Also a new poster for .NET 4.0 is announced, PDF download is available



For more information, check: Chris Koenig's and Brad Abrams's blogs.

Sunday, September 7, 2008

ITWorx Education webinars

You are invited to attend ITWorx Education webinars on Catalyst™ MLG Provisioning Suite and ExamExpert™
Click links below !!

Friday, September 5, 2008

Calling PowerShell Commands from C# code

Windows PowerShell is a solution to what the windows platform lacked, a really powerful shell !! But it does not stop at this point. Calling PowerShell commands (Cmdlets) from .net code, using the return values can add real power to you application.

In this post, I'll explian how to gain this power in a simple C# application to recursively search the file system and getting the results. The same technique can be used in many other scenarios.

Before starting to code:
First you need to install Windows PowerShell for your windows version. So you need to check How to Get Windows PowerShell 1.0

Next, add a reference to System.Management.Automation.dll to the application, It can be found under C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0 in case of windows XP installation.

After adding this using statement, you'll be ready to code:
using System.Management.Automation;

Starting simple : Getting a list of files and folders recursively:
There are many ways to integrate with PowerShell, here, I'll use a relatively simple way which is the RunspaceInvoke class.

first, let's examine this command in PowerShell:
dir C:\WINDOWS -Recurse
Executing this command in PowerShell will get all files and folders under C:\windows recursively. By the way, dir is an alias to the command Get-ChildItem, not a command itself.

This code creates a RunspaceInvoke instance and invokes dir:

System.Collections.ObjectModel.Collection<psobject> result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse");
}

Note that the Invoke method returns a generic collection of PSObjects. We'll use this collection to retrieve the results. This is one of the real powerful features of PowerShell, it talks objects not text as the old command line commands.

But what can we get from the Collection of PSObjects? PSObject class contains the ImmediateBaseObject property that contains the actual object returned by the command. In the case of dir, we expect that this command will return objects of types: System.IO.DirectoryInfo and System.IO.FileInfo. We'll see later how can we discover this. But for now, lets get the results:

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

As you see in the above code, I check the type of the result and display the appropriate value based on it. The result will be something like this:




A more useful example: Searching the file system:
You can use dir to search for all files of a specific type under a specific path using the filter parameter. This is a complete code listing:

System.Collections.ObjectModel.Collection result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse -Filter *.exe");
}

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

Console.ReadKey();

Exploring PowerShell commands results:
In the above code, I expect the result to be .net types System.IO.DirectoryInfo and System.IO.FileInfo. But how could one detect the type?
PowerShell is very discoverable. for example, executing these statements in PowerShell lets us know the return type (Note that results depend on your file system):
$result = dir c:\
$result[0].GetType().Name

this returns:
DirectoryInfo
Trying another index like 9:
$result[9].GetType().Name
returns:
FileInfo

In this post, we made use of PowerShell commands and manipulated their results. In another post, I'll explain how to check for errors that may occur when running PowerShell commands and how to handle them.

Sunday, August 24, 2008

Getting machine name in .net

Environment.MachineName is commonly used to get the machine name in .net. Few days ago, I met a problem with it after renaming a machine and joining a domain: Environment.MachineName returned the old name machine name.

While searching for the reason, I found that Environment.MachineName gets the NetBIOS name, which is stored in the registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro l\ComputerName\ComputerName\ComputerName and reflects in the Computername envronment variable.

A big limitation of NetBIOS name in this case is that it's limited to the first 15 characters of the machine name. An alternative is needed to get the full name. Which is System.Net.Dns.GetHostName() method which gets the DNS host name of the local computer, which is not limited to the first 15 characters.

Back to my problem, I edited the registry key to reflect the new machine name. That was good enough for me!!

Friday, August 1, 2008

Validating SMTP host information

This is a simple class to check if a connection to SMTP host is possible. It can be useful in case of gathering user input and the user is required to enter a valid smtp host.

The idea is simple, open a TCP connection to the host, and read the initial welcome message sent by the smtp host, it should start with response code 220.
I everything is ok, we need to end the sesion by sending QUIT command and close the connection.
For more information check RFC 821 SIMPLE MAIL TRANSFER PROTOCOL

I used Visual C# 2008 Express edition to build this example. You can check the code below, or download the code with a test application from this link:




public static class SmtpChecker
{
public static bool Check(string host,int port,out string welcomeMessage)
{
try
{
using (TcpClient smtp = new TcpClient(host, port))
using (StreamReader reader = new StreamReader(smtp.GetStream()))
{
welcomeMessage = reader.ReadLine();

//validate the reasponse
if (welcomeMessage.StartsWith("220", StringComparison.InvariantCulture))
{
//Send QUIT as recommended by RFC 821
try
{
using (StreamWriter w = new StreamWriter(smtp.GetStream()))
{
w.WriteLine("QUIT");
w.Flush();
string result =reader.ReadLine();
}
}
catch
{}

return true;
}
else
{
welcomeMessage = "";
return false;
}
}
}
catch (Exception)
{
welcomeMessage = "";
return false;
}
}
}

Friday, June 20, 2008

Converting a colored image to gray scale using C#

This is a simple method that creates a gray scale image from a colored image in C#:

public Image ToGrayScale(Image img)
{
Bitmap bitmap = new Bitmap(img);

for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
byte r = pixelColor.R;
byte g = pixelColor.G;
byte b = pixelColor.B;

byte gray=(byte)(0.299*(float)r+0.587*(float)g+0.114*(float)b);
r = g = b = gray;
pixelColor = Color.FromArgb(r, g, b);

bitmap.SetPixel(i, j, pixelColor);
}
}

Image grayImage = Image.FromHbitmap(bitmap.GetHbitmap());
bitmap.Dispose();
return grayImage;
}


The whole magic is in this line of code:

byte gray=(byte)(0.299*(float)r+0.587*(float)g+0.114*(float)b);

It extracts the Luminance component of the color in the YCbCr color system which represents the intensity of the image.

The rest is easy, all color components (R,G,B) will be the same for the image to be a gray scale.

Monday, June 16, 2008

I'm an Elite member in CodeGuru forums !!

After 2048 posts to the CodeGuru forums, I'm now an elite member :)
My journey with Code Guru has started years ago (I joined on April 5th, 2002) and I'm also an article reviewer.
Proud to be a member of this awesome community!!

BTW: I post using the nickname hspc

Wednesday, May 28, 2008

"Page not found" error after installing IIS

After you install IIS on a machine that has .net framework installed and you open an ASP.NET page, you will probably get a "Page not found - 404" error.
This is because IIS did not (recognize) the installed .net framework. You simply need to run this command line:

aspnet_regiis -i

You can run it by opening the .NET Framework SDK command prompt or by changing the current directory to "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727" and run the command. (The path may differ according to the .net version installed)

Friday, May 16, 2008

How to check query syntax programmatically

A nice feature in MS SQL Server Management studio or the old good query analyzer is the ability to check query syntax before executing it by pressing (Parse) or (Ctrl+F5).

You also can provide this functionality in your application in case your application creates queries on the fly or has a query designer.

This can be done using the PARSEONLY option. Queries that run while PARSEONLY option is ON are parsed but not executed, For example:

SET PARSEONLY ON
Go
Select * from dbo.Books
Go
SET PARSEONLY OFF


The above Select will not be executed, it will only be parsed, the result will be:

Command(s) completed successfully.

Without returning any data.

It's simple, open the database connection, execute "SET PARSEONLY ON", then execute your query, then "SET PARSEONLY OFF"

Saturday, April 26, 2008

EDC: VS2008 New Enhancements

In this post I'll try to shed some light on what Chad Hower covered in his edc2008 session :"VS2008 New Enhancements".

The new keyword "var":
It's both used in LINQ expressions and when using anonymous types (more about them later). It also can be used in any regular variable declaration and initialization, for example:

StringBuilder b = new StringBuilder();
b.Append("abc");
var varB = new StringBuilder();
varB.Append("abc");


In the above example, var keyword was used instead of the StringBuilder class name in the second declaration. And the StringBuilder is used regularly. What worth mentioning is:


  • Some ex-vb developers may think that var is the same as the vb6 Variant datatype, which will cause some performace degradation when calling methods due to late binding. This is not true. The compiler replaces the var with the type initialized in the RHS. So the compiler output of these 2 lines is the same:

    StringBuilder b = new StringBuilder();

    var b = new StringBuilder();
    We just saved some keystrokes :).

  • VS2008 has full intellisense support for var. as you can see in the screenshot:


LINQ:

Using Language Integrated Query with collections can make many of programming tasks easier, like searching for an object or objects in a collection that meet a certain criteria.
For example, if we have a List< string > and we want to find all strings that start with the letter 'S', this is the old way to do this :

List< string > found=new List< string >();
foreach (string s in items)
{
if (s.StartsWith("S"))
found.Add(s);
}

Using LINQ:

var found = from s in items
where s.StartsWith("S")
select s;

Ok, more value can be gained if you need to get them sorted by length:

var found = from s in items
where s.StartsWith("S")
orderby s.Length
select s;


Some people may think that the 'var' keyword is what indicates a LINQ expression, but no, it's actually the 'from'.

A good place to think about using LINQ is where you usually use for and foreach.

LINQ is a new feature of C# v3.0 and VB.NET v9.0

Anonymous types:
I'll talk about Anonymous types usage in LINQ, although there are other cases when are useful.
In the above LINQ example, what if we don't need to get the result as a collection of complete objects of the original collection, and we just need one or two attributes (just as we can select just a few columns from a SQL database, not all columns from the table).
Anonymous types can be used in this case:

var found = from s in items
where s.StartsWith("S")
orderby s.Length
select new { value = s, length = s.Length };


Here, we created a new type on the fly, it has 2 properties: value which is a string and length which is an integer.
But how to iterate on found when we don't know the type of the objects it holds (remember, it's anonymous). This is where var comes to be useful again:

foreach (var s in found)
{
Console.WriteLine(s);
}



Others:
Chad talked about other thinks like OBA (Office Business Applications), WPF. The most important thing is that WPF works fine with Winforms. Winforms can host WPF components.

A very interesting presentation that Chad has shown for us was the History of Microsoft Office Download it and enjoy !!
Besides being funny, it shows how MS Office navigation had to evolve.


Chad just scratched the surface, but left us hungry for more knowledge about the existing new features.

Friday, April 11, 2008

Another place when NULL gets tricky

Dealing with NULLs in SQL causes confusion in many cases. Two good articles cover a lot about NULLs in SQL server: 4 Simple Rules for Handling SQL NULLs and Gotcha! SQL Aggregate Functions and NULL.

I this the latest should have covered another situation, when aggregate functions return NULL in case of not satisfying the where condition.
Let's take this Books table as an example:

ID Title Price
--------------------------------
1 C# 10
2 Database 15
3 VB6 30
3 VB.net 35

When you want to get the sum of all books that start with 'vb', you simply use SUM function like this:

Select sum(Price) from Books where title like 'vb%'

And the result would be 65

One may expect that if he asks for the sum of c++ books prices, the result will be zero (as we have none). for example, this query returns zero:

Select count(Price) from Books where title ='c++'

But with sum:

Select sum(Price) from Books where title ='c++'

The result is NULL. Why? Because, using the same logic described in the above articles, SQL will consider this as an absence of data (It couldn't determine the total price since it did not find any prices) if that makes sense.

This can cause issues when trying to read the value returned by this query in the application which expects a float value. A simple remedy for this would be using COALESCE or ISNULL: (I prefer to use COALESCE since it is standard.)

Select COALESCE(sum(Price),0) from Books where title ='c++'
Select ISNULL(sum(Price),0) from Books where title ='c++'


The result in this case is zero as desired.

Wednesday, March 12, 2008

Promoted to Lead Software Engineer

On Sunday, March, 2, 2008, I was promoted, to be the first Lead Software Engineer in ITWorx. the new position is an extension to the technical career path inside the company.

As the case with any promotion or move, it's a new challenge!! I can conclude my new duties as: making sure that software team I work with will do things right.

Right coding standards, practices, design, testing, etc.

I had the chance to be promoted to the position of Technical Architect, but seems that I still keep a lot of love for code, for the ambition of young fellow developers, for their need to explore and get guidance. I still want to be close to the day to day software building activities.I pray to God to help me to fulfill my new responsibilities. Wish me luck.

Thursday, February 21, 2008

ITWorx' products ExamExpert and Catalyst at The Microsoft® Ingenuity Point Contest

Vote is open at the The Microsoft® Ingenuity Point Contest to select your favorite product out of many innovative software products in Health care, Education , and Clean Technology.
ITWorx (where I work as a Senior Software Engineer), participates with 2 products:
Have a look, and vote !!

Restart your machine after installing Fulltext service for MS SQL Server Express 2005

I had MS SQL server express 2005 installed without Fulltext index support. When I needed it, I installed it, created a catalog, an index, and started change tracking, then I tried to make simple CONTAINS query, nothing returned.
I worked with FTS many times and for years (mainly with SQL Server 2000). It was hard to retry many times to get any result with not good.
I tried many times to drop the index, start full population, incremental population. Nothing worked.
I looked into the event viewer, I found this error:

Errors were encountered during full-text index population for table or indexed view '[dbname].[dbo].[TableName]', database ''[dbname].[' (table or indexed view ID '1550628567', database ID '7'). Please see full-text crawl logs for details.

I looked in the fulltext log ( located at : installationpath/MSSQL.1\MSSQL\LOG\SQLFTxxxxxxxxxx.LOG.x) , this info existed in error logs:

Error '0x80040e09' occurred during full-text index population for table or indexed view '[dbname].[dbo].[TableName]' (table or indexed view ID '1550628567', database ID '7'), full-text key value 0x00000001. Attempt will be made to reindex it.
The component 'sqlfth90.dll' reported error while indexing. Component path 'C:\Program Files\Microsoft SQL Server\90\COM\sqlfth90.dll'.

After searching for such error, I found that after installing fulltext service on MS SQL Express 2005, the machine must be restarted, and that this is mentioned in the ReadMe!!

If only we read the manual !!!!

Sunday, February 17, 2008

Another reason for “Cannot Generate SSPI Context” error

Today, I had trouble with SharePoint server. Each time I open the main page I get the error page (500-internal server error). This error occurred in an environment that worked fine for months. But suffered an accidental electricity cut off.

When I looked in the event log, I realized that SharePoint cannot connect to SQL Server configuration database (which existed on another server) the error details contained the famous error:
“Cannot Generate SSPI Context”
I tried to ping the server, flush DNS, connected to SQL Server using SQL authentication, restarted some services and machines, just to get the same error.

Searching Google led me to a good article: Troubleshooting Cannot Generate SSPI Context Errors , which is really good, but I still did not find the solution.

Finally, after consulting an infrastructure engineer, he suggested to check that the net logon service is running on the domain controller. I checked in and I found that it was paused. After running it, everything went well.

So, the next time you get “Cannot Generate SSPI Context” when connecting to SQL Server, add this check to the list of checks you do, and good luck.

Friday, February 8, 2008

Visual Studio 2008 Product Comparison

This is a great guide when you decide to buy visual studio:
Visual Studio 2008 Product Comparison

Note that Standard edition differs from Professional edition mainly in office tools, crystal reports, test tools, server explorer. Whether these features worth the price difference (about $440) depends on your needs.

Monday, January 28, 2008

Windows forms: Adjust width of combobox drop down according to content

Combobox control has the DropDownWidth property to control the width of the dropped portion that appears when the user clicks the drop down arrow. This property takes the width in pixels.

It's nice to have the width of the drop down set according to the contents. This code does the job:
Assuming the name of the control is cmb:


int ItemMaxWidth = this.cmb.DropDownWidth;
Graphics gx = cmb.CreateGraphics();


for (int i = 0; i < this.cmb.Items.Count; i++)
{
//get the width of item
SizeF s = gx.MeasureString(cmb.Items[i].ToString(), cmb.Font);
if ((int)s.Width > ItemMaxWidth)
{
ItemMaxWidth = (int)s.Width;
}
}

gx.Dispose();

//Set the width :
cmb.DropDownWidth = ItemMaxWidth;

Tuesday, January 1, 2008

List of articles I read on 2007

This is a list of most of the articles I read in year 2007, I wish you find some of them interesting.