How to do it...

Install and start PowerShell Core and execute the following steps:

  1. Download a file to play around with:
# To get started, download any file to an NTFS-formatted volume.
# This lab assumes that you're storing downloads in $home\Downloads
$downloadRoot = "~\Downloads"

# Download any file, for example a release of the popular lab automation framework AutomatedLab
start https://github.com/AutomatedLab/AutomatedLab/releases/download/v5.1.0.153/AutomatedLab.msi
  1. Examine the file with Get-Item. Do you notice any irregularities? Let's see:
# At first glance, this file appears normal
Get-Item $downloadRoot\AutomatedLab.msi
  1. Now try Get-Item again, with the -Stream parameter. What is different now? Let's see:
Get-Item $downloadRoot\AutomatedLab.msi -Stream *

The previous line of code displays what you can see in the filesystem properties dialog. The stream called Zone.Identifier is responsible for creating this message in the UI!

All NTFS files contain a data stream and additional streams such as the zone identifier for file downloads.
  1. Streams can be processed with the Item and Content cmdlets:
# Streams can be processed with the Content-cmdlets
# The data stream is of course returned by default
Get-Content -Path C:\windows\logs\cbs\cbs.log -Stream ':$DATA'

# The zone identifier specifies if the file was downloaded from the Internet or another zone
# You can find out all kinds of information from this, like the content URL in this example.
# At the time of writing, the HostUrl resided on the S3 storage by Amazon and used an
# access signature to set the link expiration date
Get-Content -Path $downloadRoot\AutomatedLab.msi -Stream Zone.Identifier
  1. You can't only read them, you can also create your own:
# Let's try the other content cmdlets now...
Set-Content -Path .\TestFile -Value 'A simple file'
$bytes = [Text.Encoding]::Unicode.GetBytes('Write-Host "Virus deployed..." -Fore Red')
$base64script = [Convert]::ToBase64String($bytes)

# We have now hidden a script inside an inconspicuous file
Set-Content -Path .\TestFile -Stream Payload -Value $base64script

# And of course we can execute it in this beautiful one-liner
[scriptblock]::Create($([Text.Encoding]::Unicode.GetString($([Convert]::FromBase64String($(Get-Content .\TestFile -Stream Payload)))))).Invoke()
  1. You can also clear stream contents as well as remove streams:
# You can clear the stream manually as well
Clear-Content -Path .\TestFile -Stream Payload

# And you can remove the entire stream
Remove-Item -Stream Payload -Path .\TestFile
  1. For the zone identifier stream, the Unblock-File cmdlet makes removal easier:
# The Unblock-File cmdlet does exactly the same with the stream Zone.Identifier
Unblock-File -Path $downloadRoot\AutomatedLab.msi
Get-Item -Path $downloadRoot\AutomatedLab.msi -Stream *