Well, let’s break down your issue a little. When you’re trying to write something, you have to break down the big plan into tiny steps, so I provided the following tiny skill steps in my previous post for you
- Connecting to a remote registry
- Walking that remote registry to a specific key
- Reading all the elements in that key
- Tucking those elements into an array
- Reading the array
- And how to delete a target
- One specific method for identifying a string
Now you're trying to identify a string based on a portion of it via the -notmatch comparison operator. We could have as easily used the -notlike, or we could change our logic and use -match and -like instead of their -not variants. So let's get into a little code shall we?
To begin, we make a connection to the registry. In my case, I don’t have the key you’re looking at, so I’m going to change it to another area.
clear
#set your target
[string]$targethost = “midnight”
#Marshalled OBject targeting HKEY_Local_Machine
$RemoteKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::'LocalMachine',$targethost)
#set the path you're looking for
#[string]$regPath = “SOFTWARE\Microsoft\Windows\CurrentVersion\NetCache\PurgeAtNextLogoff\”
[string]$regPath = “SOFTWARE\Microsoft\Windows\CurrentVersion\FileAssociations\UpgradeChoice”
#Open your remote key with write permissions
$regkey = $RemoteKey.OpenSubKey($regPath,$true)
#Get the name of all elements within the key
$regkey.GetValueNames()
#Declare an array
$array = @()
#Dump the elements into the array
$array = $regkey.GetValueNames()
Write-Host `n
Now that we have a connection, and I’m dumping out some values, let’s see what I get
SkipOOBEUpgradeChoice
AppUpgradeVersion
Photos
Webbrowser
Music
Video
I’m going to pick a partial word - in this case I’m going to say “Version”. So if any value has Version in the name, I want to do something with it. I could jump straight to the answer here, but what I’m trying to do is teach you to use what you have available. A lot of times we look in forums, tutorials, etc. which can be useful in the right circumstances, but at this level you could simply write some code testing several options, and keep playing so you learn what they all do. A young programmer often doesn’t recognize the options right in front of them. So, for teaching purposes, I created a foreach loop and looked at several choices:
#Identity everything that is not the value you want
foreach($i in $array)
{
If($i -contains "version")
{
write-host "This is -contains $i"
Write-Host `n
}
If($i -like "version")
{
write-host "This is -like $i"
Write-Host `n
}
If($i -like "*version*")
{
write-host "This is -like with wildcards $i"
Write-Host `n
}
If($i -match "version")
{
write-host "This is -match $i"
Write-Host `n
}
If($i -notmatch "version")
{
Write-Host "This is -notmatch $i"
Write-Host `n
}
If($i -notlike "version")
{
Write-Host "This is -notlike $i"
Write-Host `n
}
}
So using this loop, what were the results?
This is -notmatch SkipOOBEUpgradeChoice
This is -notlike SkipOOBEUpgradeChoice
This is -like with wildcards AppUpgradeVersion
This is -match AppUpgradeVersion
This is -notlike AppUpgradeVersion
This is -notmatch Photos
This is -notlike Photos
This is -notmatch Webbrowser
This is -notlike Webbrowser
This is -notmatch Music
This is -notlike Music
This is -notmatch Video
This is -notlike Video
Hmm, we see
-notmatch
-like
-match
-notlike
but what we don’t see is -contains. So right away you know that option won’t work as it’s written. But let’s look a little closer at the output. The -notlike (without wildcards) operator kicked out one with version in the name, and the only -like I see is one with the wildcards. So now you know you have to use the ones with wildcards if you use the -like operator. So let’s take this to the next level… you wanted to target everything that didn’t have a specific partial value for deletion… programmatically we could handle that several ways, but let’s do it by creating a new array of what we want to delete. And while we’re at it, let’s see what we’re adding to the array, and what we’re skipping.
#so now we go about this programmatically
$targetdeletionarray = @()
foreach ($x in $array)
{
if($x -match "version")
{
write-host "*****************************************************"
Write-Host "***We're skipping $x because it matches***"
Write-Host "*****************************************************"
}
Else
{
write-host "Adding $x to deletion targets"
$targetdeletionarray += $x
}
}
Write-Host `n
Write-Host "We would delete these "
foreach ($y in $targetdeletionarray)
{
Write-Host $y
}
And our output is:
Adding SkipOOBEUpgradeChoice to deletion targets
*****************************************************
***We're skipping AppUpgradeVersion because it matches***
*****************************************************
Adding Photos to deletion targets
Adding Webbrowser to deletion targets
Adding Music to deletion targets
Adding Video to deletion targets
We would delete these
SkipOOBEUpgradeChoice
Photos
Webbrowser
Music
Video
The top section is us telling ourselves what we’re adding to the deletion array, and what we’re skipping. The bottom is what’s actually in the deletion array. So, we created a new array of what we want to delete, we omitted from that array anything with the partial value we didn’t want to delete. Now we just have to write a new loop to delete those targets.
Some final thoughts:
- Always make the big things into smaller bites
- In my first freehand I didn't declare variables, in this one I did a little more. PS is a little forgiving in this, other languages aren't. You should learn to declare variables, so if you're really going to learn - do that.
- Posting my code into this forum tends to remove formatting - but on my screen it's formatted well. I say this to you because if you're going to learn, you need to make the code easier to read.
- This is all one section of code, but for complex programs I always create functions and call them. If you're wanting to expand, learn this.
- Learn to put comments in your code... good comments that explain the logic. It will help you later, and it helps anyone else reading it.
- You should release things when done. So for example $RemoteKey.Close(). You'll want to do a little research on this. You'll probably also want to remove variables when your program closes. The larger the script, the more distributed com, wmi, .net calls, etc. the more resources you have open. Generally PS is pretty good about cleaning up behind itself, however it doesn't always get it all, and this is a good programmers habit to be in.
- The last thought it just this... I'm not a teacher, and the folks I generally interact with are Systems Administrators or security folks. What I mean by that is I'm not precisely in my element here, so while I'm trying to help you, it may not be perfect. I'm also new to this forum for what that's worth.
Take care, and good luck.