Friday, September 28, 2012

Managing Alternate Data Streams with Powershell 3.0

Something I've recently found out and that I think it's brilliant is the possibility under Powershell 3.0 to handle file forks natively, which is something I long expected to see implemented. Some of you maybe know already that the NTFS Master File Table (MFT) supports storing forks of files in its tree. These forks are better know under Windows (starting from NT4) as Alternate Data Streams (ADS).

Until now the only way to know if a file had one or more ADS was to recur to our friend the DIR command which, since Windows Vista, offered a /R parameter to display the existing ADS and their somewhat secret size.

Here's a sample output of DIR /R:

dir /r | find "DATA"
26 Introducing Windows Server 2008 R2.pdf:Zone.Identifier:$DATA
26 Parkdale.exe:Zone.Identifier:$DATA
26 setup.exe:Zone.Identifier:$DATA
26 Understanding Microsoft Virtualization Solutions.pdf:Zone.Identifier:$DATA

Piping the output of 'DIR /R' to the 'find' command allows the immediate listing of the files that have multiple data streams only and exclude all other 'normal' files.

As you can see in the example, many files usually have an ADS named 'Zone.Identifier' (whose size is 26 bytes). This particular fork stored withing the same filename tells you whether the file has been downloaded from the Net or not. A typical content is:

[ZoneTransfer]
ZoneId=3

with ZoneId values ranging (to my knowledge) from 0 to 4:

ZoneId=0: Local machine
ZoneId=1: Local intranet
ZoneId=2: Trusted sites
ZoneId=3: Internet
ZoneId=4: Restricted sites

If the ZoneId is equal to 3 or 4, when you will try to execute the file you will get a warning telling you "The publisher could not be verified. Are you sure you want to run this software?"...

Ok, now that we know how we can find the hidden ADS in our system, let's go back to our Powershell 3.0 command line to see in what ways it does help us in ADS management. Starting with this new version of Powershell, there is a way to find commands (using get-command) based on the parameters they accept (by adding the -parametername parameter). So let's run for instance:

gcm -ParameterName stream | select name

The returned list of cmdlets which support Alternate Data Streams is:

Add-Content
Clear-Content
Get-Content
Get-Item
Out-String
Remove-Item
Set-Content

For instance we can now retrieve the content of a fork the same way we did with

more < "Introducing Windows Server 2008 R2.pdf:Zone.Identifier"
or
more < "Introducing Windows Server 2008 R2.pdf:Zone.Identifier:$DATA"

by issuing

Get-Content "Introducing Windows Server 2008 R2.pdf" -stream Zone.Identifier
or
Get-Content "Introducing Windows Server 2008 R2.pdf" -stream Zone.Identifier$DATA

What's more, we can retrieve the properties of this ADS with Get-Item:

$ads = get-item '.\Introducing Windows Server 2008 R2.pdf' -Stream zone.identifier

The command

$ads | select filename,stream,length | fl 

will return

FileName : C:\folder\Introducing Windows Server 2008 R2.pdf
Stream   : Zone.Identifier
Length   : 26 

We can also quickly remove the fork (in this case no warning pop-up will come to disturb our inner peace!) with

Remove-Item .\file.txt -Stream  Zone.Identifier

This is a great step forward for Windows Powershell. Alternate Data Streams management has been left in the shade for almost a decade and today we can finally play with them like if they were standard user's files. 

Great, isn't it?

1 comment:

  1. I use
    $ads | select filename,stream,length | fl

    Get-Item FileBlockTestToUnblock.docx -Stream zone*

    but how can I compare zone.identifier value with "ZoneId=3: Internet" in powershell ?

    thx

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...