<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://testfirst.spaces.live.com/mmm2008-05-17_13.22/rsspretty.aspx?rssquery=en-US;http%3a%2f%2ftestfirst.spaces.live.com%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>PowerShell for Testers</title><description /><link>http://testfirst.spaces.live.com/</link><language>en-US</language><pubDate>Mon, 02 Jun 2008 21:40:10 GMT</pubDate><lastBuildDate>Mon, 02 Jun 2008 21:40:10 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><live:identity><live:id>9081042144815434356</live:id><live:alias>testfirst</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>Testing Applications with Powershell Download - PSExpect Edition</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!214.entry</link><description>&lt;p&gt;Like many of you, I noticed the download that was made available on the MSDN Tester Centre the other day - &lt;a href="http://msdn.microsoft.com/en-us/testing/bb980925.aspx" target="_blank"&gt;Testing Applications with Powershell - Sample Code&lt;/a&gt;.  This link, along with downloads and article such as the &lt;a href="http://msdn.microsoft.com/en-us/accessibility/bb892135.aspx" target="_blank"&gt;UI Automation Specification&lt;/a&gt; and associated &lt;a href="http://msdn.microsoft.com/en-us/accessibility/bb892136.aspx" target="_blank"&gt;Community Promise&lt;/a&gt; gives me some hope that it might be possible to run the same test script both with and without the UI. &lt;p&gt;That's my hope for testing tools.  Oh yeah, and that we can do that using business-oriented grammar in the scripts.  And that we can define, scope, and reuse elements of that grammar in exploratory testing, semi-automated style. &lt;p&gt;Anyway, baby steps ... baby steps. &lt;p&gt;The post was great in that it raised the awareness of how Powershell might be used for testing.  All of my examples in &lt;a href="http://www.codeplex.com/psexpect" target="_blank"&gt;PSExpect&lt;/a&gt; are against libraries or other scripts.  This example automates the UI.  And that's cool if not entirely necessary in all contexts. &lt;p&gt;I replaced the verdicts within the posted sample code with calls to PSExpect Assert* functions. There were two of them, depicted below with the original code hashed (commented) out: &lt;p&gt;$result = get-listBox $lb &amp;quot;222&amp;quot;&lt;br&gt;#    if ($result -ge 0) {&lt;br&gt;#      write-host &amp;quot;Found '222' in ListBox!&amp;quot;&lt;br&gt;#    }&lt;br&gt;#    else {&lt;br&gt;#      write-host &amp;quot;Did NOT find '222' in ListBox&amp;quot;&lt;br&gt;#      $pass = $false&lt;br&gt;#    }&lt;br&gt;AssertEqual -Expected 0 -Actual $result -Label &amp;quot;TC-1&amp;quot; -Intent $Intention.ShouldPass&lt;br&gt;... &lt;p&gt;$text = get-textBox $tb&lt;br&gt;#    if ($text -eq &amp;quot;ad&amp;quot;) {&lt;br&gt;#      write-host &amp;quot;Found 'ad' in TextBox!&amp;quot;&lt;br&gt;#    }&lt;br&gt;#    else {&lt;br&gt;#      write-host &amp;quot;Did NOT find 'ad' in TextBox&amp;quot;&lt;br&gt;#      $pass = $false&lt;br&gt;#    } &lt;br&gt;AssertEqual -Expected &amp;quot;ad&amp;quot; -Actual $text -Label &amp;quot;TC-2&amp;quot; -Intent $Intention.ShouldPass&lt;br&gt;... &lt;p&gt;and then there is the way that the test script reports back to the tester about the status of the test run: &lt;p&gt;#    if ($pass) {&lt;br&gt;#      write-host &amp;quot;`nTest scenario result = Pass&amp;quot; -foregroundcolor green&lt;br&gt;#    }&lt;br&gt;#    else {&lt;br&gt;#      write-host &amp;quot;`nTest scenario result = * FAIL *&amp;quot; -foregroundcolor red&lt;br&gt;#    }&lt;br&gt;RaiseAssertions &lt;p&gt;Running the revised test script and running it against the sample application to be tested generates the following two lines of output: &lt;p&gt;&lt;font color="#008000"&gt;02/06/2008 12:39:26 PM,SHOULDPASS,PASSED,TC-1&lt;br&gt;02/06/2008 12:39:28 PM,SHOULDPASS,PASSED,TC-2&lt;/font&gt; &lt;p&gt;Since the tests pass, they show up as green.  You can find the entire script at(&lt;a title="http://www3.telus.net/~amgeras/samples/Test-TheApp.ps1" href="http://www3.telus.net/~amgeras/samples/Test-TheApp.ps1"&gt;http://www3.telus.net/~amgeras/samples/Test-TheApp.ps1&lt;/a&gt;).  You will find that the script requires the PSExpect library in a specific location - just change that location to get the script to run (one line to edit). &lt;p&gt;We did drop a number of lines of script completing this refactoring. We also gained functionality since when you run the script, you are also generating a log file in behind the scenes that could be posted in the test results repository.  That's all good.  But there are other refactorings that we might consider that I will tackle when I get a moment. &lt;p&gt;First, from a testing perspective, the functions get-listBox is counter-intuitive since it returns an integer when given an item that it is supposed to contain.  I understand why, but the consequences to the test script are obvious when you compare the two AssertEqual statements above. &lt;p&gt;In the first AssertEqual, the expected result is '0' yet we are really looking for the value '222'.  In the second AssertEqual, we are looking for 'ad' and that is exactly what we truly are looking for.  That's more intuitive.  So in the next refactoring I would remove the comparator in the function and leave that comparison for the tester. &lt;p&gt;Second, and this only reflects my bias towards domain-driven design thinking, is that the sample application mimics some function that doesn't come through in the test script unless you look really close.   It gets the point across for people like me to talk around, so it was fit for purpose.  &lt;p&gt;But ... &lt;p&gt;If the screen functionality could be represented using a verb-noun naming convention, then that would provide the means for separating the test runner from the test actions from the set of verdicts and that would make it even more meaningful, and the test script more readable. &lt;p&gt;For example, &lt;p&gt;start-productSearch -Category $null -Item $null&lt;br&gt;test-productSearchResults -Expected 'Error' &lt;p&gt;start-productSearch -Category 'Product Name' -Item 'ad'&lt;br&gt;test-productSearchParam -Expected 'ad'&lt;br&gt;test-productSearchResults -Expected '222' &lt;p&gt;Now, the test runner is still the Powershell script (as it was before we did any refactoring).  The screen action is start-productSearch.  And the verdicts are test-productSearchParam and test-productSearchResults, both implemented in the two AssertEqual statements above but whose meanings were hidden in the interpretation of the script. &lt;p&gt;And this test script is now much more reflective of what the screen does and how we're testing it.  It communicates better to the testers, and we have this function start-productSearch that we could reuse in other , longer-running scenarios of the larger application. &lt;p&gt;Right now, these last two refactorings are musings, but I'll post them and my findings along the way as soon as I get a chance.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Testing+Applications+with+Powershell+Download+-+PSExpect+Edition&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><category>None</category><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!214.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!214.entry</guid><pubDate>Mon, 02 Jun 2008 21:40:10 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!214/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!214.entry#comment</wfw:comment><dcterms:modified>2008-06-02T21:40:10Z</dcterms:modified></item><item><title>Hyper-Testability with Powershell</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!210.entry</link><description>&lt;p&gt;Testability is a software quality attribute that is a measure of how easy (or difficult) it is to create test cases for a test target and, in combination, how easy (or difficult) it is to run those tests.  High testability is a good thing since it means that the total cost of making changes to the software is correspondingly lower.  It typically also means that you can have more than one individual contributing to the software since it is easy for them to determine whether or not their contribution has been a net positive or net negative contribution, simply by running the tests again.  Hence, we like test automation. &lt;p&gt;It turns out that when we value testability, we tend to write software that enables us to automate more types of tests, and we set up this fantastic feedback loop where defining a test becomes a means of production - the tests specify the desired behaviour, guide the development, and then verify the as-built software for as long as that behaviour remains desired.  Pretty nice, when we get to that level. &lt;p&gt;Tools like xUnit were revolutionary in the sense that they gave developers the means for valuing testability and a mechanism for expressing the low-level behaviour in the same language that our target software was (or would be) written in.  Developers liked it, and now teams in general are much more inclined to automate unit tests than ever before. &lt;p&gt;But is it enough?  That's a question that Brian Marick has been pondering publicly &lt;a href="http://www.exampler.com/blog/2008/03/23/an-alternative-to-business-facing-tdd" target="_blank"&gt;in his blog&lt;/a&gt; (it's one of those blogs that actually expands your mind when you read it) and in an on-line forum discussing automated functional testing.  I was struck by the phrase &amp;quot;&lt;i&gt;Perhaps it would be better to invest heavily in unprecedented amounts of built-in support for manual exploratory testing.&lt;/i&gt;&amp;quot; the most.  An alternative, he indicates, to automated functional testing with tools like FIT/FITNesse (read the blog entry to find out why this isn't agile heresy). &lt;p&gt;You can see where I'm going. If you have a set of Powershell cmdlets that exposes an application's functionality - and if the cmdlets expose &lt;em&gt;ALL&lt;/em&gt; of the functionality - then 'exploring' means working with those cmdlets (or an API) in a Powershell session and using whatever testing heuristics you might have in your tester's toolkit to test the application.  You may not be using the same UI as the end-users, however, there is great value to first confirming the functionality is good enough, and then second moving on to confirm that the UI is good enough. &lt;p&gt;The Powershell features that make exploratory testing an excellent experience are (but not limited to): &lt;ul&gt; &lt;li&gt;Objects on the pipeline, and in fact, having objects to work with at all.  &lt;li&gt;The get-help cmdlet that can access custom help files for custom cmdlets.  &lt;li&gt;The get-member (gm) cmdlet.  &lt;li&gt;The get-history (h) cmdlet.  &lt;li&gt;The naming convention for cmdlets.&lt;/ul&gt; &lt;p&gt;You don't even really have to know the cmdlets ahead of time because of those features since you can retrieve their calling syntax at run-time.  The get-history cmdlet can then be used to save useful cmdlets and sequences of calls, in order to support future semi-automated exploratory testing (where some scripts are run, but only for the sake of returning to a known state) or ultimately fully automated testing for something like detecting regression.  Seems that the ability of a script for passing on knowledge isn't limited to administrators ... &lt;p&gt;I can envision, however, a mismatch between the cmdlets that an application designer foresees might be a useful way of exposing the functionality and the cmdlets that a tester might find useful.  They will each bring, I believe, a different perspective. &lt;p&gt;So it might be wise to undertake this 'unprecedented support for exploratory testing' or &lt;em&gt;hyper-testability&lt;/em&gt; using a test-driven approach where the functionality of those cmdlets is influenced, or possibly specified, by the examples that a tester might deem appropriate.  Supporting manual exploratory testing by writing automated test scripts ahead of time ... seems contradictory. But there is a distinction between 'understanding-clarifying tests' (Brian Marick again) and 'verification and validation' tests.  So using a test-driven approach for understanding and clarifying requirements, and ultimately the design of the cmdlets, isn't the same as writing tests for verifying and validating the resulting application. &lt;p&gt;The bottom line?  Exposing application functionality in Powershell makes your application hyper-testable.  Use test scripts that you/your testers write ahead of time as a means of designing the cmdlets and separate the concern of testing the functionality of the application from the concern of testing the user interface.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Hyper-Testability+with+Powershell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!210.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!210.entry</guid><pubDate>Mon, 31 Mar 2008 02:04:50 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!210/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!210.entry#comment</wfw:comment><dcterms:modified>2008-03-31T02:04:50Z</dcterms:modified></item><item><title>Envisioning Next-Generation Functional Testing Tools (Continued)</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!203.entry</link><description>&lt;p&gt;I know we're not supposed to come up with solutions before fully understanding the problem, but I've got just enough experience and wide-eyed insensibility to believe that I've seen something that just might work: testing mashups. &lt;p&gt;&lt;a href="http://www.popfly.com/Overview/Default.aspx" target="_blank"&gt;Microsoft Popfly&lt;/a&gt; is a set of tools for creating web pages and the like from pre-defined blocks.  The one aspect that I am particularly intrigued by is called a mashup.  You use a tool called the Mashup Creator to build a web page comprised of blocks that come from disparate sources.  For example, build a page that lists your Facebook friends' statuses and your Twitter friends' most recent updates.  I'm assuming it's called a 'mashup' after the term that's been coined for mixing songs into single tracks (some of my favourites have sampled from 5 or more songs). &lt;p&gt;Now imagine if the &amp;quot;blocks&amp;quot; used to build a mashup were Powershell cmdlets instead of web applications and that those cmdlets were designed to expose the functionality of an application under test.  Each &amp;quot;mashup&amp;quot; you create is therefore another application scenario.  Imagine that some of the blocks you use on a mashup are data sources so that you could make the scenario data-driven. &lt;p&gt;So, why do I think this might be a good idea? &lt;p&gt;First, it may help non-programmers to develop automated test scenarios that are executable.  Second, the economics of building cmdlets for the application just changed: not only might the cmdlets be useful for system administration, but now they will also be useful in writing automated tests for the application. &lt;p&gt;Why cmdlets? Well they exhibit all the behaviour that I would want from blocks for building tests from - they have a naming convention, there are behavioural standards that they adhere to, and there is a mechanism already in place for stringing them together and running them as one scenario, so they're not just commands that can be invoked.  If the 'noun' part of the cmdlet always refers to something from the business domain, then we're working at the same level of abstraction as (hopefully) the requirements are written - so as testers we're grounded, too.  There is a tie-in to the whole world of domain-specific language and domain-driven development that just can't be ignored. &lt;p&gt;Now these aren't the only tests that would need to be considered for any system under development.  A test strategy for any software product is going to include extensive developer (unit and low-level integration) testing and manual functional and acceptance testing. I get that.   At the same time, automating more test scenarios means they are shareable and immediately executable by anyone on the team, enhancing communications and reducing communication overhead.  That's a good thing, and worth striving for.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Envisioning+Next-Generation+Functional+Testing+Tools+(Continued)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!203.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!203.entry</guid><pubDate>Tue, 19 Feb 2008 02:35:01 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!203/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!203.entry#comment</wfw:comment><dcterms:modified>2008-02-19T02:35:01Z</dcterms:modified></item><item><title>Behaviour Driven Development with Powershell</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!188.entry</link><description>&lt;p&gt;or, A Testament to the Flexibility of Powershell &lt;p&gt;The greatest impact that the Functional Testing Tools Workshop in Portland (October, 2007) had on me was to raise my awareness of behaviour-driven development, in particular, the 'given-when-then' pattern for structuring examples. &lt;p&gt;I will defer to other blogs on describing given-when-then in detail, you'll see what it means soon enough in the examples below.  For now, think of given-when-then as a means of translating the meaning of a user story into a related set of acceptance criteria using examples.  Something that has always been a bit awkward for business users and developers alike. &lt;p&gt;Given you adopt the story-telling convention popularized by Mike Cohn (I think), &lt;p&gt;As a &amp;lt;blank&amp;gt;&lt;br&gt;I want to &amp;lt;blank&amp;gt;&lt;br&gt;So that &amp;lt;blank&amp;gt; &lt;p&gt;when you want to translate the story into a set of related acceptance criteria using examples,&lt;br&gt;then use the following convention popularized by BDD proponents such as Dan North: &lt;p&gt;Given &amp;lt;a known set of conditions or state&amp;gt;&lt;br&gt;When &amp;lt;something happens&amp;gt;&lt;br&gt;Then &amp;lt;check for an expected set of conditions or state&amp;gt; &lt;p&gt;There are tools that help you do this and to make statements worded like this executable - in that case, they almost become executable requirements.  They are certainly executable examples.  The most-often-used example is for a simple account manager class (I've seen this example on a number of blogs but didn't pay attention to where it originated, but I think it was Dan North's again).  I'm not the only person looking at this - there is a NBehave project on CodePlex that provides a mechanism for writing tests in this manner.  And there are many ruby examples in both rspec and rbehave. &lt;p&gt;# Story: Transfer to cash account from savings account&lt;br&gt;# As a savings account holder&lt;br&gt;# I want to transfer money from my savings account&lt;br&gt;# So that I can get cash easily from an ATM  &lt;p&gt;# Scenario 1: Savings account is in credit&lt;br&gt;given &amp;quot;My savings account balance is 100 and my cash account balance is 10&amp;quot; &lt;br&gt;when &amp;quot;I transfer 20 to my cash account from savings&amp;quot; &lt;br&gt;then &amp;quot;my cash account balance should be 30 and my savings account balance should be 80&amp;quot;  &lt;p&gt;given &amp;quot;My savings account balance is 400 and my cash account balance is 100&amp;quot;&lt;br&gt;when &amp;quot;I transfer 100 to my cash account&amp;quot; &lt;br&gt;then &amp;quot;My cash account balance should be 200 and my savings account balance should be 300&amp;quot; &lt;p&gt;My opinion is that this is a clear way of expressing an example, albeit all that I have really seen are simplistic ones.  I'm going to enjoy working through more complex examples on an upcoming project. &lt;p&gt;Now on to Powershell.  It was always my intention to introduce some sort of behaviour-driven development helper functions in PSExpect, but I was never certain of what that could be.  Until I went to the Functional Testing Tools conference in Portland.  I love it when I can take some time off to think, and be inspired by a group of brilliant people. &lt;p&gt;Turns out we can make those examples above executable by writing a function and adding a set of aliases to our Powershell environment.  The function accepts a string parameter and a script block parameter.  All that it does is write out the string to a log file and then run the script block.  I've called it Invoke-Block for lack of imagination, and it uses the PSExpect logging mechanism so that the same log file shows the results of assertions. &lt;blockquote&gt; &lt;p&gt;function global:Invoke-Block([string]$Label, [ScriptBlock]$Script)&lt;br&gt;{&lt;br&gt;&lt;br&gt;    # build the log entry and write it out &lt;br&gt;    $entry = BuildLogEntry $Intention.ShouldPass $ResultPrefix.Passed &amp;quot;PSpec&amp;quot; $Label&lt;br&gt;    $added = $Assertions.Add($entry)&lt;br&gt;    if ($LogFileName -ne $null) {&lt;br&gt;        $logEntry = BuildMessage $entry&lt;br&gt;        $logEntry | out-file $LogFileName -append -width $LogFileLineLength&lt;br&gt;    }&lt;br&gt;    &lt;br&gt;    # now run the script block&lt;br&gt;    if ($Script)&lt;br&gt;    {&lt;br&gt;        &amp;amp;$Script&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;set-alias given invoke-block&lt;br&gt;set-alias when invoke-block&lt;br&gt;set-alias then invoke-block&lt;/blockquote&gt; &lt;p&gt;The aliases enable using the given-when-then triad in a Powershell script without generating any errors.  This means that the executable version of the example is the same as above, with the script blocks added in.  The example relies on a class library from the system under test (SUT) that the script loads using reflection (not shown) but the calling syntax to that library is hidden using a set of Powershell functions that utilize a verb-noun naming convention: create-account, transfer-money, set-accountbalance, and test-accountbalance (these are elements in the grammar of the domain-specific language, or ubiquitous language for this particular system under development). &lt;p&gt;# Story: Transfer to cash account from savings account&lt;br&gt;# As a savings account holder&lt;br&gt;# I want to transfer money from my savings account&lt;br&gt;# So that I can get cash easily from an ATM  &lt;p&gt;# Scenario 1: Savings account is in credit&lt;br&gt;given &amp;quot;My savings account balance is 100 and my cash account balance is 10&amp;quot; {&lt;br&gt;    set-variable -name SvAccount -value (create-account &amp;quot;Savings&amp;quot; 100) -scope script&lt;br&gt;    set-variable -name csAccount -value (create-account &amp;quot;Cash&amp;quot; 10) -scope script&lt;br&gt;}  &lt;p&gt;when &amp;quot;I transfer 20 to my cash account from savings&amp;quot; {&lt;br&gt;    transfer-money -From $SvAccount -To $CsAccount -Amount 20&lt;br&gt;}  &lt;p&gt;then &amp;quot;my cash account balance should be 30 and my savings account balance should be 80&amp;quot; {&lt;br&gt;    test-accountbalance -Account $SvAccount -Expected 80 -Label &amp;quot;Savings.Balance.After&amp;quot;&lt;br&gt;    test-accountbalance -Account $CsAccount -Expected 30 -Label &amp;quot;Cash.Balance.After&amp;quot;&lt;br&gt;}  &lt;p&gt;given &amp;quot;My savings account balance is 400 and my cash account balance is 100&amp;quot; {&lt;br&gt;    set-accountbalance -Account $SvAccount -Amount 400&lt;br&gt;    set-accountbalance -Account $CsAccount -Amount 100&lt;br&gt;}  &lt;p&gt;when &amp;quot;I transfer 100 to my cash account&amp;quot; {&lt;br&gt;    transfer-money -From $SvAccount -To $CsAccount -Amount 100&lt;br&gt;}  &lt;p&gt;then &amp;quot;My cash account balance should be 200 and my savings account balance should be 300&amp;quot; {&lt;br&gt;    test-accountbalance -Account $SvAccount -Expected 300 -Label &amp;quot;Savings.Balance.After&amp;quot;&lt;br&gt;    test-accountbalance -Account $CsAccount -Expected 200 -Label &amp;quot;Cash.Balance.After&amp;quot;&lt;br&gt;}  &lt;p&gt;RaiseAssertions&lt;br&gt; &lt;h5&gt;The Output&lt;/h5&gt; &lt;p&gt;29/11/2007 1:56:13 PM,SHOULDPASS,PASSED,PSpec,My savings account balance is 100 and my cash account balance is 10&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,PSpec,I transfer 20 to my cash account from savings&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,PSpec,my cash account balance should be 30 and my savings account balance should be 80&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,Savings.Balance.After&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,Cash.Balance.After&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,PSpec,My savings account balance is 400 and my cash account balance is 100&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,PSpec,I transfer 100 to my cash account&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,PSpec,My cash account balance should be 200 and my savings account balance should be 300&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,Savings.Balance.After&lt;br&gt;29/11/2007 1:56:14 PM,SHOULDPASS,PASSED,Cash.Balance.After  &lt;p&gt;The output above is from the log file that PSExpect generates on every run.  That whole SHOULDPASS concept is there to support a programming style where you first create some tests that you expect to fail - you mark them SHOULDFAIL and then PSExpect prints those assertion failures in YELLOW instead of RED like it would if an assertion labelled with SHOULDPASS fails.  I've come to rely on log files to use as evidence of passing tests, and to support debugging (since I tend to avoid using a step-through debugging tool on my own code; it's an anti-pattern for my personal coding style since using a tool like that means I'm confused and I don't have enough tests to show me the way).&lt;br&gt; &lt;h5&gt;A Way of Explanation&lt;/h5&gt; &lt;p&gt;Yes, this really executes and the output demonstrates that each of the checks pass - this example is available in the most recent upload of PSExpect on the CodePlex site in the 'samples' directory.  A couple of things worth pointing out ...  &lt;p&gt;First, the starting curly brace of the script block must be on the same line as the call to invoke-block, otherwise Powershell parses the function call without the script block and errors abound.  A minor inconvenience if that isn't already your scripting convention.  &lt;p&gt;Second, the unfortunate use of set-variable in the first 'given' script block.  That's really just in order to set the scope of variables (hence the use of the -scope parameter).  Alternatively, you could declare the variable and instantiate it before any of the 'given' clauses.  I don't think it matters, but this was the way that it was done in the NBehave example on the CodePlex site so I've copied that approach in my example. &lt;p&gt;Third, those wrapper functions.  I've mentioned in other blog entries that Powershell uses the verb-noun naming convention for all the built-in cmdlets and that you are forced into this same convention when writing your own custom cmdlets.  Well you should follow that form when writing Powershell functions too and write your functions like they are prototypes of cmdlets.  Much better all-around style, and you don't lose any ground making changes to scripts if you choose to promote a function to a cmdlet.  I prefer to use the wrapper functions in test scripts since they enhance the readability of the script for non-developers.  I've rarely specified the wrapper functions ahead of time.  Instead, I write the test scripts first and determine what wrapper functions I need based on the tests that I want to run.  Yup, test-driven test helper functions. &lt;p&gt;If you like behaviour-driven development, and you're working with a .NET class library, then using the aliases for given-when-then as specified above seems a lot easier than writing compiled code versions of the test scripts.  Further, and I shouldn't even say this, you don't even need PSExpect to do this - you can write you own version of invoke-block and set up your own aliases to match your own style.  Meta-programming is just one of the advantages of a dynamic language. &lt;h5&gt;Next Steps: Hyper-Testability&lt;/h5&gt; &lt;p&gt;But there's more that can be done if you are using Powershell.  &lt;p&gt;Visualize if the test authoring helper functions such as test-accountbalance, set-accountbalance, transfer-money, create-account were Powershell cmdlets instead of Powershell functions.  It's nice to have those tester helper functions initially in Powershell because they can be quickly modified to match the needs of the test authors, however, they will eventually stabilize.  That's when it's time to make them cmdlets and release them along with the rest of the code.  Release the testing support tools as part of the working software you're delivering (at least when you're releasing into a test environment).  &lt;p&gt;Having the cmdlets for supporting the automated testing (behaviour-driven or otherwise) makes any number of scenarios possible - and certainly enhances the testability of the system.  And I'm willing to bet that there is massive overlap between the cmdlets used for system administration and the cmdlets used for testing.  In other words, if you're planning to use cmdlets (and an MMC snap-in) to support the administration of your product, then taking it just-a-little further and creating cmdlets for testing purposes isn't all that much more work.  And the result is something that I'm starting to label &amp;quot;hyper-testability&amp;quot; - where an empowered, educated tester can write any number of scenarios using building blocks provided by the system under test.  &lt;p&gt;Three cheers for empowered testers, testable systems, and oh yes - three cheers for enlightened discourse among a group of really smart people that were kind enough to let me listen in.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Behaviour+Driven+Development+with+Powershell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!188.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!188.entry</guid><pubDate>Fri, 30 Nov 2007 04:21:04 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!188/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!188.entry#comment</wfw:comment><dcterms:modified>2007-11-30T04:21:04Z</dcterms:modified></item><item><title>Envisioning Next-Generation Functional Testing Tools</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!186.entry</link><description>&lt;p&gt;I'm at a workshop in Portland this week, participating in a workshop for envisioning the next-generation functional testing tools.  My interest is in how dynamic languages like Powershell fit with functional testing. &lt;p&gt;My experience on my last project gave me a tremendous amount of hope that Powershell is effective for executing tests and I can easily envision that a cmdlet-adorned application reduces the cost of testing, especially if _all_ the features of the application are exposed through cmdlets.  You just need the scripting skills and the domain knowledge to map the scripts to meaningful user scenarios. &lt;p&gt;The spreadsheet front-end no doubt that I slapped onto PSExpect helps the business users to get involved, but we need more than their involvement, we need them to be driving it.  We need to support the communication and the craft - two things that are hard to balance. &lt;p&gt;I'm hoping this week to see what other people are doing, what they are saying they need, and what they have done in their practice to make automated functional testing more mainstream and more accessible to the people with the domain knowledge ... &lt;p&gt;A.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Envisioning+Next-Generation+Functional+Testing+Tools&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!186.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!186.entry</guid><pubDate>Thu, 11 Oct 2007 15:47:36 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!186/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!186.entry#comment</wfw:comment><dcterms:modified>2007-10-11T15:47:36Z</dcterms:modified></item><item><title>The Developer-Tester Double-Triple</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!175.entry</link><description>&lt;p&gt;I've reached a milestone on my current project today – a Developer-Tester double-triple.  Triple-digit automated unit tests and triple-digit automated acceptance tests.  Unit tests are automated with NUnit and run interactively using &lt;a href="http://www.testdriven.net"&gt;TestDriven.net&lt;/a&gt; and NCover/NCoverExplorer that ships with TestDriven.net.  The automated acceptance tests are all written in PowerShell using &lt;a href="http://www.codeplex.com/psexpect"&gt;PSExpect&lt;/a&gt;.  The unit tests require about 5-7 seconds to run and the acceptance tests take about 1-2 minutes.
&lt;p&gt;This won't be all of the testing though, the automated unit tests and the automated acceptance tests are only part of the testing strategy on the project.  There are GUI tests to come, but we've not yet decided on a tool for automating them, if any.  Since we have a focus group of business testers, it might make sense for us to create test checklists for them to use and run those tests manually.  We'll see.  We can afford to be adaptable since we're adapting an existing site and the number of affected pages is less than 5.
&lt;p&gt;There are also additional unit tests to come as the final integration point gets wrapped in.  We've isolated that point for now with a mock provider but we'll have to swap out that mock and use the real thing soon –after it passes all its unit tests.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+The+Developer-Tester+Double-Triple&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!175.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!175.entry</guid><pubDate>Wed, 09 May 2007 15:00:33 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!175/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!175.entry#comment</wfw:comment><dcterms:modified>2007-05-09T15:00:33Z</dcterms:modified></item><item><title>PowerShell Script Logging and Tracing</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!170.entry</link><description>&lt;p&gt;&lt;em&gt;From Redmond, WA.  I'm at the Platform Adoption Center (PAC) (Building 20) for Apr 18-19 at the PowerShell &amp;amp; MMC ISV Workshop.&lt;/em&gt; 
&lt;p&gt;In some scripts, especially longer ones, you might find it handy to use logging and tracing that you can turn up or down, depending on the context and depending on yours needs at the time you are running the script. 
&lt;p&gt;Using a logging framework would let you replace your 'write-host' statements with logging statements that will have the following characteristics: 
&lt;ul&gt;
&lt;li&gt;You can turn them on or off with a single line edit (at the beginning of your script) 
&lt;li&gt;You can re-direct them to various destinations - console, file, event log - again with a single line edit 
&lt;li&gt;You can adjust the detail of the log entries - again with a single line edit&lt;/ul&gt;
&lt;p&gt;The need is so common in application development that there are multiple solutions.  The three that stand out the most (probably) are the PowerShell cmdlets write-* (including write-debug, write-warning, write-error, etc), &lt;a href="http://logging.apache.org/log4net/"&gt;log4net&lt;/a&gt;, an open source solution available from Apache, and the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=62ef5f79-daf2-43af-9897-d926f03b9e60&amp;amp;displaylang=en&amp;amp;tm"&gt;Enterprise Library&lt;/a&gt; logging application block from Microsoft's patterns and practices group. 
&lt;p&gt;During script development, it is going to be handy to have verbose output of these logging statements turned up so that you know what is going on in the code, not just by looking at the results but also by looking at a record of has been run.  During production script runs, you might need to have a log of everything your script does.  Then again in some situations, you only want to see the logging statements that are associated with errors or other exceptional conditions. 
&lt;p&gt;Adding logging might be overkill for exploratory scripting - a scripting technique that PowerShell supports so well with the 'get-member' and 'get-history' cmdlets.  But I can imagine that if you 'productionalize' those scripts developed in an exploratory scripting session, then replacing 'write-host' with a logging statement might be a valuable refactoring. 
&lt;p&gt;I'll let you choose which of the above options is best for you as an administrative scripter, but I'm inclined to think that you might go with the flow - whatever the application developers are using will probably already work for you.  If there are no application developers to follow (or lead), then the PowerShell write-* cmdlets might serve you well enough. 
&lt;h3&gt;Script Logging with Write-* Cmdlets&lt;/h3&gt;
&lt;p&gt;PowerShell has built-in cmdlets for logging that use the verb &amp;quot;write&amp;quot;.  Running the command &amp;quot;get-command write*&amp;quot; will list those commands for you (and a couple of other ones).  Each one is controlled by a shell variable that ends with &amp;quot;Preference&amp;quot;. For example, to turn the warning messages up, then set the variable $WarningPreference to &amp;quot;Continue&amp;quot;. Other options are Stop, Inquire, and SilentlyContinue. To turn down logging, set each of the $*Preference session variables to &amp;quot;SilentlyContinue&amp;quot;. To turn up logging, then set them all to &amp;quot;Continue&amp;quot;. 
&lt;p&gt;Note - if you're building cmdlets, then there are base class methods that work with the same $*Preference shell variables.  Your cmdlets will be better received if you use them. 
&lt;h3&gt;Script Logging with Log4net&lt;/h3&gt;
&lt;p&gt;Log4net has the advantage of having a very small footprint and, appropriate for scripters, it doesn't require a configuration file.  Once you downloaded and unzipped the log4net binaries in a known location (hereinafter referred to as $Log4NetHome) you can use it something like this: 
&lt;p&gt;  
&lt;div&gt;&lt;pre style="overflow:auto;background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;$logpattern &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; `    &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;%date [%thread] %-5level [%x] - %message%newline&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; load the log4net library&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;[&lt;/span&gt;&lt;span style="color:#0000ff"&gt;void&lt;/span&gt;&lt;span style="color:#000000"&gt;][Reflection.Assembly]::LoadFile($Log4NetHome &lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;\log4net.dll&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; configure logging&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;[log4net.LogManager]::ResetConfiguration()
$Appender &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#0000ff"&gt;new&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#0000ff"&gt;object&lt;/span&gt;&lt;span style="color:#000000"&gt; log4net.Appender.ConsoleAppender(`
    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;new&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#0000ff"&gt;object&lt;/span&gt;&lt;span style="color:#000000"&gt; log4net.Layout.PatternLayout($logpattern))[log4net.Config.BasicConfigurator]::Configure($Appender)

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; determines the log statements that show up&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;$Appender.Threshold &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; [log4net.Core.Level]::Info$Log &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; [log4net.LogManager]::GetLogger($Host.GetType())

$Log.Info(&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Started the main script...&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
trap
{

    $Log.Error(&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Failed...&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
   &lt;/span&gt;&lt;span style="color:#0000ff"&gt;return&lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#0000ff"&gt;continue&lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#0000ff"&gt;break&lt;/span&gt;&lt;span style="color:#000000"&gt;
}

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt;... 
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; run your script here, including other $Log.Info statements 
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt;...  &lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;$Log.Info(&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Finished the main script.&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example, the value of $logpattern is what determines the output of each log statement - the items preceded by the % character are log4net macros that correspond to attributes of the log statement, including what you have specified, %message.  The call to ResetConfiguration() is necessary if you tend to re-run the scripts in the same PowerShell session, otherwise you will have to take care to declare the logger variables as having script scope instead of the global scope (the default). 
&lt;p&gt;To configure the logging, you really only have to identify the layout of the log entries and an appender to use.  As presented above, the ConsoleAppender is used so that the log entries appear in the console.  There are also FileAppenders available as part of the framework.  I've used the PatternLayout here so that the pattern string $logpattern can dictate what shows up for each log entry.  There are other Layouts available, including a SimpleLayout that just lists the category and message for each log entry. 
&lt;p&gt;The output of the log entry in this case is something like the following: 
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:rgb(0,0,0)"&gt;2007&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;04&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;18&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;08&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;30&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;49&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;,&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;650&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; [Pipeline Execution Thread] INFO &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color:rgb(0,0,0)"&gt;  [null] - Started testing parsing&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color:rgb(0,0,0)"&gt;&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;2007&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;04&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;18&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;08&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;30&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;49&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;,&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;400&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; [Pipeline Execution Thread] ERROR &lt;br&gt;  RfcParseExceptionHandler [RFCWorker] - PRS-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;012&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;:Unrecognized&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; dish: Irregular&lt;br&gt;&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color:rgb(0,0,0)"&gt;2007&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;04&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;-&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;18&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;08&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;30&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;:&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;49&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;,&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;650&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; [Pipeline Execution Thread] INFO&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color:rgb(0,0,0)"&gt;  [null] - Finished testing parsing&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Changing the log level from &amp;quot;Info&amp;quot; to &amp;quot;Error&amp;quot; would result in only that second log entry being logged - the other ones would be ignored and not show up in the output. 
&lt;p&gt;You can match the pattern layout string above to see what each macro generates in the log file.  What I have also found handy was using the NDC stack in log4net to identify where the script was running at the time of the log entry.  The contents of the NDC stack is presented in the pattern by %x, so you can see that in the three log entries that are in the sample output, the value is only expressed in the second one.  Just so happens that's the one that was generated by the C# class library that the PowerShell script was testing.  To use the NDC stack in your script, just push a string onto it in an appropriate line preceding what you want to log, and then pop it off the stack afterwards: 
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;pre style="overflow:auto;background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;[log4net.NDC]::Push(&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;test-getrfcaction-account&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
&lt;/span&gt;&lt;span style="color:#008000"&gt;//&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#008000"&gt;//&lt;/span&gt;&lt;span style="color:#008000"&gt;... do your thing, including log statements
&lt;/span&gt;&lt;span style="color:#008000"&gt;//
&lt;/span&gt;&lt;span style="color:#000000"&gt;[log4net.NDC]::Pop()&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this sample, that would put the phrase 'test-getrfcaction-account' will appear instead of the 'null' text that appears there now.  If you push multiple values onto the stack, then as you might expect, the appended stack message will appear in those log statements, consisting of all values that have been pushed but not yet popped.  Hey, it's a stack.  You can appreciate that if you have several script file or several functions running, you might want to identify where the log entry is sourced from. 
&lt;p&gt;For my purposes, the developers were already using log4net in their application so using log4net in my test scripts seemed like a reasonable decision.  I do find the single edits handy - I can exclude the informational log entries by changing the Appender.Threshold property to &amp;quot;Error&amp;quot;.  I change the log level alot because I'm exploring a bit with the PowerShell test scripts, so until I know for certain how the code I'm testing behaves, I keep it verbose. Last thing I do before adding the test scripts to the regression suite is change the log level to &amp;quot;Error&amp;quot;. 
&lt;p&gt;So the happy conclusion is - 
&lt;ul&gt;
&lt;li&gt;add log statements throughout your script 
&lt;li&gt;show your work by changing the log level threshold to &amp;quot;Info&amp;quot; 
&lt;li&gt;hide your work by changing the log level threshold to &amp;quot;Error&amp;quot; 
&lt;li&gt;change what shows up in each log entry by editing a pattern string 
&lt;li&gt;provide a basic version of your custom script call stack using the built-in logging stack (called the NDC)&lt;/ul&gt;
&lt;p&gt;Hope this helps!&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+PowerShell+Script+Logging+and+Tracing&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!170.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!170.entry</guid><pubDate>Wed, 18 Apr 2007 15:01:07 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!170/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!170.entry#comment</wfw:comment><dcterms:modified>2007-04-26T01:02:31Z</dcterms:modified></item><item><title>Mission-Targets-Tests</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!162.entry</link><description>&lt;p&gt;Lately testing people have been talking about testing heuristics - tips, techniques, tactics, strategies for testing something.  I have one that I call MTT. 
&lt;p&gt;M - Mission&lt;br&gt;T - Targets&lt;br&gt;T - Tests 
&lt;p&gt;&lt;em&gt;But I remember it as &amp;quot;mean time to testing&amp;quot;&lt;/em&gt;.  Exploratory testing excels in part because the mean time to testing is small compared to (caution: wiki-speak ahead), say, BigUpFrontTestManagement.  As an example of minimizing the mean time to testing, the example below uses PowerShell to explore the configuration and functionality of SQL Server Reporting Services 2005. 
&lt;p&gt;&lt;strong&gt;Mission&lt;/strong&gt; 
&lt;p&gt;Encourage the team to build consensus on why testing will be conducted by paying attention to the project context - who tests and what their background is, what is the system under test, who supports the test environment, what are the communication patterns between testers and developers, ... post the essence of this as a 'test mission' in the team's work area and let them mark it up as the project evolves.  The more people that are involved in the test effort, the more useful a 'testing working agreement' becomes.  Testing faster requires that all the testers understand why they are testing so that they get to the point. 
&lt;p&gt;&lt;strong&gt;Targets&lt;/strong&gt; 
&lt;p&gt;If the mission indicates &lt;em&gt;why&lt;/em&gt; we are testing, then the targets drill deeper and identify &lt;em&gt;what&lt;/em&gt; will be tested. I see a lot of testing without clearly-defined test targets.  Some heuristics are test targets, and that helps a lot.  Exploratory testing, even when automated, fits really well with test targets because listing them gives you a testing backlog, making citing progress and indicating expected completion dates simpler using something like testing burndown charts. 
&lt;p&gt;Consider automated exploratory testing with PowerShell - let's use the Microsoft Reporting Services installation test as an example.  To use MTT heuristic and the mission stated above, the second step would be to create a testing backlog of the targets of the tests - in other words, what exactly would you want to test?  As with all things agile, this list doesn't have to be complete because you have every right to revise this backlog and prioritize it as necessary, within the context of the test mission.  It is important to avoid listing &lt;em&gt;how&lt;/em&gt; these targets might be tested - that's left to exploration. 
&lt;p&gt;&lt;em&gt;Microsoft Reporting Services Installation Test - Targets (Testing Backlog)&lt;/em&gt; 
&lt;p&gt;ReportServer - Service Control&lt;br&gt;ReportServer - Service Properties&lt;br&gt;Database - Reporting Services Db - Topology&lt;br&gt;Database - Reporting Services Db - Physical Configuration&lt;br&gt;Database - Reporting Services Db - Authentication&lt;br&gt;Database - Reporting Services Db - Authorization&lt;br&gt;Operations - Performance Monitors - Availability&lt;br&gt;Operations - Microsoft Operations Manager - Access&lt;br&gt;Operations - Microsoft Operations Manager - Alerts&lt;br&gt;Web Service - Availability&lt;br&gt;Web Service - Authentication&lt;br&gt;Web Service - Authorization&lt;br&gt;Web Service - Functional - Run Report&lt;br&gt;Report Manager - Availability&lt;br&gt;Report Manager - Authentication&lt;br&gt;Report Manager - Authorization&lt;br&gt;Report Manager - Functional - Reports&lt;br&gt;Report Manager - Functional - Data Sources&lt;br&gt;Report Manager - Capacity - Concurrency&lt;br&gt;Report Manager - Capacity - Reponse Time 
&lt;p&gt;Given this list of test targets, an exploratory test effort would start by estimating each one of the targets to create a testing burndown chart, and then diving in according to the priorities assigned in the backlog.  PowerShell is incredibly useful for this given the 'get-member' cmdlet. 
&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt; 
&lt;p&gt;Continuing the Reporting Services example, the first thing that a tiny bit of investigating reveals is that SQL Server Reporting Services has a WMI class that exposes the configuration.  Let's get that class and see what we can do with it. 
&lt;p&gt;&lt;font color="#ff00ff"&gt;$targetcomputer&lt;/font&gt; = &lt;font color="#0000ff"&gt;&amp;quot;localhost&amp;quot;&lt;br&gt;&lt;/font&gt;&lt;font color="#ff00ff"&gt;$rs&lt;/font&gt; = &lt;font color="#ff0080"&gt;get-wmiobject&lt;/font&gt; -computer &lt;font color="#ff00ff"&gt;$targetcomputer&lt;/font&gt; -namespace `&lt;br&gt;    &lt;font color="#0000ff"&gt;&amp;quot;root\Microsoft\SqlServer\ReportServer\v9\Admin&amp;quot;&lt;/font&gt; MSReportServer_ConfigurationSetting&lt;br&gt;&lt;font color="#ff00ff"&gt;$rs&lt;/font&gt; | &lt;font color="#ff0080"&gt;get-member&lt;/font&gt; 
&lt;table style="table-layout:fixed;width:718pt;border-collapse:collapse" cellspacing=0 cellpadding=0 width=956 border=0&gt;
&lt;colgroup&gt;
&lt;col style="width:188pt" width=250&gt;
&lt;col style="width:69pt" width=92&gt;
&lt;col style="width:227pt" width=302&gt;
&lt;col style="width:186pt" width=248&gt;
&lt;col style="width:48pt" width=64&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="height:15pt" colspan=5 height=20&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;Name 
&lt;td&gt;MemberType 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;---- 
&lt;td&gt;---------- 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;BackupEncryptionKey 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ConfigureSharePointExclusion 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;CreateApplicationPool 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;CreateVirtualDirectory 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DeleteEncryptedInformation 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DeleteEncryptionKey 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;GenerateDatabaseCreationScript 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;GenerateDatabaseRightsScript 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;GenerateDatabaseUpgradeScript 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;InitializeReportServer 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ListReportServersInDatabase 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ReencryptSecureInformation 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;RemoveUnattendedExecutionAccount 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ResetVirtualDirectoryMappings 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;RestoreEncryptionKey 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetDatabaseConnection 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetDatabaseLogonTimeout 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetDatabaseQueryTimeout 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetEmailConfiguration 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetPortNumber 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetSecureConnectionLevel 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetServiceState 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetUnattendedExecutionAccount 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetWebServiceIdentity 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SetWindowsServiceIdentity 
&lt;td&gt;Method 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ApplicationPoolActual 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ApplicationPoolConfigured 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ConnectionPoolSize 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseLogonAccount 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseLogonTimeout 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseLogonType 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseName 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseQueryTimeout 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;DatabaseServerName 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;InstallationID 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;InstanceName 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;IsInitialized 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;IsSharePointExclusionConfigured 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;IsSharePointInstalled 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;IsWebServiceEnabled 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;IsWindowsServiceEnabled 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;PathName 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SecureConnectionLevel 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SenderEmailAddress 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SendUsingSMTPServer 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ServerPort 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ServiceName 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;SMTPServer 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;UnattendedExecutionAccount 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;VirtualDirectory 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;VirtualDirectoryHasSSLCertificate 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;WebServiceIdentityActual 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;WebServiceIdentityConfigured 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;WebSite 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;WindowsServiceIdentityActual 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;WindowsServiceIdentityConfigured 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__CLASS 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__DERIVATION 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__DYNASTY 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__GENUS 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__NAMESPACE 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__PATH 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__PROPERTY_COUNT 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__RELPATH 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__SERVER 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;__SUPERCLASS 
&lt;td&gt;Property 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ConvertFromDateTime 
&lt;td&gt;ScriptMethod 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;ConvertToDateTime 
&lt;td&gt;ScriptMethod 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;Delete 
&lt;td&gt;ScriptMethod 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;GetType 
&lt;td&gt;ScriptMethod 
&lt;td colspan=3&gt;
&lt;tr style="height:15pt" height=20&gt;
&lt;td style="height:15pt" height=20&gt;Put 
&lt;td&gt;ScriptMethod 
&lt;td colspan=3&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;From an exploratory tester's perspective, this list is super useful.  Now you can explore the configuration settings interactively using the $rs variable (they are all listed as Property in the above listing), or create a test script and use data-driven testing to check all the Reporting Services configuration parameters against expected values.  The 'get-history' cmdlet is also useful to retrieve and save the commands that you have experimented with in a format that you can use later for building a script. 
&lt;p&gt;To do the data-driven testing in Excel, create a table with three columns and all the properties that you want to test for.  Name the range TestRsConfig and save the worksheet. 
&lt;p&gt;
&lt;table border=1&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TestCase 
&lt;td&gt;Property 
&lt;td&gt;Value 
&lt;tr&gt;
&lt;td&gt;Security - Service Identity - As Configured 
&lt;td&gt;WindowsServiceIdentityConfigured 
&lt;td&gt;NT Authority\NetworkService 
&lt;tr&gt;
&lt;td&gt;Security - Service Identity - Actual 
&lt;td&gt;WindowsServiceIdentityActual 
&lt;td&gt;NT Authority\NetworkService 
&lt;tr&gt;
&lt;td&gt;Service - Instance 
&lt;td&gt;InstanceName 
&lt;td&gt;SQLEXPRESS 
&lt;tr&gt;
&lt;td&gt;Service - ServiceName 
&lt;td&gt;ServiceName 
&lt;td&gt;ReportServer$SQLEXPRESS 
&lt;tr&gt;
&lt;td&gt;ServicesDependedOn - Database - Server 
&lt;td&gt;DatabaseServerName 
&lt;td&gt;(LOCAL)\SQLEXPRESS 
&lt;tr&gt;
&lt;td&gt;IIS - WebSite 
&lt;td&gt;WebSite 
&lt;td&gt;1 
&lt;tr&gt;
&lt;td&gt;Security - IIS - WebServiceIdentity - Configured 
&lt;td&gt;WebServiceIdentityConfigured 
&lt;td&gt;ALAPTOP\ASPNET&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Next create a script that includes a function called TestRsConfig (the same name as the named range above) as follows (this script uses the &lt;a href="http://www.codeplex.com/psexpect"&gt;PSExpect&lt;/a&gt; testing library for PowerShell): 
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;font style="background-color:#ffffff"&gt;&lt;font color="#000000"&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;set&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;psdebug &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;strict &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;trace &lt;/span&gt;&lt;span style="color:#000000"&gt;0&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;span style="color:#000000"&gt;
&lt;font style="background-color:#ffffff" color="#000000"&gt;$targetcomputer &lt;/font&gt;&lt;/span&gt;&lt;font style="background-color:#ffffff"&gt;&lt;font color="#000000"&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;localhost&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;span style="color:#000000"&gt;
&lt;font style="background-color:#ffffff" color="#000000"&gt;$rs &lt;/font&gt;&lt;/span&gt;&lt;font style="background-color:#ffffff"&gt;&lt;font color="#000000"&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;wmiobject &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;font style="background-color:#ffffff"&gt;&lt;font color="#000000"&gt;&lt;span style="color:#000000"&gt;computer $targetcomputer `
    &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;namespace&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;root\Microsoft\SqlServer\ReportServer\v9\Admin&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;span style="color:#000000"&gt;&lt;font style="background-color:#ffffff"&gt;&lt;font color="#ffffff"&gt;&lt;font color="#000000"&gt; &lt;/font&gt;`
    MSReportServer_ConfigurationSetting&lt;/font&gt;

&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; Exercises the target of the test - the 
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; and responds with a &lt;font color="#ffffff"&gt;pre&lt;/font&gt;-defined set of responses that were
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; on the worksheet as the expected results&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;function TestRsConfig()
{
    param([&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$TestCase, [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$RsConfigProperty, [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$ExpectedValue)

    $ActualValue &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; $rs.PSBase.GetPropertyValue($RsConfigProperty).ToString()
    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;if&lt;/span&gt;&lt;span style="color:#000000"&gt; ([&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]::IsNullOrEmpty($ActualValue)) {$ActualValue &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; $&lt;/span&gt;&lt;span style="color:#0000ff"&gt;null&lt;/span&gt;&lt;span style="color:#000000"&gt;}

    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;if&lt;/span&gt;&lt;span style="color:#000000"&gt; ($ExpectedValue.Trim() &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;eq &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;N/C&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
    {
        AssertNull $ActualValue &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label $TestCase &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Intention $Intention.ShouldPass    
    }
    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;else&lt;/span&gt;&lt;span style="color:#000000"&gt; 
    {
        AssertEqual $ExpectedValue $ActualValue &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label $TestCase &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Intention $Intention.ShouldPass
    }

    RaiseAssertions
}

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; run the function library that contains the PowerShell Testing Functions
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; the functions are defined as global so you don't need to use dot sourcing&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;if&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt; (&lt;/span&gt;&lt;span style="color:#000000"&gt;!&lt;/span&gt;&lt;span style="color:#000000"&gt;(Test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Path variable:_XLLIB)) { ..\src\DataLib.ps1 }
&lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;if&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt; (&lt;/span&gt;&lt;span style="color:#000000"&gt;!&lt;/span&gt;&lt;span style="color:#000000"&gt;(Test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Path variable:_TESTLIB)) { ..\src\TestLib.ps1 }

&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; Configuration and installation testing ...
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; Confirm the Reporting Services configuration matches expectations documented in 
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; the Excel workbook 'TestRsConfig.xslx'&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;write&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;host &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Configuration testing ...&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
$FieldNames &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; (&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;TestCase&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;, &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;RsConfigProperty&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;, &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;ExpectedValue&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;)
start&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;test ((&lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;location).ToString() &lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;\TestRsConfig.xlsx&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;) &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Sheet1&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt; `
    &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;TestRsConfig&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt; $FieldNames
&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The line of note contains '$rs.PSBase.GetPropertyValue' - a PowerShell base method that is proving to be really useful in writing test scripts without hard-coding the property names. In my script, I've used 'N/C' to identify Reporting Services properties that are not configured at all on my laptop.  If I had left them out and therefore avoided the if-then-else code section, the script would only have been two lines.  (The start-test function from PSExpect runs the test and matches up the named range with the test function). Not bad! 
&lt;p&gt;But that's only part of the picture - the configuration of Reporting Services.  The other part of the picture is basic functional testing.  Reporting Services exposes its functionality as the Report Manager, a web application but also as Report Server, a web service.  So - what if we used PowerShell to explore and test the Reporting Services web service?  Using the same technique as was used with the Reporting Services WMI class, we can use get-member to help with the exploration.  This doesn't mean that we don't have to test the Report Manager, but it does mean that we can get a quick check of the functionality without a manual test. 
&lt;p&gt;This requires a small bit of .NET working knowledge regarding web services.  The trick is to use the .NET SDK 'wsdl.exe' utility to generate a proxy class for the web service, and then wrap that proxy class into an assembly that PowerShell can access: 
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;wsdl http:&lt;/span&gt;&lt;span style="color:#000000"&gt;//&lt;/span&gt;&lt;span style="color:#000000"&gt;localhost&lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#000000"&gt;ReportServer&lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#000000"&gt;ReportService2005&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#000000"&gt;asmx?wsdl 
csc &lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#000000"&gt;target&lt;/span&gt;&lt;span style="color:#800000"&gt;&lt;font color="#000000"&gt;:library&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;&lt;font color="#000000"&gt; &lt;/font&gt;ReportService2005&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#000000"&gt;cs&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now load this library into PowerShell and use get-member again to investigate the methods that are available: 
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;[void][Reflection&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#000000"&gt;Assembly&lt;font color="#000000"&gt;]&lt;/font&gt;&lt;/span&gt;&lt;font color="#000000"&gt;&lt;span style="color:#008000"&gt;::&lt;/span&gt;&lt;span style="color:#008000"&gt;LoadFile(&amp;quot;C:\...\ReportingService2005.dll&amp;quot;)&lt;/span&gt;&lt;/font&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;#&lt;/span&gt;&lt;span style="color:#000000"&gt; Instantiate the proxy object &lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;for&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;&lt;font color="#000000"&gt; &lt;/font&gt;the web service
&lt;/span&gt;&lt;span style="color:#000000"&gt;$&lt;/span&gt;&lt;span style="color:#000000"&gt;repsvc &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; new-object ReportingService2005
&lt;/span&gt;&lt;span style="color:#000000"&gt;$&lt;/span&gt;&lt;span style="color:#000000"&gt;repsvc&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#000000"&gt;Credentials &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; [System&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#0000ff"&gt;&lt;font color="#000000"&gt;Net&lt;/font&gt;&lt;/span&gt;&lt;span style="color:#000000"&gt;.&lt;/span&gt;&lt;span style="color:#000000"&gt;CredentialCache]&lt;/span&gt;&lt;span style="color:#008000"&gt;::&lt;/span&gt;&lt;span style="color:#008000"&gt;DefaultCredentials&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;$&lt;/span&gt;&lt;span style="color:#000000"&gt;rs | gm&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(I won't list all the methods here because there are many).  
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;...&lt;/span&gt;&lt;span style="color:#000000"&gt;
CancelAsync
CancelBatch
CancelBatchAsync
CancelJob
CancelJobAsync
CreateBatch
CreateBatchAsync
CreateDataDrivenSubscription
CreateDataDrivenSubscriptionAsync
CreateDataSource
CreateDataSourceAsync
CreateFolder
CreateFolderAsync
CreateLinkedReport
CreateLinkedReportAsync
CreateModel
CreateModelAsync
CreateObjRef
CreateReport
CreateReportAsync
CreateReportHistorySnapshot
CreateReportHistorySnapshotAsync
CreateResource
CreateResourceAsync
CreateRole
CreateRoleAsync
CreateSchedule
&lt;/span&gt;&lt;span style="color:#000000"&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The (almost complete) example included in the PSExpect download uses the ListChildren, CreateDataSource, and CreateReport methods of the web service to check the functionality of Reporting Services.  The test script uses functions that wrap the calls to the web service in the name of making the test easier to read for testers not familiar with the Reporting Services web service interface.  This is not the complete test - ideally there would also be a 'render-report' and 'test-report' set of functions provided for the testers so that actually generating a report is also part of the test (work in progress). 
&lt;p&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:#000000"&gt;write&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;host &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Functional testing ...&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
$DsBefore &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#0000ff"&gt;get&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;datasourcecount
&lt;/span&gt;&lt;span style="color:#0000ff"&gt;new&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;datasource &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Name &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;FromPsScript&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;datasourcecount &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Expected ($DsBefore &lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;1&lt;/span&gt;&lt;span style="color:#000000"&gt;) &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Datasources.Count.AfterNew&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
remove&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;datasource &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Name &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;FromPsScript&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;datasourcecount &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Expected ($DsBefore) &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Datasources.Count.AfterRemove&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;

# Verify the report create&lt;/span&gt;&lt;span style="color:#000000"&gt;/&lt;/span&gt;&lt;span style="color:#000000"&gt;delete functionality
$RsBefore &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#0000ff"&gt;get&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;reportcount
&lt;/span&gt;&lt;span style="color:#0000ff"&gt;new&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;report &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Name &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;ReportFromPsScript&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;reportcount &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Expected ($RsBefore &lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;1&lt;/span&gt;&lt;span style="color:#000000"&gt;) &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Reports.Count.AfterNew&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
remove&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;report &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Name &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;ReportFromPsScript&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
test&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;reportcount &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Expected $RsBefore &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;Label &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;Reports.Count.AfterRemove&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The example is available for download in the latest source code version of &lt;a href="http://www.codeplex.com/psexpect"&gt;PSExpect&lt;/a&gt;.  All together, this wasn't very much code.  The 'mean-time-to-testing' is low considering the automation - and I have an artifact that other people can use for running the tests at any time. 
&lt;p&gt;RsLib.ps1 - Contains the wrapper functions new-datasource, test-datasourcecount, remove-datasource, etc.&lt;br&gt;Test-RsConfig.ps1 - the test script for both configuration and functional tests described above&lt;br&gt;Test-RsConfig.xslx - Excel spreadsheet containing the named range for properties and expected values used in configuration testing. 
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt; 
&lt;p&gt;The 'get-member' cmdlet is extremely useful for exploratory testing, especially when combined with the easy access to WMI classes and to web services in PowewrShell.  In the example, I've used the SQL Server Reporting Services WMI class to check the configuration and installation against expected values, and then used a proxy class around the Reporting Services web service to check basic functionality.  What 'get-member' and PowerShell do for us in these cases is give us the tools and the means for exploring the targets of our tests.  Oh yeah - everything is in a script that we can share and evolve as our understanding of the test target increases.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Mission-Targets-Tests&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!162.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!162.entry</guid><pubDate>Sun, 04 Mar 2007 21:05:22 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!162/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!162.entry#comment</wfw:comment><dcterms:modified>2007-03-04T21:09:50Z</dcterms:modified></item><item><title>Lowering the Cost of Test Automation</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!158.entry</link><description>&lt;p&gt;It's been pretty well-documented that test automation, especially at the higher test levels such as system or acceptance testing, is something you should undertake carefully.  Like any other development project, the economic argument has to be there to support the effort - and that economic model can be screwed up pretty easily by analysis-paralysis (planning tests without ever writing or running one) or by creating unmaintainable, brittle test scripts. &lt;p&gt;There are ways of lowering the cost of automating tests.  There is a PowerShell hook, honest. &lt;h4&gt;Increase the 'Test Cases to Test Script' Ratio&lt;/h4&gt; &lt;p&gt;One of the reasons that &lt;a href="http://fit.c2.com" target="_blank"&gt;FIT&lt;/a&gt; is spectacular is that it standardizes the test script and permits the tester to focus on providing examples in the form of combinations of test input and expected output.  It does this through the use of test fixtures like the ColumnFixture.  To use ColumnFixture, you design your test by creating a table containing all the test data (inputs and expected outputs) and then write a test fixture that translates a row in the table into a call to the system under test (SUT).  Each row in the table represents a test case - and the running of each test case is all done implicitly by FIT and your test fixture. &lt;p&gt;It's pure-and-simple data-driven testing.  You achieve a high 'test case to test script' ratio by virtue of never having to write the script beyond writing the test fixture.  The framework implicitly provides the script - and runs it. &lt;p&gt;You can replicate the use of ColumnFixture in &lt;a href="http://www.codeplex.com/psexpect"&gt;PowerShell/PSExpect&lt;/a&gt; by storing the data in Excel (and learning what a named range in Excel is).  See \samples\test-getweatherperf.ps1 for an example.  There are several advantages of using Excel for the test data: &lt;ol&gt; &lt;li&gt;You can change the scope of a test run by changing the definition of the named range on the worksheet - eliminating the need to comment out parts of an input file or worse yet, storing multiple versions of it.  &lt;li&gt;You can use formulas to help specify the test data - so some of the test cases can use randomly-generated data instead of the same data every time.  &lt;li&gt;You can ask business users or other domain experts to create or revise the worksheet - Excel is ubiquitous in corporations.  Little or no training required.&lt;/ol&gt; &lt;p&gt;But &lt;a href="http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!148.entry"&gt;I've written about PowerShell/PSExpect and Excel before&lt;/a&gt;.  On to other interesting methods of minimizing test automation costs. &lt;h4&gt;Eliminate Waste - Part 1 - Use Test Targets Wisely (Lean Test Management)&lt;/h4&gt; &lt;p&gt;'Waste' in testing comes in two forms: writing test scripts that target the wrong thing, and writing scripts in a form that makes them difficult to evolve as the system under test evolves, or as your understanding of the system under test evolves. &lt;p&gt;You can avoid testing the wrong thing by first building a list of 'test targets'.  A test target is basically anything that needs testing.  Application functionality, security, performance, etc. might be types of tests but they are not test targets.  Well at least they aren't specific enough to be used wisely. &lt;p&gt;Break out the types of tests to get specific test targets.  List the application functions (use cases, user stories, whatever) - those are functional test targets.  List the application interfaces - those are integration test targets.  Security test targets include authentication, authorization, and then any specific vulnerability you want to test for (sql command injection, os command injection, etc.).  Performance test targets will be objectives-based like throughput, resource consumption limits, or user concurrency. &lt;p&gt;You need this list so that you can be wise about setting priorities and so that you can plan to write scripts for only those test targets that really matter.  Host a workshop to decide these priorities so that the whole team is on the same page. &lt;p&gt;The list of test targets is - dare I say it - a testing backlog.  If you're familiar with Scrum and the use of a product backlog, then take those same concepts and apply them to testing and the testing backlog.  This process works well - I've used testing backlogs and Scrum concepts now on a large enterprise project (an SAP upgrade), an infrastructure project (computing infrastructure migration to Windows Server 2003), and a business intelligence project.  All with favourable results. &lt;p&gt;Using a testing backlog is only part of the picture though - the scripts themselves can become waste if they are not written wisely. &lt;h4&gt;Eliminate Waste - Part 2 - Write Lean Scripts (Or None At All)&lt;/h4&gt; &lt;p&gt;Test scripts are unmaintainable when they hard-wire the test logic, the test data, and the calls to the system under test.  Basically, if any of those three factors changes, then you have to revise the script.  As a test author, you want a test automation strategy that enables you to avoid the hard-wiring trifecta. &lt;p&gt;For manual tests, avoid writing scripts if you can - instead, rely on your testers to make the leap from the testing backlog to the test results.  they can journal their way through the test targets and still provide excellent test results documentation.  If you can't avoid writing manual test scripts, then choose to write them using only language from the domain - avoid referring to specific user interface elements, avoid binding the script to a particular processing style, etc.  For example, say 'approve invoice' not 'click the Approve button'.  Then if that handy little 'Approve' button disappears in a later revision of the system, the test script survives without changes. &lt;h4&gt;Eliminate Waste - Part 3 - Dependency Injection for Testers (Keyword-Driven Testing)&lt;/h4&gt; &lt;p&gt;Automate tests but minimize the test script's dependency on the automation API of the system under test.  This is analogous to writing manual test scripts that minimize the script's dependency on the user interface elements such as buttons or menus. &lt;p&gt;Consider the test script whose automation depends directly on the system under test.  Any changes whatsoever, and the test script may have to be revised.  To do this in PowerShell, for example, your PowerShell test script would make calls directly against the assemblies that make up the system under test. &lt;p&gt;&lt;a href="http://tk2.storage.msn.com/x1pmvPPWtnrbEViP7lO369MCUrgcgvSW9Zd-yrb2kVraZrJa1eoFPJZOOkglQXF0NFshPwNnOI6quo6AnKCCtNHDk897qIDh-DfuMmXdLpgTGlx6XPTrxQJpnG9qum7L0HKvXs1ayDTWVd6ucEWbuP1YA"&gt;&lt;img src="http://tk2.storage.msn.com/x1pmvPPWtnrbEViP7lO369MCUrgcgvSW9Zd-yrb2kVraZoeIYuU5p0fsXDrIKLNjQ-qfilUa4wlQR4Mq5AOOOY4_fDvr_AfS3ELz4qcFJAho2YQQVJOS0tvLdZ_4D9FVCcMRcl6eB4wyEfxQnrDckJksw"&gt;&lt;/a&gt; &lt;br&gt; &lt;p&gt;Now consider injecting a dependency that shields the test script from the system under test.  It's true that the test fixture may have to change, but your test scripts - ideally - would not be subject to the same degree of change as the test fixture might.   &lt;p&gt;&lt;a href="http://tk2.storage.msn.com/x1pmvPPWtnrbEViP7lO369MCUrgcgvSW9Zd-yrb2kVraZo7d_6hJCMwjbqwMgMNbQlMsKuD2RN5hqL0vxKMZQceQMePCdy1YXmYVSh_GipJX-rgWb59G380tLjKfex9E9I3t7Q0-JIAxHjIX8jCluZFUQ"&gt;&lt;img src="http://tk2.storage.msn.com/x1pmvPPWtnrbEViP7lO369MCUrgcgvSW9Zd-yrb2kVraZr6R2lSJFcU5tUJ_lwcRr4N4ma-zLoYy66OKQdeBY1AbELmBEsMj3UsBM914vgA5p3L3SF0BrsWDJxu_3Gjx4Cx9iWh4w6HByBpNmANRd-k2g"&gt;&lt;/a&gt;  &lt;p&gt;Unlike the FIT test fixtures that allow you to run several test cases, these injected test fixtures translate test steps into calls to the system under test.  That's key.  A better name for them is actually 'test-step fixtures', given their role.  Give these test-step fixtures names that originate with the business domain, and you have given life to 'keyword-driven testing' in the domain of the system under test.  Otherwise known as the ubiquitous language or domain-driven design. &lt;p&gt;I'm advocating using PowerShell to write the test scripts and PowerShell cmdlets to implement the test-step fixtures (the bridge).  Until their usefulness is proven in context, the cmdlets can be prototyped as PowerShell functions. &lt;p&gt;Two roles emerge: the business test scripter that knows the business domain, and the developer scripter that knows the automation API of the system under test.  The test scripter uses the test-step fixtures to assemble scenario tests.  The developer scripter builds the test-step fixtures, either proactively or in response to the needs of the test scripter. &lt;p&gt;So does this lower the cost of test automation?  We've decreased the coupling between the tests and the system under test by injecting a dependency that we control - so we've made the test less susceptible to technical changes, if not entirely to requirements changes.  But even then - the scenario tests are built from modular components (test-step fixtures) - and modularity is a good thing - because it increases the likelihood of high maintainability and extensibility.  The test-step fixtures may change, but ideally the test scripts themselves would only be adapted as the complexity of the system under test evolves. &lt;p&gt;On to the PowerShell hook.  Write the test-step fixtures in the form of cmdlets or PowerShell functions, following the same verb-noun naming convention that we might use for building any cmdlet or function.  EXCEPT, for testing purposes, we would prefer to &lt;em&gt;&lt;strong&gt;take the 'nouns' from the domain&lt;/strong&gt;&lt;/em&gt; (maybe even the verbs but then we could no longer build cmdlets unless the verb was also on the standard list of PowerShell verbs). &lt;p&gt;For example: &lt;p&gt;$MyAccount = get-account 'name'&lt;br&gt;set-contract $MyAccount &lt;p&gt;Once you've established a number of the domain-specific verb-noun combinations, then you can build test scenarios in PowerShell using them whose complexity matches the complexity of the system under test - they can evolve independently but at the same pace.  Those test-steps listed above in the example expose nothing of the automation API for the system under test - a good thing if we want to retain the test scripts usefulness over time. &lt;p&gt;In summary, here are the ways that PowerShell excels for keyword-driven testing: &lt;ol&gt; &lt;li&gt;The verb-noun style is PowerShell vernacular - we're not introducing anything new by asking the test scripters to use cmdlets or functions that follow a verb-noun naming convention. &lt;li&gt;PowerShell provides access to both System and custom assemblies and namespaces.  You might use either or both to implement the test-step fixtures. &lt;li&gt;The system under test may require an administration module that might also utilize PowerShell and cmdlets - there would be overlap in administration-type cmdlets and the test-step fixtures so that building them for one purpose would help satisfy the other requirement as well. &lt;li&gt;PowerShell provides exception handling so that test scripters can control the impact of any failed test-steps. &lt;li&gt;PowerShell provides all the control structures so that test scripters can control the flow and execution of test scripts - including looping.  Many other test automation styles only provide rudimentary control, if any. &lt;li&gt;The test script development cycle is short - you write a script, you run it, edit, run it again, etc. very quickly.  You can even prototype script steps in the console. &lt;li&gt;Test-step fixtures can vary in their complexity - you can extend their domain-specific nature by giving them domain-oriented parameters.  For example, new-customer 'GOOD CREDIT', might generate a new customer with a good credit rating to use in the test script.&lt;/ol&gt; &lt;p&gt;For a slightly more detailed example, there is one posted for &lt;a href="http://www.codeplex.com/psexpect"&gt;PSExpect&lt;/a&gt; that uses this style of test scripting  - samples\Test-Vcs.ps1.  The sample domain is a volunteer coordination system (vcs).&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+Lowering+the+Cost+of+Test+Automation&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!158.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!158.entry</guid><pubDate>Tue, 13 Feb 2007 23:37:09 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!158/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!158.entry#comment</wfw:comment><dcterms:modified>2007-04-24T22:40:49Z</dcterms:modified></item><item><title>PSExpect 0.3 Alpha</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!151.entry</link><description>&lt;p&gt;Release 0.3 (Alpha) of &lt;a href="http://www.codeplex.com/psexpect"&gt;PSExpect&lt;/a&gt; has been uploaded - hopefully it is clear from the samples and the tests that are included that PowerShell is well-suited for automating tests using both data-driven and keyword-driven techniques. &lt;p&gt;Release notes for 0.3 Alpha are as follows: &lt;ul&gt; &lt;li&gt;Addition of a 'start-test' function in DataLib.ps1 that uses an Excel named range and a function you build to test a target script or application library. See \samples\Test-GetWeatherPerf.ps1 for an example. &lt;li&gt;Addition of a 'select-row' function in DataLib.ps1 for those data-driven testers that want more control of their test script and its use of Excel &lt;li&gt;The Excel functions now use reflection to call the Excel COM API - so these should work in cultures other than 'en-US' &lt;li&gt;Addition of a keyword-driven testing example - using verb-noun pairs from the business domain to write maintainable test scripts. &lt;li&gt;AssertBlock  is renamed to Assert-Block and is now pipeline-aware &lt;li&gt;AssertFaster is now pipeline-aware &lt;li&gt;AssertThrows is now pipeline-aware&lt;/ul&gt; &lt;p&gt;Next up: a better explanation of keyword-driven testing using PowerShell.  I've included an example in 0.3 Alpha but only in-line comments to explain what it going on and why.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+PSExpect+0.3+Alpha&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!151.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!151.entry</guid><pubDate>Sun, 04 Feb 2007 19:09:34 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!151/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!151.entry#comment</wfw:comment><dcterms:modified>2007-02-04T19:09:34Z</dcterms:modified></item><item><title>A Compatibility Story</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!149.entry</link><description>&lt;p&gt;Kudos to the PowerShell Team and the Office Team.  I have a number of test cases for and samples of &lt;a href="http://www.codeplex.com/psexpect" target="_blank"&gt;PSExpect&lt;/a&gt; that rely on Excel - part of my kick to support data-driven testing using PowerShell. &lt;p&gt;Yesterday, Microsoft released PowerShell 1.0 for Vista, and my Vista test machine also has Office 2007.  The PSExpect tests pass on Vista/Office 2007, as they do on Windows XP/Office 2003.  Including the ones that use Excel. &lt;p&gt;That's a compatibility story, and I'm impressed.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=9081042144815434356&amp;page=RSS%3a+A+Compatibility+Story&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=testfirst.spaces.live.com&amp;amp;GT1=testfirst"&gt;</description><comments>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!149.entry#comment</comments><guid isPermaLink="true">http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!149.entry</guid><pubDate>Thu, 01 Feb 2007 23:36:35 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://testfirst.spaces.live.com/blog/cns!7E0657B7A0134A74!149/comments/feed.rss</wfw:commentRss><wfw:comment>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!149.entry#comment</wfw:comment><dcterms:modified>2007-02-01T23:36:35Z</dcterms:modified></item><item><title>PowerShell Excel Functions - Release Candidate</title><link>http://testfirst.spaces.live.com/Blog/cns!7E0657B7A0134A74!148.entry</link><description>&lt;p&gt;The technique for using Excel as the source of the data to support data-driven testing continues to evolve, but this time I think I've come to the place where I want to be for Release 0.3 of PSExpect (&lt;a href="http://www.codeplex.com/psexpect"&gt;http://www.codeplex.com/psexpect&lt;/a&gt;). 
&lt;p&gt;In 0.3, there is a new function in DataLib.ps1 called 'start-test' that takes a workbook name, a worksheet name, a range name, and a set of field names as input, and runs the tests that are described in that range.  It does this by calling a function that has the same name as the range - much like FIT calls classes/methods based on the contents of the input table. 
&lt;p&gt;So here's the process to follow to use start-test. 
&lt;ol&gt;
&lt;li&gt;Describe your tests in Excel.  You should include both inputs and expected outputs in this table.  There is no need to differentiate the inputs from expected outputs like in FIT (in FIT, you specify expected outputs by including parentheses since they represent method calls).  The column titles are meaningless in PSExpect, so you can use titles that make the worksheet easier to read and understand as needed. 
&lt;li&gt;Define a named range (Insert-&amp;gt;Name-&amp;gt;Define...) that EXCLUDES the column titles but includes all the rows.  This is why the column titles are meaningless. Unfortunately, a hyphen is not a valid character to use in a range name in Excel so your test fixture can't have a name that looks like most PoSh functions and cmdlets. 
&lt;li&gt;Write a test fixture (function) in PoSh that has exactly the same name as the name you gave the range in Step 2.  The parameters should match the columns in the table by position (because we build a string in PoSh for execution using invoke-expression).  This function must include an appropriate Assert* function call that determines whether or not the test case passes. 
&lt;li&gt;Call start-test and provide the workbook name, the worksheet name, the range name, and an array of fieldnames as parameters. 
&lt;li&gt;Run the script - your results will be on the console and in the log file.&lt;/ol&gt;
&lt;p&gt;Using 'start-test' is demonstrated in a performance test for the weather web service I've used in previous samples, \samples\Test-GetWeatherPerf.ps1.   The Excel table and the test script are listed below. 
&lt;p&gt;
&lt;table style="width:387pt;border-collapse:collapse" cellspacing=0 cellpadding=0 width=516 border=0&gt;
&lt;colgroup&gt;
&lt;col style="width:48pt" width=64&gt;
&lt;col style="width:114pt" width=152&gt;
&lt;col style="width:48pt" span=2 width=64&gt;
&lt;col style="width:129pt" width=172&gt;
&lt;tbody&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;width:48pt;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" width=64 height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;&lt;strong&gt;TestCase&lt;/strong&gt;&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;width:114pt;border-bottom:#ece9d8;background-color:transparent" width=152&gt;&lt;font face=Arial color="#000000" size=2&gt;&lt;strong&gt;Remark&lt;/strong&gt;&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;width:48pt;border-bottom:#ece9d8;background-color:transparent" width=64&gt;&lt;font face=Arial color="#000000" size=2&gt;&lt;strong&gt;Zip&lt;/strong&gt;&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;width:48pt;border-bottom:#ece9d8;background-color:transparent" width=64&gt;&lt;font face=Arial color="#000000" size=2&gt;&lt;strong&gt;Units&lt;/strong&gt;&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;width:129pt;border-bottom:#ece9d8;background-color:transparent" width=172&gt;&lt;strong&gt;&lt;font face=Arial color="#000000" size=2&gt;Title&lt;/font&gt;&lt;/strong&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;a&gt;&lt;/a&gt;&lt;a&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-1&lt;/font&gt;&lt;/a&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Success in Celsius&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;35801&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;C&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Conditions for Huntsville, AL&lt;/font&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-2&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Success in Fahrenheit&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;35801&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;F&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Conditions for Huntsville, AL&lt;/font&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-3&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Success - Bad Units&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;35801&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Z&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Conditions for Huntsville, AL&lt;/font&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-4&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Success - Default Units&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;35801&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;$null&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Conditions for Huntsville, AL&lt;/font&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-5&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Failure - No Zip&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;$null&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;F&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;City not found&lt;/font&gt;
&lt;tr style="height:12.75pt" height=17&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;height:12.75pt;background-color:transparent" height=17&gt;&lt;font face=Arial color="#000000" size=2&gt;TC-6&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;Failure - Invalid Zip&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;2&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;F&lt;/font&gt;
&lt;td style="border-right:#ece9d8;border-top:#ece9d8;border-left:#ece9d8;border-bottom:#ece9d8;background-color:transparent"&gt;&lt;font face=Arial color="#000000" size=2&gt;City not found&lt;/font&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;&lt;pre style="background-color:white"&gt;&lt;div&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; Exercises the target of the test - the get-weather web service
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; and then verifies the results against the expected values that are also on the 
&lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; worksheet (in this simple case, the $title parameter)&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;function TestGetWeather()
{
    param(  [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$TestCase, `
            [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$Remark, `
            [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$Zip, `
            [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$Units, `
            [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$Title)

    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;if&lt;/span&gt;&lt;span style="color:#000000"&gt; ($Units &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;eq &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;$null&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;) { $Units &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; $&lt;/span&gt;&lt;span style="color:#0000ff"&gt;null&lt;/span&gt;&lt;span style="color:#000000"&gt; }
    &lt;/span&gt;&lt;span style="color:#0000ff"&gt;if&lt;/span&gt;&lt;span style="color:#000000"&gt; ($Zip &lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;eq &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;$null&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;) { $Zip &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; $&lt;/span&gt;&lt;span style="color:#0000ff"&gt;null&lt;/span&gt;&lt;span style="color:#000000"&gt; }
    
    [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$urlbase&lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;http://xml.weather.yahoo.com/forecastrss&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;
    [&lt;/span&gt;&lt;span style="color:#0000ff"&gt;string&lt;/span&gt;&lt;span style="color:#000000"&gt;]$url&lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt;$urlbase &lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;?p=&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt;$Zip&lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;amp;u=&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;+&lt;/span&gt;&lt;span style="color:#000000"&gt;$Units
    
    write&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#000000"&gt;host Connecting to $url
    
    &lt;/span&gt;&lt;span style="color:#008000"&gt;#&lt;/span&gt;&lt;span style="color:#008000"&gt; create .NET Webclient object and call the web service&lt;/span&gt;&lt;span style="color:#008000"&gt;
&lt;/span&gt;&lt;span style="color:#000000"&gt;    $webclient &lt;/span&gt;&lt;span style="color:#000000"&gt;=&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#0000ff"&gt;new&lt;/span&gt;&lt;span style="color:#000000"&gt;-&lt;/span&gt;&lt;span style="color:#0000ff"&gt;object&lt;/span&gt;&lt;span style="color:#000000"&gt; &lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#000000"&gt;System.Net.WebClient&lt;/span&gt;&lt;span style="color:#000000"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#00000