Sunday, November 24, 2019

Windows 7 on Ryzen 3000

My kids’ gaming PC died in early 2019. The motherboard or CPU fried and took the other with it.  It was an FX-8370 (AM3+) based MSI system with R9 270X Video Card. I gave them a choice: I build a new one around Ryzen 2, or they wait for Ryzen 3 and get more. I am happy they chose the latter, so we waited until Ryzen 3 came out. I decided to wait more for the MSI MAX boards which have a larger firmware (BIOS) chip. I finally got tired of waiting and was going to get an ASRock Steel Legend and found the MAX on NewEgg when I started ordering. I went with this config:
I already had the power supply, GPU, and storage from the old one to reuse. After assembly, I was pleased it came up on first try. I put Windows 10 and let my youngest play FortNite on it for a few hours. Who needs CPUBurn when you have a gaming kid...!

Before it went into "production" I wanted to get Windows 7 on it for ... Reasons. MSI, AMD, and other sites only say Windows 7 is supported on these Ryzen processors:
  • Bristol Ridge (APU)
  • Summit Ridge (Ryzen 1)
  • Pinnacle Ridge (Ryzen 2)
Since mine is a Ryzen 3000, its code name is Matisse and therefore unsupported. Which is fine really, as Windows 7 goes EOL in a very short few months. This motherboard is B450 based so it should have some support compared to the newer X570 chipset. As I've proven many times over with my deployment work, just because it’s unsupported doesn't mean it won't work. So away I went!

I put a 250GB SSD I keep as a spare on port 1 of the mobo and boot off my Windows 7 AIO USB. It also includes the NVMe, TPM2, and Post SP1 rollup on it. Get to the welcome screen, and nothing. Keyboard and mouse are dead. Try a couple other ports and even the "slow" ones by the NIC used for keyboard and mouse compatibility. NOTHING. Change some USB compatibility settings in the BIOS. STILL NOTHING. Unable to interact with the wizard makes it real hard to inject drivers. It might be a short trip. Instead, I swing by my dad’s and grab an old HP PS2 keyboard since this is a gaming board. Works! Get through the wizard to where it asks what partition to install onto and it wants drivers since it cannot see the storage.

Next problem. l pull a trick from ConfigMgr and MDT: inject drivers. I grab the MSI Windows 7 drivers as well as AMD's all-in-one and inject those drivers into the boot.wim on the AIO USB and reboot. No luck. I then mount the Windows PE BOOT.WIM and put the drivers on it in a folder so I can browse them in the wizard. Still no luck. Note to self: The installer's main volume is index 2 of BOOT.WIM and this is what you could browse. I also try the Windows 10 BOOT.WIM and it errors out in fantastic ways I need to revisit.

I then decide to use an older storage controller but don’t have any available so order one and got this ASM1061-based one which I know uses built-in drivers in at least Vista, and it says it is supported back to even XP. After installing it into the machine I get to the same spot, however, I can now browse the SSD as it had a single NTFS partition on it. But I still cannot proceed.

Next problem. I attach the SSD to a Linux VM and copy the MSI and AMD drivers along with others that I think might work as I did not have to mess with the BOOT.WIM since I reverted back to the original sealed one. The error dialog changes slightly from before and hints it could not find the install media. PE will use higher performance drivers. I burn the Windows 7 AIO to a DVD and hook up a BluRay player and SUCCESS!  It did not work off the motherboard but does work off the PCIe controller I got above. Windows 7 got installed!

After boot-up I still have chipset/USB issues as only the PS2 keyboard worked, so I open a shell and install the AMD all-in-one and got USB mouse and keyboard. I also install the NIC and Audio drivers. Out of curiosity, I move the SSD to the internal controller and it boots up fine now that it had the right drivers. It was happy and I could have used it after applying patches.

Now that I got what I wanted out of Windows 7, I move the (Windows 10) SSD and hard drive from the fried system to it and give it to the kids so they can run that for a while. I will keep an eye on sales over the holidays though. I do want to get this system over to M.2 NVMe. So told the kids it will get rebuilt from scratch when I obtain those. This instance of Windows has been in about 5 or 6 different PCs. Additionally, my FX-8350 system is showing its age so I'll move to Ryzen in a few months and hand this down to my backup server. Maybe I'll have to do this again or just move the kids to a 3950X and X570 system while I take the guts from this one. Their games push a system more than my work does.


Thursday, November 21, 2019

Enforce TLS 1.2 via ConfigMgr Compliance Setting

One of the products in our environment is deprecating support for earlier TLS versions 1.0 and 1.1 (Yay!). This means we are being required to support TLS 1.2 for this product on Windows 7, Windows Server 2008 R2, and Windows Server 2012. It is default on more recent OSes, such as Windows 8 and Windows Server 2012 R2 and greater. TLS 1.2 should be enabled via  KB3140245. While installed on the majority, we found it actually was not enabled on all of the fleet even though this KB was applied a while ago.

So Piers came to the rescue with a Compliance Setting to manage this. Luckily TLS is set at the OS level via registry keys so it is not that difficult to manage. Piers enjoys using PowerShell so he went that route to mitigate.


Piers created a compliance baseline in ConfigMgr which reports on the following:

Windows 7 requirements for TLS 1.2
  • KB3140245 must be installed
  • [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
    • "DisabledByDefault"=dword:00000000
Windows 2008 R2 and 2012 requirements for TLS 1.2
(Note this is slightly different.)
  • KB3140245 must be installed
  • [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
    • "DisabledByDefault"=dword:00000000
    • "Enabled=dword:00000001"
      • Or "Enabled=dword:0xFFFFFFFF" (It equates to decimal 1 – see info here)
  • [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
    • "DisabledByDefault"=dword:00000000
    • "Enabled=dword:00000001"
      • Or "Enabled=dword:0xFFFFFFFF"
This is checking both server and workstations for TLS 1.2 enablement at the OS level. This overrides any TLS settings set explicitly for IE, as we understand it, so I don’t believe we need to check IE-specific settings (see the section "How the DefaultSecureProtocols registry entry works" in this article).
  • Firefox has had TLS 1.2 support enabled since version 27
  • For Chrome, TLS 1.2 is automatically enabled from version 29


We created several compliance items to detect TLS 1.2 and enable if not. For servers, they were eventually split out for Server and Client functions of TLS for IIS, etc. and to make use of nice features such as Supported Platforms so we can target them specifically for advertisements.

We are using the following discovery script for the client keys:

 $RegPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client'  
 $RegName = 'DisabledByDefault'  
 $RegData = '0'  
 $Return = 'Not Found'  
 $RegLookUp = Get-ItemProperty -Name $RegName -Path $RegPath -ErrorAction SilentlyContinue  
 if ($RegLookUp.$RegName -eq $RegData) {  
   $Return = 'Found'  
 if ( $RegLookUp -and ($RegLookUp.$RegName -ne $RegData) ) {  
   $Return = 'Value='+$RegLookUp.$RegName  
 Write-Host $Return  

He is using a remediation script adapted fromRoger Zander:

 # Reg2CI (c) 2019 by Roger Zander  
 if((Test-Path -LiteralPath "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client") -ne $true) { New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client" -force -ea SilentlyContinue };  
 New-ItemProperty -LiteralPath 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -Name 'DisabledByDefault' -Value 0 -PropertyType DWord -Force -ea SilentlyContinue;  

The Compliance rule is pretty straightforward. It looks for "Found" from the Discovery Script.

The configuration baselines are pretty straightforward as well.

The Client baseline contains both workstation and Server OS versions.

We have two advertisements: one to monitor, and one to remediate. The monitor is run daily and remediate is run every couple hours.

The advertisement is going to a collection that calls out the affected Operating Systems only.

For the server settings, just change the relevant registry path, as the rest is the same.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]

This is a good read on it from a Dev perspective via a Microsoft Security post.

Tuesday, November 19, 2019

Using Global Entry API to Get Better Appointment


I bit the bullet and decided to apply for TSA PreCheck for my traveling. Since it was only $15 US more for Global Entry (GE), I actually went that route. It gives me everything PreCheck does along with quicker customs processing when I return to the States. Since it has more intrusive background checks, you have to do an interview for final approval. With all the political drama going on right now, staffing these locations has been a challenge for US Customs and Border Protection. If I knew then what I know now, I would have just gotten TSA PreCheck.

I applied around February 2019 and after about a month was moved to the 'Conditionally Approved' phase so I was able to set an appointment for the interview. My brother applied a week after me and just now was made 'Conditionally Approved' this week. In my case, I set an appointment at Denver (DIA) and the soonest was May 2019. Two days before my appointment it was canceled on me and the soonest they had was July so I signed for that. That was canceled on me and Jan 2021 was the next avail. That put me at nearly a year from application. Ugh. 


As both my brother and I are in IT we started talking about getting an earlier appointment. People have to cancel their appointments for example so what happens to them? Did some research and found that the Global Entry website has an API available to talk to its database.

Sure enough, we found a blog post about it by Jeremy Stretch. ‘stretch' covers a GitHub repository he found that looks for appointments via the GE API. As the GE site changed, he had to start over and documented what he did but never finished it out as he got an appointment via the website. So my brother and I decided we could get something going based on what stretch started. My brother volunteered to write it in Python and I offered to run it on my main Ubuntu server.

As stretch documented, you can go into your browser's developer mode while looking at appointments on the website to pull out the site code.
  • Denver          6940
  • Miami           5181
  • Fort Lauderdale 5443
We looked up a few others for testing and apparently, Guam has free slots almost daily. I should go there! After identifying the office codes, we went to work within our requirements:
       Since there were no rules of engagement around the API we decided to run it every 5 minutes via cron.
       It will email us when it finds an opening. Nothing special, it just uses the MTA on the system such as PostFix.
       It will also stop once it finds one, and we have to reset it, also done around the API concerns. This drops /tmp/checkGE.disable and the script will exit out if that dropper is found.
       It should also track its history when it finds openings, and this is kept in /tmp/checkGE.history.
       Support multiple locations.
After writing it and doing some initial bug hunting it was returning results – too many, as it would show what was freshly available six to nine months out. Since I had an appointment a few months out, I was only interested in an earlier appointment so it supports regex to parse specific ranges. Initially, it was the remainder of 2019, but we then wanted the first couple months of 2020.

if re.match('^(2019-(10|11|12)|2020-(01|02))-',result):

This was done for readability more than optimized performance. Additionally, it follows ISO 8601, which is in the format of YYYY-MM-DDThh:mm:ss. In the above example, it is looking for the following months:

       October 2019
       November 2019
       December 2019
       January 2020
       February 2020

So this could have its regex streamlined as the following, but it would be much harder to read and modify if we had to go further into 2020 versus above.

if re.match(^20(19-1[0-2]|20-(0[12]))-',result):

Once it was set up, we just had to be near a PC when the email showed up to go to the website to snag the earlier appointment when we were notified one was available. I cannot prove it, but I believe the website polls the database on an interval as well. We had a few matches but they were not on the website. Initially, I thought I was too late, but a couple of appointments showed up on the website a few minutes after I got the email notification.

I really lucked out as it found an appointment two days out for me, which I snagged. I am all set up with Global Entry now. Wahoo! I might have to dust this off in 5 years if I get elected to go through another interview during the renewal process.


This script is provided as-is; no warranty is provided or implied. The author is NOT responsible for any damages or data loss that may occur through the use of this script.  Always test, test, test before rolling anything into a production environment.

Since it was not originally written to share, you will have to work on it a little. Using what stretch covered, get your locations to code on line 14. Adjust the regex on line 26. Enter your email address on line 11. You can find the script here.