June 2005 - Posts

Hi folks,

If you have a question about the Microsoft Virtual Server 2005 technology on TechEd 2005 Europe in Amsterdam next week (which you'll get for free when attending the conference :o), don't hesitate to visit the ATE booth (station 15B) to ask all of your questions. The ATE is opened on Tuesday from 11:30 AM till 4:30 PM and from 6:30 PM till 9:00 PM (evening session); on Wednesday from 11:00 AM till 5:00 PM; on Thursday from 11:00 AM till 5:00 PM; on Friday from 11:00 AM till 3:00 PM. You can find me out there on:

  • Tuesday - 6:30 PM till 9:00 PM
  • Wednesday - 2:00 PM till 5:00 PM
  • Friday - 11:00 AM till 1:15 PM

Hope to see you there!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Introduction

In the previous two posts on database access in Comega I explained how to import a database schema using Sql2Comega.exe and how to use the select keyword in Comega to query the database using the imported data access assembly that contains the metadata information about the database. By using SQL statements in the language directly, you gain in strong-typing and compiler-level checking of statements sent to the server. Actually, the Comega database access stuff can be summarized as "wrapping" keywords around the underlying data provider (currently SQL Server only).

DML

It's fine to be able to access the database using some select construction. However, it's even nicer to have the ability to manipulate the data in the database using keywords, as queries are most typing-sensitive (think of parameterized DML statements which are sent to a database server). Let's start with insertion. Generally spoken, there are two different approaches to insert a new row in a table. First, you can use an implicitly constructed row, by using the following syntax:

int n = insert CustomerID="Test", ContactName="This", CompanyName="Too" into DB.Customers;

where n returns the number of affected rows. Remark that the string values are surrounded by the Comega string delimiters, thus double quotes. Alternatively, one can create the row explicitly (without a type specification, as shown in the previous posts too):

row = new {CustomerID="Test", ContactName="This", CompanyName="Too" into DB.Customers};
int n = insert row into DB.Customers;

In case of insertion conflicts and exceptions, e.g. because a required field value is needed or a constraint is violated, the classic try...catch structure in Comega can be used:

try
{
     row = new {CustomerID=someID, ContactName=someContact, CompanyName=someName into DB.Customers};
     int n = insert row into DB.Customers;
}
catch (SqlException ex) { ... }

As shown in the sample above, variables can be used to specify the field values. It's because of this that the string concatenation and statement parameterization stuff "classic approach" is vanishing due to the introduction of data access keywords in Comega. Note that it's possible too to nest select and insert statements, e.g. to write an insert statement that uses a query (in another table for example) to retrieve the row to be inserted in the table.

I guess that the update and delete statements are pretty straightforward once you get to know the idea of the insert statement. Basically, the structure looks as follows:

update DB.Table set Field1=value1, Field2=value2 ... where Field3 == value3 && Field4 == value4 || Field5 == value5 ...;

of course not formally formulated in BNF. But it gives the informal idea. Note it's also possible to use output parameters, by specifying an assignment to a local variable in the set portion of the statement, e.g.:

update DB.Table set local_variable_to_be_get=SomeFirstField, SomeSecondField=local_variable_to_be_set where ...;

Last but not least, the delete statement which is really as straightforward as possible:

delete from DB.Table where SomeField == somevalue;

Transactions

I hope all of my blog readers know the concept of transactions. If not, well, there's enough stuff to learn about these things. Briefly, a transaction has the ACID properties, what stands for atomicity, consistency, isolation, durability. Using this concept one can guarantee that multiple edit operations on some resource (for example a database) succeed or fail together in a all-or-nothing fashion. Now, one of the problems with transactions today is the lack of built-in block structure support to express transactions, commit actions and rollback actions. Well, honestly, the System.Transactions namespace in .NET v2.0 is a great enhancement, but not on the level of the language syntax. Comega changes this but introducing the keywords transact, commit and rollback. The structure looks like this:

transact(DB)
{
     //perform some database operations
}
commit
{
     //implicitly called when transact block succeeds
}
rollback
{
     //implicitly called when transact block has thrown an exception
}

If you want explicit control, e.g. based on conditional evaluation of return values of DML-statements or output parameters in update-statements, it's also possible to use the keyword rollback where needed:

transact(DB)
{
     //let's try something
     ...

     //let's check whether it's okay for us
     if (somevar != somerequiredvalue) rollback;
}

Put some breakpoints in your code and execute the sample. You'll see nothing about the DML operations using a tool like query-analyzer till the commit is executed (because of isolation).

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

This evening my laptop offered me the option to connect to an unsecured WLAN with an unknown SSID in the living room. Pretty cool :o. Even cooler to get a valid IP address, have no MAC filtering, therefore allowing me to connect to the internet with just one click. Even more, the router admin pages are unsecured so all the ISP information can be revealed :s. Today the "WLAN owner hunting" will start to tell him/her about the problem... I hope I can spot the person in question. It's all about honesty isn't it, trying to inform people. You guys have to know I'm living in the middle of a city center with quite some apartments in the neighbourhood. So one, it will be difficult to find the owner, second there might already be others who have used the WLAN in a malicious way :s.

Time for security evangelism :-).

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Introduction

In the first part of episode 5 of my series on "Adventures in Comega" I showed you the internal IL-kitchen of database access in Comega and how the Sql2Comega.exe tool is used to export the metadata of a database for usage in the Comega language. Now I'll show you the various constructs that are available in Comega to perform database operations using built-in keywords.

Selection

Okay, the first one I showed in the previous post already is the "select"-keyword to perform ... right, selection. The syntax should be well-known and consists of a "select ... from ..." skeleton with some optional clauses I'll cover further on. An example looks like this:

results = select * from DB.Products

You don't have to worry about the type of the results-variable, it's the job of the Comega compiler to generate the necessairy constructs to make it work, as we saw in the previous post (type infer). Now you can use the foreach keyword to iterate over the rows:

foreach (result in results)
{
     string pname = result.ProductName;
     double uprice = result.UnitPrice;
     //...
}

In fact, results is just a stream (see first episodes of this series for more information about the concept of "streams"). If you do want to specify the stream type explicitly, you can do:

struct { SqlString ProductName; SqlMoney UnitPrice; }* result = select ProductName, UnitPrice from DB.Products

But this is not needed as you can see in the previous code snippets. However, it can be useful when you're using aliases:

struct { SqlString Name; }* result = select ProductName as Name from DB.Products

You can go even further by declaring a field without a name, using parentheses. I won't cover this over here, there's a sample in the Comega documentation stuff. The iteration alias can be specified using the "in" keyword:

foreach (row in select p.ProductName from p in DB.Products) { ... }

Projection

Right, we can select fields in rows. Assume you want to map these fields to attributes in class instances? How to do that? A straightforward way is this one:

class Product
{
     private SqlString ProductName;
     private SqlMoney UnitPrice;

     public Product(SqlString ProductName, SqlMoney UnitPrice)
     {
          this.ProductName = ProductName;
          this.UnitPrice = UnitPrice;
     }

     //...
}

foreach (row in select ProductName, UnitPrice from DB.Products)
{
     Product p = new Product(row.ProductName, row.UnitPrice);
     //...
}

Well, this should work. However, using projection you can actually do this work automatically, by generating a steam of Product instances (Product*):

Product* products = select new Product(ProductName, UnitPrice) from DB.Products;

Although I didn't cover XML support in Comega to the full extent yet, I'll show you how you can use XML syntax in Comega too:

class Product
{
     struct
     {
          SqlString ProductName;
          SqlMoney UnitPrice;
     }
}

Product* products =
     select
         
<Product>
               <ProductName>{ProductName}</ProductName>
               <UnitPrice>{UnitPrice}</UnitPrice>
          </Product>
     from DB.Products;

This is one of my favorite features in Comega I have to admit. Although IntelliSense is rather poor for the moment (you shouldn't expect this kind of stuff to work in experimental releases) I'm sure that a well-working IntelliSense will boost developer productivity when writing this kind of code (as the matter in fact, the <Product>-section can be generated almost automatically).

Beside of using the normal constructors in the projections, you can use functions too, or tuple constructors:

public SqlString ConvertPrice(SqlMoney unitPrice)
{
     return "EUR " + unitPrice;
}

foreach (row in select ConvertPrice(UnitPrice) from DB.Products)
{
     //row is SqlString
}

or

foreach (row in select new{Name=ProductName, Price=UnitPrice} from DB.Products)
{
     //row is tuple type with correctly-typed child attributes
}

Restricting the selection results

First of all, there's the wellknown select clause. Thanks to the integration with the Comega language you'll have a strongly-typed and type-checked syntax for the specification of where-clauses:

results = select ProductID, SupplierID from DB.Products where UnitsInStock < 5;

Other operators are >, ==, !=, <=, >=. To combine expressions the operators && (and) and || (or) can be used. It's important to realize that the selection is happening on the server, so the where-clause is translated into a WHERE-clause in a SQL statement behind the scenes. When using a variable in the condition, it will be evaluated once:

int baseLevel = 5;
results = select ProductID, SupplierID from DB.Products where UnitsInStock < baseLevel;

Next, we have the distinct keyword at our service:

results = select distinct SupplierID from DB.Products;

and the top keyword which can be useful in combinatio with sort operations too (just to give an example):

int supplier = ...;
results = select top 10 ProductName from DB.Products where SupplierID == supplier order by UnitPrice desc;

Should look familiar. The top keyword can also be combined with the keyword percent to have a factor relative to the number of selected rows (e.g. top 25 percent).

Singleton select

Now, one of the problems we have in here is that we always retrieve a stream of records, even when there's only one result. A selection on a primary key will typically generate only one result. The same holds for aggregates which are supported too:

int n = select singleton count(*) from DB.Products;
string name = select singleton ProductName from DB.Products where ProductID=1;

Joins

Okay, I guess you already can see how transparent the use of SQL keywords in Comega is, compared to the equivalent keywords in the T-SQL language. The same holds for all kind of joins:

  • just using a where-clause and different selected tables, aliased with a name (select x.PK, x.Bla, y.Bla from x as DB.TableX, y as DB.TableY where x.PK == y.FK)
  • inner joins with inner join ... in ... on ...
  • left joins with left join ... in ... on ...
  • right joins, outer joins

Grouping, aggregates, having

Exactly the same as in "classic SQL". Just try it and it should work :-)

Subqueries and quantifiers

Subqueries are supported too, which allows nesting of selects. The simplest form of this is to use a singleton select in the subquery expression and to compare that result with some given value. The documentation shows this relevant sample:

   rows = select ContactName, Phone
            from c in DB.Customers
            where (select singleton Count(OrderID)
                     from o in DB.Orders
                     where o.CustomerID == c.CustomerID)
> 10;

So, as you can see, the nested query has access to the fields of the outer query (in this case, the CustomerID) for comparison in the where clause. The idea is that a singleton select returns a scalar value, not a stream, so it can be compared with some other value or it can be inserted in the results of a select as a field. However, sometimes you want to operate on streams (e.g. a query based on the existence of a result performed by a subquery). To allow this, Comega has the operators all, any, exists that we call quantifiers. The usage of these is pretty straightforward and more information can be found in the documentation once again.

Functions

Although not all T-SQL functions are supported (luckily :o) the most relevant ones are, including mathematical functions, string functions and date/time functions.

More to come

In the next post for episode 5 I'll show the DML statements insert, update and delete, as well as transactions.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Posted Tuesday, June 21, 2005 1:22 AM by bart | with no comments
Filed under:

Okay, let's resume where we suspended :-). In the previous Monad adventure episode I've been talking about the concept of cmdlets or "command-lets" as the atomic units of work in the Monad system. Now, let's dive deeper into this stuff and show some examples of working with cmdlets.

Obtaining a list of cmdlets

In RDBMSs you can query the databases on the system using a database itself (the catalog). In a similar fashion there's a cmdlet in Monad to display all of the cmdlets on the system. It's called Get-Command:

MSH> get-command

Command Type    Name                      Definition
------------    ----                      ----------
Cmdlet          get-command               get-command [-Verb String[]] [-Nou...
Cmdlet          get-help                  get-help [[-Name] String] [-Catego...
Cmdlet          get-history               get-history [[-Id] Int64[]] [[-Cou...
Cmdlet          invoke-history            invoke-history [[-Id] String] [-Ve...
Cmdlet          add-history               add-history [[-InputObject] Object...
Cmdlet          foreach-object            foreach-object [-Process] ScriptBl...
Cmdlet          where-object              where-object [-ScriptToApply] Scri...
Cmdlet          set-mshdebug              set-mshdebug [-Trace Int32] [-Step...
Cmdlet          add-content               add-content [-Path] String[] [-Val...
Cmdlet          clear-content             clear-content [-Path] String[] [-P...
Cmdlet          clear-property            clear-property [-Path] String[] [-...
Cmdlet          combine-path              combine-path [-Path] String[] [-Ch...
Cmdlet          convert-path              convert-path [-Path] String[] [-Ve...
Cmdlet          copy-property             copy-property [-Path] String[] [[-...
Cmdlet          get-eventlog              get-eventlog [-LogName] String [-N...
Cmdlet          get-childitem             get-childitem [[-Path] String[]] [...
Cmdlet          get-content               get-content [-Path] String[] [-Rea...
Cmdlet          get-property              get-property [-Path] String[] [[-P...
Cmdlet          get-WMIObject             get-WMIObject [-Class] String [[-P...
Cmdlet          move-property             move-property [-Path] String[] [-D...
Cmdlet          get-location              get-location [-Provider String[]] ...
Cmdlet          set-location              set-location [[-Path] String] [-Pa...
Cmdlet          push-location             push-location [[-Path] String] [-P...
Cmdlet          pop-location              pop-location [-PassThru] [-StackNa...
Cmdlet          new-drive                 new-drive [-Name] String [-Provide...
Cmdlet          remove-drive              remove-drive [-Name] String[] [-Pr...
Cmdlet          get-drive                 get-drive [[-Name] String[]] [-Sco...
Cmdlet          get-item                  get-item [-Path] String[] [-Filter...
Cmdlet          new-item                  new-item [-Path] String[] [-Type S...
Cmdlet          set-item                  set-item [-Path] String[] [[-Value...
Cmdlet          remove-item               remove-item [-Path] String[] [-Fil...
Cmdlet          move-item                 move-item [-Path] String[] [[-Dest...
Cmdlet          rename-item               rename-item [-Path] String [-Name]...
Cmdlet          copy-item                 copy-item [-Path] String[] [[-Dest...
Cmdlet          clear-item                clear-item [-Path] String[] [-Forc...
Cmdlet          invoke-item               invoke-item [-Path] String[] [-Fil...
Cmdlet          get-provider              get-provider [[-Provider] String[]...
Cmdlet          new-property              new-property [-Path] String[] [-Pr...
Cmdlet          parse-path                parse-path [-Path] String[] [-Pare...
Cmdlet          test-path                 test-path [-Path] String[] [-Filte...
Cmdlet          get-process               get-process [[-ProcessName] String...
Cmdlet          stop-process              stop-process [-Id] Int32[] [-PassT...
Cmdlet          remove-property           remove-property [-Path] String[] [...
Cmdlet          rename-property           rename-property [-Path] String [-P...
Cmdlet          resolve-path              resolve-path [-Path] String[] [-Cr...
Cmdlet          get-service               get-service [[-ServiceName] String...
Cmdlet          stop-service              stop-service [-ServiceName] String...
Cmdlet          start-service             start-service [-ServiceName] Strin...
Cmdlet          suspend-service           suspend-service [-ServiceName] Str...
Cmdlet          resume-service            resume-service [-ServiceName] Stri...
Cmdlet          restart-service           restart-service [-ServiceName] Str...
Cmdlet          set-service               set-service [-ServiceName] String ...
Cmdlet          new-service               new-service [-ServiceName] String ...
Cmdlet          set-content               set-content [-Path] String[] [-Val...
Cmdlet          set-property              set-property [-Path] String[] -Pro...
Cmdlet          format-list               format-list [[-Property] Object[]]...
Cmdlet          format-custom             format-custom [[-Property] Object[...
Cmdlet          format-table              format-table [[-Property] Object[]...
Cmdlet          format-wide               format-wide [[-Property] Object] [...
Cmdlet          out-null                  out-null [-InputObject MshObject] ...
Cmdlet          out-default               out-default [-InputObject MshObjec...
Cmdlet          out-host                  out-host [-Paging] [-InputObject M...
Cmdlet          out-file                  out-file [-Path] String [[-Encodin...
Cmdlet          out-printer               out-printer [[-Printer] String] [-...
Cmdlet          out-string                out-string [-Stream] [-Width Int32...
Cmdlet          update-formatdata         update-formatdata [-Trace] [-Force...
Cmdlet          export-csv                export-csv [-Path] String -InputOb...
Cmdlet          import-csv                import-csv [-Path] String[] [-Verb...
Cmdlet          export-alias              export-alias [-Path] String [[-Nam...
Cmdlet          Invoke-Command            Invoke-Command [-Command] String [...
Cmdlet          get-alias                 get-alias [[-Name] String[]] [-Exc...
Cmdlet          get-Culture               get-Culture [-Verbose] [-Debug] [-...
Cmdlet          get-Date                  get-Date [[-To] DateTime] [-Year I...
Cmdlet          get-host                  get-host [-Verbose] [-Debug] [-Err...
Cmdlet          get-member                get-member [[-Name] String[]] [-In...
Cmdlet          get-UICulture             get-UICulture [-Verbose] [-Debug] ...
Cmdlet          get-unique                get-unique [-InputObject MshObject...
Cmdlet          import-alias              import-alias [-Path] String [-Scop...
Cmdlet          match-string              match-string [-Pattern] String[] -...
Cmdlet          Measure-Object            Measure-Object [-InputObject MshOb...
Cmdlet          new-alias                 new-alias [-Name] String [-Value] ...
Cmdlet          new-Timespan              new-Timespan [[-From] DateTime] [[...
Cmdlet          read-host                 read-host [[-Prompt] Object] [-Sec...
Cmdlet          set-alias                 set-alias [-Name] String [-Value] ...
Cmdlet          set-Date                  set-Date [-To] DateTime [-DisplayH...
Cmdlet          Start-Sleep               Start-Sleep [-Seconds] Int32 [-Ver...
Cmdlet          tee-object                tee-object [-FileName] String [-In...
Cmdlet          Time-Expression           Time-Expression [[-Expression] Scr...
Cmdlet          write-host                write-host [[-Object] Object] [-No...
Cmdlet          write-progress            write-progress [-Activity] String ...
Cmdlet          new-object                new-object [-TypeName] String [[-A...
Cmdlet          select-object             select-object [[-Property] Object[...
Cmdlet          group-object              group-object [[-Property] Object[]...
Cmdlet          sort-object               sort-object [[-Property] Object[]]...
Cmdlet          get-variable              get-variable [[-Name] String[]] [-...
Cmdlet          new-variable              new-variable [-Name] String [[-Val...
Cmdlet          set-variable              set-variable [-Name] String[] [[-V...
Cmdlet          remove-variable           remove-variable [-Name] String[] [...
Cmdlet          clear-variable            clear-variable [-Name] String[] [-...
Cmdlet          Write-debug               Write-debug [-Message] String [-Ve...
Cmdlet          Write-verbose             Write-verbose [-Message] String [-...
Cmdlet          Write-Error               Write-Error [-Message] String [-Ca...
Cmdlet          Write-Object              Write-Object [-InputObject] Object...
Cmdlet          get-tracesource           get-tracesource [[-Name] String[]]...
Cmdlet          set-tracesource           set-tracesource [-Name] String[] [...
Cmdlet          trace-expression          trace-expression [-Name] String[] ...
Cmdlet          get-acl                   get-acl [[-Path] String[]] [-Audit...
Cmdlet          set-acl                   set-acl [-Path] String[] [-ACLObje...
Cmdlet          get-PfxCertificate        get-PfxCertificate [-Path] String[...
Cmdlet          get-credential            get-credential [-Credential] MshCr...
Cmdlet          get-AuthenticodeSignature get-AuthenticodeSignature [-Path] ...
Cmdlet          set-AuthenticodeSignature set-AuthenticodeSignature [-Path] ...
Cmdlet          new-SecureString          new-SecureString [-Verbose] [-Debu...
Cmdlet          export-SecureString       export-SecureString [-SecureString...
Cmdlet          import-SecureString       import-SecureString [-String] Stri...


MSH>

Quite some stuff, right? Now, Get-Process can be used to limit this list, based on the verb, the noun, or a wildcard:

MSH> get-command -verb set

Command Type    Name                      Definition
------------    ----                      ----------
Cmdlet          set-mshdebug              set-mshdebug [-Trace Int32] [-Step...
Cmdlet          set-location              set-location [[-Path] String] [-Pa...
Cmdlet          set-item                  set-item [-Path] String[] [[-Value...
Cmdlet          set-service               set-service [-ServiceName] String ...
Cmdlet          set-content               set-content [-Path] String[] [-Val...
Cmdlet          set-property              set-property [-Path] String[] -Pro...
Cmdlet          set-alias                 set-alias [-Name] String [-Value] ...
Cmdlet          set-Date                  set-Date [-To] DateTime [-DisplayH...
Cmdlet          set-variable              set-variable [-Name] String[] [[-V...
Cmdlet          set-tracesource           set-tracesource [-Name] String[] [...
Cmdlet          set-acl                   set-acl [-Path] String[] [-ACLObje...
Cmdlet          set-AuthenticodeSignature set-AuthenticodeSignature [-Path] ...


MSH> get-command -noun acl

Command Type    Name                      Definition
------------    ----                      ----------
Cmdlet          get-acl                   get-acl [[-Path] String[]] [-Audit...
Cmdlet          set-acl                   set-acl [-Path] String[] [-ACLObje...


MSH> get-command *service

Command Type    Name                      Definition
------------    ----                      ----------
Cmdlet          get-service               get-service [[-ServiceName] String...
Cmdlet          stop-service              stop-service [-ServiceName] String...
Cmdlet          start-service             start-service [-ServiceName] Strin...
Cmdlet          suspend-service           suspend-service [-ServiceName] Str...
Cmdlet          resume-service            resume-service [-ServiceName] Stri...
Cmdlet          restart-service           restart-service [-ServiceName] Str...
Cmdlet          set-service               set-service [-ServiceName] String ...
Cmdlet          new-service               new-service [-ServiceName] String ...


MSH>

Right, there's apparently more to see about cmdlets than what is displayed (look at the ellipsis on the right-hand side). How to show this? The Format-List cmdlet should be your friend in this kind of scenarios:

MSH> get-command get-service | format-list


Name          : get-service
CommandType   : Cmdlet
Definition    : get-service [[-ServiceName] String[]] [-Include String[]] [-Exc
                lude String[]] [-Verbose] [-Debug] [-ErrorAction ActionPreferen
                ce] [-ErrorVariable String] [-OutVariable String] [-OutBuffer I
                nt32]
                get-service -DisplayName String[] [-Include String[]] [-Exclude
                 String[]] [-Verbose] [-Debug] [-ErrorAction ActionPreference]
                [-ErrorVariable String] [-OutVariable String] [-OutBuffer Int32
                ]
                get-service [-Include String[]] [-Exclude String[]] [-Input Ser
                viceController[]] [-Verbose] [-Debug] [-ErrorAction ActionPrefe
                rence] [-ErrorVariable String] [-OutVariable String] [-OutBuffe
                r Int32]

Path          :
AssemblyInfo  :
DLL           : C:\Program Files\Microsoft Command Shell\System.Management.Auto
                mation.Commands.Management.DLL
HelpFile      : System.Management.Automation.Commands.Management.dll-Help.xml
ParameterSets : {Default, DisplayName, Input}
Type          : System.Management.Automation.Commands.GetServiceCommand
Verb          : get
Noun          : service

 

MSH>

Pipelines

The previous sample showed you two things: how to use Format-List and how to use the pipe symbol (|) to combine cmdlets by redirecting the output of one cmdlet to the input of another one in kind of a chain structure. Now, let's try to apply some filtering with Where-Object:

MSH> get-service | where-object { $_.status -eq "Running" }

Status   Name               DisplayName
------   ----               -----------
Running  1-vmsrvc           Virtual Machine Additions Services ...
Running  ADAM_BISGSS        BISGSS
Running  AeLookupSvc        Application Experience Lookup Service
Running  AudioSrv           Windows Audio
Running  Browser            Computer Browser
Running  CiSvc              Indexing Service
Running  CryptSvc           Cryptographic Services
Running  DcomLaunch         DCOM Server Process Launcher
Running  Dhcp               DHCP Client
Running  dmserver           Logical Disk Manager
Running  Dnscache           DNS Client
Running  ERSvc              Error Reporting Service
Running  Eventlog           Event Log
Running  EventSystem        COM+ Event System
Running  helpsvc            Help and Support
Running  HTTPFilter         HTTP SSL
Running  IISADMIN           IIS Admin Service
Running  lanmanserver       Server
Running  lanmanworkstation  Workstation
Running  LmHosts            TCP/IP NetBIOS Helper
Running  MSDTC              Distributed Transaction Coordinator
Running  MSSQL$SHAREPOINT   MSSQL$SHAREPOINT
Running  MSSQL$SQLEXPRESS   SQL Server (SQLEXPRESS)
Running  MSSQLSERVER        SQL Server (MSSQLSERVER)
Running  MSSQLServerOLAP... Analysis Server (MSSQLSERVER)
Running  Netman             Network Connections
Running  Nla                Network Location Awareness (NLA)
Running  PlugPlay           Plug and Play
Running  PolicyAgent        IPSEC Services
Running  ProtectedStorage   Protected Storage
Running  RemoteRegistry     Remote Registry
Running  ReportServer       Report Server (MSSQLSERVER)
Running  RpcSs              Remote Procedure Call (RPC)
Running  SamSs              Security Accounts Manager
Running  Schedule           Task Scheduler
Running  seclogon           Secondary Logon
Running  SENS               System Event Notification
Running  ShellHWDetection   Shell Hardware Detection
Running  Spooler            Print Spooler
Running  SPTimer            SharePoint Timer Service
Running  SQLBrowser         SQL Browser
Running  SQLSERVERAGENT     SQL Server Agent (MSSQLSERVER)
Running  TermService        Terminal Services
Running  TFSServerScheduler TFSServerScheduler
Running  TrkWks             Distributed Link Tracking Client
Running  W32Time            Windows Time
Running  W3SVC              World Wide Web Publishing Service
Running  winmgmt            Windows Management Instrumentation
Running  wuauserv           Automatic Updates
Running  WZCSVC             Wireless Configuration


MSH>

This deserves some extra explanation. The parameter of where-object contains the condition to filter for. In this case, we obtain a reference to every item in the list using the $_ operator. Using the dot operator we can select a property, in this case we choose for status. This value is then compared to the string "Running" for equality (-eq). To show some other operators, consider the following example:

MSH> get-service | where-object { $_.status -eq "Running" -and $_.name -like "MSSQL*" }

Status   Name               DisplayName
------   ----               -----------
Running  MSSQL$SHAREPOINT   MSSQL$SHAREPOINT
Running  MSSQL$SQLEXPRESS   SQL Server (SQLEXPRESS)
Running  MSSQLSERVER        SQL Server (MSSQLSERVER)
Running  MSSQLServerOLAP... Analysis Server (MSSQLSERVER)


MSH>

Should be clear I guess? Now, what can we query on the output of a Get-Service invocation? To find out about this, together wit the types, use Get-Member:

MSH> Get-Service | Get-Member -MemberType property


    TypeName: System.ServiceProcess.ServiceController

Name                MemberType Definition
----                ---------- ----------
CanPauseAndContinue Property   System.Boolean CanPauseAndContinue {get;}
CanShutdown         Property   System.Boolean CanShutdown {get;}
CanStop             Property   System.Boolean CanStop {get;}
Container           Property   System.ComponentModel.IContainer Container {g...
DependentServices   Property   System.ServiceProcess.ServiceController[] Dep...
DisplayName         Property   System.String DisplayName {get;set;}
MachineName         Property   System.String MachineName {get;set;}
ServiceHandle       Property   System.Runtime.InteropServices.SafeHandle Ser...
ServiceName         Property   System.String ServiceName {get;set;}
ServicesDependedOn  Property   System.ServiceProcess.ServiceController[] Ser...
ServiceType         Property   System.ServiceProcess.ServiceType ServiceType...
Site                Property   System.ComponentModel.ISite Site {get;set;}
Status              Property   System.ServiceProcess.ServiceControllerStatus...


MSH>

This is where the .NET types become visible.

Whatif? Confirm!

Now assume we want to take some action for the selected services (e.g. all MSSQL* services as explained above), for example to stop these services. This can be accomplished by piping the output of the Get-Service cmdlet to the input of the Stop-Service cmdlet. However, this can be a little too agressive, we want more control. There are various ways to do this, e.g. by using a foreach construct together with Read-Host to ask the user for input. Monad has built-in functionality however to see the "showplan" of the execution, by using the -whatif parameter:

MSH> get-service | where-object { $_.status -eq "Running" -and $_.name -like "MSSQL*" } | stop-service -whatif
What if: Operation "stop-service" on Target "MSSQL$SHAREPOINT (MSSQL$SHAREPOINT)"
What if: Operation "stop-service" on Target "SQL Server (SQLEXPRESS) (MSSQL$SQLEXPRESS)"
What if: Operation "stop-service" on Target "SQL Server (MSSQLSERVER) (MSSQLSERVER)"
What if: Operation "stop-service" on Target "Analysis Server (MSSQLSERVER) (MSSQLServerOLAPService)"
MSH>

Okay, that's fine. Let's execute it, but we don't want to stop the SHAREPOINT instance. We could extend the filter or ask for manual user intervention using -confirm. Let's use the latter one:

MSH> get-service | where-object { $_.status -eq "Running" -and $_.name -like "MSSQL*" } | stop-service -confirm

Continue with this operation?
Operation "stop-service" on Target "MSSQL$SHAREPOINT (MSSQL$SHAREPOINT)"
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "N") :N

Continue with this operation?
Operation "stop-service" on Target "SQL Server (SQLEXPRESS) (MSSQL$SQLEXPRESS)"
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "N") :Y

Continue with this operation?
Operation "stop-service" on Target "SQL Server (MSSQLSERVER) (MSSQLSERVER)"
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "N") :Y
stop-service : Cannot stop service 'SQL Server (MSSQLSERVER) (MSSQLSERVER)' bec
ause it has dependent services. It can only be stopped if the Force flag is set
.
At line:1 char:98
+ get-service | where-object { $_.status -eq "Running" -and $_.name -like "MSSQ
L*" } | stop-service  <<<< -confirm

Continue with this operation?
Operation "stop-service" on Target "Analysis Server (MSSQLSERVER)
(MSSQLServerOLAPService)"
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "N") :Y
MSH>

Okay, SQL Server couldn't be stopped because it has a dependency but it draws the overall picture of the principles of pipelines in Monad.

Aliasing

Right, we saw the use of Where-Object in the previous samples. Pretty powerful but nasty to type. An interesting concept in Monad to solve this problem is the use of aliases. The Get-Alias cmdlet show us all of the defined aliases:

MSH> get-alias

Command Type    Name                      Definition
------------    ----                      ----------
Alias           ac                        add-content
Alias           clc                       clear-content
Alias           cli                       clear-item
Alias           clp                       clear-property
Alias           cpi                       copy-item
Alias           cpp                       copy-property
Alias           cv                        clear-variable
Alias           cvpa                      convert-path
Alias           epal                      export-alias
Alias           fc                        format-custom
Alias           fl                        format-list
Alias           foreach                   foreach-object
Alias           ft                        format-table
Alias           fw                        format-wide
Alias           gal                       get-alias
Alias           gc                        get-content
Alias           gci                       get-childitem
Alias           gcm                       get-command
Alias           gdr                       get-drive
Alias           ghy                       get-history
Alias           gi                        get-item
Alias           gl                        get-location
Alias           gm                        get-member
Alias           gp                        get-property
Alias           gps                       get-process
Alias           group                     group-object
Alias           gsv                       get-service
Alias           gu                        get-unique
Alias           gv                        get-variable
Alias           help                      get-help
Alias           ic                        invoke-command
Alias           ihy                       invoke-history
Alias           ii                        invoke-item
Alias           ipal                      import-alias
Alias           ipcsv                     import-csv
Alias           mi                        move-item
Alias           mp                        move-property
Alias           nal                       new-alias
Alias           ndr                       new-drive
Alias           ni                        new-item
Alias           nv                        new-variable
Alias           oh                        out-host
Alias           rdr                       remove-drive
Alias           ri                        remove-item
Alias           rmi                       rename-item
Alias           rmp                       rename-property
Alias           rp                        remove-property
Alias           rv                        remove-variable
Alias           rvpa                      resolve-path
Alias           sal                       set-alias
Alias           sasv                      start-service
Alias           sc                        set-content
Alias           select                    select-object
Alias           si                        set-item
Alias           sl                        set-location
Alias           sleep                     start-sleep
Alias           sort                      sort-object
Alias           sp                        set-property
Alias           spps                      stop-process
Alias           spsv                      stop-service
Alias           sv                        set-variable
Alias           where                     where-object
Alias           cat                       get-content
Alias           cd                        set-location
Alias           clear                     clear-host
Alias           cp                        copy-item
Alias           h                         get-history
Alias           history                   get-history
Alias           kill                      stop-process
Alias           lp                        out-printer
Alias           ls                        get-childitem
Alias           man                       get-help
Alias           mount                     new-drive
Alias           mv                        move-item
Alias           popd                      pop-location
Alias           ps                        get-process
Alias           pushd                     push-location
Alias           pwd                       get-location
Alias           r                         invoke-history
Alias           rm                        remove-item
Alias           rmdir                     remove-item
Alias           echo                      write-object
Alias           cls                       clear-host
Alias           chdir                     set-location
Alias           copy                      copy-item
Alias           del                       remove-item
Alias           dir                       get-childitem
Alias           erase                     remove-item
Alias           move                      move-item
Alias           rd                        remove-item
Alias           ren                       rename-item
Alias           set                       set-variable
Alias           type                      get-content


MSH>

Nice, so Where-Object can be abbreviated to "where". Maybe you'd like to abbreviate it further down to just w:

MSH> new-alias

Cmdlet new-alias at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Name: w
Value: where-object
MSH>

So, now w stands for where-object.

What's coming next?

In the next episodes I'll show you how to use various "utility cmdlets", how to create scripts, how to access the registry and other "providers" and how to create your own cmdlets in .NET.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Interesting download on the Microsoft Download Center: http://www.microsoft.com/downloads/details.aspx?FamilyID=acdbbf66-9e20-415e-9bce-f5c91aba9567&DisplayLang=en. Funny to see the consistency of the "System Requirements" with every download; luckily this guy's music is compatible with Longhorn ;-). Enjoy it!Del.icio.us | Digg It | Technorati | Blinklist |