Windows 10–Getting Ready for MDM

One of the big selling points of Windows 10 is the convergence of form factors and “one OS to rule them all” seeing Windows 10 desktop and Windows 10 phone merge together in some way. This started in Windows 8.1 where both device gained support for OMA DM, but there were still slight differences between the two.

With a new OS we obviously want new enterprise features as well, and MDM is also one of the areas where the intention is to go further. I have played around with the Windows 10 technical preview for desktop, and a preview build for phones should be imminent. My intention is to play around with MDM for both of them real soon, as well as other enterprise related features in due time.

While we all get ready for some hands-on Microsoft has updated their documentation:
Preview Specifications:
https://msdn.microsoft.com/en-us/library/ee941641.aspx
CSP reference: 
https://msdn.microsoft.com/en-us/library/windows/hardware/dn920025(v=vs.85).aspx

The first link contains a bunch of links to pdfs, and the one’s you’ll want are MS-MDE and MS-MDM.

I’ll get back to you once I’ve got some more details lined up Smilefjes

24 thoughts on “Windows 10–Getting Ready for MDM”

  1. It seems that the MDM agent is broken in the Windows Phone 10 – it doesn’t seem to make any discovery requests whatsoever and behaves as if there was no network.

  2. Well, they can get away with anything as long as they call it a preview build 🙂
    Jokes aside – I haven’t heard anything about MDM not working in the preview, but there could of course be issues nonetheless. (I don’t know if you tested piping the traffic through a Fiddler Proxy or something to check the traffic, or if you’ve just tested to enroll against a known working MDM server.)
    Unfortunately the WP devices I have access to don’t qualify for the preview yet so I haven’t been able to test this myself. As soon as I get my hands on a device I will be inspecting things closer.

  3. Andreas,

    I tested both. Neither worked. What i noticed though was that it retained enrollment from wp8.1 upgrade but i foolishly deleted that thinking that i’d just test the enrollment first.
    So my plan now is to rollback and then enroll and then upgrade again and see if it works that way.

  4. Just to follow up – my attempt failed. I retained enrollment and deployed apps/settings but the MDM agent (workplace) won’t sync. It is displaying the infamous ‘We’re syncing your account’ at the top and never makes any connection (with or without MiTM proxy). So it is as if the networking capability was off when the build was done or something like that. This is pretty disappointing.

  5. Hi Andreas, I found your website after a lot of research about MDM and you have a lot of experience implementing this tool.

    So, we’re running in a trouble to implement this in the server side, and we can’t do the discovery process, I know it’s the first step but we’re stuck on it.

    We trying to read the ms pdf’s docs, but it seems to be not so clear, and we trying to find some sample codes for the entire process, just to clarify our minds.

    I’ll appreciate so much if you contact me trought my e-mail and send (if it’s possible) some sample codes, just to give us some north to follow.

    Thank you very much, and congrats for your good job written and researching all this work.

    Bye

  6. Are you specifically trying to implement MDM for Windows 10, or trying to make things work for W8.1 and W10 in the same go?
    I have deliberately waited on doing actual implementation on Windows 10 since these parts of the OS have been changing between the preview builds, and haven’t been ready for prime time. (Which you can tell by the docs as well.)
    The first thing to check with the discovery process is whether the DNS and SSL pieces are in place so that the device is actually hitting the server – have you verified this?
    The XML can be quite a hassle to get right, and depends on which language you’re coding in as well. Unfortunately I cannot share fully working Visual Studio solutions, but if there is a very isolated piece of the code you’re struggling with I might be able to share small snippets.

  7. *Desperate help* in implementing simple Windows Mdm server for Windows 10. Haven’t done WCF in so long. Been reading and working with WCF, but frustrated as I’m constantly pulled on other issues. Enrollment would be a great start. Any sample C# solution/project to get me going would be greatly appreciated.

    Not sure what I”m doing wrong:

    <endpoint address="" name="IDiscoveryService" contract="WindowsEnrollmentServer.IDiscoveryService" binding="webHttpBinding" behaviorConfiguration="web" bindingConfiguration="transport"

    Interface:
    [OperationContract]
    [WebInvoke(Method = "GET" UriTemplate = "")]
    string Discover();

    [OperationContract]
    [WebInvoke(Method = "POST" UriTemplate = "")]
    string DiscoveryParameters();

  8. Yeah, WCF can be real “fun” if you’re not doing it on a daily basis. (And I’m certainly not doing that either.)

    While I do have a Visual Studio solution implementing an MDM server, I’m unfortunately not able to share the source of that. I can however share a snippet of the WCF setup.

    Web.config:

    Interface:
    [ServiceContract]
    public interface IDiscovery
    {
    [OperationContract, WebGet(UriTemplate = “”)]
    void GetData();
    [OperationContract, WebInvoke(Method = “POST”, UriTemplate = “”)]
    Stream PostData(Stream discoveryRequest);
    }

    So, slightly different syntax than your setup, but more or less the same.

    Are you getting any errors building/deploying the service or is it the classic “the device doesn’t seem to want to be managed”?

  9. Thanks! Getting somewhere. Just deploying, but not past discovery yet. 🙂

    Using Stream was the key here.

  10. I finally got to the last step of MDE. At least that’s what I think. I just want to see my device enroll. :'(

    Do I have to implement the MDM server call to see it enroll? Please help. I’m not sure why I have to specify the Basic/Digest when I just want to use the device certificate to authenticate.

    What am I missing? So difficult. Please help…..

  11. Need help! Everybody counting on me to see simple demo.

    User cert characteristic
    APPLICATION characteristic
    DMClient characteristic

    removed content more or less copy/pasted from examples.

    …..

    ….

  12. Unfortunately the commenting system strips out XML so I can’t really tell whether what you’re sending down is right or not.

    You don’t have to implement the provisioning engine to complete enrollment. But you have to tell the device that there is a server at a specified address – you can provision a fake address (as long as it is formatted like a regular url), and the device will attempt to contact it after enrollment. It doesn’t matter that it will fail.

    The basic/digest needs to be included as it is part of the OMA/DM integrity even if you present a client certificate. It’s basically there so the client will only talk to an approved server.

    The sample enrollment XML should work with minor adjustments, but be sure to get it right With regards to the correct quotation marks and spacing. You might need to verify this in an editor that properly highlight this. (Notepad is not good at this. I believe I sorted it with Notepad++ way back, but maybe VS Code also works.)

  13. I truly appreciate you helping me, Andreas.

    Could you see if you can see any issues with the following? Hopefully this will not be stripped out. Here is my provisioning wap file:

    Global replace $ with

    $?xml version=”1.0″?|
    $wap-provisioningdoc version=”1.1″|
    $characteristic type=”CertificateStore”|
    $characteristic type=”Root”|
    $characteristic type=”System”|
    $characteristic type=”440B9A2DAFD0DE41689874271ABA304E17B9E68F”|
    $parm name=”EncodedCertificate” value=”MIIFTTCCBDWgAwIBAgI … jJxyR0ywrgU=”/|
    $/characteristic|
    $/characteristic|
    $/characteristic|
    $/characteristic|
    $characteristic type=”CertificateStore”|
    $characteristic type=”My”|
    $characteristic type=”User”|
    $characteristic type=”A7F76EDF29772AEC79F976C1E280E6897E4850E7″|
    $parm name=”EncodedCertificate” value=”MIID/TCCAuWgAwIBA … aYLSmGLUAVEutzifzCCxhzpOgPVJW8VsS/NNfve2RLHKiKIydOW59xexMU0YeqcXwMVCCN5x6IdONmbDYfz7itEEjQL9bgiXL8QoYiLg3LsfL722GtrTMinCKxLU=”/|
    $/characteristic|
    $characteristic type=”PrivateKeyContainer”/|
    $!–This tag must be present for XML syntax correctness. –|
    $/characteristic|
    $/characteristic|
    $/characteristic|
    $characteristic type=”APPLICATION”|
    $parm name=”APPID” value=”w7″/|
    $parm name=”PROVIDER-ID” value=”Acme Service”/|
    $parm name=”NAME” value=”Acme”/|
    $parm name=”ADDR” value=”https://foo.acme.com/EnrollmentServer/omadm/Windows.ashx”/|
    $parm name=”CONNRETRYFREQ” value=”6″/|
    $parm name=”INITIALBACKOFFTIME” value=”30000″/|
    $parm name=”MAXBACKOFFTIME” value=”120000″/|
    $parm name=”BACKCOMPATRETRYDISABLED”/|
    $parm name=”DEFAULTENCODING” value=”application/vnd.syncml.dm+wbxml”/|
    $parm name=”SSLCLIENTCERTSEARCHCRITERIA” value=”Subject=CN%3d36F555FD-3C03-41AD-BB3E-38696E!AAE996B13652BC49B0D146A16E82F1AB&Stores=My%5CUser”/|
    $characteristic type=”APPAUTH”|
    $parm name=”AAUTHLEVEL” value=”CLIENT”/|
    $parm name=”AAUTHTYPE” value=”DIGEST”/|
    $parm name=”AAUTHSECRET” value=”password1″/|
    $parm name=”AAUTHDATA” value=”ZHVtbXk=”/|
    $/characteristic|
    $characteristic type=”APPAUTH”|
    $parm name=”AAUTHLEVEL” value=”APPSRV”/|
    $parm name=”AAUTHTYPE” value=”BASIC”/|
    $parm name=”AAUTHNAME” value=”testclient”/|
    $parm name=”AAUTHSECRET” value=”password2″/|
    $/characteristic|
    $/characteristic|
    $characteristic type=”DMClient”|
    $!– When available, an enrollment server should use DMClient CSP XML to configure DM polling schedules. –|
    $characteristic type=”Provider”|
    $!– ProviderID in DMClient CSP must match to PROVIDER-ID in w7 APPLICATION characteristics –|
    $characteristic type=”Acme Service”|
    $parm name=”UPN” value=”johndoe@acme.com” datatype=”string”/|
    $characteristic type=”Poll”|
    $parm name=”NumberOfFirstRetries” value=”8″ datatype=”integer”/|
    $parm name=”IntervalForFirstSetOfRetries” value=”15″ datatype=”integer”/|
    $parm name=”NumberOfSecondRetries” value=”5″ datatype=”integer”/|
    $parm name=”IntervalForSecondSetOfRetries” value=”3″ datatype=”integer”/|
    $parm name=”NumberOfRemainingScheduledRetries” value=”0″ datatype=”integer”/|
    $!– MDM push can be used where avaialble to support real-time communication. The DM client long term polling schedule retry waiting interval should be more than 24 hours (1440) to reduce the impact to data consumption and battery life. Refer to the DMClient Configuration Service Provider section for information about polling schedule parameters.–|
    $parm name=”IntervalForRemainingScheduledRetries” value=”1560″ datatype=”integer”/|
    $parm name=”PollOnLogin” value=”true” datatype=”boolean”/|
    $/characteristic|
    $parm name=”EntDeviceName” value=”Administrator_Windows” datatype=”string”/|
    $/characteristic|
    $/characteristic|
    $/characteristic|
    $/wap-provisioningdoc|

  14. Here is my RequestSecurityTokenResponse:

    $?xml version=”1.0″?|
    $s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:a=”http://www.w3.org/2005/08/addressing” xmlns:u=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”|
    $s:Header|
    $Action s:mustUnderstand=”1″|http://schemas.microsoft.com/windows/pki/2009/01/enrollment/RSTRC/wstep$/Action|
    $a:RelatesTo|urn:uuid:81a5419a-496b-474f-a627-5cdd33eed8ab$/a:RelatesTo|
    $o:Security xmlns:o=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” s:mustUnderstand=”1″|
    $u:Timestamp u:Id=”_0″|
    $u:Created|2016-11-26T21:40:11.0073887Z$/u:Created|
    $u:Expires|2026-11-26T21:40:11.0073887Z$/u:Expires|
    $/u:Timestamp|
    $/o:Security|
    $/s:Header|
    $s:Body|
    $RequestSecurityTokenResponseCollection xmlns=”http://docs.oasis-open.org/ws-sx/ws-trust/200512″|
    $RequestSecurityTokenResponse|
    $TokenType|http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentToken$/TokenType|
    $RequestedSecurityToken|
    $BinarySecurityToken xmlns=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” ValueType=”http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentProvisionDoc” EncodingType=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#base64binary”|PHdhcC1wcm92aXNpb25pbmdkb2MgdmVyc2lvbiA9ICIxLjEiPjxjaGFy ….. C1wcm92aXNpb25pbmdkb2M+$/BinarySecurityToken|
    $/RequestedSecurityToken|
    $RequestID xmlns=”http://schemas.microsoft.com/windows/pki/2009/01/enrollment”|0$/RequestID|
    $/RequestSecurityTokenResponse|
    $/RequestSecurityTokenResponseCollection|
    $/s:Body|
    $/s:Envelope|

  15. The edited XML came through. Now, I haven’t done a character by character comparison with what I have in my code, and I’m certainly not able to parse it all as a mental exercise 🙂 But from the initial looks it seems you’ve included most of the things you need in the right places.
    The thing I can’t verify is the certs. You are pushing out boot the CA’s root cert and the client cert right? How do you implement the enrollment for the client certificate? It will fail if you fake it.

  16. Thanks Andreas.

    I figured it out and found that I was creating the certificate wrong. 😀 So now I’m on to the next step of receiving/responding to MDM calls.

    Once again, I’m really stuck trying to parse the first MDM call from the device. After enrollment, it calls the MDM server URL. Filled with control characters and jibberish. I see parts that is valid data, but cannot parse to XML or whatever it needs to be.

    Why is it so difficult. Parsing UTF-8 shouldn’t be this tough. What am I doing wrong??? Please help!

  17. I hope you can tell me you also ran into this issue and resolved it.

    I’m simply just reading the request body. I’ve also tried converting to ASCII, removing control chars, etc. Just can’t quite get a clean request payload to properly parse.

    MemoryStream reqMemStream = new MemoryStream(Request.BinaryRead(Request.ContentLength));
    using (StreamReader reqReader = new StreamReader(reqMemStream))
    {
    return reqReader.ReadToEnd();
    }

  18. Hi Andreas. I appreciate all of the help you’ve given me. I’ll be glad to donate! I owe you big for all your time.

    I think I’m at the final stretch. Demo is Tues! :’o

    The problem I’m seeing is that the device is sending me a 500 for every “SyncHdr” status response. The enrolled device shows “The sync could not be initiated (0x82ab0000)” as the sync status in the control panel.

    Starting from the SyncML response from the initial “call home” I send a status element (SyncHdr) back to the client with a 200 (I’m careful of the target/source/msgref (CmdID=1, MsgRef=1, CmdRef=0, Cmd=SyncHdr, TargetRef=https://www.acme.com/mdm, SourceRef=, Data=200 ) and status elements to the 2 alerts + replace commands (as below).

    Response from device:
    CmdID=1, MsgRef=2, CmdRef=0, Cmd=SyncHdr, Data=500
    (MsgRef from server is 2) and the rest is the same payload from initial message *every time*. Alert (1201), Alert (1224), Replace (DevId, Man, Mod, Dmv, Lang)

    Maybe related? Am I supposed to see a Chal from client? I’m sending APPAUTH\AAUTHTYPE (CLIENT) as DIGEST, AAUTHSECRET=, AAUTHDATA=BASE64()
    APPAUTH\AAUTHTYPE (APPSRV) as BASIC, AAUTHNAME=, AAUTHSECRET=

    AAUTHNAME doesn’t have to be enrolling user. Doesn’t look like it.

    Anyways, any thoughts on the 500? The device isn’t accepting any command

  19. APPAUTH\AAUTHTYPE (CLIENT) as DIGEST, AAUTHSECRET=..GUID.., AAUTHDATA=BASE64(..GUID..)
    APPAUTH\AAUTHTYPE (APPSRV) as BASIC, AAUTHNAME=..GUID.., AAUTHSECRET=..GUID..

    Above SourceRef=..device id..

  20. I’m not even going to bother implementing push notification for demo unless I get this 500, it’s too risky. I made the poll frequency to 5 mins.

    I just need it to lock screen. I’ll be talking during those 5 mins. 😀

  21. The device will send a digest that you can check to see it is who you think it is. But the server can ignore this more or less (not recommended of course). There’s basically three parts of the message you send back to the client; a sort of header, command section (body), and a section to close all tags 🙂 Include SyncHdr, Alert, and Get in the start of the body to “ACK” the device.

    Each CMD tag will need a unique id. So in the header you might have “1”, and in the XML for sending the lock you would have “2” as the id. (You can choose whatever id you like.) MsgId is incremented for each message.

    When you get a 500 back from the client you are in the clear on most things, and have the connectivity right. It is “simply” a matter of assembling the right OMA DM messages. (I know that can be tricky, but you’re through with the provisioning and all at least.)

Leave a Reply

Your email address will not be published. Required fields are marked *

*