1

I'm trying to remove a bunch of OSX alternate data streams on an NTFS volume. However no matter what I try I cannot get Powershell to do it. Yes, I admit that my powershell is not great. Is anyone able to help?

Objective: Remove the ADS "AFP_AfpInfo" from any directory in the volume.

Current Code:

Get-ChildItem E:\ -Directory -Recurse | ForEach-Object {
    $streams = Get-Content -Path $_ -Stream AFP_AfpInfo -ErrorAction SilentlyContinue
    if ($streams) {
        $streams | ForEach-Object {
            try {
                Remove-Item -Path "$($_.PSPath)" -Stream AFP_AfpInfo -Recurse -Force -ErrorAction Silentlycontinue
            }
            catch {
                Write-Host "An error occurred: $($_.Exception.Message)"
            }
        }
    }
}

Current error:

An error occurred: A parameter cannot be found that matches parameter name 'Stream'.

Note: Running Powershell 7.3

Mario Mateaș
  • 638
  • 7
  • 25
Rob P
  • 99
  • 1
  • 4

2 Answers2

2

-Recurse and -Stream don't seem to go together even though in the documentation they appear in the same Parameter Sets. In this case -Recurse should be removed. GitHub Issue #9822 was submitted to add clarification to the Remove-Item doc.

Also, you're seeking for an exact stream, AFP_AfpInfo, so I don't see a need to enumerate $streams. Lastly, checking if a file or folder has an alternative stream should be done with Get-Item instead of Get-Content for efficiency.

As a final aside, the code must use the .Remove method from EngineIntrinsics to work, Remove-Item -Confirm:$false -Force will always ask for confirmation on folders, arguably a bug. Remove-Item should skip confirmation checks if -Stream is in use and -Confirm:$false -Force. GitHub issue #19154 was submitted to follow up on this.

$removeFunc   = $ExecutionContext.InvokeProvider.Item.Remove
$targetStream = 'AFP_AfpInfo'

Get-ChildItem E:\ -Recurse -Directory | ForEach-Object {
    if ($stream = $_ | Get-Item -Stream $targetStream -ErrorAction SilentlyContinue) {
        try {
            $removeFunc.Invoke($stream.PSPath, $false, $true, $true)
        }
        catch {
            Write-Host "An error occurred: $($_.Exception.Message)"
        }
    }
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
0

Why are you not just using the Unblock-File cmdlet to remove ADS?

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/unblock-file?view=powershell-7.3

Description This cmdlet only works on the Windows and macOS platforms.

The Unblock-File cmdlet lets you open files that were downloaded from the internet. It unblocks PowerShell script files that were downloaded from the internet so you can run them, even when the PowerShell execution policy is RemoteSigned. By default, these files are blocked to protect the computer from untrusted files.

Before using the Unblock-File cmdlet, review the file and its source and verify that it is safe to open.

Internally, the Unblock-File cmdlet removes the Zone.Identifier alternate data stream, which has a value of 3 to indicate that it was downloaded from the internet.

 Get-Help -Name Unblock-FIle -Examples

NAME
    Unblock-File
    
SYNOPSIS
    Unblocks files that were downloaded from the internet.
    
    
    ------------------ Example 1: Unblock a file ------------------
    
    PS C:\> Unblock-File -Path C:\Users\User01\Documents\Downloads\PowerShellTips.chm
    
    
    -------------- Example 2: Unblock multiple files --------------
    
    PS C:\> dir C:\Downloads\*PowerShell* | Unblock-File
    
    
    ------------- Example 3: Find and unblock scripts -------------
    
    PS C:\> Get-Item * -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
       FileName: C:\ps-test\Start-ActivityTracker.ps1

See also Get-Item, Clear-Content and Remove-Item cmdlets use case:

Friday Fun with PowerShell and Alternate Data Streams https://jdhitsolutions.com/blog/scripting/8888/friday-fun-with-powershell-and-alternate-data-streams

You could also just use the MSSysinternals tool to remove ADS as well in your PS code.

https://learn.microsoft.com/en-us/sysinternals/downloads/streams

postanote
  • 15,138
  • 2
  • 14
  • 25