Remoting and registry

  • Issue

I’ve recently encountered a weird issue while using Windows PowerShell Remoting.

Using a the following

New-PSSession -ComputerName RemoteServer

failed with the following message:
New-PSSession : Requested registry access is not allowed.
+ FullyQualifiedErrorId : PSSessionOpenFailed


icm -ComputerName RemoteServer -Authentication Kerberos { 1 }

failed with the following message:
Requested registry access is not allowed.
+ FullyQualifiedErrorId : PSSessionStateBroken

Sorry, what’s the link between Remoting and the registry?

  • Solution

Well, it appears that I cannot open a logon session on the remote server as well.
Remoting isn’t the culprit. Neither is the version of PowerShell nor the version of the operating system as I suspected initially.
I could also use remoting properly when I provided other credentials in the same shell where it previously failed.

It appears that the User profile service tells us what’s missing:

Windows cannot load classes registry file.
DETAIL – The system cannot find the file specified.

Yes, I can see that there’s no AppData\Local\Microsoft\Windows\UsrClass.dat in the profile.

I deleted the “corrupted” profile and the issue went away πŸ™‚

  • How to better detect this issue?

On the client (source shell), WSMAN has some difficulties to delete the shell (that never opened, I presume)

On the server (target server),

You can use the following code to detect it on the remote server.

Get-WinEvent -FilterHashtable @{ 
    LogName = "Windows PowerShell" ;
    Level = 2 ;
    Id = 103 

Windows PowerShell remoting rocks when the registry doesn’t fail πŸ˜‰ Have fun 😎


PSReadline 2.0 not working on Windows 10 1809

  • Context:

I’m running a Windows 10 1809 at home and encountered something weird about PSReadline.
You know PSReadline is the module from Jason Shirk that enables great command line editing in the PowerShell console host.
It maintains an history of commands accross consoles and the ability to search the history (it works using CTRL+R, the same way a Bash shell works), and much more!

  • Issue:

As you can see below in the picture. I’m running a En-US input language with a french keybord layout.
The module version 2.0 that shipped in Windows is loaded but the history isn’t maintained. That’s why I cannot search the history and invoke the following method although the class exists:


NB: This method only exist in version 2.0. It does not exist in version 1.2 that shipped in Windows 10 1803.
It throws the following error:
“The type initializer for ‘Microsoft.PowerShell.PSConsoleReadLine’ threw an exception.”

  • Solution:

I had a look at the issues on GitHub and I’m not the first one who noticed this issue.

Because Jason wrote the following , I went this route:

If you’d rather not use PsGet, you can just download the file and extract the contents into your C:\Users\[User]\Documents\WindowsPowerShell\modules\PSReadLine folder. (You may have to create these directories if they don’t exist.)

I also needed to modify the Execution policy:

Note that if you’ve an Application Control solution, nothing is signed digitally:

  • Caveat

The above solution works in a admin console, the command history is maintained and is searchable πŸ™‚
But it still doesn’t work with a filtered admin token in a non-admin console 😦

About January 2019 LCU (Latest Cumulative Update)

All the LCU (Latest Cumulative Update) in January 2019 contain the following note:

After reading that I just wondered:
Is PowerShell or remoting vulnerable and not mentioned in any CVEs released in January 2019.
How to assess the impact of the LCU on any endpoint that deals with remoting?
What’s the scenario?

  • January 8, 2019β€”KB4480116 (OS Build 17763.253) for Windows 10 version 1809 and Windows Server 2019
  • January 8, 2019β€”KB4480966 (OS Build 17134.523) for Windows 10 version 1803
  • January 8, 2019β€”KB4480978 (OS Build 16299.904) for Windows 10 version 1709
  • January 8, 2019β€”KB4480973 (OS Build 15063.1563) for Windows 10 version 1703
  • January 8, 2019β€”KB4480961 (OS Build 14393.2724) for Windows 10 version 1607 and Windows Server 2016
  • January 8, 2019β€”KB4480963 (Monthly Rollup) for Windows 8.1 and Windows Server 2012 R2
  • January 8, 2019β€”KB4480970 (Monthly Rollup) for Windows 7 SP1 and Windows Server 2008 R2 SP1

Based on feedback from MVP raised on the private distribution list, the PowerShell team published the following blog post: Windows Security change affecting PowerShell.

After the blog post was published, Paul Higinbotham from the PowerShell Team also asked for all KB articles to be modified as follow:

My first concern was: if it’s a security vulnerability, what’s its CVE? The blog post answer is: CVE-2019-0543 discovered by James Forshaw of Google Project Zero

My second concern was twofold. Is the chapter about A Least Privilege Model Implementation Using Windows PowerShell published in the PowerShell Conference Book impacted by this change? Should I stop deploying Windows 10 at work because the LCU of January 2019 breaks my loopback scenario?

The answer is no and explained by the blog post Windows Security change affecting PowerShell

you would not be affected by this change, unless you explicitly set up loopback endpoints on your machine to allow non-Administrator account access

Let’s boot a 1709 VM, apply the LCU of January 2019, reboot and compare the endpoint permissions that will be impacted by the change named MyNonAdmin and the one set in the PowerShell Conference Book‘s chapter named MakeMeAdmin:

Now let’s test the behavior:

Holy moly! Cool down!! The odds you are impacted is very very low.

And if you’re in trouble, Microsoft proposed these two solutions:

A workaround for a loopback connection is to always use Administrator credentials.
Another option is to use PSCore6 with SSH remoting.

Then I tried to set the same permissions that work for the MakeMeAdmin endpoint (EP) on the MyNonAdmin EP.
The answer was crystal clear. Having the same permissions doesn’t work.

I then wondered why my loopback scenario works?

Based on my 2nd testing wave, it appears that:
– a non admin local account can only use loopback remoting if the account is a member of the local administrators group when remoting is being accessed.
– endpoint permissions isn’t what will give access to an non admin local account when using loopback remoting.
– when it doesn’t work, opening the session or handling a remoting request/response takes more time.
– when it doesn’t work, opening the session or handling a remoting request/response creates errors in the ‘Windows Remote Management’ operational log:

Get-WinEvent -FilterHashtable @{ 
 LogName = 'Microsoft-Windows-WinRM/Operational' ; 
 Level = 2

Request response: WSMan operation CreateShell failed, error code 2148007941
Request handling: The WSMan service could not launch a host process to process the given request. Make sure the WSMan provider host server and proxy are properly registered. Error code 2148007941

The article also says:

The breaking change is not in PowerShell but in a system security fix that restricts process creation between Windows sessions. This fix is preventing WinRM (which PowerShell uses as a remoting transport and host) from successfully creating the remote session host, for this particular scenario. There are no plans to update WinRM.

So, it’s the identity that really matters. In other words, a non admin local account cannot open a local (loopback) remote session that uses WinRM.

Again, why my loopback scenario works?

The answer is also in the article:

This does not affect JEA (Just Enough Administration) sessions.


Ok, if JEA isn’t affected, what it’s so special in JEA? Permissions? No. Roles/Capability? Yes, for sure!
Let’s dig into JEA. If it’s not permissions that made a difference, then what is it?
Is it the SchemaVersion, the SessionType, the LanguageMode,…?

My testing shows that the endpoint (EP) must run under another identity whether it’s a virtual local admin account, a gMSA or just another account (it can be the local admin account (RID:500)).

Ok, how can I find endpoints that are not affected by the non admin user loopback issue?
Well, like this:

Get-PSSessionConfiguration | Where {
 ($_.RunAsVirtualAccount -eq 'True') -or
 ([string]::empty -ne $_.RunAsUser)  -or 
 ([string]::Empty -ne $_.RunAsVirtualAccountGroups)
} | Select Name,*Run* | ft -AutoSize

NB: isn’t it a shame that these properties are only strings?

To summarize,
Here are two EP:

# Common parameters for both endpoints: permissions
$HT = @{
 SecurityDescriptorSddl = 'O:NSG:BAD:P(A;;GA;;;BA)(A;;GA;;;BU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)'
 Force = [switch]::Present
# Create an EP that won't work
Register-PSSessionConfiguration -Name NOKMyNonAdminEP @HT

# Create an EP that will work
New-PSSessionConfigurationFile -RunAsVirtualAccount -Path c:\OKMyNonAdminEP.pssc
Register-PSSessionConfiguration -Name OKMyNonAdminEP @HT -Path c:\OKMyNonAdminEP.pssc

# Compare their properties
Get-PSSessionConfiguration | 
Select Name,Schema*,GUID,Session*,RunAs*,Perm* |ogv

Let’s quickly measure the performance issue I mentioned above:

Measure-Command { 
 New-PSSession -ConfigurationName OkMyNonAdminEP -ComputerName localhost
Measure-Command {
 New-PSSession -ConfigurationName NOkMyNonAdminEP -ComputerName localhost

30 seconds compared to 288 milliseconds…

Friday fun: follow URI redirects

Lee Holmes twitted recently the following:

It’s available on the PowerShell gallery: resolve-uri.ps1

It appears that I wrote another script to achieve the same because of VSCode that introduced another redirect back in November.
Mine looks like this:

  • What are the differences between the 2 approaches?
    • Mine sends back only a single string in the output stream while his solution sends all the URI used and being redirected:

    • Mine uses a recursive approach and his approach uses a while loop.
    • Mine shows in the verbose stream what kind of redirect happened, if it’s a temporary redirect or if it’s permanent.

    As usual, there are always more than one way to skin a cat πŸ˜€

More on PowerShell Constrained Language mode and the Dot-Source Operator

The PowerShell team recently published a blog post about PowerShell Constrained Language mode and the Dot-Source Operator

It’s worth reading because it clearly explains how and when you can cross language mode boundaries.

It also shows that mixing language modes usually results in getting an error message.

I have been experiencing constrained-language-mode for a few months and I must say that it’s has a sharp learning curve.

Here’s what I’d like to highlight about what I’ve learned so far:

  • “-File” and CmdletBinding don’t play well together

Apart the profile.ps1 catch-22, there’s another caveat. “-File” and CmdletBinding don’t play well together especially if the files are store in trusted location on the network. The solution is very simple, remove the “-File”.

Let’s say you have Applocker in whitelist mode and have trusted a remote share location \\localhost\c$\*.ps1 in this applocker policy. I’ve been using the same script content as the one provided in the blog post PowerShell Constrained Language mode and the Dot-Source Operator except that it’s an advanced script with a begin/process/end structure. As you can see the only difference between the two files named NoCmdletBinding.ps1 and WithCmdletBinding.ps1 is the presence of the CmdletBinding statement at the begining of the script.
Here’s what the problem looks like because a picture is worth a thousand words:

  • Remoting using “-File” is also broken

Remoting using “-File” is also broken the same way. In the picture below that shows the issue, I’m using the content of the MyHelper.ps1 file found in the blog post PowerShell Constrained Language mode and the Dot-Source Operator except that there’s no function.

cat C:\Windows\myFile.ps1
icm -ComputerName localhost -ScriptBlock { $ExecutionContext.SessionState.LanguageMode }
icm -ComputerName localhost -FilePath C:\Windows\myFile.ps1
icm -ComputerName localhost { C:\Windows\myFile.ps1 }

Although my account used for remoting is an admin on the target remote computer, the Applocker whitelist mode enforces the Constrained Language mode with the “-File” parameter.
When I use the Scriptblock and just run C:\windows\myFile.ps1, it runs because there’s a rule in Applocker that allows the file to be executed. So it’s allowed to cross languade mode boundaries and run in FullLanguage mode. The second line doesn’t throw an error this time and it’s also discarded from the output because remoting doesn’t transport back console paintings.
The workaround in this case consists in first copying the file locally and then invoking it using a scriptblock.

# Solution
Copy-Item ~/Documents/myFile.ps1 -Destination \\TargetPC\c$\Windows\temp\myFile.ps1
Invoke-Command -ComputerName TargetPC -ScriptBlock { C:\Windows\temp\myFile.ps1 }
  • The r alias of the Invoke-History cmdlet may be broken based on what you want to re-execute

The r alias of the Invoke-History cmdlet may be broken based on what you want to re-execute:

Adobe FlashPlayer Emergency Group Policy

After posting a message to the distribution list about my strategy as a reaction to the following article, where I said that:

My strategy has always been a risk based approach.
If there’s a vulnerability, something needs to be done about the risk. The risk needs first to be identified and assessed.
The risk can then be:
– accepted (just inventory and evaluate your specific context, wait for a patch when it’s a 0-day)
– reduced, mitigated (apply the workaround instead of patching first, that gives you more time and you can patch later)
– shared, transferred (get more budget and buy a more expensive insurance)
– avoided (patch immediately or remove the offending software/component)

I’ve been contacted by Mitch Tulloch who is a widely recognized expert on Windows Server and cloud technologies who has written more than a thousand articles and has authored or been series editor for over 50 books for Microsoft Press. He is a twelve-time recipient of the Microsoft Most Valuable Professional (MVP) award in the technical category of Cloud and Datacenter Management.

I provided some recent examples to illustrate the above strategy.
He wrote a nice article on

I mentioned in the above article that:

Whenever there’s a zero-day in Flash, you can apply the workaround and set a kill-bit in the registry

The kill-bit is a registry value to tell the browser to avoid loading the vulnerable component.
It’s always documented as a mitigation in the workaround section of every Adobe FlashPlayer security bulletin posted by Microsoft:

The Office part is also well documented on this support page:
Let’s see how to easily achieve using #PowerShell πŸ™‚

You end up with the following GPO settings:

What’s next? Just link the GPO in Active Directory where it makes sense to apply it to computers beneath.

About File Associations

The following article Microsoft Broke Windows 10’s File Associations With a Botched Update appeared recently and states that:

File associations no longer work properly on Windows 10 after a buggy update. Windows won’t let you select certain applications as your defaults.
For example, here’s what happens when we try setting Notepad++ as our default application for .txt files in Windows 10’s Settings app. Windows just ignores our choice and chooses Notepad as the default.


It appears that I’ve experienced the same thing on a Windows 10 Enterprise (1803). Just keep in mind that we see in the above gif that only “registered” applications can be set. Applications like notepad++ isn’t registered and cannot be set and used for the .txt file association.

I’ve set successfully a group policy that defines the .pdf file to be opened by Adobe Reader. It’s still there and works fine. I’ve created it using the official guidance from Microsoft and the ProgID found in the Adobe documentation on this page.

Using my Google-fu, I also found the following articles that shed some lights on how the file associations work:

I was not able to define and load a custom xml file where I could set notepad++ as the default .txt handler.

After I removed the anti-tampering protection where Microsoft sets a DENY permission on the
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xxx\UserChoice registry key, I could delete values under that key.

I didn’t need to reverse engineer secret hashes under that key like some known tools (setuserfta) do.

All I did actually is remove anything under the UserChoice, create my own ProgId under the OpenWithProgids key and create its related value under the OpenWithList list.

Bonus: If you use the Reset button under Default Apps, Microsoft will gracefully restore the previous behavior.
With the above function or script, your user (admin or not) is autonomous and can restore his favorite file associations until Microsoft changes the rules…