Getting a specific process id from a powershell output - powershell

Hi I'm new to powershell scripting and I would like to retrieve a specific process id based on the file's hash. However I can only get either a table with the hash value or a table with the id,process name and path
$ps = Get-Process | Select-Object -Property Id,ProcessName,Path
$hashlist = Get-FileHash(Get-Process|Select-Object -ExpandProperty Path) -Algorithm MD5
Is it possible for me to merge the two tables together so that I can get a view of Id,ProcessName and Hash using the path to link them together?

EDIT: totally different approach due to new information from comment
I don't think it is so easy to identify malware with a file MD5 hash.
Modern AntiVirusSoftware uses heuristics to overcome the problem of mean malware which includes random data and also obfuscates it's origin.
## Q:\Test\2018\11\11\SO_53247430.ps1
# random hex string replace with your malware signature
$MalwareMD5Hash = 'D52C11B7E076FCE593288439ABA0F6D4'
Get-Process | Where-Object Path | Select-Object ID,Path | Group-Object Path | ForEach-Object {
if ($MalwareMD5Hash -eq (Get-FileHash $_.Name -Alg MD5).Hash){
##iterate group to kill all processes matching
ForEach ($PID in $_.Group.ID){
Stop-Process -ID $PID -Force -WhatIF
}
}
$_.Name | Remove-Item -Force -WhatIf # to delete the physical file.
}
As I suggested in my comment:
$HashList = [ordered]#{}
Get-Process |Where-Object Path | Select-Object Path |Sort-Object Path -Unique | ForEach-Object {
$HashList[$_.Path]=(Get-FileHash $_.Path -Alg MD5).Hash
## or the reverse, the hash as key and the path as value
# $HashList[(Get-FileHash $_.Path -Alg MD5).Hash]=$_.Path
}
$Hashlist | Format-List
Shorted sample output
Name : C:\Program Files\Mozilla Firefox\firefox.exe
Value : BFE829AB5A4B729EE4565700FC8853DA
Name : C:\WINDOWS\Explorer.EXE
Value : E4A81EDDFF8B844D85C8B45354E4144E
Name : C:\WINDOWS\system32\conhost.exe
Value : EA777DEEA782E8B4D7C7C33BBF8A4496
Name : C:\WINDOWS\system32\DllHost.exe
Value : 2528137C6745C4EADD87817A1909677E
> $hashlist['C:\WINDOWS\Explorer.EXE']
E4A81EDDFF8B844D85C8B45354E4144E
Or with the reversed list
> $hashlist['E4A81EDDFF8B844D85C8B45354E4144E']
C:\WINDOWS\Explorer.EXE

Related

How do I edit a #{ that powershell automatically puts registry keys ins?

so I have a powershell command that grabs a registry key. But when using select-pattern, it always sticks the whole key within a line, and I've been googling everywhere but no where is telling me how to only grab certain language from the line, and not return the full like. Like below:
Line : #{t0_recursive=\\ad\; t7_recursive=\\ad\chrolit; t5_recursive=\\ad\arolit; t3_recursive=k:\;
t9_recursive=\\ad\fwrolit; t10_recursive=\\ad\larolit; t15_recursive=\\ad\slrolit;
t6_recursive=\\ad\brolit; t11_recursive=\\ad\mirolit; t14_recursive=\\ad\sfrolit;
t12_recursive=\\ad\nyrolit; t2_recursive=j:\; t16_recursive=\\ad\enfcases; t1_recursive=f:\;
t8_recursive=\\ad\drolit; t4_recursive=m:\; t13_recursive=\\ad\plrolit; t17_recursive=C:\ENFProcessing;
t129=c:\enfprocessing; t99=\\ad\slrolit; t9=\\ad\; t84=\\ad\sfrolit; t69=\\ad\plrolit; t54=\\ad\nyrolit;
t39=\\ad\mirolit; t279_recursive=C:\Users; t264=\\ad\fwrolit; t249=\\ad\drolit; t24=\\ad\larolit;
t234=\\ad\chrolit; t219=\\ad\brolit; t204=\\ad\arolit; t159_recursive=\\AD.SEC.GOV\Projects;
t144_recursive=\\AD.SEC.GOV\users; t114=\\ad\enfcases;
PSPath=Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\Policies\Adobe\Adobe
Acrobat\DC\FeatureLockDown\cTrustedFolders\cAlwaysTrustedForJavaScript;
PSParentPath=Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\Policies\Adobe\Adobe
Acrobat\DC\FeatureLockDown\cTrustedFolders; PSChildName=cAlwaysTrustedForJavaScript;
PSProvider=Microsoft.PowerShell.Core\Registry}
I get this output, but can't just return PSPath and the C:\Users* from the line, it always returns the full line.
Why is this?
$value = Get-ChildItem -Path 'Registry::HKEY_CURRENT_USER\SOFTWARE\Adobe\Adobe Acrobat\DC\TrustManger\cTrustedFolder' 2>NULL | findstr : | measure-object -line | select-object -expandproperty lines ; if ( $value -lt 1 ) { echo 'PASSED, HKEY_CURRENT_USER\SOFTWARE\Adobe\Adobe Acrobat\DC\TrustManger\cTrustedFolder is NULL' } else { $value2 = Get-ChildItem -Path 'Registry::HKEY_CURRENT_USER\SOFTWARE\Adobe\Adobe Acrobat\DC\TrustManger\cTrustedFolder' -Recurse | ForEach-Object {Get-ItemProperty -Path $_.PSPath -Name t*} |Select-String -Pattern 'c:\\users*' | select -ExpandProperty Line| findstr /i /V /c:Desktop, /c:downloads|format-list LineNumber,Line
I tried googling how to edit lines in powershell, to no avail.
Take out findstr. It turns objects to strings.
The get-childitem output is a bit confusing for the registry. The formatting file $PSHOME\Registry.format.ps1xml runs get-itemproperty. Use get-itemproperty to get registry values.
I have a replacement for get-itemproperty that can be used for recursive searches here: Use PowerShell to search for string in registry keys and values
For example:
get-childitem -recurse hklm:\software\adobe | get-itemproperty2 |
? name -like distiller*
Path Name Value Type
---- ---- ----- ----
HKLM:\software\adobe\Acrobat Distiller\10.0\Uninstall Distiller 1 DWord

How to view a list of descriptions of available COM objects in PowerShell?

When I execute this powershell command to get a list of running COM objects that match the prefix "Python", I get the following output:
PS C:\Users\{path-to-arbitrary-directory}> Get-ChildItem HKLM:\Software\Classes | Where-Object {
$_.PSChildName -match '^Python[\.a-zA-Z]*$' } | Select-Object
Hive: HKEY_LOCAL_MACHINE\Software\Classes
Name Property
---- --------
Python (default) : Python ActiveX Scripting Engine
Python.Dictionary (default) : Python Dictionary
Python.Interpreter (default) : Python Interpreter
Python.TestServer (default) : Python Test COM Server
What I would like to do is just get a list of the Name and Description.
Currently I am able to get the names with this command:
PS C:\Users\{path-to-arbitrary-directory}> Get-ChildItem HKLM:\Software\Classes | Where-Object {
$_.PSChildName -match '^Python[\.a-zA-Z]*$' } | Select-Object PSChildName,Property
PSChildName Property
----------- --------
Python {(default)}
Python.Dictionary {(default)}
Python.Interpreter {(default)}
Python.TestServer {(default)}
But I can't for the life of me figure out how to show the Descriptions that I see when I execute the 1st command?
This is the output I would want:
Name Description
---- --------
Python Python ActiveX Scripting Engine
Python.Dictionary Python Dictionary
Python.Interpreter Python Interpreter
Python.TestServer Python Test COM Server
(if it helps anyone, I am also able to view the description with this command)
PS C:\Users\{path-to-arbitrary-directory}> Get-ChildItem HKLM:\Software\Classes | Where-Object {
$_.PSChildName -match '^Python[\.a-zA-Z]*$' } | Get-ItemProperty
(default) : Python ActiveX Scripting Engine
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Classes\Python
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Classes
PSChildName : Python
PSProvider : Microsoft.PowerShell.Core\Registry
...
One way to do this is the use of calculated properties. You can use Get-ItemProperty to get the value of the (default) registry key property. Then you can show this value as a calculated property.
Get-ChildItem HKLM:\software\Classes\ |
Where-Object {$_.PSChildName -match 'document'} |
Select-Object PSChildName, #{Name = "Default"; Expression = {($_ | Get-ItemProperty)."(default)"}}
Try this out. Things like this are better in functions.
function Get-COMDescription {
Param(
[parameter(Mandatory=$true)][string]$Search
)
Get-ChildItem HKLM:\Software\Classes | Where-Object {
# Match naming convention for COM Object ensure they key has a CLSID folder.
$_.PSChildName -match "^$Search\.\w+$" -and (Test-Path -Path "$($_.PSPath)\CLSID") } |
Select-Object PSChildName,#{l="Description";e={$_ | Get-ItemProperty | select -ExpandProperty "(default)" }}
}
Usage example:
PS C:\> Get-COMDescription -Search GoogleUpdate
PSChildName Description
----------- -----------
GoogleUpdate.CoCreateAsync CoCreateAsync
GoogleUpdate.CoreClass Google Update Core Class
GoogleUpdate.CoreMachineClass Google Update Core Class
GoogleUpdate.CredentialDialogMachine GoogleUpdate CredentialDialog
GoogleUpdate.OnDemandCOMClassMachine Google Update Broker Class Factory
GoogleUpdate.OnDemandCOMClassMachineFallback Google Update Legacy On Demand
GoogleUpdate.OnDemandCOMClassSvc Google Update Legacy On Demand
GoogleUpdate.PolicyStatus Google Update Policy Status Class
GoogleUpdate.ProcessLauncher Google Update Process Launcher Class
GoogleUpdate.Update3COMClassService Update3COMClass
GoogleUpdate.Update3WebMachine Google Update Broker Class Factory
GoogleUpdate.Update3WebMachineFallback GoogleUpdate Update3Web
GoogleUpdate.Update3WebSvc GoogleUpdate Update3Web
The existing answers are helpful, but let me add some background information:
The reason that the default output shows the target keys' values is that the default output formatting enumerates them, as this command reveals:
(Get-FormatData Microsoft.Win32.RegistryKey -PowerShellVersion $PSVersionTable.PSVersion).FormatViewDefinition.Control.Rows.Columns.DisplayEntry.Value
This shows:
PSChildName # column 1 - below is the script block that defines column 2
$result = (Get-ItemProperty -LiteralPath $_.PSPath |
Select * -Exclude PSPath,PSParentPath,PSChildName,PSDrive,PsProvider |
Format-List | Out-String | Sort).Trim()
$result = $result.Substring(0, [Math]::Min($result.Length, 5000) )
if($result.Length -eq 5000) { $result += "..." }
$result
As you can see, Get-ItemProperty is called behind the scenes to enumerate a key's values.
As an aside: This method of enumerating values as part of the formatting leads to incorrect output when retrieving values from a remote registry - see this answer.
While calling Get-ItemProperty in the script block of a calculated property, as shown in the other answers, definitely works, there is a more efficient alternative: You can call the .GetValue() method of the Microsoft.Win32.RegistryKey instances that Get-Item outputs:
Get-ChildItem HKLM:\Software\Classes |
Where-Object PSChildName -match '^Python[\.a-z]*$' |
Select-Object #{ n='Name'; e='PSChildName' },
#{ n='(default)'; e={ $_.GetValue('') } }

error when using Compare-Object in powershell

I am trying to run a diff of two files using Compare-Object cmdlet and print the ones missing in the second file (slave.txt) when compared to the first file (master.txt). In this example, I wanted to print user1, user3 which are in master.txt but not present in slave.txt. I have a pre-requisite of storing each values in the file as a variable, so "mobj" and "sobj" cannot be ignored.
I am finding this error when running the script. what could be the issue here?
~]# cat master.txt
user1
user2
user3
~]# cat slave.txt
user2
user4
Code:
$mfile = Get-Content "C:\master.txt"
$sfile = Get-Content "C:\slave.txt"
foreach ($mobj in $mfile) {
foreach($sobj in $sfile){
Compare-Object (ls $mobj) (ls $sobj) -Property Name, Length, LastWriteTime -passthru | Where { $_.PSParentPath -eq (gi $mobj).PSPath }
}
}
The error reported is:
Compare-Object : Cannot bind argument to parameter 'ReferenceObject' because it is null.
Er, not what your last question meant. Just because that question was marked as a duplicate doesn't mean that's the exact unmodified code you have to use.
Try this:
$mfile = Get-Content "C:\master.txt"
$sfile = Get-Content "C:\slave.txt"
#In master.txt not in slave.txt
Compare-Object $mfile $sfile | Where-Object { $_.SideIndicator -eq '<=' } | Select-Object -ExpandProperty InputObject
#In slave.txt not in master.txt
Compare-Object $mfile $sfile | Where-Object { $_.SideIndicator -eq '=>' } | Select-Object -ExpandProperty InputObject
Either start running your code from the directory where the user's folders are, or you need to edit your master and slave files.
You're runnig LS/Dir and without executing in the source directory where the user's profiles are found, or explicitly specifying the full path to their profiles in the source file, you're going to have this error, because LS will throw a non-terminating error(which is interpreted as a null, as no data or objects go to stdout/the pipeline) if it can't find a directory.

can't seem to match two values in registry

I am trying to get all the NICs on my system and then using that information to insert registry values of *TCPChecksumOffloadIPv4 etc. However, I am failing this task miserably!
I can get all the GUID's and want to match that to what is in this registry path: HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\*
I get all the GUID's by this:
$GuidSet = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\*" | select -ExpandProperty pschildname
Output:
{1FE01120-3866-437F-81FF-556B08999AA4}
{2533855F-2A59-485D-87A0-167E5DA39E45}
{2A6471FB-C1D6-47D2-A665-9F276D142D7C}
{306D2DED-18B5-45D8-858E-BB3F49E3BD6A}
{30EF50B2-E4B3-400D-9614-B590E37DE4D8}
{4A208C06-0D99-4DE4-9B2F-86285AEF864E}
{B7883140-E15B-4409-BA1B-96E37A45425C}
{D129DDA8-C64B-46A1-B99A-EA74FC4FAF81}
{D5C9183B-E542-4010-866F-4443AD55F28C}
This is where I am stuck now...how can I use this information to match what is in the registry path of "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\*" ?
I tried the below but I get access denied - I think this is because of the "Properties" registry key - how can I ignore that registry key?
$path1 = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\*" |?{$_.NetCfgInstanceId -match $guidset} | select -ExpandProperty pspath
Once that is done though then do I construct a foreach loop on each entry and then add in the registry keys I need?
ANSWER:
you know what...when your in a muddle and you have lots of scripts...take a break, open a new window and start from scrath! That's what I did and in 10min I figured it out...!
$aGUID_SET = #(Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\*" | select -ExpandProperty pschildname)
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\*" -exclude "Properties" |
Where-Object {$aGUID_SET.Contains($_.NetCfgInstanceId)} |
ForEach-Object {
""
$_.DriverDesc
$_.NetCfgInstanceId
}
You are on the right track.
The Get-ItemProperty cmdlet will only get the properties of the items specified, not including any sub-items.
Since the registry values you are looking for are not actually properties of the registry key HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318} but instead are properties of subkeys of that key, the first thing we need to do is list the subkeys: $path = "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}"
We can then use Get-ChildItem $path to list the subkeys.
After formatting the paths properly (add Registry:: to the front), you can then input that to Get-ItemProperty. I would filter with something like: Where-Object {$guidset -contains $_.NetcfgInstanceID} | Select-Object -ExpandProperty PSPath.
Finally, you should have an array of paths to keys that matched $guidset, which
Set-ItemProperty can take.
EDIT: The error you are receiving is because permissions on those "Properties" subkeys is restricted. I would tack an -ErrorAction SilentlyContinue to Get-ChildItem because it is not a terminating error and does not actually affect the results.
You can do it like this
ForEach ($item in $(Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\*" |?{$_.NetCfgInstanceId -match $guidset} | select -ExpandProperty pspath)) {
Try {
Write-Host $item
} Catch {
Write-Host "error..."
}
}

Variable referencing. How to create arrays getting their names from elements of another array

This is as simplified version of what I'd like to achieve... I think it's called 'variable referencing'
I have created an array containing the content of the folder 'foo'
$myDirectory(folder1, folder2)
Using the following code:
$myDirectory= Get-ChildItem ".\foo" | ForEach-Object {$_.BaseName}
I'd like to create 2 arrays named as each folders, with the contained files.
folder1(file1, file2)
folder2(file1, file2, file3)
I tried the following code:
foreach ($myFolder in $myDirectory) {
${myFolder} = Get-ChildItem ".\$myFolders" | forEach-Object {$_.BaseName}
}
But obviously didn't work.
In bash it's possible create an array giving it a variable's name like this:
"${myForder[#]}"
I tried to search on Google but I couldn't find how to do this in Powershell
$myDirectory = "c:\temp"
Get-ChildItem $myDirectory | Where-Object{$_.PSIsContainer} | ForEach-Object{
Remove-Variable -Name $_.BaseName
New-Variable -Name $_.BaseName -Value (Get-ChildItem $_.FullName | Where-Object{!$_.PSIsContainer} | Select -ExpandProperty Name)
}
I think what you are looking for is New-Variable. Cycle through all the folders under C:\temp. For each folder make a new variable. It would throw errors if the variable already exists. What you could do for that is remove a pre-exising variable. Populate the variable with the current folders contents in the pipeline using Get-ChildItem. The following is a small explanation of how the -Value of the new variable is generated. Caveat Remove-Variable has the potiential to delete unintended variables depending on your folder names. Not sure of the implications of that.
Get-ChildItem $_.FullName | Where-Object{!$_.PSIsContainer} | Select -ExpandProperty Name
The value of each custom variable is every file ( not folder ). Use -ExpandProperty to just gets the names as strings as supposed to a object with Names.
Aside
What do you plan on using this data for? It might just be easier to pipe the output from the Get-ChildItem into another cmdlet. Or perhaps create a custom object with the data you desire.
Update from comments
$myDirectory = "c:\temp"
Get-ChildItem $myDirectory | Where-Object{$_.PSIsContainer} | ForEach-Object{
[PSCustomObject] #{
Hotel = $_.BaseName
Rooms = (Get-ChildItem $_.FullName | Where-Object{!$_.PSIsContainer} | Select -ExpandProperty Name)
}
}
You need to have at least PowerShell 3.0 for the above to work. Changing it for 2.0 is easy if need be. Create and object with hotel names and "rooms" which are the file names from inside the folder. If you dont want the extension just use BaseName instead of Name in the select.
This is how I did it at the end:
# Create an array containing all the folder names
$ToursArray = Get-ChildItem -Directory '.\.src\panos' | Foreach-Object {$_.Name}
# For each folder...
$ToursArray | ForEach-Object {
# Remove any variable named as the folder's name. Check if it exists first to avoid errors
if(Test-Path variable:$_.BaseName){ Remove-Variable -Name $_.BaseName }
$SceneName=Get-ChildItem ".\.src\panos\$_\*.jpg"
# Create an array using the main folder's name, containing the names of all the jpg inside
New-Variable -Name $_ -Value ($SceneName | Select -ExpandProperty BaseName)
}
And here it goes some code to check the content of all the arrays:
# Print Tours information
Write-Verbose "Virtual tours list: ($($ToursArray.count))"
$ToursArray | ForEach-Object {
Write-Verbose " Name: $_"
Write-Verbose " Scenes: $($(Get-Variable $_).Value)"
}
Output:
VERBOSE: Name: tour1
VERBOSE: Scenes: scene1 scene2
VERBOSE: Name: tour2
VERBOSE: Scenes: scene1