As Adrian Milliner, mentioned on his blog here : Alternate Data Streams , Alternate Data Streams are not supported in PowerShell,
To make it even worse, the reason for this is that also the .NET framework does not support it, you need to use a API ,
As for vista in CMD.exe the support for Alternate datastream is improved (a little bit) See this Blogentry by Martin Zugec
Scripting, Vista & Deployment : Alternate Data Streams - remember ... , this was really a Shortcoming in for me
If you alternative datastream's are, or want to know more about them , you can find very good information in the following Wiki's :
Fork (filesystem) - Wikipedia, the free encyclopedia ,
wikistc : Alternate_data_streams
But nothing is lost as it's easy to add this functionality to PowerShell
I did find a good solution for this some time ago, And it was still on my "To Blog list" and that post triggered me to make a post about it :
I will show in this post how to access Alternate Data-Streams in PowerShell, using Typedata files to add this functionality to fileInfo objects for easy access and also I will show you how to use this for Unblocking downloaded PowerShell scripts
As I did make program in VB.NET before to work with Alternate datastreams in VS2002 (wrapping the API ), I did think then about rewriting it as a CmdLet at the time ,
but when the need for ADS support came up again for unblocking files in PowerShell, as the FileBlocking feature of Internet Explorer also uses Alternate data-streams to store this information, and also the Execution Policy in PowerShell does use this information, ( see the following NewsGroups threads ( Marking items as downloaded , Alternate Data Streams on files )
But when I could not find the source for the VB.NET solution that quickly, and did a search for reference information on the Internet, I did find the following project in C# on www.codeproject.com :
Accessing alternative data-streams of files on an NTFS volume ... , that features a Library in c# for working with ADS.
(as it is in C# already it would be handier as my old VB.NET work anyway and when I did see that project in VS later , I did think I most likely used this a base for my VB.NET version then in the first place. )
So I started to Download it as a reference for making the CmdLet, but when I unpacked the Project, and was thinking about how to go on, and that as I wanted to do C# for the Cmdlet, I maybe instead of rewriting just could use the library in my CMDlet,
Then I did realize how simple this really would be ... !!!
I do not even need to write anything to get Alternate Stream support in PowerShell !!
I can just import the complete library into PowerShell by just loading the DLL
And so I did, I extracted the DLL and placed it in my powershell directory and just loaded it in Powershell :
[System.Reflection.Assembly]::LoadFile("c:\powershell\ntfs.dll")
And yes, that was enough to add ADS support to PowerShell I was ready to use it in Powershell :
PoSH> "echo test" | out-file c:\powershell\test.ps1 PoSH> PoSH> $FS = new NTFS.FileStreams('c:\powershell\test.ps1') PoSH> PoSH> $FS PoSH> PoSH> $fs.add('MowStream') 0 PoSH> PoSH> $stream = $fs.Item('MowStream').open() PoSH> PoSH> $sw = [System.IO.streamwriter]$stream PoSH> $Sw.writeline('/\/\o\/\/ was here ') PoSH> $sw.writeline('http://thePowerShellGuy.com') PoSH> $sw.close() PoSH> PoSH> $stream.close() PoSH> PoSH> $FS Name Size ---- ---- MowStream 0 PoSH> PoSH> $stream = $fs.Item('MowStream').open() PoSH> $stream CanRead : True CanWrite : True CanSeek : True IsAsync : False Length : 50 Name : [Unknown] Position : 0 Handle : 2060 SafeFileHandle : Microsoft.Win32.SafeHandles.SafeFileHandle CanTimeout : False ReadTimeout : WriteTimeout : PoSH> $stream.ReadToEnd() /\/\o\/\/ was here http://thePowerShellGuy.com PoSH> $stream.Close() PoSH>
So now we also can use this to Unblock files downloaded from the Internet,
if you download a PowerShell script from the internet and your execution-policy is remoteSigned you can not run it when you do not un-block it
if you look at the properties of the file, you can see that a Security section is added , that contains some information and an "Unblock" button.
Image may be NSFW.
Clik here to view.
because as you could see in the Newsgroup thread, Internet explorer does also use Alternate Data-Streams to indicate that a file is downloaded from the Internet
That works like this :.
when Internet Explorer downloads something from the Internet, it will add an Alternate Data-Stream to it named : Zone.Identifier,
in this ADS stream it will place information about the zone the file came from (see example below ), if we just delete this stream the file is "Unblocked"
as using the NTFS namespace I made a TypeData file fir (Posted below examples) that will provide some shortcuts for using it ,
you need to load this first for the examples to work
Update-TypeData C:\PowerShell\TypeData\TypedataFileStream.ps1xml
I placed this in my profile and now I can just unblock a file by using the .Unblock() method
Other Methods added are :
On System.IO.FileInfo
- GetFileStreams
- Block
- UnBlock
and a method on NTFS.StreamInfo to get a streamreader and read all text from the stream :
- readAll()
after loading you can use it like this :
(In XP you need to start a new PowerShell console for this to work, in Vista this works direct)
PoSH> C:\PowerShell\HelloWorld.ps1 File C:\PowerShell\HelloWorld.ps1 cannot be loaded. The file C:\PowerShell\HelloWorld.ps1 is not digitally signed. The script will not exec ute on the system. Please see "get-help about_signing" for more details.. At line:1 char:28 + C:\PowerShell\HelloWorld.ps1 <<<< PoSH> ( Get-Item .\HelloWorld.ps1 ).GetFileStreams() Name Size ---- ---- Zone.Identifier 26 PoSH> ( Get-Item .\HelloWorld.ps1 ).GetFileStreams()['Zone.Identifier'].readAll() [ZoneTransfer] ZoneID=4 PoSH> ( Get-Item .\HelloWorld.ps1 ).UnBlock() True PoSH> C:\PowerShell\HelloWorld.ps1 Hello World! PoSH> ( Get-Item .\HelloWorld.ps1 ).UnBlock Script : $FS = new NTFS.FileStreams($this.fullname) $fs['Zone.Identifier'].delete() OverloadDefinitions : {System.Object UnBlock();} MemberType : ScriptMethod TypeNameOfValue : System.Object Value : System.Object UnBlock(); Name : UnBlock IsInstance : False PoSH>
and the TypeData file used for this is
TypedataFileStream.ps1xml
<Types>
<Type>
<Name>System.IO.FileInfo</Name>
<Members>
<ScriptMethod>
<Name>Block</Name>
<Script>
$FS = new NTFS.FileStreams($this.fullname)
$fs.add('Zone.Identifier')
$stream = $fs.Item('Zone.Identifier').open()
$sw = [System.IO.streamwriter]$stream
$Sw.writeline('[ZoneTransfer]')
$sw.writeline('ZoneID=4')
$sw.close()
$stream.close()
</Script>
</ScriptMethod>
<ScriptMethod>
<Name>UnBlock</Name>
<Script>
$FS = new NTFS.FileStreams($this.fullname)
$fs['Zone.Identifier'].delete()
</Script>
</ScriptMethod>
<ScriptMethod>
<Name>GetFileStreams</Name>
<Script>
$FS = new NTFS.FileStreams($this.fullname)
return @(,$fs)
</Script>
</ScriptMethod>
</Members>
</Type>
<Type>
<Name>NTFS.StreamInfo</Name>
<Members>
<ScriptMethod>
<Name>ReadAll</Name>
<Script>
$stream = $this.open()
$streamReader = new System.IO.streamreader($stream)
$streamReader.ReadToEnd()
$stream.Close()
$streamReader.Close()
</Script>
</ScriptMethod>
</Members>
</Type>
</Types>
You can see that because you can load .NET DLL's into PowerShell, you do not need to write a Cmdlet for this,
And by updating the typeData you can make the functionality in the library more easy to access
(e.g. as the NTFS.StreamInfo returned a stream and for commandline use we just want the text returned, I just added the ReadAll() Method to the NTFS.StreamInfo object from the library.)
So its really easy to use .NET libraries from PowerShell adding even more power to it,
I really love how extendable PowerShell is ,
Enjoy,
Greetings /\/\o\/\/
Image may be NSFW.Clik here to view.