Sorting the Desired State Configuration (DSC) “Running scripts is disabled on this system” error

Ever come across the following error when executing a Desired State Configuration (DSC) configuration against a target machine?

image

The error we see is one often associated with misconfiguration of execution policies, so is pretty generic.

C:\Windows\system32\WindowsPowerShell\v1.0\Modules\WebAdministration\WebAdministrationAliases.ps1
cannot be loaded because running scripts is disabled on this system. For more information, see
about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
    + CategoryInfo          : SecurityError: (:) [], CimException
    + FullyQualifiedErrorId : UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand
    + PSComputerName        : computer_name

Indeed, when I checked the execution policy using Get-ExecutionPolicy, all seemed fine, a bit of head scratching ensued

PS C:\> Get-ExecutionPolicy

PS C:\> Unrestricted

The problem

Ignore for the moment that this is squealing about a specific Powershell script ‘WebAdministration\WebAdministrationAliases.ps1’, this error can occur for any DSC configuration that references a DSC Resource that in turn executes an external Powershell script. In this particular case I was using the xWebAdministration Module – PowerShell Desired State Configuration Resource Kit that effectively wraps the Web Server (IIS) Administration Cmdlets in Windows PowerShell to provide DSC style configuration of IIS, out of scope in this post but thought it best to set the context.

This issue seems to manifest itself when applying a DSC configuration, using Start-DSCConfiguration either to the localmachine of to a remote target machine by specifically targeting the –ComputerName property of Start-DSCConfiguration, i.e. like so:

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

or

PS C:\> Start-DscConfiguration .\Stop_AppPool -ComputerName remote_server_name -Wait -Verbose

Note: I’m seeing this on Windows 7 and Windows 2008 R2 in a managed domain

As I mentioned above, simply running Get-ExecutionPolicy on local and remote machines gave me the expected outcome, i.e. Unrestricted (RemoteSigned will also suffice), that said, if we delve a little deeper in to the scope of execution policies we can indeed get a little more detail.

PS C:\> Get-ExecutionPolicy -List | Format-List
Scope           : MachinePolicy
ExecutionPolicy : Undefined
Scope           : UserPolicy
ExecutionPolicy : Unrestricted
Scope           : Process
ExecutionPolicy : Undefined
Scope           : CurrentUser
ExecutionPolicy : Undefined
Scope           : LocalMachine
ExecutionPolicy : Undefined

Note: I’ve piped to Format-List just to make web formatting a little easier.

The scopes we’re interested here are UserPolicy and LocalMachine, and this is where the problem lies, although my UserPolicy (as controlled by Active Directory Group Policy) is Unrestricted, the LocalMachine scoped policy is Undefined, this is important in DSC world.

A quick reminder of how the DSC Local Configuration Manager (LCM) works

From the official technet article “Local Configuration Manager  is the Windows PowerShell Desired State Configuration (DSC) engine. It runs on all target nodes, and it is responsible for calling the configuration resources that are included in a DSC configuration script.”

Further more, the LCM runs under the security context of Local System, this is by design to limit the scope of DSC to the local machine. I’m unable to find an official Microsoft statement on this, but it is widely known and discussed in more detail here: http://blogs.citrix.com/2014/09/18/what-is-desired-state-configuration/

In Push mode, DSC operation can be simplified and though of as in figure 1 below. Taken from Windows PowerShell Blog – Push and Pull Configuration Modes

image

Figure 1. DSC Push mode.

So, to summarise, the DSC LCM runs in the Local System security context, which would suggest the LocalMachine scoped execution policy needs to be set to either a RemoteSigned or Unrestricted level, so let’s try that.

The solution

Assuming we’re working on a single machine, we can run the following

PS C:\> Get-ExecutionPolicy -List | Format-List
Scope           : MachinePolicy
ExecutionPolicy : Undefined
Scope           : UserPolicy
ExecutionPolicy : Unrestricted
Scope           : Process
ExecutionPolicy : Undefined
Scope           : CurrentUser
ExecutionPolicy : Undefined
Scope           : LocalMachine
ExecutionPolicy : Undefined

 

Running our DSC configuration as follows.

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

We get the error we’ve been discussing.

C:\Windows\system32\WindowsPowerShell\v1.0\Modules\WebAdministration\WebAdministrationAliases.ps1
cannot be loaded because running scripts is disabled on this system. For more information, see
about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
    + CategoryInfo          : SecurityError: (:) [], CimException
    + FullyQualifiedErrorId : UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand
    + PSComputerName        : computer_name

Now, let’s set that pesky LocalMachine execution policy and see what happens.

PS C:\> Set-ExecutionPolicy RemoteSigned -Scope LocalMachine –Force

Note: You may receive the following error when attempting this on a domain joined machine, it explains itself well really and we can safely ignore it.

“Set-ExecutionPolicy : Windows PowerShell updated your execution policy successfully, but the setting is overridden by
a policy defined at a more specific scope.  Due to the override, your shell will retain its current effective
execution policy of Unrestricted. Type “Get-ExecutionPolicy -List” to view your execution policy settings. For more
information please see “Get-Help Set-ExecutionPolicy”.
At line:1 char:1
+ Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (:) [Set-ExecutionPolicy], SecurityException
    + FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand”

Now, checking the execution polices again, we now get.

PS C:\> Get-ExecutionPolicy -List | Format-List
Scope           : MachinePolicy
ExecutionPolicy : Undefined
Scope           : UserPolicy
ExecutionPolicy : Unrestricted
Scope           : Process
ExecutionPolicy : Undefined
Scope           : CurrentUser
ExecutionPolicy : Undefined
Scope           : LocalMachine
ExecutionPolicy : RemoteSigned

Running our DSC configuration again, like so.

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

And success.

VERBOSE: Operation ‘Invoke CimMethod’ complete.
VERBOSE: Time taken for configuration job to complete is 2.698 seconds

A little bit more, validating the fix

We can indeed roll this back and prove that setting the LocalMachine execution policy back to Undefined causes the error again, however, there are a few hoops to jump through to validate that, here goes.

Checking those execution polices again, we still have the correct value for LocalMachine.

PS C:\> Get-ExecutionPolicy -List | Format-List
Scope           : MachinePolicy
ExecutionPolicy : Undefined
Scope           : UserPolicy
ExecutionPolicy : Unrestricted
Scope           : Process
ExecutionPolicy : Undefined
Scope           : CurrentUser
ExecutionPolicy : Undefined
Scope           : LocalMachine
ExecutionPolicy : RemoteSigned

Running our DSC configuration again, like so.

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

We get success, as expected.

VERBOSE: Operation ‘Invoke CimMethod’ complete.
VERBOSE: Time taken for configuration job to complete is 2.698 seconds

Setting the LocalMachine scoped execution policy back to Undefined like so

PS C:\> Set-ExecutionPolicy Undefined -Scope LocalMachine –Force

Yields what we expect, all good so far.

PS C:\> Get-ExecutionPolicy -List | Format-List
Scope           : MachinePolicy
ExecutionPolicy : Undefined
Scope           : UserPolicy
ExecutionPolicy : Unrestricted
Scope           : Process
ExecutionPolicy : Undefined
Scope           : CurrentUser
ExecutionPolicy : Undefined
Scope           : LocalMachine
ExecutionPolicy : Undefined

Running our DSC configuration again.

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

VERBOSE: Operation ‘Invoke CimMethod’ complete.
VERBOSE: Time taken for configuration job to complete is 2.698 seconds

Oh, we still get success, not expected!

Ok, so we have a DSC engine issue I would believe, See ‘My resources won’t update: How to reset the cache’ in this post for more details about re-starting the process that is hosting the DSC engine, but for now, running the following I can get a process Id (PID)

PS C:\> Get-WmiObject msft_providers | Where-Object {$_.provider -like ‘dsccore’} | Select-Object HostProcessIdentifier,Provider
HostProcessIdentifier Provider
——————— ——–
4324 dsccore

And then I can forcefully kill it.

PS C:\> Get-Process -Id 4324 | Stop-Process

Running our DSC configuration again.

PS C:\> Start-DscConfiguration .\Stop_AppPool -Wait –Verbose

We finally get the error we’ve been discussing back again, as expected.

C:\Windows\system32\WindowsPowerShell\v1.0\Modules\WebAdministration\WebAdministrationAliases.ps1
cannot be loaded because running scripts is disabled on this system. For more information, see
about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
    + CategoryInfo          : SecurityError: (:) [], CimException
    + FullyQualifiedErrorId : UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand
    + PSComputerName        : computer_name