Restore Open Command Window Here to Windows 10

Microsoft has made some rather evil changes to Windows 10 – not the least of which was disabling references to the command window / command prompt. Super nice feature they added by default was the ability to open a command window in the current folder. Then they screwed it up by replacing it with PowerShell.

PowerShell has it’s place, but it’s no replacement for cmd.exe.

So, you may have looked into the steps to fix it and felt a little dirty – you have to take ownership and fool with ACLs in the registry…

Also you may have found that it is not possible to get the command prompt back in the windows explorer ribbon file menu.

How about no and no.

Download this utility and run it – it requires admin privileges (unfortunately unavoidable). Windows SmartScreen will likely try to block the app as unrecognized – click more info and allow it to run. (If you have concerns feel free to decompile or build from source)

Binary: RestoreCommandPrompt.exe



You have 3 options. You can restore the folder shift-right click context menu, the folder background menu, and you can replace the Open Powershell here with the much more useful “Open Command Prompt”


Log out and back in and windows is at least 6 times better.

Validating Alexa Skill Web Requests in c#

Amazon went a little OCD on the security verification for Alexa skill requests to custom https endpoints. During testing it will work fine if you don’t validate, but they check for this as part of the skill submission process.

I have been developing a custom connector for Alexa to work with the Microsoft Bot Framework, and just recently discovered the security requirements. Now I may be reinventing the wheel here a little bit, but I decided to build my own model classes. Maybe I’m a little OCD.

Anyway, to validate the alexa skill requests you must do the following:
1: Validate that the url supplied in a header for a certificate chain is valid
2: Validate the certificate and its chain
3: Use the certificate to verify the digital signature (which is supplied in another header) against the request body
4: Make sure the timestamp in the request body is within 150 seconds of now

Amazon’s instructions with regard to step 3 are a little misleading. They suggest you “decrypt” the digital signature using the public key. From what I can gather, RSA public keys do not decrypt; they only encrypt. Thankfully the digital signature validation process is something that is already implemented in the .NET Framework, so it’s not terribly difficult.

The two “tricky” parts are getting .NET to read certificates from a PEM container, and checking the signing certificate’s SAN list.

So hopefully this will be helpful to somebody.

First we have a helper class for parsing the PEM and a couple other little things

using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace AlexaCustomChannel
    public static class PemHelper
        static string CertHeader = "-----BEGIN CERTIFICATE-----";
        static string CertFooter = "-----END CERTIFICATE-----";

        static HttpClient _client = new HttpClient();

        public static IEnumerable<string> ParseSujectAlternativeNames(X509Certificate2 cert)
            Regex sanRex = new Regex(@"^DNS Name=(.*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);

            var sanList = from X509Extension ext in cert.Extensions
                          where ext.Oid.FriendlyName.Equals("Subject Alternative Name", StringComparison.Ordinal)
                          let data = new AsnEncodedData(ext.Oid, ext.RawData)
                          let text = data.Format(true)
                          from line in text.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
                          let match = sanRex.Match(line)
                          where match.Success && match.Groups.Count > 0 && !string.IsNullOrEmpty(match.Groups[1].Value)
                          select match.Groups[1].Value;

            return sanList;

        public static bool ValidateCertificateChain(X509Certificate2 certificate, IEnumerable<X509Certificate2> chain)
            using (var verifier = new X509Chain())
                var result = verifier.Build(certificate);
                return result;

        public static X509Certificate2 ParseCertificate(string base64CertificateText)
            var bytes = Convert.FromBase64String(base64CertificateText);
            X509Certificate2 cert = new X509Certificate2(bytes);
            return cert;

        public static async Task<X509Certificate2[]> DownloadPemCertificatesAsync(string pemUri)
            var pemText = await _client.GetStringAsync(pemUri);
            if (string.IsNullOrEmpty(pemText)) return null;
            return ReadPemCertificates(pemText);

        public static X509Certificate2[] ReadPemCertificates(string pemString)
            var lines = pemString.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            List<string> certList = new List<string>();
            StringBuilder grouper = null;
            for (int i = 0; i < lines.Length; i++)
                var curLine = lines[i];
                if (curLine.Equals(CertHeader, StringComparison.Ordinal))
                    grouper = new StringBuilder();
                else if (curLine.Equals(CertFooter, StringComparison.Ordinal))
                    grouper = null;
                    if (grouper != null)

            List<X509Certificate2> collection = new List<X509Certificate2>();

            foreach (var certText in certList)
                var cert = ParseCertificate(certText);

            return collection.ToArray();

You will need to change the signature of your controller to accept something that gives you access to the raw request body – such as an HttpRequestMessage.

Then you can call the following method with your request to validate per Amazon’s requirements
(Note the AlexaRequestBody is my custom request model. You just need to get the timestamp from the request)

        static Dictionary<string, X509Certificate2> _validatedCertificateChains = new Dictionary<string, X509Certificate2>();
        async Task ValidateRequestSecurity(HttpRequestMessage httpRequest, byte[] requestBytes, AlexaRequestBody requestBody)
            if (requestBody == null || requestBody.Request == null || requestBody.Request.Timestamp == null)
                throw new InvalidOperationException("Alexa Request Invalid: Request Timestamp Missing");

            var ts = requestBody.Request.Timestamp.Value;
            var tsDiff = (DateTimeOffset.UtcNow - ts).TotalSeconds;

            if (System.Math.Abs(tsDiff) >= 150)
                throw new InvalidOperationException("Alexa Request Invalid: Request Timestamp outside valid range");

            httpRequest.Headers.TryGetValues("SignatureCertChainUrl", out var certUrls);
            httpRequest.Headers.TryGetValues("Signature", out var signatures);

            var certChainUrl = certUrls.FirstOrDefault();
            var signature = signatures.FirstOrDefault();

            if (string.IsNullOrEmpty(certChainUrl))
                throw new InvalidOperationException("Alexa Request Invalid: missing SignatureCertChainUrl header");

            if (string.IsNullOrEmpty(signature))
                throw new InvalidOperationException("Alexa Request Invalid: missing Signature header");

            var uri = new Uri(certChainUrl);

            if (uri.Scheme.ToLower() != "https")
                throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl bad scheme");

            if (uri.Port != 443)
                throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl bad port");

            if (uri.Host.ToLower() != "")
                throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl bad host");

            if (!uri.AbsolutePath.StartsWith("/echo.api/"))
                throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl bad path");

            X509Certificate2 signingCertificate = null;

            if (!_validatedCertificateChains.ContainsKey(uri.ToString()))
                System.Diagnostics.Trace.WriteLine("Validating cert URL: " + certChainUrl);

                var certList = await PemHelper.DownloadPemCertificatesAsync(uri.ToString());

                if (certList == null || certList.Length < 2)
                    throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl download failed or too few certificates");

                var primaryCert = certList[0];

                var subjectAlternativeNameList = PemHelper.ParseSujectAlternativeNames(primaryCert);

                if (!subjectAlternativeNameList.Contains(""))
                    throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl certificate missing from Subject Alternative Names");

                List<X509Certificate2> chainCerts = new List<X509Certificate2>();

                for (int i = 1; i < certList.Length; i++)

                if (!PemHelper.ValidateCertificateChain(primaryCert, chainCerts))
                    throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl certificate chain validation failed");

                signingCertificate = primaryCert;

                lock (_validatedCertificateChains)
                    if (!_validatedCertificateChains.ContainsKey(uri.ToString()))
                        System.Diagnostics.Trace.WriteLine("Adding validated cert url: " + uri.ToString());
                        _validatedCertificateChains[uri.ToString()] = primaryCert;
                        System.Diagnostics.Trace.WriteLine("Race condition hit while adding validated cert url: " + uri.ToString());
                signingCertificate = _validatedCertificateChains[uri.ToString()];

            if (signingCertificate == null)
                throw new InvalidOperationException("Alexa Request Invalid: SignatureCertChainUrl certificate generic failure");

            var signatureBytes = Convert.FromBase64String(signature);

            var thing = signingCertificate.GetRSAPublicKey();
            if (!thing.VerifyData(requestBytes, signatureBytes, System.Security.Cryptography.HashAlgorithmName.SHA1, System.Security.Cryptography.RSASignaturePadding.Pkcs1))
                throw new InvalidOperationException("Alexa Request Invalid: Signature verification failed");

Visual Studio Publish Events

Suppose you want to be able to run a command line tool to make changes to the transformed web.config during the publish / deploy of a web project in visual studio.

You need to be able to trigger your command after the web.config is transformed but before it is deployed. Additionally, you need to know the folder used for packaging the deploy.

Here is how.

Right click your project and unload it. Now you can right-click and select Edit the .csproj.

Down near the bottom of the csproj, you can add the following

  <Target Name="MyPublishTask" BeforeTargets="MSDeployPublish">
    <Exec Command="$(ProjectDir)..\ToolFolder\Tool.exe $(ProjectDir)$(IntermediateOutputPath)Package\PackageTmp\ web.config" />

Do not simply name your target “MSDeployPublish” – this overrides the publish functionality. If you use AfterTargets it will run your tool after the deploy finishes. Using BeforeTargets is just about right – it will transform the web.config and copy all the output files to the Package Temp folder. The other piece you need is the path where the package is built – $(ProjectDir)$(IntermediateOutputPath)Package\PackageTmp\ will get you there. Your tool can wreak whatever havoc necessary on the files before they are published.

One you are done editing, reload your project. Now when you publish your tool will run.

Error creating Azure IOT Hub

I was trying to create an IOT Hub in the Azure Portal and the UI was displaying errors on the Pricing and scale tier as well as the Subscription selections.

The error details said “Unable to get property ‘value’ of undefined or null reference”

When I attempted to create the IOT Hub using the azure CLI, we got to the real cause of the issue: the subscription was not enabled for “Microsoft.Devices”

To resolve, follow the directions here to register the Microsoft.Devices resource provider on your subscriptions

(Open the subscription, look for the “Resource Providers” option, search for “devices” – click register)

Once you have done this, you will be able to create an IOT Hub.

SQLite Studio

If you are doing any work with a SQLite database, you need this tool.

It’s a fantastic free, open source GUI for working with SQLite databases. Clean, fast, surprisingly well featured – it should really be at the top of the list for SQLite GUI tools.

Enabling Windows 10 Continuum on Lumia 640 (theoretically any Windows 10 Lumia)

It can be done, and I have done it!

I have a Cricket wireless Lumia 640 with continuum mode working.

Follow the directions here:

I have mirrored the files here:

Some notes:

1. After you install the Interop Tools app, you may need to reboot the phone. Before rebooting, I encountered crashes when attempting to open the INTEROP UNLOCK menu

2. You will probably need to first “Restore NDTKSvc” and reboot. Then the other unlock options will work

3. The directions include a tool – iutool.exe – in the that allows for installing cab files on the phone. This tool is touchy, and is version specific. IF YOUR PHONE DOESN’T REBOOT ITSELF, THE TOOL DIDN’T WORK.
– Make sure phone is configured for developer mode
– Make sure phone has recent OS update – I believe the instructions were intended for the Anniversary Update.

When I first tried it, the tool immediately failed with an error. This probably means the tool couldn’t figure out which phone to update.

To resolve this, detach the phone, open the “Devices and Printers” control panel (search for it in the start menu). Remove any windows phones in the list. Reattach the phone, wait for windows to finish detecting, and try the command line again.

Next if it uploads the update but then fails, you may have the wrong version of iutool.exe.

I got the latest Phone updates for insider preview, and was able to successfully install Continuum using the version of iutool.exe here:

(Mirrored here:

The msi installer places the executable here: C:\Program Files (x86)\Windows Kits\10\Tools\bin\i386

When it works, the phone will reboot itself, you will see gears, etc. Even though the instructions say you may see an error, I did not when it worked.

Now I can use Word, Excel, etc on a Miracast connected display with a Bluetooth keyboard and mouse. If I were desperate for some spreadsheet or word processing action and all I had was the phone – I can now make it happen. When Continuum is enabled, your phone works like an input device for the TV, so you don’t technically need the keyboard and mouse.

Make SQL Server Collation act similar to SQLite

The default SQL Server database collation (“SQL_Latin1_General_CP1_CI_AS”) sorts some Unicode values as equal when they are not. If you have an nvarchar field defined as part of a primary key or unique index, you can run into some surprise duplicate keys.

In particular, I was loading data from a SQLite database into an Azure SQL (SQL Server) database. I had removed all the duplicates as far as SQLite was concerned, but there were some records that SQL Server complained as being duplicate. From what I can tell, one record used single byte characters for the word “Final” and the other used double-byte characters.

The solution in this case was to change the collation of the field to one that uses a binary sort.

“Latin1_General_100_BIN” seems to work swimmingly. No more strange collisions.

Returning custom HTTP Status codes for WCF SOAP Exceptions

When WCF encounters an unhandled exception, the thrown exception is wrapped up in a FaultException and returned to the client. You can of course throw your own FaultException to have better control over the contents of the error, but one thing you cannot control by default is the HTTP response code. It is always 500.

I had a situation where I needed to return a 503 error under certain circumstances in a WCF SOAP service.

The solution is not as simple as I might like, but it isn’t terrible. There are examples out there for changing the http status code for all exceptions (, but this was not at all what we want.

The solution uses the same basic framework as the mentioned article however. An Endpoint Behavior Extension registers a Dispatch Message Inspector that watches for faults. In the case of a fault. Inside the BeforeSendReply method, you have access to the reply message. For performance reasons it is best to not unwrap the XML, so we use the SOAP Action header to trigger the HTTP Status code update.

I decided to create a simple custom exception class that sets the SOAP Action to a predefined value

    /// <summary>
    /// Custom Fault Exception that when used with the CustomFaultStatusBehavior Endpoint Behavior
    /// allows returning custom HTTP status codes to the client
    /// </summary>
    public class StatusFaultException : FaultException
        /// <summary>
        /// Create new exception
        /// </summary>
        /// <param name="statusCode">HTTP Status code to be returned to the client</param>
        /// <param name="faultReason">SOAP Fault Reason</param>
        /// <param name="faultCode">SOAP Fault Code</param>
        public StatusFaultException(System.Net.HttpStatusCode statusCode, string faultReason, FaultCode faultCode)
            :base(faultReason, faultCode, "CustomFaultStatus" + ((int)statusCode).ToString())
            //StatusCode is placed in the response Action. Action would be "CustomFaultStatus503" to return a 503 error code

Here is the Custom Behavior that consumes the SOAP Action

    /// <summary>
    /// Endpoint Behavior that allows returning custom HTTP response codes for SOAP Faults 
    /// </summary>
    public class CustomFaultStatusBehavior : BehaviorExtensionElement, IEndpointBehavior
        //based on
        public override Type BehaviorType
                return typeof(CustomFaultStatusBehavior);

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            CustomFaultStatusMessageInspector inspector = new CustomFaultStatusMessageInspector();

        public void Validate(ServiceEndpoint endpoint)

        protected override object CreateBehavior()
            return new CustomFaultStatusBehavior();

    /// <summary>
    /// Message Inspector that updates the HTTP response code for faulted messages with a CustomFaultStatus action
    /// </summary>
    public class CustomFaultStatusMessageInspector : IDispatchMessageInspector
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            return null;

        public void BeforeSendReply(ref Message reply, object correlationState)
            if (!reply.IsFault) return;
            if (!reply.Headers.Action.StartsWith("CustomFaultStatus", StringComparison.Ordinal)) return;
            //get the string value for desired response code
            string statusCodeString = reply.Headers.Action.Substring(17);
            //convert to int
            int statusCodeInt;
            if (!int.TryParse(statusCodeString, out statusCodeInt)) return;

            //cast to HttpStatusCode
            System.Net.HttpStatusCode statusCode = System.Net.HttpStatusCode.InternalServerError;
                statusCode = (System.Net.HttpStatusCode)statusCodeInt;
            catch (Exception ex)

            // Here the response code is changed
            reply.Properties[HttpResponseMessageProperty.Name] = new HttpResponseMessageProperty() { StatusCode = statusCode };

The CustomFaultStatusBehavior must be registered in your web.config as a behavior extension, then it must be referenced in an endpoint behavior. Finally this behavior should be applied to the endpoint using the behaviorConfiguration attribute.

Free Tool: Dynamics CRM User Language Update Tool

Just had an encounter with a user who needed their language updated. The UI Language was set to Korean – I wasn’t able to walk the user through updating it since I don’t read Korean either.

So I whipped up a little tool to do the job for me.

You supply a connection string for the target CRM Organization (Should support everything – CRM Online, On-Premise – just paste everything in the CRM url up to (but not including) the “/main.aspx”)

You can search for the user by Guid, Full Name or DomainName (aka User Name) (all the search fields auto add wildcards)

The tool returns a list of matching users – select the user to update, select the desired values for language code and click Update. Pretty basic and there are instructions for doing it, but I didn’t see anything so simple out there.

You can get the binaries here: Dynamics CRM User Language Update Tool

And the source code here: Dynamics CRM User Language Update Tool Source Code

(Note that you may need to have Windows Identity Foundation installed – this is a prerequisite of the CRM SDK)

This tool works with Dynamics CRM 2011, Dynamics CRM 2013, Dynamics CRM 2015, Dynamics CRM Online, and the forthcoming Dynamics CRM 2016 (ie everything 2011 and later)

windows net user add password with special characters

The command line to add a local windows user called “newuser” with the password “p&ssw^rd”

You try

net user newuser p&ssw^rd /ADD

Uh-oh – it fails!

C:\> net user newuser p&ssw^rd /ADD
The user name could not be found.

More help is available by typing NET HELPMSG 2221.

'sswrd' is not recognized as an internal or external command,
operable program or batch file.

If the password contains certain special characters – like an ampersand “&” or a caret “^”, the password will be garbled, broken, butchered.

One solution is to have it prompt for the password

net user newuser * /ADD

but if you are scripting, this isn’t really helpful.

No, you cannot use quotes.

The solution: All Ampersands must be escaped with a caret “^”, and all carets in the password must be similarly escaped.

UPDATE: turns out in more recent versions of windows, exclamation marks “!” must also be escape with two carets.
See here for a good list of how to escape things.

So, to use the password p&ssw^rd in a command line, you would need to replace it with p^&ssw^^rd

net user newuser p^&ssw^^rd /ADD

This will do what you expect

Note that if you do not escape the carets, the command may succeed, but the password will be wrong.