How to delete registry properties with randomized names - powershell

I'm trying to remove junk registry items left from adware in several machines. The adware created registry keys in the following path:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\
Property: a random name that is different from machine to machine
Value: a malicious string that is the same from machine to machine
Get-ChildItem -path HKLM:\System\Controlset001\Services |
Get-ItemProperty |
Where-Object {$_.ValueName -eq "Value"} |
Remove-ItemProperty -ErrorAction SilentlyContinue
I´ve tried the method above to delete keys when I know the subkey and properties, but since the property is random I am getting no results. Thank you very much!

Here's an alternative script for get-itemproperty:
# get-itemproperty2.ps1
param([parameter(ValueFromPipeline)]$key)
process {
$key.getvaluenames() |
foreach {
$value = $_
[pscustomobject] #{
Path = $key -replace 'HKEY_CURRENT_USER',
'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
Name = $Value
Value = $Key.GetValue($Value)
Type = $Key.GetValueKind($Value)
}
}
}
So you can do something like:
Get-ChildItem HKLM:\System\Controlset001\Services | .\Get-ItemProperty2 |
Where Value -eq MyValue | Remove-ItemProperty -Whatif

Use of Get-ItemProperty isn't required for your task (and there is no need to re-implement a variation of it, the way that the currently accepted answer does).
Instead, filter by the output from the .GetValue() method applied to each subkey of the registry path of interest, assuming a known property name (registry value name):
# Specify whatever fixed value the malware stored in the 'ImagePath'
# property of the randomly named keys.
$propValue = '...'
Get-ChildItem -LiteralPath HKLM:\System\ControlSet001\Services |
Where-Object { $_.GetValue('ImagePath') -eq $propValue } |
Remove-Item -WhatIf
Note: Common parameter -WhatIf previews the operation; remove it to perform the actual operation.
Get-ChildItem -LiteralPath HKLM:\System\ControlSet001\Services enumerates all subkeys of the specified path.
Where-Object { $_.GetValue('ImagePath') -eq $propValue } selects only those subkey(s) whose ImagePath property has the specified value.
Remove-Item then removes the selected subkey(s).
If you want to find data (a property value) among all properties (registry values) of the input keys, you can use the following approach:
$propValue = '...'
Get-ChildItem -LiteralPath HKLM:\System\ControlSet001\Services |
Where-Object {
foreach ($name in $_.GetValueNames()) {
if ($_.GetValue($name) -eq $propValue) { return $true } }
}
}| Remove-Item -WhatIf

Related

Powershell - Is there any way to sort unique objects in ForEach-Object?

I have an array where I need to sort the unique values, and duplicates, and show that to Show-ListView. I am a beginner in making PowerShell scripts, especially for Sitecore so my code is going to look very bad, but bare with me.
Here is the code so far:
#($rootItem) + #($rootItem.Axes.GetDescendants() | Initialize-Item) |
ForEach-Object {
$currentItem = $_
Get-ItemField -Item $currentItem -ReturnType Field -Name "*" `
| ForEach-Object{
$NewValue = $value.Split(",")
ForEach($i in $NewValue) {
if($PSItem.Value -match $i -and $PSItem.Name.Contains("Tags")){
[pscustomobject]#{
"Name"=$currentItem.DisplayName
"ItemId"=$currentItem.ID
"FieldName"=$_.Name
"ItemPath" = Get-MediaUrl($currentItem)
}
Copy-Item -Path $currentItem.ItemPath -Destination $folderToMove.Paths.FullPath;
}
}
}
} | Show-ListView
The $rootItem is just a folder where those items exist (sitecore/Media Library/Images). Now I need to copy those items to another folder. That is actually not a problem, since in Sitecore it does not copy duplicate values, but in Show-ListView it shows them.
To describe you the problem I am encountering, I basically want to get Images that have certain tags. When you input one tag, everything is fine, but when I input set of tags, for example stackoverflow,sitecore, it shows one item that has these two tags, two times.
Is there any way for me to sort ForEach-Object. I now there is Sort-Object -Unique, but I do not know if that would help me.
Like #MathiasR.Jessen said in the comments, basically I had to add the |Sort-Object -Unique ItemID | Show-ListView at the end of the code.
The working code looks like this now:
#($rootItem) + #($rootItem.Axes.GetDescendants() | Initialize-Item) |
ForEach-Object {
$currentItem = $_
Get-ItemField -Item $currentItem -ReturnType Field -Name "*" `
| ForEach-Object{
$NewValue = $value.Split(",")
ForEach($i in $NewValue) {
if($PSItem.Value -match $i -and $PSItem.Name.Contains("Tags")){
[pscustomobject]#{
"Name"=$currentItem.DisplayName
"ItemId"=$currentItem.ID
"FieldName"=$_.Name
"ItemPath" = Get-MediaUrl($currentItem)
}
Copy-Item -Path $currentItem.ItemPath -Destination $folderToMove.Paths.FullPath;
}
}
}
} | Sort-Object -Unique ItemID | Show-ListView

Is there a way to search for Registry Keys and Values, export and delete them

Im searching for an way to delete the Registry Keys/Values from remote printers, the Keys/Values include the name "(umgeleitet", cause they are slowing down the whole RDP-Sessions. But I want to backup them just in case something gets deleted that shouldn't
I have already tried doing it with Get-ChildItem and Get-ItemProperty
$Folder = "C:\Users\Public\Documents\Backup"
Reg export HKU "$Folder\Backup.reg"
Get-ChildItem -path REGISTRY::HKEY_USERS\ -Recurse | where { $_.Name -match "(umgeleitet *)"}>> "$Folder\Log.log"
Get-ChildItem -path REGISTRY::HKEY_USERS\ -Recurse | where { $_.Name -match "(umgeleitet *)"} | Remove-Item -Force -Recurse
The code above doesn't delete the Values just the Keys.
Exporting:
Your question already shows the proper solution use: reg.exe export <key-path> <file> to export a registry key's subtree to a file.
Note that if you wanted to export the specific keys found as shown below, you'll have to call reg export for each, to separate files, given that reg export supports only a single target key path, and doesn't support appending to existing files.
Specifically, you could pipe the command below to reg export as follows, to create file1.reg, file2.reg, ... files:
$i = 1
Get-ChildItem -path REGISTRY::... | ForEach-Object {
reg.exe export $_.Name "file$(($i++)).reg"
}
Locating keys via matching against their value names:
Get-ChildItem -path REGISTRY::HKEY_USERS\ -Recurse | Where-Object {
$_.GetValueNames() -match '\(umgeleitet .*\)'
}
Note the need to use a proper regular expression with -match, in which literal ( and ) must be \-escaped, and in which .* represents any sequence of characters.
By contrast, what you used, (umgeleitet *), is a wildcard expression, to be used with -like (though note that wildcard expressions must match the entire input string).
If you wanted to match against value data, a little more work would be needed.
To remove the keys found, simply pipe the above to Remove-Item, as in your question:
... | Remove-Item -Force -Recurse
I rewrote the registry query a tiny bit, to match on the PSChildName property, which is shorter and will match a bit faster.
$matchingRegKeys = Get-ChildItem -path REGISTRY::HKEY_USERS\ -Recurse | where PSChildName -match "(umgeleitet *)"
You'll notice I also placed the results into a variable so we can iterate through them with a simple ForEach loop.
ForEach ($regkey in $matchingRegKeys){
"Removing $($regkey.Name)" | Tee-Object -Append "$Folder\Log.log"
$regkey >> "$Folder\Log.log"
Remove-Item -Path $regkey.PSPath
}
The Tee-Object command tells PowerShell to both write the output to the screen and also place the items appended into the filepath specified. Then we write the regkeys values out as well to the file.
Finally, we call Remove-Item and provide the $regkey.PSPath property, which corresponds to the full path of the key, so you can clear it out and any values.
In operation :
Removing HKEY_CURRENT_USER\Software\umgeleitet
Removing HKEY_CURRENT_USER\Software\umgeleitet2
Removing HKEY_CURRENT_USER\Software\umgeleitetTheAwakening
And a snip of the log file created:
Removing HKEY_CURRENT_USER\Software\umgeleitet
Hive: HKEY_CURRENT_USER\Software
Name Property
---- --------
umgeleitet SomeTestValue : true
The completed code
$Folder = "C:\Users\Public\Documents\Backup"
Reg export HKU "$Folder\Backup.reg"
$matchingRegKeys = Get-ChildItem -path REGISTRY::HKEY_USERS\ -Recurse | where PSChildName -match "(umgeleitet *)"
ForEach ($regkey in $matchingRegKeys){
"Removing $($regkey.Name)" | Tee-Object -Append "$Folder\Log.log"
$regkey >> "$Folder\Log.log"
Remove-Item -Path $regkey.PSPath
}
Here's a script alternative to get-itemproperty:
# get-itemproperty2.ps1
# get-childitem skips top level key properties, use get-item for that
# example pipe to set-itemproperty:
# ls -r hkcu:\key1 | get-itemproperty2 | where value -match value |
# set-itemproperty -value myvalue -whatif
param([parameter(ValueFromPipeline)]$key)
process {
$valuenames = $key.getvaluenames()
if ($valuenames) {
$valuenames | foreach {
$value = $_
[pscustomobject] #{
Path = $key -replace 'HKEY_CURRENT_USER',
'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
Name = $Value
Value = $Key.GetValue($Value)
Type = $Key.GetValueKind($Value)
}
}
} else {
[pscustomobject] #{
Path = $key -replace 'HKEY_CURRENT_USER',
'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
Name = ''
Value = ''
Type = ''
}
}
}
Then you can do things like:
ls -r hkcu:\key1 | .\get-itemproperty2 | where value -match value
Path Name Value Type
---- ---- ----- ----
HKCU:\key1\key2 name2 myvalue String
HKCU:\key1\key2\key3 name3 myvalue String
ls -r hkcu:\key1 | .\get-itemproperty2 | where value -match value | Remove-ItemProperty -WhatIf
What if: Performing the operation "Remove Property" on target "Item: HKEY_CURRENT_USER\key1\key2 Property: name2".
What if: Performing the operation "Remove Property" on target "Item: HKEY_CURRENT_USER\key1\key2\key3 Property: name3".

Delete all registries containing a string/value

I am trying to get this script to find all registries containing "e:\UC" in either its data or name. Most of the matches are not going to be an exact match and "e:\UC" will be in the beginning or middle of the Data or Name.
This is the script I cannot get to work with what I am trying to do. I believe that it is checking the data but not the name.
$RE = 'e:\UC'
$Key = 'HKLM'
Get-ChildItem $Key -Rec -EA SilentlyContinue | ForEach-Object {
$CurrentKey = (Get-ItemProperty -Path $_.PSPath)
if ($CurrentKey -match $RE) {
$CurrentKey | Remove-Item -Force -Whatif
}
}

search for a specific value name and its associated datakey in the registry with powershell

i'm trying to search any value name in the registry (HKLM:\Cluster\Resources) that match = VirtualServerName. and output his associated datakey to an array.
For Example:
Name Type Data
VirtualServerName REG_SZ SQLDEP05
But i couldn't find the right switch for a recurring search with the Get-ItemProperty command.
so ive tried using the Get-ChileItem insted:
$Reg = "HKLM:\Cluster\Resources\"
Get-ChildItem -recurse "$Reg" | Select-Object -Property VirtualServerName -ExcludeProperty $exclude | ForEach-Object { $_.PSObject.Properties.Value }
Which works only when im using the .Name option in the $_.PSObject.Properties switch.
But when i'm trying to get the value of VirtualServerName, .Value:
$Reg = "HKLM:\Cluster\Resources\"
Get-ChildItem -recurse "$Reg" | Select-Object -Property VirtualServerName -ExcludeProperty $exclude | ForEach-Object { $_.PSObject.Properties.Value }
i don't get any output.
Use Where-Object to test if a value name exists under a specific key with the GetValueNames() method:
$Keys = Get-ChildItem -Path $Reg -Recurse |Where-Object {$_.GetValueNames() -contains 'VirtualServerName'}
Now that you've got the relevant key(s), you can grab the value data with Get-ItemProperty:
$Keys |Get-ItemProperty VirtualServerName
or the GetValue() method:
$Keys |ForEach-Object {
$_.GetValue('VirtualServerName')
}

Using Array and get-childitem to find filenames with specific ids

In the most basic sense, I have a SQL query which returns an array of IDs, which I've stored into a variable $ID. I then want to perform a Get-childitem on a specific folder for any filenames that contain any of the IDs in said variable ($ID) There are three possible filenames that could exist:
$ID.xml
$ID_input.xml
$ID_output.xml
Once I have the results of get-childitem, I want to output this as a text file and delete the files from the folder. The part I'm having trouble with is filtering the results of get-childitem to define the filenames I'm looking for, so that only files that contain the IDs from the SQL output are displayed in my get-childitem results.
I found another way of doing this, which works fine, by using for-each ($i in $id), then building the desired filenames from that and performing a remove item on them:
# Build list of XML files
$XMLFile = foreach ($I in $ID)
{
"$XMLPath\$I.xml","$XMLPath\$I`_output.xml","$XMLPath\$I`_input.xml"
}
# Delete XML files
$XMLFile | Remove-Item -Force
However, this produces a lot of errors in the shell, as it tries to delete files that don't exist, but whose IDs do exist in the database. I also can't figure out how to produce a text output of the files that were actually deleted, doing it this way, so I'd like to get back to the get-childitem approach, if possible.
Any ideas would be greatly appreciated. If you require more info, just ask.
You can find all *.xml files with Get-ChildItem to minimize the number of files to test and then use regex to match the filenames. It's faster than a loop/multiple test, but harder to read if you're not familiar with regex.
$id = 123,111
#Create regex-pattern (search-pattern)
$regex = "^($(($id | ForEach-Object { [regex]::Escape($_) }) -join '|'))(?:_input|_output)?$"
$filesToDelete = Get-ChildItem -Path "c:\users\frode\Desktop\test" -Filter "*.xml" | Where-Object { $_.BaseName -match $regex }
#Save list of files
$filesToDelete | Select-Object -ExpandProperty FullName | Out-File "deletedfiles.txt" -Append
#Remove files (remove -WhatIf when ready)
$filesToDelete | Remove-Item -Force -WhatIf
Regex demo: https://regex101.com/r/dS2dJ5/2
Try this:
clear
$ID = "a", "b", "c"
$filesToDelete = New-Object System.Collections.ArrayList
$files = Get-ChildItem e:\
foreach ($I in $ID)
{
($files | Where-object { $_.Name -eq "$ID.xml" }).FullName | ForEach-Object { $filesToDelete.Add($_) }
($files | Where-object { $_.Name -eq "$ID_input.xml" }).FullName | ForEach-Object { $filesToDelete.Add($_) }
($files | Where-object { $_.Name -eq "$ID_output.xml" }).FullName | ForEach-Object { $filesToDelete.Add($_) }
}
$filesToDelete | select-object -Unique | ForEach-Object { Remove-Item $_ -Force }