navigation
 Tuesday, June 12, 2007

At Tech Ed in Orlando last week John Waters picked up "Windows PowerShell Unleashed by Tyson Kopczynski" and as John has a eye for cool technology I did likewise and got hooked on PowerShell.  I'm not usually a live-on-the-command-line-love-batch-files kind of guy but PowerShell covers enough ground in a powerful and consistent way that I'm considering adding this to my technology toolbox.  Although PowerShell is intended for system administrator use, there may be a place for PowerShell in development to do limited testing against .NET objects, task automatation and general exploration.  In any case it's a great toy and a hoot to play with.

PowerShell has several important differences from cmd.exe. 

  • PowerShell lets you use NET FCL objects, COM objects and even your own .NET classes.
  • PowerShell scripts can be code signed (see Windows PowerShell Unleashed by Tyson Kopczynski for detailed steps).  Previous scripting environments like Windows Scripting Host (WSH) opened large security holes.  This feature allows scripts from trusted sources to be run.
  • PowerShell is object based, not text based.  This eliminates parsing and reformatting to use the output from a command.
  • PowerShell provides a consistent interface. 
    • You can navigate through files, the certificate store, environmental variables and the registry, all using commands you already know. 
    • Commands confirm to the pattern verb-name, i.e. "get-service" to cut down on memorization.  There are aliases for historic DOS and UNIX commands so you can list a directory with the PowerShell native "get-childitem", UNIX style "ls" or DOS "dir". 
    • PowerShell lets you locate and interrogate available commands and objects.
  • PowerShell is extensible.  You can create your own commands in a .NET assembly and register them for use in PowerShell.  There are several other points of extensibility including providers for navigation, types and formatting.

Here's a sample session of PowerShell to give you a very brief notion of how it works.  Be aware that this is only scratching the surface of the possibilities for PowerShell.  Let's say we want to work with Windows services, so we need to know what commands are available:

 
PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> get-command *service
CommandType     Name                                                Definition
-----------     ----                                                ----------
Cmdlet          Get-Service                                         Get-Service [[-Name] <String[]>] [-Include <Stri...
Cmdlet          New-Service                                         New-Service [-Name] <String> [-BinaryPathName] <...
Cmdlet          Restart-Service                                     Restart-Service [-Name] <String[]> [-Force] [-Pa...
Cmdlet          Resume-Service                                      Resume-Service [-Name] <String[]> [-PassThru] [-...
Cmdlet          Set-Service                                         Set-Service [-Name] <String> [-DisplayName <Stri...
Cmdlet          Start-Service                                       Start-Service [-Name] <String[]> [-PassThru] [-I...
Cmdlet          Stop-Service                                        Stop-Service [-Name] <String[]> [-Force] [-PassT...
Cmdlet          Suspend-Service                                     Suspend-Service [-Name] <String[]> [-PassThru] [...

From here we can see what services are available for SQL Server:

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> get-service MSSQL*
Status   Name               DisplayName
------   ----               -----------
Running  MSSQL$NRLAPTOP2    MSSQL$NRLAPTOP2
Running  MSSQL$SQLEXPRESS   SQL Server (SQLEXPRESS)
Running  MSSQL$TELERIK      MSSQL$TELERIK
Running  MSSQLSERVER        SQL Server (MSSQLSERVER)
Stopped  MSSQLServerADHe... SQL Server Active Directory Helper
Running  MSSQLServerOLAP... SQL Server Analysis Services (MSSQL...

Now we want to stop the MSSQLSERVER service and any dependant services:

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> stop-service "MSSQLSERVER" -force

If we re-run get-service we can see that the service is stopped:

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> get-service mssql*
Status   Name               DisplayName
------   ----               -----------
Running  MSSQL$NRLAPTOP2    MSSQL$NRLAPTOP2
Running  MSSQL$SQLEXPRESS   SQL Server (SQLEXPRESS)
Running  MSSQL$TELERIK      MSSQL$TELERIK
Stopped  MSSQLSERVER        SQL Server (MSSQLSERVER)
Stopped  MSSQLServerADHe... SQL Server Active Directory Helper
Running  MSSQLServerOLAP... SQL Server Analysis Services (MSSQL...

You can also interrogate the service objects using the get-member command. For example you could take the service objects returned by get-service and direct them to the get-member command using the "|" pipe symbol. The following is only a partial listing.

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> get-service | get-member
   TypeName: System.ServiceProcess.ServiceController
Name                      MemberType    Definition
----                      ----------    ----------
Name                      AliasProperty Name = ServiceName
Close                     Method        System.Void Close()
Continue                  Method        System.Void Continue()
CreateObjRef              Method        System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
Dispose                   Method        System.Void Dispose()
Equals                    Method        System.Boolean Equals(Object obj)
ExecuteCommand            Method        System.Void ExecuteCommand(Int32 command)
get_DependentServices     Method        System.ServiceProcess.ServiceController[] get_DependentServices()
get_DisplayName           Method        System.String get_DisplayName()
get_MachineName           Method        System.String get_MachineName()
get_ServiceHandle         Method        System.Runtime.InteropServices.SafeHandle get_ServiceHandle()

What about navigation?  If I want to change locations in the file system of course there's "CD" or the PS native "set-location". What's unique here is that you can navigate the registry, environmental variables, certificate stores or any other system that PS has a provider for (yes, you can write your own providers).  For example the following is perfectly legal:

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> cd env:
PS Env:\> dir
Name                           Value
----                           -----
Path                           C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\ATI Technolo...
TEMP                           C:\DOCUME~1\NOELRI~1\LOCALS~1\Temp
SESSIONNAME                    RDP-Tcp#1
PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.PSC1
USERDOMAIN                     NRLAPTOP
PROCESSOR_ARCHITECTURE         x86

You could image using CD to navigate hiearchical database information in this way (to what practical end I do not know, but it is amusing). Find out what PowerShell drives are available on your machine by using get-psdrive:

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> get-psdrive
Name       Provider      Root                                                                           CurrentLocation
----       --------      ----                                                                           ---------------
Alias      Alias
C          FileSystem    C:\                                    Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug
cert       Certificate   \
D          FileSystem    D:\
Env        Environment
Function   Function
HKCU       Registry      HKEY_CURRENT_USER
HKLM       Registry      HKEY_LOCAL_MACHINE
Variable   Variable

Use get-psprovider to find the providers on your system.  See the MSDN for examples of writing your own provider. 

PS C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug> Get-PSProvider
Name                 Capabilities                                      Drives
----                 ------------                                      ------
Alias                ShouldProcess                                     {Alias}
Environment          ShouldProcess                                     {Env}
FileSystem           Filter, ShouldProcess                             {C, D}
Function             ShouldProcess                                     {Function}
Registry             ShouldProcess                                     {HKLM, HKCU}
Variable             ShouldProcess                                     {Variable}
Certificate          ShouldProcess                                     {cert}

You can download PowerShell at http://www.microsoft.com/technet/scriptcenter/topics/msh/download.mspx.  It comes with the install and docs for "Getting Started", "Quick Reference" and "Users Guide".

posted on June 12, 2007  #    by Noel Rice  Comments [0] Trackback
 Saturday, June 02, 2007

San Jose, CA June 2nd 2007 - While the software industry has benefited greatly from project productivity management solutions, very few industries have seen a truly all-inclusive easy-to-use tool for managing projects throughout their entire lifecycle. Falafel Software has recognized this industry gap and has developed ActiveFocus, a Web 2.0 application that allows multiple types of organizations to take advantage of modern project management technologies. ActiveFocus represents the first truly multipurpose project productivity solution on the market today and Falafel Software is proudly launching it at Microsoft TechEd in Orlando, Florida, June 4th to 8th 2007.

"Calling ActiveFocus a multipurpose project productivity solution really doesn't even scratch the surface of what our product can do," remarked Lino Tadros, President and CEO of Falafel Software

"What's really remarkable is all of the amazing features that will help any business get through any project. We're really excited about ActiveFocus and our current partners and customers are eagerly waiting to see what ActiveFocus can do for them."

“It is exciting to see how customers such as Falafel Software have used the power and productivity of ASP.NET 2.0, AJAX and Microsoft SQL Server 2005 to deliver a project productivity management solution to their customers,” said Keith Smith, group product manager of the Developer Tools Team at Microsoft Corp. “The combination of ASP.NET 2.0, AJAX and SQL Server 2005 gives ActiveFocus a solid platform for developing its applications.”

posted on June 2, 2007  #    by Lino Tadros  Comments [0] Trackback
 Thursday, May 31, 2007

A higher-order function is defined as a function that returns a function as a result. Higher-order functions are common in the world of functional programming, but have only recently started to become more mainstream. As of C# 2.0, they are starting to become part of the language. A perfect example of their use would be with the generic List<T>.FindAll() method, which takes a Predicate<T> as an argument. A Predicate<T> is a delegate, which is a strongly typed method reference. One way to search for all the items in a list is to use anonymous delegates. For example, given a list of Falafel employees:

List<Falafel> falafels = new List<Falafel>();
falafels.Add( new Falafel( "Lino", "Tadros" ) );
falafels.Add( new Falafel( "John", "Waters" ) );
falafels.Add( new Falafel( "Noel", "Rice" ) );
falafels.Add( new Falafel( "Adam", "Anderson" ) );
falafels.Add( new Falafel( "Xavier", "Pacheco" ) );
falafels.Add( new Falafel( "Adam", "Markowitz" ) );
falafels.Add( new Falafel( "Mike", "Dugan" ) );
falafels.Add( new Falafel( "Bary", "Nusz" ) );
falafels.Add( new Falafel( "Rick", "Miller" ) );
falafels.Add( new Falafel( "Mike", "Saad" ) );
falafels.Add( new Falafel( "Eric", "Titolo" ) );

You could search for all employees whose name starts with "A" like this:

falafels.FindAll( delegate( Falafel item ) { return item.FirstName.StartsWith( "A" ); } )

Output:
Adam Anderson
Adam Markowitz

However, if you wanted to perform another search for all employees whose name starts with "M", you'd have to write an entirely different anonymous delegate. That's where higher-order functions can help. Let's create a higher-order function that will return a delegate that searches for Falafels whose first name starts with a string we pass as a parameter:

public static class Predicates
{
  public static Predicate<Falafel> FirstNameStartsWith( string s )
  {
    return delegate( Falafel item ) { return item.FirstName.StartsWith( s ); };
  }
}

Now we can search for employees whose name starts with any letter we want:

falafels.FindAll( Predicates.FirstNameStartsWith( "A" ) );
falafels.FindAll( Predicates.FirstNameStartsWith( "M" ) );

Output:
Adam Anderson
Adam Markowitz

Mike Dugan
Mike Saad

But the fun doesn't stop there! If you define a set of primitive Predicates, you can define more complex Predicates as a combination of the simpler ones. Here is how to define higher-order functions that take a list of Predicates and returns a Predicate that returns the result of evaluating each of them and combining the result with the logical AND or OR operator:

public static Predicate<Falafel> And( params Predicate<Falafel>[] predicates )
{
  return delegate( Falafel item )
  {
    foreach ( Predicate<Falafel> predicate in predicates )
      if ( !predicate( item ) )
        return false;
    return true;
  };
}

public static Predicate<Falafel> Or( params Predicate<Falafel>[] predicates )
{
  return delegate( Falafel item )
  {
    foreach ( Predicate<Falafel> predicate in predicates )
      if ( predicate( item ) )
        return true;
    return false;
  };
}

Using these, we can create a single Predicate that searches for all Falafels whose first name starts with "A" or "R" and whose last name starts with "M":

Predicate<Falafel> predicate = Predicates.Or( Predicates.FirstNameStartsWith( "A" ), Predicates.FirstNameStartsWith( "R" ) );
predicate = Predicates.And( predicate, Predicates.LastNameStartsWith( "M" ) );
falafels.FindAll( predicate );

Output:
Adam Markowitz
Rick Miller

Higher-order functions are a powerful abstraction, and they're only going to become more common and easier to write with C# 3.0 lambda expressions, so give them a try and see how they can help make your code more concise and expressive.

posted on May 31, 2007  #    by Adam Anderson  Comments [0] Trackback
 Wednesday, May 23, 2007

Visual Studio comes with some handy (and some not-so-handy) code snippets, but for some reason there isn't one for declaring a method. It isn't that big of a deal, but after a while you might start resenting finishing your method header, then having to type Enter, {, Enter, }, Up, Enter to start the method body. Here's a snippet that will automatically put an open and closing brace after your method declaration, with the cursor ready to go in between:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>method</Title>
      <Shortcut>m</Shortcut>
      <Description>Code snippet for methods</Description>
      <Author>Adam Anderson</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>method-modifiers</ID>
          <ToolTip>Method modifiers</ToolTip>
          <Default>public</Default>
        </Literal>
        <Literal>
          <ID>return-type</ID>
          <ToolTip>Return type</ToolTip>
          <Default>void</Default>
        </Literal>
        <Literal>
          <ID>member-name</ID>
          <ToolTip>Method name</ToolTip>
          <Default>Name</Default>
        </Literal>
        <Literal>
          <ID>param-list</ID>
          <ToolTip>Parameter list</ToolTip>
          </Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[$method-modifiers$ $return-type$ $member-name$( $param-list$ )
{
$end$
}]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

posted on May 23, 2007  #    by Adam Anderson  Comments [0] Trackback
 Tuesday, May 15, 2007

There's a fascinating little article "Create Advanced Web Applications With Object-Oriented Techniques" by Ray Djajadinata that delves into how JavaScript implements objects, inheritance, anonymous methods, and even a bit about simulating private properties and namespaces.  This may be relevant if you want greater depth in AJAX, particularly the Microsoft flavor ASP.NET AJAX.  There's a sidebar (by Bertrand Le Roy) about the ASP.NET AJAX OOPS implementation and use of JavaScript to add reflection and other .NET familar constructs including properties, events, enumerations and interfaces.

posted on May 15, 2007  #    by Noel Rice  Comments [0] Trackback
 Monday, May 14, 2007

This is one of those little things I'm looking forward to getting out of C# 3.0: inferred types. I've always throught to myself, "I just declared the variable to be that type, can't you figure it out without me spelling it out for you, C# compiler?" Well, the compiler can't figure it out yet, but here's a little snippet I cooked up so at least I don't have to type the type name twice:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>var</Title>
      <Shortcut>var</Shortcut>
      <Description>Code snippet for declaring and initializing a variable with a type cast</Description>
      <Author>Adam Anderson</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>type</ID>
          <ToolTip>Variable type</ToolTip>
          <Default>Type</Default>
        </Literal>
        <Literal>
          <ID>name</ID>
          <ToolTip>Variable name</ToolTip>
          <Default>Name</Default>
        </Literal>
        <Object>
          <ID>value</ID>
          <ToolTip>Initial value</ToolTip>
          <Default>Value</Default>
          <Type>System.Object</Type>
        </Object>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[$type$ $name$ = ($type$) $value$;
        $end$]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

To install, copy and paste the above XML into a file and save it with a .snippet extension to your code snippets directory (My Documents\Visual Studio 2005\Code Snippets\Visual C#\My Code Snippets). To use, simply type "var" and press Tab.

Now as you type the type name, it will be duplicated for you in the type cast.

Every little annoyance eliminated is productivity gained. Enjoy!

posted on May 14, 2007  #    by Adam Anderson  Comments [0] Trackback
 Monday, May 07, 2007

We recently decided to use Developer Express XtraReports for one of our projects. While it's an impressive product with rich functionality, its design-time support within a web project definitely isn't as robust as it is within a windows project. After some trial and error, I discovered the trick to getting the designer preview tab to work with a parameterized query. Here's how it's done:

  1. In a web project, add a new XtraReport
  2. With the XtraReports designer open, double-click on a DataAdapter. If no DataAdapters are visible in your toolbar (none were in mine by default), you'll have to add them to the toolbar manually.
  3. Configure the DataAdapter using the wizard
  4. In the property grid, navigate to the DataAdapter's SelectCommand | Parameters property. Use the Parameters dialog to set a default value for each parameter. This will enable the report to execute the command at design-time.
  5. Select "Generate DataSet" from the DataAdapter's context menu. In the dialog that appears, make sure to check the box that says "Add this dataset to designer."
  6. The report's DataSource, DataMember, and DataAdapter properties should already be set correctly. Click on the report and examine the properties to confirm.
  7. Try adding a few fields to the detail band of the report, then click the preview tab. After a short delay, the preview should appear!

This approach uses DataAdapter classes directly. The default adapter created by Visual Studio if you create the DataSet first and then add a table will be a TableAdapter. TableAdapters will not work with this approach, because they have no facility to set default parameter values at design time. Unfortunately, the only adapters that appear in the XtraReports' DataAdapter property editor are TableAdapters. However, if you click in the grid and start typing the name of your DataAdapter, the property grid will locate it and assign it to the property correctly.

posted on May 7, 2007  #    by Adam Anderson  Comments [0] Trackback
 Sunday, May 06, 2007

I recently ran into an unexpected behavior of SSRS while writing a complex report. The report required various calculations that would refer to specific previous groups and details, and I had decided to solve the problem by writing a custom report function that would evaluate on each detail row, saving the information I would need later in a dictionary. My solution worked fine, as long as my custom calculation in a group footer didn't depend on the contents of that group's details. Upon further investigation, I learned something very interesting about the order in which SSRS evaluates group headers, footers, and details...

Here is how to observe the behavior for yourself: create a stored procedure like this one, that generates some simple test data:

CREATE PROCEDURE dbo.HundredRows
AS
SET NOCOUNT ON

create table #result (
id int,
grp int
)

declare @id int
set @id = 1

while @id <= 100
begin
insert #result
values ( @id, ( @id - 1 ) / 5 )

set @id = @id + 1
end

select *
from #result

This will return a result set whose id column increments in steps of one from 1 to 100, and whose grp column increments in steps of one for every five rows. Next, create a simple report layout with a table, showing the values of each column and grouping by the grp column. In the group header and footer, include the same column references. Next, add this custom code:

Dim eval_order As Integer = 0

Public Function show_eval_order() As String
  eval_order = eval_order + 1
  Return eval_order.ToString()
End Function

Display the result of this function in the group header, footer, and detail rows. Your layout should look like this:

Once you have the report set up, click on the preview tab to see the surprising results:

I've only shown the first two groups here, but notice what has happened! The order column clearly indicates that the group header and footer are both evaluated before the details in between! By looking at the value of the id column in the footer, we can see that the the group's header and footer rows are printed while the "current" row in the dataset is still positioned on the first row in the group.

While this is interesting, it isn't very important as long as you stick to using SSRS's built-in aggregation functions. It is only when you attempt to "roll your own" by saving the dataset in your own storage for later reference that you might run into trouble. In my case, I used the following workarounds:

  1. Move calculations that rely on the details having been traversed from the group footer to the following group's header. It's clunky and less intuitive, but that's what SSRS has forced upon us.
  2. For the final group, move the calculation out of the table entirely, and put it into textboxes just below the table. While there is no way to tell SSRS to evaluate the textboxes after it evaluates the table, it does so at least for the 2005 version.

In summary, it sure would have been nice if SSRS would have evaluated group headers and footers after it evaluated the details that each group contains, but since we have clearly demonstrated that it doesn't, we now know what we will have to do in order to make custom report code produce the output we want: by putting those custom calculations into the following group's header, and by putting the final footer calculation outside the table entirely.

posted on May 6, 2007  #    by Adam Anderson  Comments [0] Trackback