PoshCode Logo PowerShell Code Repository

Remove-DownloadFlag by Joel Bennett 28 months ago
embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1430"></script>download | new post

Allows setting and removing the Zone.Identifier alternate data stream (on NTFS file systems) which flags scripts as downloaded to heighten security. Part of the PoshCode Module.

  1. function Set-DownloadFlag {
  2. <#
  3. .Synopsis
  4.         Sets the ZoneTransfer flag which marks a file as being downloaded from the internet.
  5. .Description
  6.         Creates a Zone.Identifier alternate data stream (on NTFS file systems) and writes the ZoneTransfer marker
  7. .Parameter Path
  8.         The file you wish to block
  9. .Parameter Passthru
  10.         If set, outputs the FileInfo object
  11. #>
  12. [CmdletBinding()]
  13. PARAM (
  14.    [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
  15.    [Alias("FullName")]
  16.    [string]
  17.    $Path
  18. ,
  19.    [Switch]$Passthru
  20. )
  21.    $FS = new-object NTFS.FileStreams($Path)
  22.    $null = $fs.add('Zone.Identifier')
  23.    $stream = $fs.Item('Zone.Identifier').open()
  24.  
  25.    $sw = [System.IO.streamwriter]$stream
  26.    $Sw.writeline('[ZoneTransfer]')
  27.    $sw.writeline('ZoneID=4')
  28.    $sw.close()
  29.    $stream.close()
  30.    if($Passthru){ Get-ChildItem $Path }
  31. }
  32.  
  33. function Remove-DownloadFlag {
  34. <#
  35. .Synopsis
  36.         Removes the ZoneTransfer flag which marks a file as being downloaded from the internet.
  37. .Description
  38.         Deletes the Zone.Identifier alternate data stream (on NTFS file systems)
  39. .Parameter Path
  40.         The file you wish to block
  41. .Parameter Passthru
  42.         If set, outputs the FileInfo object
  43. #>
  44. [CmdletBinding()]
  45. PARAM (
  46.    [Parameter(Position=0, Mandatory=$false, ValueFromPipelineByPropertyName=$true)]
  47.    [Alias("FullName")]
  48.    [string]
  49.    $Path
  50. ,
  51.    [Switch]$Passthru
  52. )
  53.    $FS = new-object NTFS.FileStreams($Path)
  54.    $null = $fs['Zone.Identifier'].delete()
  55.    if($Passthru){ Get-ChildItem $Path }
  56. }
  57.  
  58. Add-Type -TypeDefinition @'
  59. using System;
  60. using System.IO;
  61. using System.Collections;
  62. using System.Runtime.InteropServices;
  63. using Microsoft.Win32.SafeHandles;
  64.  
  65.  
  66. ///<summary>
  67. ///Encapsulates access to alternative data streams of an NTFS file.
  68. ///Adapted from a C++ sample by Dino Esposito,
  69. ///http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/ntfs5.asp
  70. ///</summary>
  71. namespace NTFS {
  72.   /// <summary>
  73.   /// Wraps the API functions, structures and constants.
  74.   /// </summary>
  75.   internal class Kernel32
  76.   {
  77.      public const char STREAM_SEP = ':';
  78.      public const int INVALID_HANDLE_VALUE = -1;
  79.      public const int MAX_PATH = 256;
  80.      
  81.      [Flags()] public enum FileFlags : uint
  82.      {
  83.         WriteThrough = 0x80000000,
  84.         Overlapped = 0x40000000,
  85.         NoBuffering = 0x20000000,
  86.         RandomAccess = 0x10000000,
  87.         SequentialScan = 0x8000000,
  88.         DeleteOnClose = 0x4000000,
  89.         BackupSemantics = 0x2000000,
  90.         PosixSemantics = 0x1000000,
  91.         OpenReparsePoint = 0x200000,
  92.         OpenNoRecall = 0x100000
  93.      }
  94.  
  95.      [Flags()] public enum FileAccessAPI : uint
  96.      {
  97.         GENERIC_READ = 0x80000000,
  98.         GENERIC_WRITE = 0x40000000
  99.      }
  100.      /// <summary>
  101.      /// Provides a mapping between a System.IO.FileAccess value and a FileAccessAPI value.
  102.      /// </summary>
  103.      /// <param name="Access">The <see cref="System.IO.FileAccess"/> value to map.</param>
  104.      /// <returns>The <see cref="FileAccessAPI"/> value.</returns>
  105.      public static FileAccessAPI Access2API(FileAccess Access)
  106.      {
  107.         FileAccessAPI lRet = 0;
  108.         if ((Access & FileAccess.Read)==FileAccess.Read) lRet |= FileAccessAPI.GENERIC_READ;
  109.         if ((Access & FileAccess.Write)==FileAccess.Write) lRet |= FileAccessAPI.GENERIC_WRITE;
  110.         return lRet;
  111.      }
  112.  
  113.      [StructLayout(LayoutKind.Sequential)] public struct LARGE_INTEGER
  114.      {
  115.         public int Low;
  116.         public int High;
  117.  
  118.         public long ToInt64()
  119.         {
  120.            return (long)High * 4294967296 + (long)Low;
  121.         }
  122.      }
  123.  
  124.      [StructLayout(LayoutKind.Sequential)] public struct WIN32_STREAM_ID
  125.      {
  126.         public int dwStreamID;
  127.         public int dwStreamAttributes;
  128.         public LARGE_INTEGER Size;
  129.         public int dwStreamNameSize;
  130.      }
  131.      
  132.      [DllImport("kernel32")] public static extern SafeFileHandle CreateFile(string Name, FileAccessAPI Access, FileShare Share, int Security, FileMode Creation, FileFlags Flags, int Template);
  133.      [DllImport("kernel32")] public static extern bool DeleteFile(string Name);
  134.      [DllImport("kernel32")] public static extern bool CloseHandle(SafeFileHandle hObject);
  135.  
  136.      [DllImport("kernel32")] public static extern bool BackupRead(SafeFileHandle hFile, IntPtr pBuffer, int lBytes, ref int lRead, bool bAbort, bool bSecurity, ref int Context);
  137.      [DllImport("kernel32")] public static extern bool BackupRead(SafeFileHandle hFile, ref WIN32_STREAM_ID pBuffer, int lBytes, ref int lRead, bool bAbort, bool bSecurity, ref int Context);
  138.      [DllImport("kernel32")] public static extern bool BackupSeek(SafeFileHandle hFile, int dwLowBytesToSeek, int dwHighBytesToSeek, ref int dwLow, ref int dwHigh, ref int Context);
  139.   }
  140.  
  141.   /// <summary>
  142.   /// Encapsulates a single alternative data stream for a file.
  143.   /// </summary>
  144.   public class StreamInfo
  145.   {
  146.      private FileStreams _parent;
  147.      private string _name;
  148.      private long _size;
  149.  
  150.      internal StreamInfo(FileStreams Parent, string Name, long Size)
  151.      {
  152.         _parent = Parent;
  153.         _name = Name;
  154.         _size = Size;
  155.      }
  156.  
  157.      /// <summary>
  158.      /// The name of the stream.
  159.      /// </summary>
  160.      public string Name
  161.      {
  162.         get { return _name; }
  163.      }
  164.      /// <summary>
  165.      /// The size (in bytes) of the stream.
  166.      /// </summary>
  167.      public long Size
  168.      {
  169.         get { return _size; }
  170.      }
  171.      
  172.      public override string ToString()
  173.      {
  174.         return String.Format("{1}{0}{2}{0}$DATA", Kernel32.STREAM_SEP, _parent.FileName, _name);
  175.      }
  176.      public override bool Equals(Object o)
  177.      {
  178.         if (o is StreamInfo)
  179.         {
  180.            StreamInfo f = (StreamInfo)o;
  181.            return (f._name.Equals(_name) && f._parent.Equals(_parent));
  182.         }
  183.         else if (o is string)
  184.         {
  185.            return ((string)o).Equals(ToString());
  186.         }
  187.         else
  188.            return base.Equals(o);
  189.      }
  190.      public override int GetHashCode()
  191.      {
  192.         return ToString().GetHashCode();
  193.      }
  194.  
  195. #region Open
  196.      /// <summary>
  197.      /// Opens or creates the stream in read-write mode, with no sharing.
  198.      /// </summary>
  199.      /// <returns>A <see cref="System.IO.FileStream"/> wrapper for the stream.</returns>
  200.      public FileStream Open()
  201.      {
  202.         return Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
  203.      }
  204.      /// <summary>
  205.      /// Opens or creates the stream in read-write mode with no sharing.
  206.      /// </summary>
  207.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> action for the stream.</param>
  208.      /// <returns>A <see cref="System.IO.FileStream"/> wrapper for the stream.</returns>
  209.      public FileStream Open(FileMode Mode)
  210.      {
  211.         return Open(Mode, FileAccess.ReadWrite, FileShare.None);
  212.      }
  213.      /// <summary>
  214.      /// Opens or creates the stream with no sharing.
  215.      /// </summary>
  216.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> action for the stream.</param>
  217.      /// <param name="Access">The <see cref="System.IO.FileAccess"/> level for the stream.</param>
  218.      /// <returns>A <see cref="System.IO.FileStream"/> wrapper for the stream.</returns>
  219.      public FileStream Open(FileMode Mode, FileAccess Access)
  220.      {
  221.         return Open(Mode, Access, FileShare.None);
  222.      }
  223.      /// <summary>
  224.      /// Opens or creates the stream.
  225.      /// </summary>
  226.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> action for the stream.</param>
  227.      /// <param name="Access">The <see cref="System.IO.FileAccess"/> level for the stream.</param>
  228.      /// <param name="Share">The <see cref="System.IO.FileShare"/> level for the stream.</param>
  229.      /// <returns>A <see cref="System.IO.FileStream"/> wrapper for the stream.</returns>
  230.      public FileStream Open(FileMode Mode, FileAccess Access, FileShare Share)
  231.      {
  232.         try
  233.         {
  234.            SafeFileHandle hFile = Kernel32.CreateFile(ToString(), Kernel32.Access2API(Access), Share, 0, Mode, 0, 0);
  235.            return new FileStream(hFile, Access);
  236.         }
  237.         catch
  238.         {
  239.            return null;
  240.         }
  241.      }
  242. #endregion
  243.  
  244. #region Delete
  245.      /// <summary>
  246.      /// Deletes the stream from the file.
  247.      /// </summary>
  248.      /// <returns>A <see cref="System.Boolean"/> value: true if the stream was deleted, false if there was an error.</returns>
  249.      public bool Delete()
  250.      {
  251.         return Kernel32.DeleteFile(ToString());
  252.      }
  253. #endregion
  254.   }
  255.  
  256.  
  257.   /// <summary>
  258.   /// Encapsulates the collection of alternative data streams for a file.
  259.   /// A collection of <see cref="StreamInfo"/> objects.
  260.   /// </summary>
  261.   public class FileStreams : CollectionBase
  262.   {
  263.      private FileInfo _file;
  264.  
  265. #region Constructors
  266.      public FileStreams(string File)
  267.      {
  268.         _file = new FileInfo(File);
  269.         initStreams();
  270.      }
  271.      public FileStreams(FileInfo file)
  272.      {
  273.         _file = file;
  274.         initStreams();
  275.      }
  276.  
  277.      /// <summary>
  278.      /// Reads the streams from the file.
  279.      /// </summary>
  280.      private void initStreams()
  281.      {
  282.         //Open the file with backup semantics
  283.         SafeFileHandle hFile = Kernel32.CreateFile(_file.FullName, Kernel32.FileAccessAPI.GENERIC_READ, FileShare.Read, 0, FileMode.Open, Kernel32.FileFlags.BackupSemantics, 0);
  284.         if (hFile.IsInvalid) return;
  285.  
  286.         try
  287.         {
  288.            Kernel32.WIN32_STREAM_ID sid = new Kernel32.WIN32_STREAM_ID();
  289.            int dwStreamHeaderSize = Marshal.SizeOf(sid);
  290.            int Context = 0;
  291.            bool Continue = true;
  292.            while (Continue)
  293.            {
  294.               //Read the next stream header
  295.               int lRead = 0;
  296.               Continue = Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref Context);
  297.               if (Continue && lRead == dwStreamHeaderSize)
  298.               {
  299.                  if (sid.dwStreamNameSize>0)
  300.                  {
  301.                     //Read the stream name
  302.                     lRead = 0;
  303.                     IntPtr pName = Marshal.AllocHGlobal(sid.dwStreamNameSize);
  304.                     try
  305.                     {
  306.                        Continue = Kernel32.BackupRead(hFile, pName, sid.dwStreamNameSize, ref lRead, false, false, ref Context);
  307.                        char[] bName = new char[sid.dwStreamNameSize];
  308.                        Marshal.Copy(pName,bName,0,sid.dwStreamNameSize);
  309.  
  310.                        //Name is of the format ":NAME:$DATA\0"
  311.                        string sName = new string(bName);
  312.                        int i = sName.IndexOf(Kernel32.STREAM_SEP, 1);
  313.                        if (i>-1) sName = sName.Substring(1, i-1);
  314.                        else
  315.                        {
  316.                           //This should never happen.
  317.                           //Truncate the name at the first null char.
  318.                           i = sName.IndexOf('\0');
  319.                           if (i>-1) sName = sName.Substring(1, i-1);
  320.                        }
  321.  
  322.                        //Add the stream to the collection
  323.                        base.List.Add(new StreamInfo(this,sName,sid.Size.ToInt64()));
  324.                     }
  325.                     finally
  326.                     {
  327.                        Marshal.FreeHGlobal(pName);
  328.                     }
  329.                  }
  330.  
  331.                  //Skip the stream contents
  332.                  int l = 0; int h = 0;
  333.                  Continue = Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context);
  334.               }
  335.               else break;
  336.            }
  337.         }
  338.         finally
  339.         {
  340.            Kernel32.CloseHandle(hFile);
  341.         }
  342.      }
  343. #endregion
  344.  
  345. #region File
  346.      /// <summary>
  347.      /// Returns the <see cref="System.IO.FileInfo"/> object for the wrapped file.
  348.      /// </summary>
  349.      public FileInfo FileInfo
  350.      {
  351.         get { return _file; }
  352.      }
  353.      /// <summary>
  354.      /// Returns the full path to the wrapped file.
  355.      /// </summary>
  356.      public string FileName
  357.      {
  358.         get { return _file.FullName; }
  359.      }
  360.  
  361.      /// <summary>
  362.      /// Returns the size of the main data stream, in bytes.
  363.      /// </summary>
  364.      public long FileSize {
  365.         get {return _file.Length;}
  366.      }
  367.  
  368.      /// <summary>
  369.      /// Returns the size of all streams for the file, in bytes.
  370.      /// </summary>
  371.      public long Size
  372.      {
  373.         get
  374.         {
  375.            long size = this.FileSize;
  376.            foreach (StreamInfo s in this) size += s.Size;
  377.            return size;
  378.         }
  379.      }
  380. #endregion
  381.  
  382. #region Open
  383.      /// <summary>
  384.      /// Opens or creates the default file stream.
  385.      /// </summary>
  386.      /// <returns><see cref="System.IO.FileStream"/></returns>
  387.      public FileStream Open()
  388.      {
  389.         return new FileStream(_file.FullName, FileMode.OpenOrCreate);
  390.      }
  391.  
  392.      /// <summary>
  393.      /// Opens or creates the default file stream.
  394.      /// </summary>
  395.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> for the stream.</param>
  396.      /// <returns><see cref="System.IO.FileStream"/></returns>
  397.      public FileStream Open(FileMode Mode)
  398.      {
  399.         return new FileStream(_file.FullName, Mode);
  400.      }
  401.  
  402.      /// <summary>
  403.      /// Opens or creates the default file stream.
  404.      /// </summary>
  405.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> for the stream.</param>
  406.      /// <param name="Access">The <see cref="System.IO.FileAccess"/> for the stream.</param>
  407.      /// <returns><see cref="System.IO.FileStream"/></returns>
  408.      public FileStream Open(FileMode Mode, FileAccess Access)
  409.      {
  410.         return new FileStream(_file.FullName, Mode, Access);
  411.      }
  412.  
  413.      /// <summary>
  414.      /// Opens or creates the default file stream.
  415.      /// </summary>
  416.      /// <param name="Mode">The <see cref="System.IO.FileMode"/> for the stream.</param>
  417.      /// <param name="Access">The <see cref="System.IO.FileAccess"/> for the stream.</param>
  418.      /// <param name="Share">The <see cref="System.IO.FileShare"/> for the stream.</param>
  419.      /// <returns><see cref="System.IO.FileStream"/></returns>
  420.      public FileStream Open(FileMode Mode, FileAccess Access, FileShare Share)
  421.      {
  422.         return new FileStream(_file.FullName, Mode, Access, Share);
  423.      }
  424. #endregion
  425.  
  426. #region Delete
  427.      /// <summary>
  428.      /// Deletes the file, and all alternative streams.
  429.      /// </summary>
  430.      public void Delete()
  431.      {
  432.         for (int i=base.List.Count;i>0;i--)
  433.         {
  434.            base.List.RemoveAt(i);
  435.         }
  436.         _file.Delete();
  437.      }
  438. #endregion
  439.  
  440. #region Collection operations
  441.      /// <summary>
  442.      /// Add an alternative data stream to this file.
  443.      /// </summary>
  444.      /// <param name="Name">The name for the stream.</param>
  445.      /// <returns>The index of the new item.</returns>
  446.      public int Add(string Name)
  447.      {
  448.         StreamInfo FSI = new StreamInfo(this, Name, 0);
  449.         int i = base.List.IndexOf(FSI);
  450.         if (i==-1) i = base.List.Add(FSI);
  451.         return i;
  452.      }
  453.      /// <summary>
  454.      /// Removes the alternative data stream with the specified name.
  455.      /// </summary>
  456.      /// <param name="Name">The name of the string to remove.</param>
  457.      public void Remove(string Name)
  458.      {
  459.         StreamInfo FSI = new StreamInfo(this, Name, 0);
  460.         int i = base.List.IndexOf(FSI);
  461.         if (i>-1) base.List.RemoveAt(i);
  462.      }
  463.  
  464.      /// <summary>
  465.      /// Returns the index of the specified <see cref="StreamInfo"/> object in the collection.
  466.      /// </summary>
  467.      /// <param name="FSI">The object to find.</param>
  468.      /// <returns>The index of the object, or -1.</returns>
  469.      public int IndexOf(StreamInfo FSI)
  470.      {
  471.         return base.List.IndexOf(FSI);
  472.      }
  473.      /// <summary>
  474.      /// Returns the index of the <see cref="StreamInfo"/> object with the specified name in the collection.
  475.      /// </summary>
  476.      /// <param name="Name">The name of the stream to find.</param>
  477.      /// <returns>The index of the stream, or -1.</returns>
  478.      public int IndexOf(string Name)
  479.      {
  480.         return base.List.IndexOf(new StreamInfo(this, Name, 0));
  481.      }
  482.  
  483.      public StreamInfo this[int Index]
  484.      {
  485.         get { return (StreamInfo)base.List[Index]; }
  486.      }
  487.      public StreamInfo this[string Name]
  488.      {
  489.         get
  490.         {
  491.            int i = IndexOf(Name);
  492.            if (i==-1) return null;
  493.            else return (StreamInfo)base.List[i];
  494.         }
  495.      }
  496. #endregion
  497.  
  498. #region Overrides
  499.      /// <summary>
  500.      /// Throws an exception if you try to add anything other than a StreamInfo object to the collection.
  501.      /// </summary>
  502.      protected override void OnInsert(int index, object value)
  503.      {
  504.         if (!(value is StreamInfo)) throw new InvalidCastException();
  505.      }
  506.      /// <summary>
  507.      /// Throws an exception if you try to add anything other than a StreamInfo object to the collection.
  508.      /// </summary>
  509.      protected override void OnSet(int index, object oldValue, object newValue)
  510.      {
  511.         if (!(newValue is StreamInfo)) throw new InvalidCastException();
  512.      }
  513.  
  514.      /// <summary>
  515.      /// Deletes the stream from the file when you remove it from the list.
  516.      /// </summary>
  517.      protected override void OnRemoveComplete(int index, object value)
  518.      {
  519.         try
  520.         {
  521.            StreamInfo FSI = (StreamInfo)value;
  522.            if (FSI != null) FSI.Delete();
  523.         }
  524.         catch {}
  525.      }
  526.  
  527.      public new StreamEnumerator GetEnumerator()
  528.      {
  529.         return new StreamEnumerator(this);
  530.      }
  531. #endregion
  532.  
  533. #region StreamEnumerator
  534.      public class StreamEnumerator : object, IEnumerator
  535.      {
  536.         private IEnumerator baseEnumerator;
  537.            
  538.         public StreamEnumerator(FileStreams mappings)
  539.         {
  540.            this.baseEnumerator = ((IEnumerable)(mappings)).GetEnumerator();
  541.         }
  542.            
  543.         public StreamInfo Current
  544.         {
  545.            get
  546.            {
  547.               return ((StreamInfo)(baseEnumerator.Current));
  548.            }
  549.         }
  550.            
  551.         object IEnumerator.Current
  552.         {
  553.            get
  554.            {
  555.               return baseEnumerator.Current;
  556.            }
  557.         }
  558.            
  559.         public bool MoveNext()
  560.         {
  561.            return baseEnumerator.MoveNext();
  562.         }
  563.            
  564.         bool IEnumerator.MoveNext()
  565.         {
  566.            return baseEnumerator.MoveNext();
  567.         }
  568.            
  569.         public void Reset()
  570.         {
  571.            baseEnumerator.Reset();
  572.         }
  573.            
  574.         void IEnumerator.Reset()
  575.         {
  576.            baseEnumerator.Reset();
  577.         }
  578.      }
  579. #endregion
  580.   }
  581. }
  582. '@
  583.  
  584. Set-Alias block Set-DownloadFlag
  585. Set-Alias unblock Remove-DownloadFlag
  586.  
  587. #Export-ModuleMember -Function Remove-DownloadFlag, Set-DownloadFlag -alias block, unblock

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me