Search code examples
windowspowershellregistrynvidia

How to find necessary entry in registry via powershell script?


I made a small PowerShell script that suppose to find uniquely named monitor folder in registry and then create a key in other pre-defined entry - https://github.com/SLStyler/Dithering-for-Windows-Simple-BAT-

These lines should define the right entry\path:

$DisplayPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\DISPLAY" \\ This path should contain display "unique" name
$GetDisplay = Get-ChildItem -Path $DisplayPath -exclude Default* | Select-Object Name |Split-Path -Leaf
$GetDisplay = $GetDisplay.replace("}","")
$Path = "HKLM:\SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase\" \\ This path should contain "unique" display identifier subkey and some other subkeys, so using $GetDisplay, script chooses the right one   
$GetFolder = Get-ChildItem -Path $Path -include $GetDisplay* -recurse |Select-Object Name |Split-Path -Leaf
$GetFolder = $GetFolder.replace("}","")

It works perfectly fine on my system and this entry contains only two subentries\subkeys.

Picture of $GetDisplay = HKLM:\SYSTEM\CurrentControlSet\Enum\DISPLAY

GSM5B55 is my display's "unique" name and just by excluding the "Default_Monitor", script finds the one needed.

But on some systems script shows error at launch because it cannot find the folder, either because there is more than one "uniquely" named subkey or none at all. (I don't know what it depends on but probably only Nvidia developer can explain.)

In my case there is only one with the name of the monitor GSM5B55..., so script have no errors in deciding which subentry to use:

Picture of $GetFolder = HKLM:\SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase\

This is a screenshot of a random guy's same path. I suppose in his case the unique display identifier is ACI27EC. But for some reason my script doesn't work on his pc.

enter image description here

I'm absolutely out of ideas, and would be glad to receive any form of help, thank you


Solution

    • You must handle the following edge case:

      • There may be only a default monitor.
      • There may be multiple non-default monitors.
    • Replace Select-Object Name with either Select-Object -ExpandProperty Name or, more simply, ForEach-Object Name.

      • Select-Object (select) by default returns a [pscustomobject] instance that has the requested properties - even when you're only asking for a single property. The suggested change returns only the Name property's value. See this answer for background information.

    Therefore:

    $displayPath = 'HKLM:\SYSTEM\CurrentControlSet\Enum\DISPLAY' 
    $nonDefaultMonitorNames = 
      Get-ChildItem -LiteralPath $displayPath -Exclude Default* | 
      ForEach-Object Name |
      Split-Path -Leaf
    
    $displayDatabasePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase'
    $displayDatabaseKeyNames = 
      Get-ChildItem -Recurse -LiteralPath $displayDatabasePath -Include $nonDefaultMonitorNames.ForEach({ $_ + '*' }) |
        ForEach-Object Name |
        Split-Path -Leaf
    
    • Windows PowerShell solution:

    Unfortunately, in Windows PowerShell the use of -Include and -Exclude is subject to many quirks and bugs.
    While PowerShell (Core) is no longer plagued by them with respect to the registry provider, specifically, it unfortunately still is with respect to the file-system provider; see the bottom section of this answer, whose techniques are borrowed for the solution below.

    $displayPath = 'HKLM:\SYSTEM\CurrentControlSet\Enum\DISPLAY' 
    $nonDefaultMonitorNames = 
      Get-Item -Path $displayPath\* -Exclude Default* | 
      ForEach-Object Name |
      Split-Path -Leaf
    
    $displayDatabasePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase'
    $displayDatabaseKeyNames = 
      Get-ChildItem -Recurse -Path $displayDatabasePath -Include $nonDefaultMonitorNames.ForEach({ $_ + '*' }) |
        ForEach-Object Name |
        Split-Path -Leaf
    

    Note:

    • The HKLM:\SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase registry key is seemingly NVIDIA-specific, so may not be present on all machines.

    • $nonDefaultMonitorNames.ForEach({ $_ + '*' }) potentially creates an array of inclusion patterns, by appending '*' to the value of / each element of $nonDefaultMonitorNames, using the intrinsic .ForEach() method