1
votes

I'm looking to thin down how many folders I need to recover after a cryptolocker outbreak at a clients site and started looking into powershell as a good way to do this. What I need to do is recover a folder if it has any file inside with the extension .encrypted.

I can run the below

get-childitem C:\ -recurse -filter “*.encrypted” | %{$_.DirectoryName} | Get-Unique

And get a list of all folders that have .encrypted files in them but what I would like to do is thin down the list for example if we have the below file list and assume * means the folder contains encrypted files.

C:\Folder1

C:\Folder1\Folder2\Folder4*

C:\Folder1\Folder2*

C:\Folder1\Folder3\Folder5*

C:Folder1\Folder3\Folder6\

rather than returning

C:\Folder1\Folder2\Folder4*

C:\Folder1\Folder2*

C:\Folder1\Folder3\Folder5*

I would like it just to return as this would be the optimal recovery option.

C:\Folder1\Folder2*

C:\Folder1\Folder3\Folder5*

I know this is a fairly complex problem so I'm not asking anyone to solve it for me just some pointers in the right direction would be awesome as my brain is fried at the moment and I need to write this fairly quickly.

2
That is a pretty complicated request. A simple answer to help you with this would be to append | Sort to the end of that command you are running...it will at least help you visually narrow things down.Noah Sparks
The rules of your output are ambiguous. Example - if there's an encrypted file in the root of the drive, then your entire output will be a single line: "c:\" -- is this what you want?x0n

2 Answers

2
votes

Here's a simple way to do this that should be pretty efficient:

PS C:\> dir -ad -rec | where { test-path (join-path $_.FullName *.encrypted) }
  • dir is an alias for get-childitem
  • where is an alias for where-object
  • -ad means return directories only
  • -rec means recurse
  • test-path returns $true if the path exists (yes, it handles wildcards)

S, we recurse through all folders forwarding the folder object down the pipeline. We get the full name of the folder and append *.encrypted to it. If test-path returns $true for this path, we forward the folder down the pipeline. The folder ends up in the console output.

Now, if you want to get a little fancier, here's a more fleshed out one-liner than will report the folders and the encrypted files count into a csv file named after the machine:

dir -ad -rec | ? { test-path (join-path $_.FullName *.txt) } | % {
    [pscustomobject]@{"Path"=$_.fullname;"Count"=(dir (join-path $_ *.txt)).count}} |`
    Export-Csv "c:\temp\$(hostname).csv" -NoTypeInformation

(? and % are aliases for where-object and foreach-object respectively)

With a little more effort, you could use a fan-out scan of the entire company assuming powershell remoting is enabled on each target machine and have it return all results to you from all machines.

Good luck!

0
votes

This is too much for a comment, but I don't know that it would be a good answer, just a kind of hackish way to get it done...

The only thing I could think of is to get your list of folders, then start matching them all against each other, and when you get two that at least partially match remove the longer one.

$FullList = GCI C:\*.encrypted | Select -Expand DirectoryName -Unique | Sort -Property Length
$ToRemove = @()
foreach($Folder in $FullList){$ToRemove+=$FullList| Where{$_ -ne $Folder -and ($_ -match [regex]::Escape($Folder))}}
$FinalList = $FullList | Where{$ToRemove -notcontains $_}

That's going to be slow though, there has to be a better way to do it. I just haven't thought of a better way yet.

Don't get me wrong, this will work, and it's faster than going through things by hand for sure, but I'm sure that there has to be a better way to do it.