Remotely delete multiple registry keys in a wildcard folder using powershell?

1.3k views Asked by At

I am working on a script that will delete App-V keys stored in the registry. When a user opens an application, it creates a key within the following location:

HKLM\SOFTWARE\Microsoft\AppV\MAV\Configuration\Packages\**PackageID**\UserConfigEx\**SID**

The PackageID and the SID are unique each time and I want to be able to delete the SID subkey within each PackageID key.

The user will enter the SID and then I would like to use a wildcard (if possible) to navigate into each Package ID which is present.

So far I have the following:

#Take user input
$SID = Read-Host "Please enter users SID"
$computer = Read-Host "Please enter computer name"

#Test connection
Write-Host "Connecting to $computer"

if (Test-Connection -ComputerName $computer -Quiet -BufferSize 16 -Count 1) {

#Connect to registry and delete key
try
{
    $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘LocalMachine’, $computer)
    $regKey = $reg.OpenSubKey(“HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\AppV\\MAV\\Configuration\\Packages\\*\\UserConfigEx\\$SID”,$true )

    if ($regkey.GetValue(“$SID”))
    {
        $regKey.DeleteValue(“$SID”)
        Write-Host
        Write-Host "$SID key deleted successfully" -ForegroundColor Green
    }
    else
    {
        Write-Host
        Write-Host "No keys with this SID exist." -ForegroundColor Red
    }


} catch {

    $ErrorMessage = $_.Exception.Message
    Write-Host "Unable to connect to $computer. Error: $($ErrorMessage)." -ForegroundColor Red 

}

} else 

    { 

    Write-Host "Unable to connect to $computer. Please ensure correct computer name / IP address has been entered correctly." -ForegroundColor Red

}

If I run this I receive:

You cannot call a method on a null-valued expression.
At line:51 char:9
+     if ($regkey.GetValue(“$SID”))
+         ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

I am using some of the script which I received help with here to remotely connect to the machine.

2

There are 2 answers

4
mklement0 On BEST ANSWER
  • The .NET registry API doesn't support wildcards (*) in key paths.

    • As a result, the $regKey.GetValue() failed, because $regKey = $reg.OpenSubKey(...) returned $null due to not finding a key, and calling a method on $null always results in the error message quoted in the question.
  • By contrast, PowerShell's registry provider, via the *-Item* cmdlets, does, but you need PowerShell remoting in order to use it remotely.

    • PowerShell remoting is enabled by default on Windows Server 2012 and above; on older OS versions you can enable it by running Enable-PSRemoting on the target machine(s) (requires PSv3+).

    • With PowerShell remoting enabled, you need to wrap your code in an Invoke-Command -ComputerName <name> { ... } call (to which you may have to pass credentials too).

  • If enabling PowerShell remoting is not an option, you must emulate wildcard-based matching via a nested loop based on per-element wildcard matching of the results from .GetSubkeyNames().

  • As an aside: you never need to escape \ as \\ in PowerShell strings; PowerShell uses ` as the escape character inside "...", so the only character you need to escape there is ` itself, as ``.

A PowerShell remoting-based solution:

Note that Invoke-Command -ComputerName ... must be called from an elevated session (Run As Administrator):

try {
  Invoke-Command -ErrorAction Stop -ComputerName $computer {

    # Define wildcard-based path.
    $keyPath = "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppV\MAV\Configuration\Packages\*\UserConfigEx\$SID"

    # See if it matches any keys.
    if (Test-Path $keyPath) {
      # Note: I'm assuming you want to remove the entire *key*.
      #       To only remove a key's *value*, use Remove-ItemProperty.
      Remove-Item -Path $keyPath
    } else {
      Write-Warning "No keys with SID $SID exist."
    }

  }

} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
  # Note: Depending on the specifics of your Invoke-Command call, the reason may
  #       be permissions-related; when in doubt, examine $_
  Write-Warning "Unable to connect to $computer. Please ensure correct computer name / IP address has been entered correctly:`n$_"
} catch {
  # Other, unexpected failure.
  Throw
}
2
committhisgit On

Looks like an ascii vs unicode quotation mark issue:

You have:

$regkey.GetValue(“$SID”)

which should be replaced with:

$regkey.GetValue("$SID")