<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">Speaking of which...</title><subtitle type="html">Sample solutions from Internet development support</subtitle><id>http://blogs.msdn.com/johan/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/johan/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2008-05-29T14:14:58Z</updated><entry><title>Investigating Locks</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/10/09/investigating-locks.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/10/09/investigating-locks.aspx</id><published>2009-10-09T16:49:56Z</published><updated>2009-10-09T16:49:56Z</updated><content type="html">&lt;p&gt;Consider the following scenario:&lt;/p&gt;  &lt;p&gt;You have an ASP.NET application which intermittently responds sluggishly. As the problem occurs memory usage is about average, as is CPU usage, but still certain pages respond slower and slower. The machine acts just as if it is under heavy load, but judging from the CPU it isn't. In fact CPU usage might even &lt;em&gt;decrease&lt;/em&gt; rather than increase. When trying to access non .NET content such as plain text/html or images you usually find that response times are just as fast as ever.&lt;/p&gt;  &lt;p&gt;When you find that your application has hung in a low CPU state it is usually because of one of the following reasons (in order of likelihood based on my experience) :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;External resources responding slowly. E.g. a database query or AD lookup is taking a long time to complete and so the application is simply waiting for another server to respond. &lt;/li&gt;    &lt;li&gt;One of the threads of the application has entered a critical section and now several other threads are waiting to enter the same critical section. &lt;/li&gt;    &lt;li&gt;A classic deadlock. Thread A waits for thread B which waits for thread C which waits for thread A. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Quite often you'll see a mixture of items 1 and 2. A thread enters a critical section, calls a remote database, or similar, and all other threads attempting to enter the same critical section will have to nicely stay in line until the struggling database has responded. Still, it is quite possible that the critical section is waiting for a local event to finish, but then you'd usually see a higher CPU load on the machine. (Though not necessarily in the w3wp.exe process.)&lt;/p&gt;  &lt;h1&gt;What are Critical Sections?&lt;/h1&gt;  &lt;p&gt;In case you've forgotten or simply not worked that much with critical sections it might be necessary to refresh your memory on this.&lt;/p&gt;  &lt;p&gt;A Critical Section is a segment of code that you do not want to be executed more than one at a time. In order to ensure this you use the &lt;strong&gt;lock&lt;/strong&gt; keyword to ensure that a certain block of code is able to complete with no interruption from any other threads. To illustrate this I've created the following code sample:&lt;/p&gt;  &lt;div class="SampleCode"&gt;   &lt;pre&gt;public class FileIO
{
    private static object myLock = new object();

	public FileIO()
	{
	}

    public string performLockOperation()
    {
        string strResult = &amp;quot;The Lock Operation started on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        lock (myLock)
        {
            // Let the thread sleep for 10 seconds
            // This way we simulate a File IO operation that takes some time to complete.
            System.Threading.Thread.Sleep(10000);
        }
        strResult += &amp;quot; and ended on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        return strResult;
    }

    public string performNoLockOperation()
    {
        string strResult = &amp;quot;The No Lock Operation started on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        System.Threading.Thread.Sleep(10000);
        strResult += &amp;quot; and ended on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        return strResult;
    }

}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let's take a quick look at the parts of this class that I've written, called FileIO:&lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;myLock&lt;/h2&gt;

&lt;p&gt;The class has a static variable called myLock that I will be using to identify the lock I'm about to create. This is why the variable is static. Otherwise I'd be creating new locks for each instance of the FileIO class leaving the lock operation completely redundant. Now that I use a static variable the lock spans all instances of the FileIO class.&lt;/p&gt;

&lt;h2&gt;constructor&lt;/h2&gt;

&lt;p&gt;The constructor is empty. Move along. Nothing to see here.&lt;/p&gt;

&lt;h2&gt;performLockOperation&lt;/h2&gt;

&lt;p&gt;This is the most interesting part of the class. It is the function we'll be using to actually reproduce the potential problems. The function returns a string which will contain information about when the call to the function was made and when it completed. We store this data in a string called strResult which we will eventually be returning as the result of the function call.&lt;/p&gt;

&lt;p&gt;Having declared this variable and put the initial time of the function call in it we then create our lock. This is simply done with the following syntax:&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;lock (object)
{
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Any code within this block will first make sure that there is not already a lock taken on this object. If there is, then they will pause execution and wait for the lock to become available before continuing execution.&lt;/p&gt;

&lt;p&gt;Inside our lock we then simulate a slow File IO operation by letting the thread sleep for 10 seconds.&lt;/p&gt;

&lt;p&gt;After that we append the current time to the result and return it.&lt;/p&gt;

&lt;h2&gt;performNoLockOperation&lt;/h2&gt;

&lt;p&gt;This function is identical to the previous one, except this time we do not have a critical section. This function is included just for comparison.&lt;/p&gt;

&lt;h1&gt;The potential problem&lt;/h1&gt;

&lt;p&gt;Now, let's get down to business. If we have a web page that makes a call to the performLockOperation-function and that page is requested at the same time by four different clients. What would be the response times?&lt;/p&gt;

&lt;p&gt;The answer is 10, 20, 30 &amp;amp; 40 seconds.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The thread handling the first request enters the critical section, effectively locking it for everyone else. When it is complete 10 seconds have passed due to the Sleep-call. &lt;/li&gt;

  &lt;li&gt;One of the other threads enters the critical section once the first request is finished. It has already waited for 10 seconds, and the thread will now sleep for an additional 10 seconds. &lt;/li&gt;

  &lt;li&gt;As the second thread finishes one of the remaining two enters the critical section. It has now waited for 20 seconds and will sleep for an additional 10. &lt;/li&gt;

  &lt;li&gt;The final request is able to enter the critical section after having waited for 30 seconds. Once it is complete 40 seconds have passed. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we'd been using the performNoLockOperation instead then all requests would have responded after 10 seconds.&lt;/p&gt;

&lt;p&gt;Now, I know that 10 seconds is an exceptionally long time to let the thread sleep, but this was all for illustration purposes. Imagine instead that the sleeping time was 1 second and the number of requests was 200...&lt;/p&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;Troubleshooting this issue&lt;/h1&gt;

&lt;p&gt;Okay, so what would it look like when this problem occurs? Let's have a look. If you haven't looked at my posts on getting started with Windbg, then I suggest reading them before continuing. (&lt;a href="http://blogs.msdn.com/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx"&gt;Part I&lt;/a&gt; &amp;amp; &lt;a href="http://blogs.msdn.com/johan/archive/2008/05/28/powershell-an-introduction-part-ii.aspx"&gt;Part II&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;First of all I fire up WinDbg, then I attach to the w3wp.exe. I then use &amp;quot;~*e!clrstack&amp;quot; to look at the managed threads of the w3wp.exe application. Here is a snippet of what I get:&lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;OS Thread Id: 0xce0 (24)
Child-SP         RetAddr          Call Site
000000000447e0f0 000007ff001e13d2 FileIO.performLockOperation()
000000000447e170 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
000000000447e1b0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000447e1e0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000447e210 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000447e250 000007fee79498ac System.Web.UI.Control.LoadRecursive()
000000000447e2a0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000447e370 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000447e3d0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
000000000447e430 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000447e490 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
000000000447e4c0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000447e570 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000447e610 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
000000000447e7a0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
000000000447e7f0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
000000000447e910 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000447ea80 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000447eae0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
000000000447f310 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000000447f3f0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000447f560 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000447f5c0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x15ec (25)
Unable to walk the managed stack. The current thread is likely not a 
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x1958 (26)
Child-SP         RetAddr          Call Site
0000000004c1dd10 000007ff001e13d2 FileIO.performLockOperation()
0000000004c1dd90 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
0000000004c1ddd0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
0000000004c1de00 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
0000000004c1de30 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
0000000004c1de70 000007fee79498ac System.Web.UI.Control.LoadRecursive()
0000000004c1dec0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000004c1df90 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000004c1dff0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
0000000004c1e050 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000004c1e0b0 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
0000000004c1e0e0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0000000004c1e190 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0000000004c1e230 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
0000000004c1e3c0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
0000000004c1e410 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
0000000004c1e530 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1e6a0 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1e700 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
0000000004c1ef30 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
0000000004c1f010 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1f180 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1f1e0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x1e28 (27)
Child-SP         RetAddr          Call Site
000000000492dcf0 000007ff001e13d2 FileIO.performLockOperation()
000000000492dd70 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
000000000492ddb0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000492dde0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000492de10 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000492de50 000007fee79498ac System.Web.UI.Control.LoadRecursive()
000000000492dea0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000492df70 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000492dfd0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
000000000492e030 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000492e090 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
000000000492e0c0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000492e170 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000492e210 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
000000000492e3a0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
000000000492e3f0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
000000000492e510 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000492e680 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000492e6e0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
000000000492ef10 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000000492eff0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000492f160 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000492f1c0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x1c38 (28)
Child-SP         RetAddr          Call Site
0000000004d0e0b0 000007ff001e13d2 FileIO.performLockOperation()
0000000004d0e130 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
0000000004d0e170 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
0000000004d0e1a0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
0000000004d0e1d0 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
0000000004d0e210 000007fee79498ac System.Web.UI.Control.LoadRecursive()
0000000004d0e260 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000004d0e330 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000004d0e390 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
0000000004d0e3f0 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000004d0e450 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
0000000004d0e480 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0000000004d0e530 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0000000004d0e5d0 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
0000000004d0e760 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
0000000004d0e7b0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
0000000004d0e8d0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0ea40 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0eaa0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
0000000004d0f2d0 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
0000000004d0f3b0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0f520 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0f580 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, what does this tell us?&lt;/p&gt;

&lt;p&gt;Well, obviously we have four threads that call my function FileIO.performLockOperation() from Page_Load.&lt;/p&gt;

&lt;p&gt;Please note that we don't have any additional callstack, and since the performLockOperation-function was named by me it could just as well have been named &amp;quot;foo&amp;quot;. In order to find out that these threads are actually waiting for a lock we need to look at the native callstack using the kb-command. Let's take a look at thread 24: &lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;0:029&amp;gt; ~24kb
ntdll!NtDelayExecution+0xa
kernel32!SleepEx+0x84
mscorwks!EESleepEx+0x2d
mscorwks!Thread::UserSleep+0x71
mscorwks!&lt;font color="#ff0000"&gt;ThreadNative::Sleep&lt;/font&gt;+0xf9
App_Code_tvh3usvo!&lt;font color="#ff0000"&gt;FileIO.performLockOperation&lt;/font&gt;()+0x8a
App_Web_uywrbugj!_Default.Page_Load(System.Object, System.EventArgs)+0x32
System_Web_RegularExpressions_ni!System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)+0x19
System_Web_ni!System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)+0x2a
System_Web_ni!System.Web.UI.Control.OnLoad(System.EventArgs)+0x84
System_Web_ni!System.Web.UI.Control.LoadRecursive()+0x42
System_Web_ni!System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)+0x97c
System_Web_ni!System.Web.UI.Page.ProcessRequest(Boolean, Boolean)+0xa0
System_Web_ni!System.Web.UI.Page.ProcessRequest()+0x5b
System_Web_ni!System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)+0xf0
App_Web_uywrbugj!ASP.default_aspx.ProcessRequest(System.Web.HttpContext)+0x9
System_Web_ni!System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+0x257
System_Web_ni!System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)+0xab
System_Web_ni!System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)+0x501
System_Web_ni!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)+0x72&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Apparently we entered FileIO.performLockOperation, and then called sleep, (which is what we're doing in this repro in order to simulate a slow IO operation.) So, what do the other threads look like? Here's thread 26:&lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;0:029&amp;gt; ~26kb
ntdll!ZwWaitForMultipleObjects+0xa
kernel32!WaitForMultipleObjectsEx+0x10b
mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0xc1
mscorwks!Thread::DoAppropriateAptStateWait+0x41
mscorwks!Thread::DoAppropriateWaitWorker+0x191
mscorwks!Thread::DoAppropriateWait+0x5c
mscorwks!&lt;font color="#ff0000"&gt;CLREvent::WaitEx&lt;/font&gt;+0xbe
mscorwks!AwareLock::EnterEpilog+0xc9
mscorwks!AwareLock::Enter+0x72
mscorwks!AwareLock::Contention+0x1fb
mscorwks!JITutil_MonContention+0xdf
App_Code_tvh3usvo!&lt;font color="#ff0000"&gt;FileIO.performLockOperation&lt;/font&gt;()+0x7f
App_Web_uywrbugj!_Default.Page_Load(System.Object, System.EventArgs)+0x32
System_Web_RegularExpressions_ni!System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)+0x19
System_Web_ni!System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)+0x2a
System_Web_ni!System.Web.UI.Control.OnLoad(System.EventArgs)+0x84
System_Web_ni!System.Web.UI.Control.LoadRecursive()+0x42
System_Web_ni!System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)+0x97c
System_Web_ni!System.Web.UI.Page.ProcessRequest(Boolean, Boolean)+0xa0
System_Web_ni!System.Web.UI.Page.ProcessRequest()+0x5b&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is one of the threads waiting for the critical section. It then found that it was unable to get a lock and so began waiting for the critical section on thread 24 to end.&lt;/p&gt;

&lt;h1&gt;Resolving the problem&lt;/h1&gt;

&lt;p&gt;This is the tricky part. There is no quick-fix for this. We can use the debugger to identify the bottleneck, but after that we'll need to review our design in order to get this working smoothly. A couple of generic things to try would be the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Review what you're doing inside the critical section. Is it really necessary to perform all of the operations you're doing, or would it be possible to do some/all of them outside the scope of the critical section?&lt;/li&gt;

  &lt;li&gt;Identify the reason for the lock taking so much time. Can it be resolved by load-balancing or clustering the resource we're waiting for?&lt;/li&gt;

  &lt;li&gt;If we're waiting for another server, make sure the physical infrastructure is okay. Are network response times within the expected parameters or do you need to fix your wiring, router, etc?&lt;/li&gt;

  &lt;li&gt;Are &lt;em&gt;all &lt;/em&gt;calls to the critical section taking the same amount of time, or are there certain calls that take an &lt;em&gt;exceptional&lt;/em&gt; amount of time? Perhaps most calls to the function are just fine, but intermittently a call comes along that tries to get &lt;em&gt;everything &lt;/em&gt;from the AD, database, etc. In order to investigate this I'd use the commands outlined in &lt;a href="http://blogs.msdn.com/johan/archive/2007/11/26/getting-started-with-windbg-part-ii.aspx"&gt;Getting started with windbg -part II&lt;/a&gt;. Identify the thread owning the lock and investigate the callstack and stack objects using !clrstack and !dso. Use !dso and !do to query the stack objects and try to find the SQL query or AD query that is causing the thread to take such a long time to finish. Is the query significantly different from the ones waiting to execute, then this is most likely our culprit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Post Script&lt;/h1&gt;

&lt;p&gt;A quick thought on locks and their limits:&lt;/p&gt;

&lt;p&gt;Locks do not scale well. A lock can only be made within a specific process, so if you're using a web farm, or in any other way more than one w3wp.exe, then you will not be able to lock &lt;em&gt;all &lt;/em&gt;processes. In other words. Server 1 can get a lock, and so can Server 2. Both will happily execute their code independent of each other. For products such as SQL server you'd deal with this in your SQL query, but if you're performing other operations, such as File IO you might have to work around this by using the same approach as Ms Word. Create a lock file in a shared space, and before you enter your critical section you simply check if the file exists:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You are entering your critical section. Look for lock file in shared location&lt;/li&gt;

  &lt;li&gt;If file exists, then wait&lt;/li&gt;

  &lt;li&gt;If/when file doesn't/no longer exist, create file and enter critical section&lt;/li&gt;

  &lt;li&gt;Make sure you have &lt;em&gt;solid&lt;/em&gt; exception handling within the critical section so that you under no circumstances leave the critical section without removing the lock file.&lt;/li&gt;

  &lt;li&gt;When done, remove lock file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9905467" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Performance" scheme="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx" /><category term="WinDbg" scheme="http://blogs.msdn.com/johan/archive/tags/WinDbg/default.aspx" /><category term="Debugging School" scheme="http://blogs.msdn.com/johan/archive/tags/Debugging+School/default.aspx" /><category term="ASP.NET" scheme="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx" /><category term="Hangs" scheme="http://blogs.msdn.com/johan/archive/tags/Hangs/default.aspx" /></entry><entry><title>Problems with Flash-content in the WebBrowser control</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/08/06/problems-with-flash-content-in-the-webbrowser-control.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/08/06/problems-with-flash-content-in-the-webbrowser-control.aspx</id><published>2009-08-06T17:59:34Z</published><updated>2009-08-06T17:59:34Z</updated><content type="html">&lt;p&gt;A recent case I worked on involved the following scenario.&lt;/p&gt;  &lt;h1&gt;Problem description&lt;/h1&gt;  &lt;p&gt;The client was building a kiosk-like application. I.e. a WinForms application with the WebBrowser control slapped onto it. The application worked fine for the most part, but they'd found that when viewing video via &lt;a href="http://www.facebook.com/" target="_blank"&gt;facebook&lt;/a&gt; they were only able to view the video the first time. Any additional attempt to view the video would fail with a custom error from the facebook application stating that the video was either restricted or no longer available.&lt;/p&gt;  &lt;p&gt;This only happened when viewing the page via the WinForms application. Using IE directly worked just fine. We also found that this problem occurred with both IE7 and IE8 installed, so it seemed not to be related to the browser version.&lt;/p&gt;  &lt;p&gt;Other sites using the Adobe Flash player to display video, such as &lt;a href="http://video.msn.com" target="_blank"&gt;MSN&lt;/a&gt; or &lt;a href="http://www.youtube.com/" target="_blank"&gt;Youtube&lt;/a&gt; worked just fine.&lt;/p&gt;  &lt;h1&gt;Troubleshooting&lt;/h1&gt;  &lt;p&gt;Using the Developer tools included in IE8 I found that the facebook application displays a placeholder image with a play-button. Once that button is clicked the .swf player is loaded via client-side script. The .swf player then downloads the .mp4 that is to be displayed and divides it into suitable chunks.&lt;/p&gt;  &lt;p&gt;Fiddler traces revealed that the mp4 was downloaded when using IE but not when using the WinForms application. No errors were reported, instead the request was simply never made.&lt;/p&gt;  &lt;p&gt;We removed all code behind. All that remained was the On_Load event that set a starting page for the WebBrowser control, still we were unable to successfully load the movie.&lt;/p&gt;  &lt;p&gt;Adding facebook to the trusted zone changed nothing.&lt;/p&gt;  &lt;p&gt;Using the COM-version of the WebBrowser control still reproduced the problem.&lt;/p&gt;  &lt;p&gt;I then suspected restrictions in cross-domain access or similar, (facebook uses a lot of different domains,) but couldn't find anything conclusive.&lt;/p&gt;  &lt;p&gt;Finally I stumbled upon the root cause.&lt;/p&gt;  &lt;h1&gt;Cause&lt;/h1&gt;  &lt;p&gt;The problem is due to a bug within the Adobe Flash-player: &lt;a href="http://bugs.adobe.com/jira/browse/FP-256"&gt;http://bugs.adobe.com/jira/browse/FP-256&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The problem occurs when dynamically trying to display a cached .swf application with an external interface through script. So, another quick repro would be the following (Copied from the Adobe bug report):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Create a C# application with an embedded WebBrowser control.&lt;/li&gt;    &lt;li&gt;Load a HTML page with no content.&lt;/li&gt;    &lt;li&gt;Via JavaScript, add a SWF with external interface to the page via an object tag. (At this point I see server traffic, requesting the SWF.)&lt;/li&gt;    &lt;li&gt;From JavaScript, access the external interface of the SWF. Works OK.&lt;/li&gt;    &lt;li&gt;Browse to a second web page.&lt;/li&gt;    &lt;li&gt;Browse back to the empty one.&lt;/li&gt;    &lt;li&gt;Via JavaScript, add the SWF again. Cannot contact the external interface. (There is no server traffic, indicating that the SWF is already being cached.)&lt;/li&gt; &lt;/ol&gt;  &lt;h1&gt;Solution&lt;/h1&gt;  &lt;p&gt;While waiting for a fix from Adobe the only way to circumvent this is to manually remove the cached .swf. Article &lt;a href="http://support.microsoft.com/kb/262110" target="_blank"&gt;262110&lt;/a&gt; describes in detail how you can do this. Unfortunately this can be a bit tricky some times. In the sample repro above you'd resolve it by simply removing all .swf items from the cache upon page-load, but this wouldn't work in the facebook situation, since it might use the same control repeatedly without refreshing the page in between. Depending on your level of control over the target platform it might be easier to simply turn of caching.&lt;/p&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9859220" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Shockwave" scheme="http://blogs.msdn.com/johan/archive/tags/Shockwave/default.aspx" /><category term="WebBrowser control" scheme="http://blogs.msdn.com/johan/archive/tags/WebBrowser+control/default.aspx" /></entry><entry><title>Adding Server ROles to an IIS installation on an RODC</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/05/05/adding-server-roles-to-an-iis-installation-on-an-rodc.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/05/05/adding-server-roles-to-an-iis-installation-on-an-rodc.aspx</id><published>2009-05-05T17:10:15Z</published><updated>2009-05-05T17:10:15Z</updated><content type="html">&lt;p&gt;In a recent case I was involved with I stumbled upon something quite interesting. The customer had set up a brand new Windows 2008 Server running IIS, and made it into a &lt;em&gt;Read Only Domain Controller&lt;/em&gt; (RODC). Having done this they now wanted to add the FTP-server Role to the existing IIS installation and found that they couldn't.&lt;/p&gt;  &lt;p&gt;The reason for this is that the RODC is quite picky about what server roles and features it will allow you to install. I recommend looking at the following articles, but they still don't cover everything.&lt;/p&gt;  &lt;p&gt;Applications That Are Known to Work with RODCs   &lt;br /&gt;&lt;a title="http://technet.microsoft.com/en-us/library/cc732790.aspx" href="http://technet.microsoft.com/en-us/library/cc732790.aspx"&gt;http://technet.microsoft.com/en-us/library/cc732790.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Planning for Application Compatibility with RODCs   &lt;br /&gt;&lt;a title="http://technet.microsoft.com/en-us/library/cc731746.aspx" href="http://technet.microsoft.com/en-us/library/cc731746.aspx"&gt;http://technet.microsoft.com/en-us/library/cc731746.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The main lesson to be learned is that although the application is listed as known to work with RODCs that doesn't necessarily mean it installs well once the server has been promoted to RODC. When it comes to FTP you have two valid options to get this working:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Install the FTP server &lt;em&gt;before&lt;/em&gt; promoting the server to RODC&lt;/li&gt;    &lt;li&gt;Install the &lt;a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=b7f5b652-8c5c-447a-88b8-8cfc5c13f571" target="_blank"&gt;FTP Service 7.5 for IIS7&lt;/a&gt;. This is a stand-alone installer and works just fine.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9588868" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="IIS7" scheme="http://blogs.msdn.com/johan/archive/tags/IIS7/default.aspx" /><category term="Misc" scheme="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx" /></entry><entry><title>Creating a game for the Zune</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/03/31/creating-a-game-for-the-zune.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="286924" href="http://blogs.msdn.com/johan/attachment/9522814.ashx" /><id>http://blogs.msdn.com/johan/archive/2009/03/31/creating-a-game-for-the-zune.aspx</id><published>2009-03-31T17:34:00Z</published><updated>2009-03-31T17:34:00Z</updated><content type="html">&lt;P&gt;I've finally had the time to sit down and create a simple game for my Zune. Rather than running off and creating a complex game requiring a lot of AI, etc I wanted to create a simple application so that I could focus on the XNA-specifics. I decided to make a Code Breaker game, also known as Master Mind. It's a pretty straight-forward game. There is no increasing difficulty curve and no fancy AI to be written, so it seemed like an excellent first attempt.&lt;/P&gt;
&lt;H1&gt;&lt;/H1&gt;
&lt;H1&gt;Prerequisites&lt;/H1&gt;
&lt;P&gt;Before I could start I needed to install the necessary software. I already had &lt;A href="http://www.microsoft.com/visualstudio/en-us/default.mspx" target=_blank mce_href="http://www.microsoft.com/visualstudio/en-us/default.mspx"&gt;Visual Studio 2008&lt;/A&gt; and the &lt;A href="http://www.zune.net/en-us/software/download/default.htm" target=_blank mce_href="http://www.zune.net/en-us/software/download/default.htm"&gt;Zune Software&lt;/A&gt;. Actually you don't need the full Visual Studio 2008. You can use the completely free &lt;A href="http://www.microsoft.com/express/download/" target=_blank mce_href="http://www.microsoft.com/express/download/"&gt;Visual C# 2008 Express Edition&lt;/A&gt; instead.&lt;/P&gt;
&lt;P&gt;You &lt;EM&gt;do&lt;/EM&gt; need to sign up as a creator in the &lt;A href="http://creators.xna.com/en-US" target=_blank mce_href="http://creators.xna.com/en-US"&gt;XNA Creators Club&lt;/A&gt;. Having done that, download the XNA Game Studio and install it. Now you're set to go.&lt;/P&gt;
&lt;H1&gt;Creating content&lt;/H1&gt;
&lt;P&gt;I gathered a few sound effects and whipped up some graphics for my project. I decided that this is what I wanted the game to look like:&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/johan/images/9522730/original.aspx" mce_src="http://blogs.msdn.com/photos/johan/images/9522730/original.aspx"&gt; &lt;/P&gt;
&lt;P&gt;The background would be customizable. I wanted to be able to cycle through the available pictures on your device.&lt;/P&gt;
&lt;H1&gt;The architecture&lt;/H1&gt;
&lt;P&gt;I decided on a fairly simple architecture for my game. In my main class (Game1.cs) I deal with the necessities. E.g. I load the sound effects that will be used throughout the application, and I create the GraphicsDeviceManager that will be used to draw to the screen. Apart from that I have two classes that I use. MainGame and MainMenu. As their names imply they either show a menu or the game screen. User input is handled in the main class and it then calls methods in the relevant classes. E.g. if the menu is shown and the user clicks on the Zune "squircle" then a menu item has been selected and the event should bubble to the MainMenu class and not to the MainGame class.&lt;/P&gt;
&lt;P&gt;I do more or less the same thing in the Draw-method of the main class. Depending on what is shown on screen individual methods of the two classes are called. And the screen is updated accordingly.&lt;/P&gt;
&lt;H1&gt;Zune features&lt;/H1&gt;
&lt;P&gt;I made sure to add at least &lt;EM&gt;some&lt;/EM&gt; of the Zune-specific features.&lt;/P&gt;
&lt;H2&gt;Pictures&lt;/H2&gt;
&lt;P&gt;Like I've already mentioned I added support for getting backgrounds from the pictures on the device.&lt;/P&gt;
&lt;H2&gt;Music&lt;/H2&gt;
&lt;P&gt;I also let the player choose a playlist to be running in the background. (Anything already playing when the game is started will continue to play until the player actually changes this setting) I could have given full access to each individual song, but building an interface for that would have been quite ridiculous. Playlists only seemed like a good idea.&lt;/P&gt;
&lt;H2&gt;Touch interface&lt;/H2&gt;
&lt;P&gt;After some usability testing I found that in order to get this game working properly I needed to decide if I should incorporate the touch/sweep interface of the Zune 2.0 devices, or if I should settle for "proper" clicks only. I decided on the latter. Mainly because I still needed to rely on the center click, and it was easy to accidentally brush away to the side when trying to click. It also ment that this application would work with &lt;EM&gt;all&lt;/EM&gt; Zunes.&lt;/P&gt;
&lt;H2&gt;Other design choices&lt;/H2&gt;
&lt;P&gt;In the beginning I let the player change colors by clicking up/down and going to the next "peg" by clicking right/left.&lt;/P&gt;
&lt;P&gt;This turned out to be a bit complicated. It was quite easy to accidentally click up or down as well which would mean that you not only moved to the next peg, but also changed the previous pegs color. I ended up using the following key settings.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Click Right - Move Right&lt;/LI&gt;
&lt;LI&gt;Click Left - Move Left&lt;/LI&gt;
&lt;LI&gt;Center Click - Change color / Click button&lt;/LI&gt;
&lt;LI&gt;Play / Pause - Change color "back"&lt;/LI&gt;
&lt;LI&gt;Back - Menu&lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;Installing&lt;/H1&gt;
&lt;P&gt;If you want to install and run this little game you need to go through the motions filed under &lt;EM&gt;Prerequisites &lt;/EM&gt;above. Open the project in Visual Studio 2008 and dock your Zune. You should then be able to deploy the release version or debug the application directly on the device.&lt;/P&gt;
&lt;H1&gt;Download&lt;/H1&gt;
&lt;P&gt;You can download the project &lt;A href="http://blogs.msdn.com/johan/attachment/9522814.ashx" mce_href="http://blogs.msdn.com/johan/attachment/9522814.ashx"&gt;here&lt;/A&gt;&lt;/P&gt;
&lt;H1&gt;Additional screenshots&lt;/H1&gt;
&lt;P&gt;Here are some additional screenshots of the game:&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/johan/images/9522727/original.aspx" mce_src="http://blogs.msdn.com/photos/johan/images/9522727/original.aspx"&gt;&amp;nbsp;&lt;IMG src="http://blogs.msdn.com/photos/johan/images/9522647/original.aspx" mce_src="http://blogs.msdn.com/photos/johan/images/9522647/original.aspx"&gt; &lt;IMG src="http://blogs.msdn.com/photos/johan/images/9522729/original.aspx" mce_src="http://blogs.msdn.com/photos/johan/images/9522729/original.aspx"&gt;&lt;/P&gt;
&lt;P&gt;I hope you enjoy it!&lt;/P&gt;
&lt;P&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9522814" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Misc" scheme="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx" /><category term="Off topic" scheme="http://blogs.msdn.com/johan/archive/tags/Off+topic/default.aspx" /><category term="XNA" scheme="http://blogs.msdn.com/johan/archive/tags/XNA/default.aspx" /></entry><entry><title>Internet Explorer 8 Released today</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/03/19/internet-explorer-8-released-today.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/03/19/internet-explorer-8-released-today.aspx</id><published>2009-03-19T15:57:00Z</published><updated>2009-03-19T15:57:00Z</updated><content type="html">&lt;P&gt;Today we release Internet Explorer 8. You'll be able to download it later today from &lt;A href="http://www.microsoft.se/ie8"&gt;http://www.microsoft.se/ie8&lt;/A&gt;&lt;A title=http://www.microsoft.com/windows/internet-explorer/download-ie.aspx href="http://www.microsoft.com/windows/internet-explorer/download-ie.aspx" mce_href="http://www.microsoft.com/windows/internet-explorer/download-ie.aspx"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9489849" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="IE8" scheme="http://blogs.msdn.com/johan/archive/tags/IE8/default.aspx" /></entry><entry><title>Glimpsing 10 years into the future</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/03/09/glimpsing-10-years-into-the-future.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/03/09/glimpsing-10-years-into-the-future.aspx</id><published>2009-03-09T13:58:27Z</published><updated>2009-03-09T13:58:27Z</updated><content type="html">&lt;p&gt;Stephen Elop, the president of Microsoft's Business Division recently held a presentation where he allowed the viewers to glimpse 10 years into the future. It's amazing to look at a &amp;quot;real&amp;quot; interpretation of the future interfaces and technologies rather than the standard hollywood stuff. - You know the holographic projections that for some strange reason still use slow-typing green text on a black background. The video is really inspirational, and what I &lt;em&gt;really&lt;/em&gt; liked was how Stephen, after showing the video, went through all the technologies show in the clip and discussed how they could be accomplished.&lt;/p&gt; &lt;iframe src="http://www.microsoft.com/PressPass/SilverlightApps/videoplayer_3/standalone.aspx?xml=http://www.microsoft.com/winme/0902/1000046/Wharton_Tech_Conference_MBR.asx&amp;amp;r=embed&amp;amp;id=0" frameborder="0" width="350" scrolling="no" height="340"&gt;&lt;/iframe&gt;  &lt;p&gt;If you're in a rush you can skip the first part of the presentation and jump to directly to the video at about 14&amp;#189; minutes. But I really recommend watching the whole thing, especially the final rundown where he discusses the underlying technologies.&lt;/p&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9467642" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Off topic" scheme="http://blogs.msdn.com/johan/archive/tags/Off+topic/default.aspx" /><category term="Future releases" scheme="http://blogs.msdn.com/johan/archive/tags/Future+releases/default.aspx" /></entry><entry><title>Running a scheduled PowerShell script on a pre-Vista OS</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2009/03/05/running-a-scheduled-powershell-script-on-a-pre-vista-os.aspx" /><id>http://blogs.msdn.com/johan/archive/2009/03/05/running-a-scheduled-powershell-script-on-a-pre-vista-os.aspx</id><published>2009-03-05T13:00:50Z</published><updated>2009-03-05T13:00:50Z</updated><content type="html">&lt;p&gt;It's been fun to see the reception that PowerShell has gotten. People are using it for tons of different stuff and the ingenuity in some of the scenarios is quite impressive. There is one thing, however, that you should be aware of. PowerShell is not an ideal candidate for execution through the Task Scheduler.&lt;/p&gt;  &lt;h1&gt;Problem&lt;/h1&gt;  &lt;p&gt;A long-running PowerShell script is being executed using the Task Scheduler. At apparently random intervals the script will fail with a &lt;span class="InlineCode"&gt;System.Management.Automation.PipelineStoppedException&lt;/span&gt;.&lt;/p&gt;  &lt;h1&gt;Cause&lt;/h1&gt;  &lt;p&gt;Looking up the exception on &lt;a href="http://msdn.microsoft.com/en-us/library/system.management.automation.pipelinestoppedexception(VS.85).aspx" target="_blank"&gt;MSDN&lt;/a&gt; might not shed any light on the situation unless you know what is happening.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;The exception thrown when a cmdlet or a Windows PowerShell provider attempts to write to the pipeline or perform a number of other Windows PowerShell operations after the pipeline has been terminated. The pipeline could have been terminated before the call was made or during the call.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;When the Task Scheduler executes a PowerShell script it needs to use the .NET Framework. When running the .NET Framework it uses the console session (Session 0). This problem occurs when someone is logged on to the root console (either physically or using Terminal Services) and logs off &lt;em&gt;while the script is executing&lt;/em&gt;.&lt;/p&gt;  &lt;h1&gt;Repro&lt;/h1&gt;  &lt;p&gt;You can easily reproduce this by creating a small script that sleeps for a while. Schedule the script to run immediately and then log off. To illustrate I've used the following script:&lt;/p&gt;  &lt;div class="SampleCode"&gt;function Main()    &lt;br /&gt;{     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Start-Transcript &amp;quot;C:\Test\Psjob.txt&amp;quot;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 'Start-Sleep'     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Start-Sleep (2*60)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 'Ready'     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Stop-Transcript     &lt;br /&gt;}     &lt;br /&gt;&amp;#160; &lt;br /&gt;Main&lt;/div&gt;  &lt;p&gt;When correctly executed this script will generate a transcript that looks like this:&lt;/p&gt;  &lt;div class="DebugSample"&gt;**********************    &lt;br /&gt;Windows PowerShell Transcript Start     &lt;br /&gt;Start time: 20090305111600     &lt;br /&gt;Username&amp;#160; : DOMAIN\SYSTEM     &lt;br /&gt;Machine&amp;#160;&amp;#160; : MACHINENAME (Microsoft Windows NT 5.2.3790 Service Pack 2)     &lt;br /&gt;**********************     &lt;br /&gt;Transcript started, output file is C:\Test\Psjob.txt     &lt;br /&gt;Start-Sleep     &lt;br /&gt;Ready     &lt;br /&gt;**********************     &lt;br /&gt;Windows PowerShell Transcript End     &lt;br /&gt;End time: 20090305111800     &lt;br /&gt;**********************&lt;/div&gt;  &lt;p&gt;However, if I log off the console while the script is executing I get the following transcript:&lt;/p&gt;  &lt;div class="DebugSample"&gt;**********************    &lt;br /&gt;Windows PowerShell Transcript Start     &lt;br /&gt;Start time: 20090305114300     &lt;br /&gt;Username&amp;#160; : DOMAIN\SYSTEM     &lt;br /&gt;Machine&amp;#160;&amp;#160; : MACHINENAME (Microsoft Windows NT 5.2.3790 Service Pack 2)     &lt;br /&gt;**********************     &lt;br /&gt;Transcript started, output file is C:\Test\Psjob.txt     &lt;br /&gt;Start-Sleep     &lt;br /&gt;**********************     &lt;br /&gt;Windows PowerShell Transcript End     &lt;br /&gt;End time: 20090305114340     &lt;br /&gt;**********************&lt;/div&gt;  &lt;p&gt;As you can see the transcript is properly ended as PowerShell shuts down, but if you look at the output in the middle you'll see that we never write &amp;quot;Ready&amp;quot; to the file. This is because the script was prematurely terminated.&lt;/p&gt;  &lt;h1&gt;Resolution&lt;/h1&gt;  &lt;p&gt;The quick and easy resolution is to upgrade to Vista, Windows Server 2008 or later, since as of Windows Vista the console session is no longer running in Session 0.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9459530" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Misc" scheme="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx" /><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>PowerShell - Managing Feature Delegation in IIS7</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/12/16/powershell-managing-feature-delegation-in-iis7.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/12/16/powershell-managing-feature-delegation-in-iis7.aspx</id><published>2008-12-16T16:51:54Z</published><updated>2008-12-16T16:51:54Z</updated><content type="html">&lt;p&gt;Perhaps you've read my earlier post on &lt;a href="http://blogs.msdn.com/johan/archive/2008/10/02/powershell-advanced-configuration-editing-in-iis7.aspx"&gt;advanced feature delegation&lt;/a&gt; using PowerShell and the &lt;a href="http://learn.iis.net/page.aspx/429/installing-the-iis-70-powershell-provider/"&gt;IIS 7.0 PowerShell Provider&lt;/a&gt;. This could actually be called Part II.&lt;/p&gt;  &lt;p&gt;The previous post was based on a quick question from a premier customer. He is a never-ending source of intriguing questions and I always enjoy his &amp;quot;just one thing&amp;quot;-type of inquiries. They often force you to think a little extra. Anyway, the other day he came with a question, which (as always) seemed simple enough at a first glance. The goal was to set Feature Delegation for SMTP E-mail And Forms Authentication to &amp;quot;Read Only&amp;quot;.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/9225741/original.aspx" /&gt; &lt;/p&gt;  &lt;p&gt;Now, most basic configuration topics have been covered in countless posts, and at first I thought that this shouldn't be so hard. There is, however, a major difference. The SMTP E-mail and Forms Authentication settings are set in the root web.config. Not in applicationhost.config.&lt;/p&gt;  &lt;p&gt;If we open up and compare web.config before, and after we change the setting, we'll notice that the change made by the IIS Manager is adding the following into the root &amp;lt;configuration&amp;gt;-block:&lt;/p&gt;  &lt;div class="DebugSample"&gt;&amp;lt;location path=&amp;quot;&amp;quot; overrideMode=&amp;quot;Deny&amp;quot;&amp;gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;system.net&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;mailSettings&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;smtp&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;network /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;specifiedPickupDirectory /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/smtp&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/mailSettings&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/system.net&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;system.web&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;authentication&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;forms&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;credentials /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/forms&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;passport /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/authentication&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/system.web&amp;gt;     &lt;br /&gt;&amp;lt;/location&amp;gt; &lt;/div&gt;  &lt;p&gt;Okay, so using what we already know from the &lt;a href="http://blogs.msdn.com/johan/archive/2008/10/02/powershell-advanced-configuration-editing-in-iis7.aspx"&gt;old post&lt;/a&gt; we should put together a call that looks something like this:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Set-WebConfiguration &amp;quot;/System.Net/mailSettings/smtp&amp;quot;&amp;#160; -value @{&amp;lt;something... overrideMode=&amp;quot;Deny&amp;quot;, maybe?&amp;gt;} -PSPath IIS:\&lt;/div&gt;  &lt;p&gt;Please note that this is &lt;strong&gt;NOT&lt;/strong&gt; the correct syntax. It is close, but no cigar. What we need to do is:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Correctly set the overrideMode. The above sample is &lt;em&gt;not &lt;/em&gt;the way to do it. &lt;/li&gt;    &lt;li&gt;Make sure the changes are saved to web.config &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So, the final, (and correct,) call to the Set-WebConfiguration cmdlet would look like this:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Set-WebConfiguration //System.Net/mailSettings/smtp -metadata overrideMode -value Deny -PSPath MACHINE/WEBROOT&lt;/div&gt;  &lt;p&gt;The Forms Authentication call would look like this:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Set-WebConfiguration //System.Web/authentication -metadata overrideMode -value Deny -PSPath MACHINE/WEBROOT&lt;/div&gt;  &lt;p&gt;I've searched quite extensively for samples on this and so far I've found none. So I thought &lt;em&gt;someone &lt;/em&gt;should write it down. :)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Happy Holidays! / Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9225881" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="IIS7" scheme="http://blogs.msdn.com/johan/archive/tags/IIS7/default.aspx" /><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>Office Automation</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/10/14/office-automation.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/10/14/office-automation.aspx</id><published>2008-10-14T16:15:30Z</published><updated>2008-10-14T16:15:30Z</updated><content type="html">&lt;p&gt;A very common scenario that keeps sprouting new heads like a hydra is Office Automation. Let me start by saying that this is &lt;strong&gt;not &lt;/strong&gt;supported.&lt;/p&gt;  &lt;p&gt;There is a KB-article number &lt;a href="http://support.microsoft.com/kb/257757/en-us"&gt;257757&lt;/a&gt; discusses this, and clearly states the following:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.&lt;/strong&gt;&lt;/p&gt;  &lt;h1&gt;&lt;strong&gt;Why is this not supported?&lt;/strong&gt;&lt;/h1&gt;  &lt;p&gt;The crucial thing to consider is the fact that Microsoft Office is designed to be an end-user, single client product. Automating Microsoft Office in a client application, using the identity and security context of the logged on client is supported, but unattended execution is not.&lt;/p&gt;  &lt;p&gt;There are a number of things that can go wrong and article &lt;a href="http://support.microsoft.com/kb/257757/en-us"&gt;257757&lt;/a&gt; lists most of them. For arguments sake, let's consider the following scenario:&lt;/p&gt;  &lt;p&gt;Your server application starts up and uses CreateObject to create an instance of MS Word. Word tries to read the settings of the current client and since your application is using the Network Service account this presents an immediate problem. There are, for example, certain methods that rely on a default printer being installed. All this can lead to serious problems. You then need to monitor the server, since Office might show a modal dialogue for some reason. The &amp;quot;install on first use&amp;quot; feature of MSI might also kick in, prompting the client to install additional features. All this would hang the current thread. Also, running one instance of Word, might be okay, but what happens when you get 100 more or less concurrent requests and each request starts up an instance of Word? MS Word is not a server, it's an excellent piece of single-client software.&lt;/p&gt;  &lt;h1&gt;So what should I do instead?&lt;/h1&gt;  &lt;p&gt;Actually, most of your problems can be resolved using HTML. I've seen applications where lines and lines of complex code were used for generating an Excel document, when it could just as well have been made using a standard HTML-table. Excel would have no problems whatsoever reading a table like the one below:&lt;/p&gt;  &lt;div class="SampleCode"&gt;&amp;lt;table&amp;gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;&amp;lt;b&amp;gt;Person&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;&amp;lt;b&amp;gt;Age&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;Pete&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;Claire&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;40&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;tr&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;Average age&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;td&amp;gt;=AVERAGE(B2:B3)&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/tr&amp;gt;     &lt;br /&gt;&amp;lt;/table&amp;gt;&lt;/div&gt;  &lt;p&gt;As you can see all formatting, and even the functions, would be interpreted correctly.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/8999380/original.aspx" /&gt; &lt;/p&gt;  &lt;p&gt;Obviously Word is great with HTML as well, so most formatting issues can quite easily be resolved using this approach.&lt;/p&gt;  &lt;h2&gt;So how do I do this?&lt;/h2&gt;  &lt;p&gt;The solution is quite easy. In order to generate an Excel document all you need to do is to create a table with the data you want, and add the following two lines to the Page_Load event of your page:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Response.ContentType = &amp;quot;application/vnd.ms-excel&amp;quot;;    &lt;br /&gt;Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;attachment; filename=Data.xls;&amp;quot;);&lt;/div&gt;  &lt;p&gt;The first line, sets the returned ContentType to Excel, and the second changes the filename of the returned file. This means that the client will be prompted to Open/Save the file, and the filename will be set to &amp;quot;Data.xls&amp;quot; rather than &amp;quot;Default.aspx&amp;quot; (or whatever your original document may be called.)&lt;/p&gt;  &lt;p&gt;If you wanted to return a word document you'd set the ContentType to &amp;quot;application/msword&amp;quot; instead.&lt;/p&gt;  &lt;p&gt;One little thing to consider is the fact that by default you're probably adding a lot of redundant information to your webpage. You might want to remove all excessive HTML from the page so that you remove all unnecessary headers, stylesheets, viewstate, etc. For an example, please consider the code below:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Response.Clear();    &lt;br /&gt;Response.Buffer = true;     &lt;br /&gt;Response.ContentType = &amp;quot;application/vnd.ms-excel&amp;quot;;     &lt;br /&gt;Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;attachment; filename=Data.xls;&amp;quot;);     &lt;br /&gt;this.EnableViewState = false;     &lt;br /&gt;System.IO.StringWriter oSw = new System.IO.StringWriter();     &lt;br /&gt;System.Web.UI.HtmlTextWriter oHtml = new System.Web.UI.HtmlTextWriter(oSw);     &lt;br /&gt;Table oTable = new Table();     &lt;br /&gt;for (int ctr = 1; ctr &amp;lt;= 10; ctr++)     &lt;br /&gt;{     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TableRow oRow = new TableRow();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TableCell oCell1 = new TableCell();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; oCell1.Text = ctr.ToString();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TableCell oCell2 = new TableCell();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; oCell2.Text = (ctr*10).ToString();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; oRow.Cells.Add(oCell1);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; oRow.Cells.Add(oCell2);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; oTable.Rows.Add(oRow);     &lt;br /&gt;}     &lt;br /&gt;oTable.RenderControl(oHtml);     &lt;br /&gt;Response.Write(oSw.ToString());     &lt;br /&gt;Response.End();&lt;/div&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Security issues in Office 2007&lt;/h2&gt;  &lt;p&gt;If you're running Office 2007 you might come across the following error message:&lt;/p&gt;  &lt;p&gt;&amp;quot;The file you are trying to open, 'Data.xls', is in a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Do you want to open the file now?&lt;/p&gt;  &lt;p&gt;&amp;lt;Yes&amp;gt; &amp;lt;No&amp;gt; &amp;lt;Help&amp;gt;&lt;/p&gt;  &lt;p&gt;This is completely by design. In this example Excel has noticed that though the file is named .xls it does in fact contain html, so it's warning us about this inconsistency. We might bypass this by actually changing the file extension to htm or, perhaps saving the data as comma separated values (csv) which Excel also supports, but both options would be opened directly in the browser rather than passed on to Excel, so this is a design consideration we have to take into account.&lt;/p&gt;  &lt;p&gt;There is really no way of bypassing this security feature other than manually disabling it, client-side, using a registry hack. (The key is &lt;span class="InlineCode"&gt;HKCU\Software\Microsoft\Office\12.0\Excel\Security\&lt;/span&gt; Add a DWORD named &lt;span class="InlineCode"&gt;xtensionHardening&lt;/span&gt; and set it to 0.) For obvious reasons this is not something that is generally recommended.&lt;/p&gt;  &lt;h2&gt;Other options&lt;/h2&gt;  &lt;p&gt;There are also third-party products available for generating MS Office-compatible documents, but there are also some articles in the knowledge base on the subject. For example this little gem which can easily be adopted to ASP.NET as well:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://support.microsoft.com/kb/270906/en-us"&gt;How to use ASP to generate a Rich Text Format (RTF) document to stream to Microsoft Word&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8999436" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Misc" scheme="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx" /><category term="ASP.NET" scheme="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx" /><category term="Automation" scheme="http://blogs.msdn.com/johan/archive/tags/Automation/default.aspx" /><category term="Office" scheme="http://blogs.msdn.com/johan/archive/tags/Office/default.aspx" /></entry><entry><title>PowerShell - Advanced configuration editing in IIS7</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/10/02/powershell-advanced-configuration-editing-in-iis7.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/10/02/powershell-advanced-configuration-editing-in-iis7.aspx</id><published>2008-10-02T16:28:18Z</published><updated>2008-10-02T16:28:18Z</updated><content type="html">&lt;p&gt;I've written a lot of PowerShell posts lately and here's another one. :-)&lt;/p&gt;  &lt;p&gt;I got a question from one of the account managers if it was possible to alter the FTP Authorization Rules for a specific folder on his IIS.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/8973271/original.aspx" /&gt; &lt;/p&gt;  &lt;p&gt;The appcmd for the operation was&lt;/p&gt;  &lt;p&gt;&lt;span class="InlineCode"&gt;appcmd.exe set config &amp;quot;FTPFolder&amp;quot; -section:system.ftpServer/security/authorization /+&amp;quot;[accessType='Allow',users='*',roles='*',permissions='Read, Write']&amp;quot; /commit:apphost&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span class="InlineCode"&gt;&lt;/span&gt;He wanted to know if there was a PowerShell equivalent. Sure, you could use the appcmd directly from powershell, but if you're going to use the command line for everything, then what's the use of PowerShell?&lt;/p&gt;  &lt;p&gt;The section in applicationhost.config that we want to edit is the following:&lt;/p&gt;  &lt;div class="DebugSample"&gt;&amp;lt;location path=&amp;quot;FTPFolder&amp;quot;&amp;gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;system.ftpServer&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;security&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;authorization&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;add accessType=&amp;quot;Allow&amp;quot; users=&amp;quot;?&amp;quot; permissions=&amp;quot;Read, Write&amp;quot; /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/authorization&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/security&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/system.ftpServer&amp;gt;     &lt;br /&gt;&amp;lt;/location&amp;gt;&lt;/div&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;System Specs&lt;/h2&gt;  &lt;p&gt;As you might have noticed from the screenshots already he was Running Windows 2008 with &lt;a href="http://learn.iis.net/page.aspx/263/installing-and-troubleshooting-ftp7/"&gt;FTP 7&lt;/a&gt; installed. He also had the &lt;a href="http://learn.iis.net/page.aspx/429/installing-the-iis-70-powershell-provider/"&gt;IIS 7.0 PowerShell Provider&lt;/a&gt; installed.&lt;/p&gt;  &lt;h1&gt;Troubleshooting&lt;/h1&gt;  &lt;p&gt;There are a lot of cool things you can do with the WebSites using the IIS7 PowerShell provider. Below is a sample copied from &lt;a href="http://learn.iis.net/page.aspx/436/changing-simple-configuration-settings-in-configuration-sections/"&gt;iis.net&lt;/a&gt;. To use it properly, go to an IIS directory such as IIS:\DemoSite\DemoApp:&lt;/p&gt;  &lt;div class="SampleCode"&gt;$winAuth = Get-WebConfiguration -filter /system.webServer/security/authentication/windowsAuthentication    &lt;br /&gt;$winAuth.enabled = $false     &lt;br /&gt;$winAuth | set-Webconfiguration -filter /system.webServer/security/authentication/windowsAuthentication -PSPath IIS:\ -location &amp;quot;DemoSite/DemoApp&amp;quot;     &lt;br /&gt;&lt;/div&gt;  &lt;p&gt;So judging from the sample above we should simply have to set anonymousAuthentication.enabled = $true or something like that. Unfortunately this isn't the case. If you try to access the section of applicationhost.config that we're attempting to edit (see above) you will see that we don't have any applicable properties for the object. &lt;span class="InlineCode"&gt;$ftpAuth = Get-WebConfiguration -filter /system.ftpServer/security/authorization&lt;/span&gt; will not throw any exceptions, but using TAB to cycle through the properties of $ftpAuth will show us no immediate properties or methods of use. &lt;/p&gt;  &lt;h1&gt;Solution&lt;/h1&gt;  &lt;p&gt;The solution in this scenario is to use the Add-WebConfiguration cmdlet. The applicationhost.config can easily be translated to a valid Add-WebConfiguration call:&lt;/p&gt;  &lt;div class="SampleCode"&gt;Add-WebConfiguration &amp;quot;/system.ftpServer/security/authorization&amp;quot;&amp;#160; -value @{accessType=&amp;quot;Allow&amp;quot;;users=&amp;quot;?&amp;quot;;permissions=3} -PSPath IIS:\ -location FTPFolder&lt;/div&gt;  &lt;p&gt;The only thing that sticks out as being out of the ordinary is the permissions=3 setting. Why isn't it &amp;quot;Read, Write&amp;quot;? Actually, passing &amp;quot;Read, Write&amp;quot; as a parameter will not work. It will leave the permissions setting blank. &amp;quot;Read&amp;quot; or &amp;quot;Write&amp;quot; &lt;em&gt;only&lt;/em&gt; will work, but not both together. I've tried figuring out if there's a valid way of passing both arguments, but so far I've drawn blanks. I've tried putting them in an array {&amp;quot;Read&amp;quot;;&amp;quot;Write&amp;quot;}, passing them as &amp;quot;ReadWrite&amp;quot;, &amp;quot;Read;Write&amp;quot;, &amp;quot;Read+Write&amp;quot; etc. but the only way I've found so far is to pass the value 3 which is the obvious sum of the two enum values for Read and Write.&lt;/p&gt;  &lt;p&gt;Later! / Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8973569" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="IIS7" scheme="http://blogs.msdn.com/johan/archive/tags/IIS7/default.aspx" /><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>PowerShell - Editing permissions on a file or folder</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/10/01/powershell-editing-permissions-on-a-file-or-folder.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/10/01/powershell-editing-permissions-on-a-file-or-folder.aspx</id><published>2008-10-01T15:52:49Z</published><updated>2008-10-01T15:52:49Z</updated><content type="html">&lt;p&gt;I got the following question from a reader the other day:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;I've been trying to figure out how to change permissions on a folder in PowerShell. I've looked at the Get-Acl and Set-Acl, but I can only use them to copy the settings from a pre-existing object. How do I manually configure permissions?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;This is actually a quite common question, so I thought I'd write a quick post on the subject.&lt;/p&gt;  &lt;h1&gt;Get-Acl and Set-Acl&lt;/h1&gt;  &lt;p&gt;To quote the PowerShell documentation &amp;quot;Get-Acl &lt;em&gt;gets&lt;/em&gt; the security descriptor for a resource, such as a file or registry key.&amp;quot; while &amp;quot;Set-Acl &lt;em&gt;changes&lt;/em&gt; the security descriptor of a specified resource, such as a file or a registry key.&amp;quot; In other words; if you want Folder_A to have the exact same permissions as Folder_B, then you simply copy the Access Control List (ACL) of Folder_B and &amp;quot;paste&amp;quot; it onto Folder_A.&lt;/p&gt;  &lt;div class="SampleCode"&gt;   &lt;pre&gt;$Acl = Get-Acl &amp;quot;C:\Folder_B&amp;quot;
Set-Acl &amp;quot;C:\Folder_A&amp;quot; $Acl&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So far, so good.&lt;/p&gt;

&lt;h1&gt;Changing the ACL&lt;/h1&gt;

&lt;p&gt;Okay, so you want to change the ACL. Here's some sample code for how to do that:&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;New-Item -type directory -path C:\MyFolder
$Acl = Get-Acl &amp;quot;C:\MyFolder&amp;quot;
$Ar = New-Object  system.security.accesscontrol.filesystemaccessrule(&amp;quot;username&amp;quot;,&amp;quot;FullControl&amp;quot;,&amp;quot;Allow&amp;quot;)
$Acl.SetAccessRule($Ar)
Set-Acl &amp;quot;C:\MyFolder&amp;quot; $Acl&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, first we create a new folder. We then copy the ACL of that folder. We then create a new AccessRule that gives &amp;quot;username&amp;quot; full control. We then add this AccessRule to the ACL, and finally we reapply the new, altered ACL to the folder.&lt;/p&gt;

&lt;p&gt;If we wanted to we could also have used &lt;span class="InlineCode"&gt;$Acl.RemoveAccessRule($Ar)&lt;/span&gt; or possibly &lt;span class="InlineCode"&gt;$Acl.RemoveAccessRuleAll()&lt;/span&gt; as well.&lt;/p&gt;

&lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8971522" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Script" scheme="http://blogs.msdn.com/johan/archive/tags/Script/default.aspx" /><category term="Sample Code" scheme="http://blogs.msdn.com/johan/archive/tags/Sample+Code/default.aspx" /><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>PowerShell - Automatically organizing your mp3-collection</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/09/23/powershell-automatically-organizing-your-mp3-collection.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/09/23/powershell-automatically-organizing-your-mp3-collection.aspx</id><published>2008-09-23T14:53:23Z</published><updated>2008-09-23T14:53:23Z</updated><content type="html">&lt;p&gt;Is your mp3-collection perfectly sorted? I know mine wasn't. I thought I'd address that while creating a pretty good demo-script to show some basic filtering, script structures, etc. Since I also wanted the script to extract the metadata from every file in my collection I had to use the Shell.Application Com-object as well. All in all I think it turned out pretty well.&lt;/p&gt;  &lt;p&gt;NOTE:&lt;/p&gt;  &lt;p&gt;This script is provided completely as is. It is not an official product in any way and I take no responsibility for any harm it may cause.&lt;/p&gt;  &lt;p&gt;Please note that certain metadata editors that integrate directly into the Shell may cause some severe confusion in the metadata, so I'd recommend disabling them before trying. Off course I would also recommend making a backup copy of the music library before surrendering it to the mercy of PowerShell.&lt;/p&gt;  &lt;p&gt;If you're new to PowerShell and haven't done so already I'd recommend looking at my earlier posts on the subject:    &lt;br /&gt;&lt;a href="http://blogs.msdn.com/johan/archive/2008/05/28/powershell-an-introduction-part-i.aspx"&gt;PowerShell - An introduction, Part I&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://blogs.msdn.com/johan/archive/2008/08/25/powershell-an-introduction-part-ii.aspx"&gt;PowerShell - An introduction, Part II&lt;/a&gt;&lt;/p&gt;  &lt;h1&gt;The script    &lt;br /&gt;&lt;/h1&gt;  &lt;div class="SampleCode"&gt;   &lt;pre&gt;Param([String] $Folder)
$INVALIDCHARS = [System.IO.Path]::GetInvalidPathChars() + &amp;quot;/&amp;quot;, &amp;quot;\&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;?&amp;quot;, &amp;quot;:&amp;quot;
$MUSICATTRIBS = &amp;quot;*.m4a&amp;quot;, &amp;quot;*.m4b&amp;quot;, &amp;quot;*.mp3&amp;quot;, &amp;quot;*.mp4&amp;quot;, &amp;quot;*.wma&amp;quot;, &amp;quot;*.flc&amp;quot;
$PLAYLISTATTRIBS = &amp;quot;*.m3u&amp;quot;, &amp;quot;*.zpl&amp;quot;
$ALLATTRIBS = $MUSICATTRIBS + $PLAYLISTATTRIBS&lt;br /&gt;$PLAYLISTSFOLDER = &amp;quot;Playlists&amp;quot;
$objShell = New-Object -ComObject Shell.Application
$iTotalFiles = 0
$iCurrentFile = 0

function checkFolderName($FolderName)
{
	&lt;font color="#00ff00"&gt;&lt;font color="#008000"&gt;# Make sure the folder doesn't contain any invalid characters&lt;/font&gt;
&lt;/font&gt;
	if(!$FolderName) { $FolderName = &amp;quot;Unknown&amp;quot; }
	$INVALIDCHARS | % {$FolderName = $FolderName.replace($_, &amp;quot;&amp;quot;)}
	return $FolderName
}



function MoveFiles($startDir)
{
	Write-Host &amp;quot;Indexing playlists...&amp;quot;
	
	&lt;font color="#008000"&gt;# Do a recursive DIR in the starting directory, include everything with the attributes of a playlist.
	# Filter the result by excluding everything that is a Container (folder)
&lt;/font&gt;	$dirResult = get-childitem -force -path $startDir -recurse -include $PLAYLISTATTRIBS | where{! $_.PSIsContainer}
	if($dirResult)
	{
		Write-Host &amp;quot;Moving playlists...&amp;quot;

		foreach($dirItem in $dirResult)
		{
			move-item $dirItem.FullName ($PLAYLISTSFOLDER + &amp;quot;\&amp;quot; + $dirItem.Name)
		}
	}
	Write-Host &amp;quot;Indexing music...&amp;quot;

&lt;font color="#008000"&gt;	# Do a recursive DIR in the starting directory, include everything with the attributes of a music file.
	# Again we filter the result by excluding everything that is a Container.
&lt;/font&gt;	$dirResult = get-childitem -force -path $startDir -recurse -include $MUSICATTRIBS | where{! $_.PSIsContainer}
	
&lt;font color="#008000"&gt;	# Make a note of how many hits we got, so we can show the progress to the client.
&lt;/font&gt;	$iTotalFiles = $dirResult.Count
	if($dirResult)
	{
		foreach($dirItem in $dirResult)
		{
&lt;font color="#008000"&gt;			# Up the counter for how many files we've processed so that we can show progress
&lt;/font&gt;			$iCurrentFile +=1

&lt;font color="#008000"&gt;			# Get the metadata for the file
&lt;/font&gt;			$fileData = getMP3MetaData($dirItem.FullName)
			
&lt;font color="#008000"&gt;			# Find the path where we the song should be stored
&lt;/font&gt;			$ArtistPath = $fileData[&amp;quot;Album Artist&amp;quot;]
			if (!$ArtistPath) { $ArtistPath = $fileData[&amp;quot;Artists&amp;quot;] }
			if (!$ArtistPath) { $ArtistName = &amp;quot;Unknown&amp;quot; }

&lt;font color="#008000"&gt;			# Make shure it's a valid path
&lt;/font&gt;			$ArtistPath = checkFolderName($ArtistPath)
			$AlbumPath = checkFolderName($fileData.Album)
			$ArtistPath = join-path $startDir $ArtistPath 
			$AlbumPath = join-path $ArtistPath $AlbumPath

&lt;font color="#008000"&gt;			# Check if the file should be moved
&lt;/font&gt;			if($dirItem.DirectoryName -ne $AlbumPath)
			{
				if(!(test-path $ArtistPath)) &lt;font color="#008000"&gt;# If the Artist folder doesn't exist
&lt;/font&gt;				{
					MKDIR $ArtistPath | out-null
				}
				if(!(test-path $AlbumPath)) &lt;font color="#008000"&gt;# If the Album folder doesn't exist&lt;/font&gt;
				{
					MKDIR $AlbumPath | out-null
				}
				move-item $dirItem.FullName ($AlbumPath + &amp;quot;\&amp;quot; + $dirItem.Name)
			}

&lt;font color="#008000"&gt;			# Show progress
&lt;/font&gt;			$percentage = ([int](($iCurrentFile / $iTotalFiles)*100))
			cls
			Write-Host &amp;quot;$percentage% ($iCurrentFile files of $iTotalFiles) complete&amp;quot;
		}
	}
}


function removeEmptyFolders($startDir)
{
&lt;font color="#008000"&gt;	# Get all folders and subfolders
&lt;/font&gt;	$dirResult = Get-childitem $startDir -recurse | where{$_.PSIsContainer}
	if($dirResult)
	{
		foreach($dirItem in $dirResult)
		{
&lt;font color="#008000"&gt;			# If the folder is empty (Doesn't contain any music or playlists) it should be deleted
&lt;/font&gt;			if(isfolderempty($dirItem.FullName))
			{
&lt;font color="#008000"&gt;				# Check if the path is still valid, we may have deleted the folder already recursively.
&lt;/font&gt;				if(Test-Path $dirItem.FullName)
				{
					remove-item -path $dirItem.FullName -force -recurse
				}
			}
		}
	}
}

function removeOtherFiles($startDir)
{
&lt;font color="#008000"&gt;	# Get all non-music files (except *.jpg-files) and remove them 
&lt;/font&gt;	$dirResult = Get-childitem $startDir -recurse -exclude ($ALLATTRIBS + &amp;quot;*.jpg&amp;quot;) | where{! $_.PSIsContainer}
	if($dirResult)
	{
		foreach($dirItem in $dirResult)
		{
			if(Test-Path $dirItem.FullName)
			{
&lt;font color="#008000"&gt;				# Make sure the file still exists, and hasn't been deleted already
&lt;/font&gt;				remove-item -path $dirItem.FullName -force
			}
		}
	}
}

function isFolderEmpty($folderPath)
{
&lt;font color="#008000"&gt;	# Search for any remaining music items in the folder.&lt;/font&gt;
	if(Test-Path $folderPath)
	{
		$dirChildren = get-childitem -force -path $folderPath -recurse -include $ALLATTRIBS | where{! $_.PSIsContainer}
		if($dirChildren -ne $null)
		{
			return $false
		}
		else
		{
			return $true
		}
	}
	else
	{
&lt;font color="#008000"&gt;		# No use trying to delete the folder if it doesn't exist
&lt;/font&gt;		return $false
	}
}

function getMP3MetaData($path)
{
&lt;font color="#008000"&gt;	# Get the file name, and the folder it exists in
&lt;/font&gt;	$file = split-path $path -leaf
	$path = split-path $path
	$objFolder = $objShell.namespace($path)
	$objFile = $objFolder.parsename($file)
	$result = @{}
	0..266 | % {
		if ($objFolder.getDetailsOf($objFile, $_))
		{
			$result[$($objFolder.getDetailsOf($objFolder.items, $_))] = $objFolder.getDetailsOf($objFile, $_)
		}
	}
	return $result
}

&lt;font color="#008000"&gt;# MAIN FUNCTION&lt;/font&gt;

&lt;font color="#008000"&gt;# If no argument was passed, see if anything was piped to the function instead.&lt;/font&gt;
if (!$Folder)
{
	$input | % { $Folder = $_ }
}

&lt;font color="#008000"&gt;# Check if the path is valid, if not reset it to &amp;quot;&amp;quot;&lt;/font&gt;
if ($Folder) { if (!(Test-Path -path $Folder)) { $Folder = &amp;quot;&amp;quot; }}

&lt;font color="#008000"&gt;# Since no valid path was given, prompt the user for a proper path.&lt;/font&gt;
while (!$Folder)
{
	&amp;quot;Please enter the full path to the folder where you wish to rearrange your MP3's&amp;quot;
	$Folder = Read-Host
	if ($Folder) { if (!(Test-Path -path $Folder)) { $Folder = &amp;quot;&amp;quot; }}
}

&lt;font color="#008000"&gt;# Make sure we have a folder to store the playlists in.&lt;/font&gt;
$PLAYLISTSFOLDER = join-path $Folder $PLAYLISTSFOLDER
if(!(test-path $PLAYLISTSFOLDER)) # If the Playlists folder doesn't exist
{
	MKDIR $PLAYLISTSFOLDER | out-null
}

&lt;font color="#008000"&gt;# Now that everything is ready, begin rearranging the files.&lt;/font&gt;
MoveFiles($Folder)
removeEmptyFolders($Folder)
removeOtherFiles($Folder)&lt;/pre&gt;
&lt;/div&gt;

&lt;h1&gt;&amp;#160;&lt;/h1&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;Running the script&lt;/h1&gt;

&lt;p&gt;So, how do you run this script?&lt;/p&gt;

&lt;p&gt;It's quite easy. The first step would be to copy it into notepad save it with a .ps1 extension and open up PowerShell&lt;/p&gt;

&lt;h2&gt;Execution policy&lt;/h2&gt;

&lt;p&gt;If this is the first time you try to execute a script from PowerShell you will most likely have to change the execution policy for PowerShell. I'd recommend setting it to RemoteSigned. This (obviously) means that all remote scripts must be signed or PowerShell will refuse to execute them. To change the execution policy simply type:&lt;/p&gt;

&lt;div class="SampleCode"&gt;Set-ExecutionPolicy RemoteSigned&lt;/div&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;If you're uncertain what your execution policy setting is you simply type:&lt;/p&gt;

&lt;div class="SampleCode"&gt;Get-ExecutionPolicy&lt;/div&gt;

&lt;p&gt;Okay, having changed that we can now execute the script. If you saved the script in a folder that is in your system path you only need to type the filename of the .ps1 file. (The .ps1 is optional) So, if you saved it as RearrangeMP3s.ps1 you'd write &lt;span class="InlineCode"&gt;RearrangeMP3s&lt;/span&gt; and press enter &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h1&gt;Breakdown&lt;/h1&gt;

&lt;p&gt;Okay, so let's take a look at the separate parts of the script.&lt;/p&gt;

&lt;h2&gt;Initial variables and constants&lt;/h2&gt;

&lt;p&gt;First we declare the parameters we're going to use. In this case it's just one: $Folder.&lt;/p&gt;

&lt;p&gt;After that we have some constants. You may want to change $MUSICATTRIBS or $PLAYLISTATTRIBS to include, or remove, extensions based on your needs. $PLAYLISTSFOLDER is a constant which indicates in which subfolder you wish to store your playlists.&lt;/p&gt;

&lt;p&gt;Finally we have some variables. $objShell is used for file system operations, and rather than creating a new object all the time I'd rather have a global one. $iTotalFiles and $iCurrentFile are two integers used to create a progress indicator.&lt;/p&gt;

&lt;h2&gt;Functions&lt;/h2&gt;

&lt;p&gt;After the initial variables come the sub functions called by the main function. To see what each individual function does I'd recommend looking at the comments. I've prioritized readability over minimum number of keystrokes, so yes, instead of writing:&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;foreach($dirItem in $dirResult)
{
	move-item $dirItem.FullName ($PLAYLISTSFOLDER + &amp;quot;\&amp;quot; + $dirItem.Name)
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;I could have written&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;$dirResult | % { mv $_.FullName ($PLAYLISTSFOLDER + &amp;quot;\&amp;quot; + $_.Name) }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;But in this case I think that would have been counterproductive.&lt;/p&gt;

&lt;h2&gt;The main function&lt;/h2&gt;

&lt;p&gt;Finally we have the main function. It is written last in the script. Why is that? Well, actually PowerShell is the most sequential language you'll ever come across. It will not bother to check the entire script for function declarations. Instead it will go through the script one line at a time. This means that the following script will not work:&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;SayHello

function SayHello
{
	Write-Host &amp;quot;Hello World&amp;quot;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When you call SayHello in the sample above the function has not yet been declared, so PowerShell will throw an exception in your face saying that SayHello is unrecognized.&lt;/p&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;Footnote&lt;/h1&gt;

&lt;p&gt;There is actually a &lt;em&gt;supported&lt;/em&gt; way of achieving the very same thing, but where's the fun in that?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Open up Windows Media Player&lt;/li&gt;

  &lt;li&gt;Go to Options -&amp;gt; Library and tick the checkbox for &amp;quot;Rearrange music in rip folder&amp;quot;&lt;/li&gt;

  &lt;li&gt;Go to the &amp;quot;Rip Music&amp;quot;-tab&lt;/li&gt;

  &lt;li&gt;Make sure the path is correct in the &amp;quot;Rip music to this location&amp;quot;-section&lt;/li&gt;

  &lt;li&gt;Click OK&lt;/li&gt;

  &lt;li&gt;Select &lt;em&gt;all&lt;/em&gt; files in the library&lt;/li&gt;

  &lt;li&gt;Right-click and choose the &amp;quot;Advanced Tag Editor&amp;quot;-option&lt;/li&gt;

  &lt;li&gt;Do not change anything. Simply click Apply&lt;/li&gt;

  &lt;li&gt;Windows Media Player will now rearrange all the files using your Rip settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8962147" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Script" scheme="http://blogs.msdn.com/johan/archive/tags/Script/default.aspx" /><category term="Sample Code" scheme="http://blogs.msdn.com/johan/archive/tags/Sample+Code/default.aspx" /><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>PowerShell - An introduction, Part II</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/08/25/powershell-an-introduction-part-ii.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/08/25/powershell-an-introduction-part-ii.aspx</id><published>2008-08-25T14:22:12Z</published><updated>2008-08-25T14:22:12Z</updated><content type="html">&lt;p&gt;This is a continuation of &lt;a href="http://blogs.msdn.com/johan/archive/2008/05/28/powershell-an-introduction-part-i.aspx"&gt;part I&lt;/a&gt;. If you haven't read it I suggest at least going through the summary at the end of the post.&lt;/p&gt;  &lt;h1&gt;Working with Drives&lt;/h1&gt;  &lt;p&gt;In your basic command prompt you have the normal file system drives that you use to access your hard-drive, floppy, DVD, USB-stick, network shares etc. PowerShell uses this established interface to access other data sources as well. The following providers are accessible by default through drives in PowerShell 1.0:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Registry (HKLM: or HKCU:) &lt;/li&gt;    &lt;li&gt;Certificate store (Cert:) &lt;/li&gt;    &lt;li&gt;Environment variables (Env:) &lt;/li&gt;    &lt;li&gt;Aliases (Alias:) &lt;/li&gt;    &lt;li&gt;Functions (Function:) &lt;/li&gt;    &lt;li&gt;Variables (Variable:) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;When you install extensions for like the one fore IIS, etc. you usually get another drive accessible where you can look at the current webapplications and check their properties.&lt;/p&gt;  &lt;h2&gt;Navigating&lt;/h2&gt;  &lt;p&gt;Selecting one of the PowerShell drives is easy. It is &lt;em&gt;almost&lt;/em&gt; like in MS-DOS.&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt;CD HKLM:    &lt;br /&gt;PS HKLM:\&amp;gt; DIR&lt;/div&gt;  &lt;p&gt;You can use the same commands as you'd do in MS-DOS, such as CD, DIR, MKDIR, etc.&lt;/p&gt;  &lt;p&gt;To get a certain property for a registry key, (or a regular folder for that matter) you use the Get-ItemProperty cmdlet.&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS HKLM:\&amp;gt; CD system    &lt;br /&gt;PS HKLM:\system&amp;gt; CD CurrentControlSet\Control     &lt;br /&gt;PS HKLM:\system\CurrentControlSet\Control&amp;gt; Get-ItemProperty CrashControl     &lt;br /&gt;&amp;#160; &lt;br /&gt;PSPath&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\system\CurrentControlSet\Control\CrashControl     &lt;br /&gt;PSParentPath&amp;#160;&amp;#160;&amp;#160;&amp;#160; : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\system\CurrentControlSet\Control     &lt;br /&gt;PSChildName&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : CrashControl     &lt;br /&gt;PSDrive&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : HKLM     &lt;br /&gt;PSProvider&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : Microsoft.PowerShell.Core\Registry     &lt;br /&gt;AutoReboot&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 1     &lt;br /&gt;CrashDumpEnabled : 2     &lt;br /&gt;Overwrite&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 1     &lt;br /&gt;LogEvent&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 1     &lt;br /&gt;DumpFile&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : C:\Windows\MEMORY.DMP     &lt;br /&gt;MinidumpDir&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : C:\Windows\Minidump&lt;/div&gt;  &lt;p&gt;All in all it's more or less the same working with Aliases or Environment variables. Note the following difference in output, though:&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS Env:\&amp;gt; Dir Env:PROCESSOR_ARCHITECTURE    &lt;br /&gt;&amp;#160; &lt;br /&gt;Name&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Value     &lt;br /&gt;----&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; -----     &lt;br /&gt;PROCESSOR_ARCHITECTURE&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; AMD64     &lt;br /&gt;&amp;#160; &lt;br /&gt;PS Env:\&amp;gt; $Env:PROCESSOR_ARCHITECTURE     &lt;br /&gt;AMD64     &lt;br /&gt;PS Env:\&amp;gt;&lt;/div&gt;  &lt;p&gt;Did you note how putting a $-sign before the variable name gave us the value of the variable instead of a complete object? This brings us quite nicely to the subject of variables.&lt;/p&gt;  &lt;h1&gt;Variables&lt;/h1&gt;  &lt;p&gt;Variables aren't that tricky to work with. They do not need to be pre-initiated. They do, however, require a $ to be identified as variables. Otherwise you get the following error message:&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $Name = &amp;quot;Johan&amp;quot;    &lt;br /&gt;PS C:\&amp;gt; Name = &amp;quot;Johan&amp;quot;     &lt;br /&gt;&lt;font color="#ff0000"&gt;The term 'Name' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again.      &lt;br /&gt;At line:1 char:5       &lt;br /&gt;+ Name&amp;#160; &amp;lt;&amp;lt;&amp;lt;&amp;lt; = &amp;quot;Johan&amp;quot;&lt;/font&gt;     &lt;br /&gt;PS C:\&amp;gt;&lt;/div&gt;  &lt;p&gt;To display the value of a variable you simply type the name of the variable and PowerShell kindly returns the contents&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $Name    &lt;br /&gt;Johan&lt;/div&gt;  &lt;p&gt;When it comes to strings, you can choose for yourself if you want to use double quotes or single quotes, but there is one minor difference: &lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $str1 = &amp;quot;Hello&amp;quot;    &lt;br /&gt;PS C:\&amp;gt; $str2 = &amp;quot;World!&amp;quot;     &lt;br /&gt;PS C:\&amp;gt; $strCombo1 = &amp;quot;$str1 $str2&amp;quot;     &lt;br /&gt;PS C:\&amp;gt; $strCombo2 = '$str1 $str2'     &lt;br /&gt;PS C:\&amp;gt; $strCombo1     &lt;br /&gt;Hello World!     &lt;br /&gt;PS C:\&amp;gt; $strCombo2     &lt;br /&gt;$str1 $str2     &lt;br /&gt;PS C:\&amp;gt; &lt;/div&gt;  &lt;p&gt;As you can see, a variable within double quotes will be evaluated, while within single quotes it will be interpreted literally.&lt;/p&gt;  &lt;p&gt;Apart from strings you can also store integers and dates. Integers do not need delimiters and dates are most easily created using the Get-Date function&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $birthday = 11/15/1973&lt;/div&gt;  &lt;h1&gt;&amp;#160;&lt;/h1&gt;  &lt;h1&gt;Arrays&lt;/h1&gt;  &lt;p&gt;Declaring Arrays is a breeze. PowerShell will automatically &lt;em&gt;Split&lt;/em&gt; any comma-separated sequence of values so creating a arrays is as easy as this:&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $Colors = &amp;quot;Red&amp;quot;, &amp;quot;Green&amp;quot;, &amp;quot;Blue&amp;quot;&lt;/div&gt;  &lt;p&gt;The arrays are also dynamic by default, so adding values to them is a simple matter as well.&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $Colors += &amp;quot;Cyan&amp;quot;, &amp;quot;Magenta&amp;quot;, &amp;quot;Yellow&amp;quot;&lt;/div&gt;  &lt;p&gt;Creating two-dimensional arrays are done by declaring each row of the array as a one-dimensional array and then adding them to &lt;em&gt;another&lt;/em&gt; array:&lt;/p&gt;  &lt;div class="SampleCode"&gt;PS C:\&amp;gt; $arr1 = 1, 2, 3    &lt;br /&gt;PS C:\&amp;gt; $arr2 = &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;     &lt;br /&gt;PS C:\&amp;gt; $arr3 = $arr1, $arr2     &lt;br /&gt;PS C:\&amp;gt; $arr3[0][0]     &lt;br /&gt;1     &lt;br /&gt;PS C:\&amp;gt; $arr3[1][1]     &lt;br /&gt;B     &lt;br /&gt;PS C:\&amp;gt;&lt;/div&gt;  &lt;h1&gt;&amp;#160;&lt;/h1&gt;  &lt;h1&gt;User input &lt;/h1&gt;  &lt;p&gt;Finally, to get dynamic user input you can use the Read-Host cmdlet.&lt;/p&gt;  &lt;div class="SampleCode"&gt;$Name = Read-Host &amp;quot;What is your name?&amp;quot;&lt;/div&gt;  &lt;h1&gt;&amp;#160;&lt;/h1&gt;  &lt;h1&gt;Summary&lt;/h1&gt;  &lt;p&gt;Okay, so to summarize we have now covered the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;PowerShell uses system drives to access the registry, environment variables, etc.&lt;/li&gt;    &lt;li&gt;Variables are preceded with a $&lt;/li&gt;    &lt;li&gt;To access the value of a variable, simply type it's name.&lt;/li&gt;    &lt;li&gt;Arrays are comma-separated lists of variables&lt;/li&gt;    &lt;li&gt;User input can be handled by the Read-Host cmdlet&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Next post will probably cover some script logic such as if-clauses, looping, etc. After that I think it will be time to post some sample scripts.&lt;/p&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8893706" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="PowerShell" scheme="http://blogs.msdn.com/johan/archive/tags/PowerShell/default.aspx" /></entry><entry><title>Back in business</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/08/22/back-in-business.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/08/22/back-in-business.aspx</id><published>2008-08-22T18:00:00Z</published><updated>2008-08-22T18:00:00Z</updated><content type="html">&lt;P&gt;Okay, after a summer break that no doubt got a little longer than expected I am now I'm now back in the saddle again.&lt;/P&gt;
&lt;P&gt;Next post will most likely be a follow-up on the PowerShell post I wrote a while back. Stay tuned.&lt;/P&gt;
&lt;P&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8887957" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="Misc" scheme="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx" /><category term="Off topic" scheme="http://blogs.msdn.com/johan/archive/tags/Off+topic/default.aspx" /></entry><entry><title>The first thing you should do after setting up an IIS7-server</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/johan/archive/2008/05/29/the-first-thing-you-should-do-after-setting-up-an-iis7-server.aspx" /><id>http://blogs.msdn.com/johan/archive/2008/05/29/the-first-thing-you-should-do-after-setting-up-an-iis7-server.aspx</id><published>2008-05-29T15:14:58Z</published><updated>2008-05-29T15:14:58Z</updated><content type="html">&lt;p&gt;As you're probably well aware IIS7 relies heavily on a master configuration file named ApplicationHost.config. Now, instead of using a history file like IIS6 did, IIS7 will check this file every 2 minutes to see if it's changed. If the file has been updated, then a backup copy of the old .config will be stored in the inetpub\history-directory.&lt;/p&gt; &lt;h1&gt;Configuration history&lt;/h1&gt; &lt;p&gt;This is really cool and a very useful feature. There's only one little caveat in my opinion and that's the fact that by default IIS7 will only save up to 10 backups. All the other backups will be discarded. This means that if you're spending 20 minutes fiddling with the settings in ApplicationHost.config you will quite likely have overwritten all your old backups. Now, if something goes wrong at that point and you decide to spend another 20 minutes trying to fix this problem by &lt;em&gt;further &lt;/em&gt;editing the ApplicationHost.config you will &lt;em&gt;surely&lt;/em&gt; have overwritten the backups.&lt;/p&gt; &lt;p&gt;In a worst case scenario you might even have gone from &lt;em&gt;Healthy Server &lt;/em&gt;to &lt;em&gt;Unstable Server &lt;/em&gt;to &lt;em&gt;Server Down &lt;/em&gt;and you now find that you aren't even able to restore it to the &lt;em&gt;Unstable &lt;/em&gt;state.&lt;/p&gt; &lt;p&gt;My suggestion is to increase the default number of backups to 100, or why not 1000? You can then feel certain that any backups taken aren't overwritten when you try to undo the very same changes. Here's how you do it:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Go to %windir%\system32\inetsrv\config\  &lt;li&gt;Open applicationHost.config in notepad  &lt;li&gt;Locate the system.applicationHost section group  &lt;li&gt;Add the following item to the section group:&lt;br&gt;&lt;span class="InlineCode"&gt;&amp;lt;configHistory maxHistories="100" period="00:02:00" /&amp;gt;&lt;/span&gt;&lt;br&gt;(Naturally the maxHistories value can be whichever value you prefer)  &lt;li&gt;Save&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;To restore one of the previous configurations, simply go to inetpub\history\cfgHistory_[nnnnnnnnnn] and copy the config from there, or use appcmd. (See below) &lt;/p&gt; &lt;h1&gt;Backup using appcmd&lt;/h1&gt; &lt;p&gt;Now that we've done this there is one more thing I'd strongly recommend doing:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Open up a command-line with administrative priviliges  &lt;li&gt;Go to %windir%\system32\inetsrv  &lt;li&gt;Run "&lt;span class="InlineCode"&gt;appcmd add backup "[Name of your backup]"&lt;/span&gt;"&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;What you've done now is to create a manual backup of your current config. It's always good to have a decent (and persistent) restore point to return to.&lt;/p&gt; &lt;p&gt;If you wish to restore this backup you simply use the following syntax: "&lt;span class="InlineCode"&gt;appcmd restore backup "[Name of your backup]"&lt;/span&gt;". You can also delete a backup using the "delete" keyword, or you can list all backups, including the ones generated by the Configuration history, like this: "&lt;span class="InlineCode"&gt;appcmd list backup&lt;/span&gt;"&lt;/p&gt; &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/8557875/original.aspx"&gt; &lt;/p&gt; &lt;p&gt;Okay, so now we have made sure we have some extensive automatic backups in place which might save us a lot of headaches later on.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Later! / Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8557977" width="1" height="1"&gt;</content><author><name>JohanS</name><uri>http://blogs.msdn.com/members/JohanS.aspx</uri></author><category term="IIS7" scheme="http://blogs.msdn.com/johan/archive/tags/IIS7/default.aspx" /><category term="Did you know?" scheme="http://blogs.msdn.com/johan/archive/tags/Did+you+know_3F00_/default.aspx" /></entry></feed>