Configuring 802.1x Authentication for Windows Deployment – Part 2 – Building an 802.1x Enabled WinPE Boot Image

This is Part 2 in my Configuring 802.1x Authentication for Windows Deployment series. Be sure to check out all of the other parts here.

Note: I don’t have 802.1x setup in a lab to show how to configure the 802.1x service on the server side. However, I do know that you will need to configure your 802.1x service to allow PXE traffic. I believe that Cisco ISE has a setting already that you can just turn on to allow it. So, if you can’t even PXE in on an 802.1x enabled port, you will need to start there. According to my ISE admin, the switch is configured to spy on DHCP requests. ISE applied the appropriate authorization policy based on the type of request. You will need to work with your 802.1x manager/vendor to determine the proper configuration for your environment if you want to PXE over 802.1x. Also, carefully consider the security risks associated with allowing PXE over 802.1x outside of dedicated imaging location.

In order to get the Task Sequence wizard to load in WinPE on an 802.1x protected network, you will need to get authenticated to your network. This post will show you how to auto inject your 802.1x authentication script and files into your WinPE image each time you add or update boot image in ConfigMgr. While you can use this to add ANY files to you boot image, I’m just showing how to do it for 802.1x (I’ll add some links to the Resources post at the end of the series). Also, these steps are for an x64 boot image. You would do the same for x86, just use the x86 versions of everything listed.

Here’s what you need

All of the files you created in Part 1
OSDInjection.XML – The master file manifest used by SCCM to inject files into all of your boot images that you import into SCCM.
winpeshl.ini – A configuration file that tells WinPE what to launch on startup (Think Autoexec.bat)


You can find your OSDInjection.XML on your ConfigMgr primary server under [SCCM Install directory]\bin\x64\OSDInjection.XML. This file is a manifest that SCCM uses to inject specific files into your boot image. There are several sections in the XML, so be sure to make your entries in the correct location.

Create a new folder named Custom under [SCCM Install directory]\OSD. Add your 802.1x script, profile XML, and certificates to this new folder. Add new lines to your OSDInjection.XML file that correspond to each of your new files. Each entry should include the source folder Custom and a destination folder on the OS. The destination paths are based on the root drive that PE is working from (generally X:).


You won’t find a winpeshl.ini file on your server (unless you’ve done this before) and will need to create one. This file is referenced by WinPE as it is starting up and tells PE what to launch. If we add our 802.1x authentication script to this file, we can force authentication to happen before any other process, even your boot image Pre-Start commands (we never could get them to work for 802.1x pre-auth, but they may be an option here – not sure honestly). Here’s the contents of mine.

The bat file listed should be the name of your 802.1x authentication script. The last step tells PE to launch the Task Sequence wizard. If you didn’t create this file, you could watch the SMSProv.log on your primary and see when this file is created dynamically during your boot image import process.

Save the winpeshl.ini file to [SCCM Install directory]\OSD\bin\x64\winpeshl.ini. You will notice that the file isn’t included in the OSDInjection.xml file. That’s because SCCM uses the injection file first, then creates or imports (if it exists in the correct folder) the winpeshl.ini file afterwards, so whatever you copied with the injection process gets overwritten. (Ask me how I know that one!)

The big finish!

At this point, you should have the following files in the following locations

[SCCM Install directory]\Bin\x64\OSDInjection.XML
[SCCM Install directory]\OSD\Custom\ImportComputerAuthProfile.bat
[SCCM Install directory]\OSD\Custom\ComputerAuthProfile.xml
[SCCM Install directory]\OSD\Custom\Certs\Root.cer
[SCCM Install directory]\OSD\Custom\Certs\ComputerAuthCert.pfx
[SCCM Install directory]\OSD\bin\x64\Winpeshl.ini

Next, import a new boot image in your ConfigMgr console and wait a bit. You can watch SMSProv.log (if you have a busy site, good luck, it scrolls and rolls fast!) and see the injection happening. It will log if any files weren’t found. You can also just mount your boot image to check to see if your files ended up where you specified in the Destination field in OSDInjection.XML. In our case, you should have a new root folder named Custom with everything in it (except winplshl.ini which will be in c:\Windows\System32).

Now boot a machine into WinPE and check it out. If you did it right, you should see your script run and get authenticated through 802.1x. You can check the winpeshl.log in WinPE to see what it ran if you are having issues.

An alternative approach to this would be to customize the WinPE WIM on your primary, but you would still have to have the custom winplshl.ini file to launch your custom script. Also, every time you update your ADK, you will have to service the WinPE WIM. This method will ensure that it gets updated every time. You can even update the script after you’ve imported the boot image, then just Update Distribution Points for your boot image and it SCCM will re-inject the files without you having to open the WIM up with DISM.

Part 3 will cover Bare Metal Task Sequence configuration


  • Reply
    July 30, 2018 at 11:26 am

    For the Winpeshl.ini file, is the location on the SCCM server as you listed [SCCM Install directory]\OSD\x64\Winpeshl.ini? Or should it be [SCCM Install directory]\OSD\bin\x64\Winpeshl.ini?

    • Reply
      Adam Gross
      July 30, 2018 at 11:33 am

      Oh. Good catch. I’ll update it. Sorry about that! Looks like I missed it for the OSDInjection.xml path too.

      • Reply
        July 30, 2018 at 11:38 am

        Awesome, thanks!

      • Reply
        July 30, 2018 at 11:47 am

        I’m having another issue now. I try to import a new boot wim from my ADK and it gives me the following error:

        The specified file can not be imported. Make sure the file is not read only and you have read and write access to it.

        I followed all of your instructions exactly and double-checked everything to make sure I didn’t type something wrong but it does not want to import the clean boot.wim. Any ideas what could be causing this? I just updated my normal boot wim this morning before finding your excellent guide so it can’t be an issue with my server.

        • Reply
          Adam Gross
          July 30, 2018 at 11:52 am

          Check your SMSProv.log during the import process. You should be able to see the file that’s causing the issue get logged as missing. The log rolls fast, so you may have to be ready to create a copy of it as soon as the error shows on your console. I had the same error initially and found that the OSDInjection.Xml wasn’t pointing to the right location.

        • Reply
          September 11, 2018 at 5:44 pm

          Hi Andrew. Did you manage to fix this issue as I am experiencing problems too. If so what was the resolution?

  • Reply
    September 11, 2018 at 5:40 pm

    Hi Adam, thanks for the guide. i’m having this same issue now. I try to import a new boot wim from my ADK and it gives me the following error:

    The specified file can not be imported. Make sure the file is not read only and you have read and write access to it. How do I fix this.

    Also the modified winpeshl.ini script runs the batch script and then loads winpe again in a continuous loop. The task sequence wizard does not run after the batch file. If i use the default winpeshl.ini file the task sequence wizard starts and i can run the batch file manually to authenticate to 802.1x and then select what task sequence to run. Any help on this will be most appreciated.

    • Reply
      Adam Gross
      September 11, 2018 at 8:06 pm

      I believe Andrew found that his XML file was missing the tag.
      Also, I have a new script that I’m working to publish that lets you whitelist the MAC so you potentially don’t have to do these customizations in the future. I’m still a few weeks out on being able to get it out though.

  • Reply
    October 22, 2018 at 2:50 pm


    I can see the following error messages in my SMSProv.log.
    “Failed to load OsdInjection.xml”
    “ERROR> Failed to copy OSD files.”
    “Copied log file ‘Setupapi.offline.log’ to ‘d:\Microsoft Configuration Manager\Logs\Setupapi.offline.log’ for inspection of boot image update process”
    ~~..\sspbootimagepackage.cpp(4236) : Failed to insert OSD binaries into the WIM file~~

    I have checked file level permissions on the “new” osdinjection.xml and compared them to a copy of the “old” osdinjection.xml and the permissions are the same. I’ve also started the admin console with admin rights. Any suggestions?

  • Reply
    Jason Ligon
    October 22, 2018 at 3:03 pm


    I am seeing the following messages in the SMSProv.log when attempting to create a new boot image.

    “Failed to load OsdInjection.xml”
    “ERROR> Failed to copy OSD files.”
    “Copied log file ‘Setupapi.offline.log’ to ‘d:\Microsoft Configuration Manager\Logs\Setupapi.offline.log’ for inspection of boot image update process”
    ~~..\sspbootimagepackage.cpp(4236) : Failed to insert OSD binaries into the WIM file~~

    I checked Setupapi.offline.log and the most recent logs were from over two weeks ago.

    I ensured to start up the Admin Console with admin rights. I also did file level security comparison on the “new” osdinjection.xml file vs. the “old” original copy of osdinjection.xml and the security was exactly the same.

    Any ideas what might be going on?

    • Reply
      Adam Gross
      October 22, 2018 at 4:50 pm

      Check the xml for typos and test by swapping the xml back to the default and trying the build again. The smsprov log should list the file it can’t find if it’s a file pathing issue.

  • Reply
    November 25, 2018 at 7:30 pm


    Great articles, thanks for taking the time to write them!

    Just a quick question, Can you use the “enable pre-start command” under the customization tab of the boot image’s properties to launch the script?

    • Reply
      Adam Gross
      November 25, 2018 at 7:53 pm

      Yes, I believe you can use the pre-start commands. You just have to remember to add them each time you make a new boot image. I did t like having to remember that extra step, so I use the OSDInjection.XML instead.

    • Reply
      December 15, 2018 at 8:27 am

      Hi Matt, I found out that the prestart command does not run when you start your task sequence from the configmgr client (I am using ConfigMgr 1806). If you start from PXE or Media, it works fine.

      The prestart files, however, are integrated into the boot image. The solution it to run the script as the first TS step after the reboot, which can be found in a fixed location: %systemdrive%\sms\PKG\SMS10000\script.bat

      This avoids messing up with the OSDInjection.xml

  • Reply
    July 4, 2019 at 6:33 am

    Hi Adam,
    I have tried to run this but unfortunately the boot.wim file does not recognize the commands, such as sc.exe as this doesn’t exist.

    Any idea how to rectify?

  • Comment

    This site uses Akismet to reduce spam. Learn how your comment data is processed.


    Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113 Stack trace: #0 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(156): Guzzle in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113