Using Lines of File to Lookup other information

Back story - we recently found out that we were seeing Windows 11 upgrades failing and it appears to be due to a BlockMigration flag that equals True in the ScanResult.xml file in c:$WINDOWS.~BT\Sources\Panther. From the ones we looked at we were able to verify that they were microsoft Scan to pdf and Microsoft XPS Document writer but I was trying to get a wider scope by looking at the files for machines via relevance to get a better picture of any other drivers that might be blocking feature updates or windows upgrades.

This gets me the 2 oem___.inf files that are set to BlockMigration=“True” but what I would like to do is get the names of those inf files that have blockmigration=“True”, find them in c:\windows\inf and get the driver listed under [Microsoft.NTamd64] . Does anyone know if it’s possible or feasible to bridge multiple file searches?

This is what the line looks like in the oemxx.inf file in c:\windows\inf

[Microsoft.NTamd64]
“Microsoft XPS Document Writer v4” = MXDW,{0F4130DD-19C7-7ab6-99A1-980F03B2EE4E}

This relevance will give the name of the oemxx.inf file or files (I have 2) that have BlockMigration=“True”

(preceding texts of lasts “%22 BlockMigration=” of following texts of firsts “<DriverPackage Inf=%22” of lines containing “BlockMigration=%22True%22” of (file “ScanResult.xml” of folder “$WINDOWS.~BT\Sources\Panther” of drive of system folder) as string)

What does that second query give you? Just the “oemxx.inf” string, or the full path to the file?

It just gives the Oemxx.inf string, it does not give the full path but that inf file should be located in “c:\windows\inf”

One challenge to me is that it gives me 2 oemxx.inf files and I really need to look up the values for both of them

I updated the description in the original post to hopefully clarify that

Yes, I understand the problem (and have come across it myself a few times).

It’s definitely possible, but it’s not simple, at all, due to a combination of relevance limitations & unresolved bugs.

We can definitely use your query to retrieve the files that we want to inspect, the problem then is that once we know we want to look in \windows\inf\oem1.inf and \windows\inf\oem3.inf, we need to retrieve the right values from those files.

The first inclination I had was to use the ‘section of file’ and ‘key of section’ inspectors to treat these as INI files; the problem there is that we have no iterator for sections or keys, you have to know the exact names of the sections and the exact names of the keys to retrieve the values. In this case we might know the names of the sections (it’s not always exactly Microsoft.NTamd64, sometimes it would be Microsoft.NTamd64.10.0 for example) … but in no case would we know the names of the values we want to retrieve.

The next solution I’d try would be to use the ‘variables of file’ inspector, which would give a list of every variable name and value in a format like

q: variables of (native files "c:\temp\test.inf")
A: [Version].Signature="$Windows NT$"
A: [Version].Class=Net
A: [Version].ClassGUID={4d36e972-e325-11ce-bfc1-08002be10318}
A: [Version].Provider=%25Microsoft%25
A: [Version].CatalogFile=msux64w10.cat   ;; for WHQL certified
A: [Version].DriverVer=01/24/2017,10.4.0124.2017
A: [Manufacturer].%25Microsoft%25=Microsoft, NTamd64.10.0
A: [ControlFlags].ExcludeFromSelect=*

…but this inspector is broken in that it cannot process files encoded in anything other than ASCII / UTF-8, and most of these INF files are encoded in UTF-16; they give no results for the ‘variables of file’ inspector.

With the easy paths out of the way, I think we’ll have to build our own parsing logic. That makes this similar to a relevance challenge I posted previously at Relevance Challenge December 2019 BONUS: Parsing Paragraphs (answer provided) that has several different solutions.

Of the solutions there, I think the easiest to understand and probably the best to use in this case is where we concatenate all the lines together into one string so we can use ‘preceding text’ and ‘following text’ to isolate the one section that we want, then split that back out into its individual lines. I concatenate (and then split) on the "%0a" character, which is a newline character so we know it’s not actually a literal value in the file. Leaving aside ‘how to find the right INF file’ for the moment, this illustrates what I mean:

q: lines of files "c:\temp\test.inf"
A: ; ** COPYRIGHT (C) 2007-2017 Microsoft CORPORATION
A: ;
...
A: 
A: [Version]
A: Signature   = "$Windows NT$"
...
A: 
A: [Microsoft.NTamd64.10.0]
A: %25RTL8153.DeviceDesc%25 = RTL8153.ndi,USB\VID_045E&PID_07C6&REV_3000
A: %25RTL8153.DeviceDesc%25 = RTL8153B.ndi,USB\VID_045E&PID_0927&REV_3100
A: %25RTL8153.DeviceDesc%25 = RTL8153B_S5WOL.ndi,USB\VID_045E&PID_0927&REV_3101
A: 
A: ;;****************************************************************************
A: ;; Windows 10
A: ;;****************************************************************************
A: [RTL8152B.ndi.NT]
A: AddReg = MSUX64W10.NT.Reg
...


q: concatenation "%0a" of lines of files "c:\temp\test.inf"
A: ; ** COPYRIGHT (C) 2007-2017 Microsoft CORPORATION%0a;%0a%0a;;%0a;; This product is covered by one or more of the following patents:%0a;; US6,570,884, US6,115,776, and US6,327,625.%0a;;%0a%0a[Version]%0aSignature   = "$Windows NT$"%0aClass       = Net%0aClassGUID   = {4d36e972-e325-11ce-bfc1-08002be10318}%0aProvider    = %25Microsoft%25%0aCatalogFile = msux64w10.cat   ;; for WHQL certified%0aDriverVer   = 01/24/2017,10.4.0124.2017%0a%0a[Manufacturer]%0a%25Microsoft%25 = Microsoft, NTamd64.10.0%0a%0a[ControlFlags]%0aExcludeFromSelect = *%0a%0a[Microsoft]%0a;Empty section, so this INf does not support win2000%0a%0a[Microsoft.NTamd64.10.0]%0a%25RTL8153.DeviceDesc%25 = RTL8153.ndi,USB\VID_045E&PID_07C6&REV_3000%0a%25RTL8153.DeviceDesc%25 = RTL8153B.ndi,USB\VID_045E&PID_0927&REV_3100%0a%25RTL8153.DeviceDesc%25 = RTL8153B_S5WOL.ndi,USB\VID_045E&PID_0927&REV_3101%0a%0a;;****************************************************************************%0a;; Windows 10%0a;;****************************************************************************%0a[RTL8152B.ndi.NT]%0aAddReg = MSUX64W10.NT.Reg%0a



// isolate the section that we want - beginning from the first ']' after '[Microsoft.NTamd64' and ending at the next combination of newline & '[' (or, the end of the file, if there is no new section after this one).  ALso keep track of the filename, since we may want to reference the specific oemxx.inf file later:

q: (names of it, ((preceding text of first "%0a[" of it | it) of following texts of firsts "]" of following texts of firsts "[Microsoft.NTamd64" of it) of concatenations "%0a" of lines of it) of files ("oem1.inf";"oem3.inf") of folders "c:\windows\inf"
A: oem3.inf, ( %0a%25RTL8153.DeviceDesc%25 = RTL8153.ndi,USB\VID_045E&PID_07C6&REV_3000%0a%25RTL8153.DeviceDesc%25 = RTL8153B.ndi,USB\VID_045E&PID_0927&REV_3100%0a%25RTL8153.DeviceDesc%25 = RTL8153B_S5WOL.ndi,USB\VID_045E&PID_0927&REV_3101%0a%0a;;****************************************************************************%0a;; Windows 10%0a;;**************************************************************************** )
T: 33.677 ms
I: plural ( string, substring )

//  with the right section isolated, split it back up into separate results again

q: (names of it, (substrings separated by "%0a" of it) of ((preceding text of first "%0a[" of it | it) of following texts of firsts "]" of following texts of firsts "[Microsoft.NTamd64" of it) of concatenations "%0a" of lines of it) of files ("oem1.inf";"oem3.inf") of folders "c:\windows\inf"
A: oem3.inf, 
A: oem3.inf, ( %25RTL8153.DeviceDesc%25 = RTL8153.ndi,USB\VID_045E&PID_07C6&REV_3000 )
A: oem3.inf, ( %25RTL8153.DeviceDesc%25 = RTL8153B.ndi,USB\VID_045E&PID_0927&REV_3100 )
A: oem3.inf, ( %25RTL8153.DeviceDesc%25 = RTL8153B_S5WOL.ndi,USB\VID_045E&PID_0927&REV_3101 )
A: oem3.inf, 
A: oem3.inf, ;;****************************************************************************
A: oem3.inf, ;; Windows 10
A: oem3.inf, ;;****************************************************************************
T: 33.293 ms
I: plural ( string, substring )

// since we only want the names of the values, take the preceding texts of the equals signs.  And since the name may be repeated, take the 'unique values of it'.

q: (names of it, unique values of (preceding texts of firsts " = " of it as trimmed string) of (substrings separated by "%0a" of it) of ((preceding text of first "%0a[" of it | it) of following texts of firsts "]" of following texts of firsts "[Microsoft.NTamd64" of it) of concatenations "%0a" of lines of it) of files ("oem1.inf";"oem3.inf") of folders "c:\windows\inf"
A: oem3.inf, %25RTL8153.DeviceDesc%25
T: 33.641 ms
I: plural ( string, string with multiplicity )

Next we need to deal with retrieving the right .inf files to inspect. Here’s an example of testing more than one file; we’ll just need to substitute in your query in place of the list of filenames

q: (names of it, unique values of (preceding texts of firsts " = " of it as trimmed string) of (substrings separated by "%0a" of it) of ((preceding text of first "%0a[" of it | it) of following texts of firsts "]" of following texts of firsts "[Microsoft.NTamd64" of it) of concatenations "%0a" of lines of it) of files ( /* YOUR QUERY HERE */  "oem1.inf";"oem3.inf"  ) of folders "c:\windows\inf"
A: oem3.inf, %25RTL8153.DeviceDesc%25
T: 15.200 ms
I: plural ( string, string with multiplicity )

So, what I think should work is

q: (names of it, unique values of (preceding texts of firsts "=" of it as trimmed string) of (substrings separated by "%0a" of it) of ((preceding text of first "%0a[" of it | it) of following texts of firsts "]" of following texts of firsts "[Microsoft.NTamd64" of it) of concatenations "%0a" of lines of it) of files ( (preceding texts of lasts "%22 BlockMigration=" of following texts of firsts "<DriverPackage Inf=%22" of lines containing "BlockMigration=%22True%22" of (file "ScanResult.xml" of folder "$WINDOWS.~BT\Sources\Panther" of drive of system folder) as string) ) of folders "c:\windows\inf"

4 Likes

I genuinely appreciate how you didn’t just provide the answer and broke down the equation down at each level and explained the what’s and why’s for what you were doing. This relevance worked for me on one machine already and will be testing it on a couple others before I set it up as an analysis so other failed machines will report the date. I greatly appreciate the insight on this and it will be a huge help for me and hopefully it will help others who might read this post in the future.

3 Likes