#requires -version 2.0 ## PoshCode module v 3.3 ## See comments for each function for changes ... ############################################################################################################## ## Provides cmdlets for working with scripts from the PoshCode Repository: ## Get-PoshCodeUpgrade - get the latest version of this script from the PoshCode server ## Get-PoshCode - Search for and download code snippets ## New-PoshCode - Upload new code snippets ## Unblock-Code - Unblock files downloaded from the internet ## Block-Code - Mark files as downloaded (used by Get-PoshCode) ## Get-WebFile - Download ############################################################################################################## Set-StrictMode -Version Latest $PoshCode = "http://PoshCode.org/" | Add-Member -type NoteProperty -Name "UserName" -Value "Anonymous" -Passthru | Add-Member -type ScriptProperty -Name "ScriptLocation" -Value { $module = $null Get-Module PoshCode | Select -expand Path -EA "SilentlyContinue" | Tee -var module if(!$module) { # Try finding it by path, since it's not loaded as "PoshCode" Get-Module | ? {$_.Name -match "^$([RegEx]::Escape($PsScriptRoot))"} | Select -expand Path } } -Passthru | Add-Member -type ScriptProperty -Name "ModuleName" -Value { if( Get-Module PoshCode ) { "PoshCode" } else { Get-Module | ? {$_.Name -match "^$([RegEx]::Escape($PsScriptRoot))"} | Select -expand Name } } -Passthru | Add-Member -type NoteProperty -Name "ScriptVersion" -Value 3.3 -Passthru | Add-Member -type NoteProperty -Name "ApiVersion" -Value 1 -Passthru ## Block-Code ############################################################################################################## ## marks code as being "remote" (i.e.: downloaded from the internet) ## That is, we set the alternate data stream, like IE7 or Firefox3 would ############################################################################################################## CMDLET Block-Code -snapin Huddled.PoshCode { PARAM ( [Parameter(Position=0, Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [Alias("FullName")] [string] $Path , [Switch]$Passthru ) $FS = new-object NTFS.FileStreams($Path) $null = $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() if($Passthru){ Get-ChildItem $Path } } ## Unblock-Code ############################################################################################################## ## removes the alternate data stream that marks code as being "remote" (i.e.: downloaded from the internet) ############################################################################################################## CMDLET Unblock-Code -snapin Huddled.PoshCode { PARAM ( [Parameter(Position=0, Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [Alias("FullName")] [string] $Path , [Switch]$Passthru ) $FS = new-object NTFS.FileStreams($Path) $null = $fs['Zone.Identifier'].delete() if($Passthru){ Get-ChildItem $Path } } ## New-PoshCode (formerly Send-Paste) ############################################################################################################## ## Uploads code to the PowerShell Script Repository and returns the url for you. ############################################################################################################## ## Usage: ## get-content myscript.ps1 | New-PoshCode "An example for you" "This is just to show how to do it" ## would send the script with the specified title and description ## ls *.ps1 | New-PoshCode -Keep Forever ## would flood the pastebin site with all your scripts, using filename as the title ## and a generic description, and mark them for storing indefinitely ## get-history -count 5 | % { $_.CommandLine } | New-PoshCode ## would paste the last 5 commands in your history! ############################################################################################################## ## History: ## v 3.1 - Fixed the $URL parameter so that it's settable again. *This* function should work on any pastebin site ## v 3.0 - Renamed to New-PoshCode. ## Removed the -Permanent switch, since this is now exclusive to the permanent repository ## v 2.1 - Changed some defaults ## - Added "PermanentPosh" switch ( -P ) to switch the upload to the PowerShellCentral repository ## v 2.0 - works with "pastebin" (including posh.jaykul.com/p/ and PowerShellCentral.com/scripts/) ## v 1.0 - Worked with a special pastebin ############################################################################################################## CMDLET New-PoshCode -snapin Huddled.PoshCode { PARAM( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [Alias("FullName")] [string] $Path , [Parameter(Position=5, Mandatory=$true)][string]$Description , [Parameter(Position=10)][string]$Author = $($PoshCode.UserName) , [Parameter(Position=15)][PoshCodeLanguage]$Language="posh" , [Parameter(Position=20, Mandatory=$false)] [ValidateScript({ if($_ -match "^[dmf]") { return $true } else { throw "Please specify 'day', 'month', or 'forever'" } })] [string]$Keep="f" , [Alias("BaseName,Name")] [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [string]$Title , [Parameter(Mandatory=$false)][string]$url= $($PoshCode) ) BEGIN { $null = [Reflection.Assembly]::LoadWithPartialName("System.Web") [string]$data = "" [string]$meta = "" if($language) { $meta = "format=" + [System.Web.HttpUtility]::UrlEncode($language) # $url = $url + "?" +$lang } else { $meta = "format=text" } # Note how simplified this is by switch -regex ($Keep) { "^d" { $meta += "&expiry=d" } "^m" { $meta += "&expiry=m" } "^f" { $meta += "&expiry=f" } } if($Description) { $meta += "&descrip=" + [System.Web.HttpUtility]::UrlEncode($Description) } else { $meta += "&descrip=" } $meta += "&poster=" + [System.Web.HttpUtility]::UrlEncode($Author) function Send-PoshCode ($meta, $title, $data, $url= $($PoshCode)) { $meta += "&paste=Send&posttitle=" + [System.Web.HttpUtility]::UrlEncode($Title) $data = $meta + "&code2=" + [System.Web.HttpUtility]::UrlEncode($data) $request = [System.Net.WebRequest]::Create($url) $request.ContentType = "application/x-www-form-urlencoded" $request.ContentLength = $data.Length $request.Method = "POST" $post = new-object IO.StreamWriter $request.GetRequestStream() $post.Write($data,0,$data.Length) $post.Flush() $post.Close() # $reader = new-object IO.StreamReader $request.GetResponse().GetResponseStream() ##,[Text.Encoding]::UTF8 # write-output $reader.ReadToEnd() # $reader.Close() write-output $request.GetResponse().ResponseUri.AbsoluteUri $request.Abort() } } PROCESS { $EAP = $ErrorActionPreference $ErrorActionPreference = "SilentlyContinue" if(Test-Path $Path -PathType Leaf) { $ErrorActionPreference = $EAP Write-Verbose $Path Write-Output $(Send-PoshCode $meta $Title $([string]::join("`n",(Get-Content $Path))) $url) } elseif(Test-Path $Path -PathType Container) { $ErrorActionPreference = $EAP Write-Error "Can't upload folders yet: $Path" } else { ## Todo, handle folders? $ErrorActionPreference = $EAP if(!$data -and !$Title){ $Title = Read-Host "Give us a title for your post" } $data += "`n" + $Path } } END { if($data) { Write-Output $(Send-PoshCode $meta $Title $data $url) } } } ## Get-PoshCode (download Repository script) ############################################################################################################## ## Downloads a specified script from a Pastbin.com based site, by Id ## ### OR ### ## Searches the powershellcentral.com/script site and returns lists of results ## All search terms are automatically surrounded with wildcards ## NOTE: powershellcentral.com currently uses MySql fulltext search syntax... ############################################################################################################## ## Usage: ## Get-PoshCode Authenticode ## will search the repository for scripts dealing with Authenticode, and list the results ## Normally, you will take one of those IDs and do this: ## Get-PoshCode 456 ## will download the script 456 and save it to file (based on it's name/contents) ## This example would yield a file: Get_Set Signature (CTP2).psm1 ## Get-PoshCode 456 -passthru ## would output the contents of that script into the pipeline, so eg: ## (Get-PoshCode 456 -passthru) -replace "AuthenticodeSignature","SillySig" ## Get-PoshCode 456 $ProfileDir\Authenticode.psm1 ## would download the script to Authenticode.ps1 in the specified directory ## Get-PoshCode SCOM | Get-PoshCode ## would search the repository for all scripts about SCOM, and then download them! ## Get-PoshCode SCOM | Get-PoshCode | Unblock-Code ## would search the repository for all scripts about SCOM, and then download them and unblock them ## see the comments on Block-Code and Unblock-Code ############################################################################################################## ## History: ## v 3.2 - Add "-Upgrade" switch to cause the script to upgrade itself. ## v 3.1 - Add "Huddled.PoshCode.ScriptInfo" to TypeInfo, so it can be formatted by a ps1xml ## - Add ConvertTo-Module function to try to rename .ps1 scripts to .psm1 ## - Fixed exceptions thrown by searches which return no results ## - Removed the auto-wildcards!!!! ## NOTE: to get the same results as before you must now put * on the front and end of searches ## This is so that searches on the website work the same as searches here... ## My intention is to improve the website's search instead of leaving this here. ## NOTE: the website currently will not search for words less than 4 characters long ## v 3.0 - Working against the new RSS-based API ## - And using ParameterSets, which work in CTP2 ## v 2.0 - Combined with Find-Poshcode into a single script ## v 1.0 - Working against our special pastebin ############################################################################################################## CMDLET Get-PoshCode -snapin Huddled.PoshCode -DefaultParameterSet Download { PARAM( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Search")] [string]$Query , [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="Download" )] [int]$Id , [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Upgrade")] [switch]$Upgrade , [Parameter(Position=1, Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [Alias("FullName")] [string]$SaveAs , [switch]$InBrowser , [switch]$Passthru , [Parameter(Mandatory=$false)][string]$url= $($PoshCode) ) PROCESS { Write-Debug "ParameterSet Name: $($PSCmdlet.ParameterSetName)" switch($PSCmdlet.ParameterSetName) { "Search" { $results = @(([xml](Get-WebFile "$($url)api$($PoshCode.ApiVersion)/$($query)" -passthru)).rss.channel.GetElementsByTagName("item")) if($results.Count -eq 0 ) { Write-Host "Zero Results for '$query'" -Fore Red -Back Black } else { $results | Select @{ n="Id";e={$($_.link -replace $url,'') -as [int]}}, @{n="Title";e={$_.title}}, @{n="Author";e={$_.creator}}, @{n="Date";e={$_.pubDate }}, @{n="Link";e={$_.guid.get_InnerText() }}, @{n="Description";e={"$($_.description.get_InnerText())`n" }} | ForEach { $_.PSObject.TypeNames.Insert( 0, "Huddled.PoshCode.ScriptInfo" ); $_ } } } "Download" { if(!$InBrowser) { if($Passthru) { Get-WebFile "$($url)?dl=$id" -Passthru } elseif($SaveAs) { Get-WebFile "$($url)?dl=$id" -fileName $SaveAs | ConvertTo-Module | Block-Code -Passthru } else { Get-WebFile "$($url)?dl=$id" | ConvertTo-Module | Block-Code -Passthru } } else { [Diagnostics.Process]::Start( "$($url)$id" ) } } "Upgrade" { Get-PoshCodeUpgrade } } } } ## Get-PoshCodeUpgrade ############################################################################################################## ## Downloads a new PoshCode script version, and archives old versions.. ############################################################################################################## ## History: ## v3.3 - Removes old versions, and checks the signature. ## v3.2 - First script version with Upgrade function ############################################################################################################## function Get-PoshCodeUpgrade { $VersionFile = [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ("{0}{1}" -f $PoshCode.ScriptVersion, [IO.Path]::GetExtension($PoshCode.ScriptLocation))) # Copy it to make sure we don't loose it Copy-Item $PoshCode.ScriptLocation $VersionFile # Remove old ones ... Remove-Item ( [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ".*$([IO.Path]::GetExtension( $($PoshCode.ScriptLocation) ))") ) -exclude ([IO.Path]::GetFileName($VersionFile)) -Confirm # Finally, get the new one $NewFile = Get-WebFile "$($PoshCode)PoshCode.psm1" -fileName ( [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ".INVALID.ps1")) if( Test-Signature -File $NewFile ) { Move-Item $NewFile $PoshCode.ScriptLocation -Force -passthru | Unblock-Code -Passthru Add-Module $($PoshCode.ModuleName) -Force } else { Write-Error "Signature is Not Valid on new version." Get-Item $NewFile } } ## Test-Signature - Returns true if the signature is valid OR is signed by "F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5" CMDLET Test-Signature -snapin Huddled.PoshCode -DefaultParameterSet "File" { PARAM ( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Signature")] # We can't actually require the type, or we won't be able to check the fake ones from Joel's Authenticode module # [System.Management.Automation.Signature] $Signature , [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="File")] [System.IO.FileInfo] $File ) PROCESS { if($File -and (Test-Path $File -PathType Leaf)) { $Signature = Get-AuthenticodeSignature $File } if(!$Signature) { return $false } else { $result = $false; try { $result = ((($Signature.Status -eq "UnknownError") -and $Signature.SignerCertificate -and ($Signature.SignerCertificate.Thumbprint -eq "F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5") ) -or $Signature.Status -eq "Valid" ) } catch { } finally { return $result } } } } filter ConvertTo-Module { $oldFile = $_ if( ([IO.Path]::GetExtension($oldFile) -eq ".ps1") -and [Regex]::Match( [IO.File]::ReadAllText($oldFile), "^[^#]*Export-ModuleMember.*", "MultiLine").Success ) { $fileName = [IO.Path]::ChangeExtension($oldFile, ".psm1") Move-Item $oldFile $fileName -Force Get-Item $fileName } else { $oldFile } } ## Get-WebFile (aka wget for PowerShell) ############################################################################################################## ## Downloads a file or page from the web ## History: ## v3.7 - Add file-name guessing and cleanup ## v3.6 - Add -Passthru switch to output TEXT files ## v3.5 - Add -Quiet switch to turn off the progress reports ... ## v3.4 - Add progress report for files which don't report size ## v3.3 - Add progress report for files which report their size ## v3.2 - Use the pure Stream object because StreamWriter is based on TextWriter: ## it was messing up binary files, and making mistakes with extended characters in text ## v3.1 - Unwrap the filename when it has quotes around it ## v3 - rewritten completely using HttpWebRequest + HttpWebResponse to figure out the file name, if possible ## v2 - adds a ton of parsing to make the output pretty ## added measuring the scripts involved in the command, (uses Tokenizer) ############################################################################################################## function Get-WebFile { param( $url = (Read-Host "The URL to download"), $fileName = $null, [switch]$Passthru, [switch]$quiet ) Write-Verbose "Downloading '$url'" $req = [System.Net.HttpWebRequest]::Create($url); $res = $req.GetResponse(); if($fileName -and !(Split-Path $fileName)) { $fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName } elseif((!$Passthru -and ($fileName -eq $null)) -or (($fileName -ne $null) -and (Test-Path -PathType "Container" $fileName))) { [string]$fileName = ([regex]'(?i)filename=(.*)$').Match( $res.Headers["Content-Disposition"] ).Groups[1].Value $fileName = $fileName.trim("\/""'") $ofs = "" $fileName = [Regex]::Replace($fileName, "[$([Regex]::Escape(""$([System.IO.Path]::GetInvalidPathChars())$([IO.Path]::AltDirectorySeparatorChar)$([IO.Path]::DirectorySeparatorChar)""))]", "_") $ofs = " " if(!$fileName) { $fileName = $res.ResponseUri.Segments[-1] $fileName = $fileName.trim("\/") if(!$fileName) { $fileName = Read-Host "Please provide a file name" } $fileName = $fileName.trim("\/") if(!([IO.FileInfo]$fileName).Extension) { $fileName = $fileName + "." + $res.ContentType.Split(";")[0].Split("/")[1] } } $fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName } if($Passthru) { $encoding = [System.Text.Encoding]::GetEncoding( $res.CharacterSet ) [string]$output = "" } if($res.StatusCode -eq 200) { [int]$goal = $res.ContentLength $reader = $res.GetResponseStream() if($fileName) { $writer = new-object System.IO.FileStream $fileName, "Create" } [byte[]]$buffer = new-object byte[] 4096 [int]$total = [int]$count = 0 do { $count = $reader.Read($buffer, 0, $buffer.Length); if($fileName) { $writer.Write($buffer, 0, $count); } if($Passthru){ $output += $encoding.GetString($buffer,0,$count) } elseif(!$quiet) { $total += $count if($goal -gt 0) { Write-Progress "Downloading $url" "Saving $total of $goal" -id 0 -percentComplete (($total/$goal)*100) } else { Write-Progress "Downloading $url" "Saving $total bytes..." -id 0 } } } while ($count -gt 0) $reader.Close() if($fileName) { $writer.Flush() $writer.Close() } if($Passthru){ $output } } $res.Close(); if($fileName) { Block-Code $fileName -PassThru } } Export-ModuleMember Get-PoshCode, New-PoshCode, Unblock-Code, Block-Code, Get-WebFile, Get-PoshCodeUpgrade #Add-Type -Path "$PsScriptRoot\NTFS.cs" Add-Type -TypeDefinition @' using System; using System.IO; using System.Collections; using System.Runtime.InteropServices; /// ///Encapsulates access to alternative data streams of an NTFS file. ///Adapted from a C++ sample by Dino Esposito, ///http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/ntfs5.asp /// namespace NTFS { /// /// Wraps the API functions, structures and constants. /// internal class Kernel32 { public const char STREAM_SEP = ':'; public const int INVALID_HANDLE_VALUE = -1; public const int MAX_PATH = 256; [Flags()] public enum FileFlags : uint { WriteThrough = 0x80000000, Overlapped = 0x40000000, NoBuffering = 0x20000000, RandomAccess = 0x10000000, SequentialScan = 0x8000000, DeleteOnClose = 0x4000000, BackupSemantics = 0x2000000, PosixSemantics = 0x1000000, OpenReparsePoint = 0x200000, OpenNoRecall = 0x100000 } [Flags()] public enum FileAccessAPI : uint { GENERIC_READ = 0x80000000, GENERIC_WRITE = 0x40000000 } /// /// Provides a mapping between a System.IO.FileAccess value and a FileAccessAPI value. /// /// The value to map. /// The value. public static FileAccessAPI Access2API(FileAccess Access) { FileAccessAPI lRet = 0; if ((Access & FileAccess.Read)==FileAccess.Read) lRet |= FileAccessAPI.GENERIC_READ; if ((Access & FileAccess.Write)==FileAccess.Write) lRet |= FileAccessAPI.GENERIC_WRITE; return lRet; } [StructLayout(LayoutKind.Sequential)] public struct LARGE_INTEGER { public int Low; public int High; public long ToInt64() { return (long)High * 4294967296 + (long)Low; } } [StructLayout(LayoutKind.Sequential)] public struct WIN32_STREAM_ID { public int dwStreamID; public int dwStreamAttributes; public LARGE_INTEGER Size; public int dwStreamNameSize; } [DllImport("kernel32")] public static extern IntPtr CreateFile(string Name, FileAccessAPI Access, FileShare Share, int Security, FileMode Creation, FileFlags Flags, int Template); [DllImport("kernel32")] public static extern bool DeleteFile(string Name); [DllImport("kernel32")] public static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32")] public static extern bool BackupRead(IntPtr hFile, IntPtr pBuffer, int lBytes, ref int lRead, bool bAbort, bool bSecurity, ref int Context); [DllImport("kernel32")] public static extern bool BackupRead(IntPtr hFile, ref WIN32_STREAM_ID pBuffer, int lBytes, ref int lRead, bool bAbort, bool bSecurity, ref int Context); [DllImport("kernel32")] public static extern bool BackupSeek(IntPtr hFile, int dwLowBytesToSeek, int dwHighBytesToSeek, ref int dwLow, ref int dwHigh, ref int Context); } /// /// Encapsulates a single alternative data stream for a file. /// public class StreamInfo { private FileStreams _parent; private string _name; private long _size; internal StreamInfo(FileStreams Parent, string Name, long Size) { _parent = Parent; _name = Name; _size = Size; } /// /// The name of the stream. /// public string Name { get { return _name; } } /// /// The size (in bytes) of the stream. /// public long Size { get { return _size; } } public override string ToString() { return String.Format("{1}{0}{2}{0}$DATA", Kernel32.STREAM_SEP, _parent.FileName, _name); } public override bool Equals(Object o) { if (o is StreamInfo) { StreamInfo f = (StreamInfo)o; return (f._name.Equals(_name) && f._parent.Equals(_parent)); } else if (o is string) { return ((string)o).Equals(ToString()); } else return base.Equals(o); } public override int GetHashCode() { return ToString().GetHashCode(); } #region Open /// /// Opens or creates the stream in read-write mode, with no sharing. /// /// A wrapper for the stream. public FileStream Open() { return Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); } /// /// Opens or creates the stream in read-write mode with no sharing. /// /// The action for the stream. /// A wrapper for the stream. public FileStream Open(FileMode Mode) { return Open(Mode, FileAccess.ReadWrite, FileShare.None); } /// /// Opens or creates the stream with no sharing. /// /// The action for the stream. /// The level for the stream. /// A wrapper for the stream. public FileStream Open(FileMode Mode, FileAccess Access) { return Open(Mode, Access, FileShare.None); } /// /// Opens or creates the stream. /// /// The action for the stream. /// The level for the stream. /// The level for the stream. /// A wrapper for the stream. public FileStream Open(FileMode Mode, FileAccess Access, FileShare Share) { try { IntPtr hFile = Kernel32.CreateFile(ToString(), Kernel32.Access2API(Access), Share, 0, Mode, 0, 0); return new FileStream(hFile, Access, true); } catch { return null; } } #endregion #region Delete /// /// Deletes the stream from the file. /// /// A value: true if the stream was deleted, false if there was an error. public bool Delete() { return Kernel32.DeleteFile(ToString()); } #endregion } /// /// Encapsulates the collection of alternative data streams for a file. /// A collection of objects. /// public class FileStreams : CollectionBase { private FileInfo _file; #region Constructors public FileStreams(string File) { _file = new FileInfo(File); initStreams(); } public FileStreams(FileInfo file) { _file = file; initStreams(); } /// /// Reads the streams from the file. /// private void initStreams() { //Open the file with backup semantics IntPtr hFile = Kernel32.CreateFile(_file.FullName, Kernel32.FileAccessAPI.GENERIC_READ, FileShare.Read, 0, FileMode.Open, Kernel32.FileFlags.BackupSemantics, 0); if (hFile.ToInt32() == Kernel32.INVALID_HANDLE_VALUE) return; try { Kernel32.WIN32_STREAM_ID sid = new Kernel32.WIN32_STREAM_ID(); int dwStreamHeaderSize = Marshal.SizeOf(sid); int Context = 0; bool Continue = true; while (Continue) { //Read the next stream header int lRead = 0; Continue = Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref Context); if (Continue && lRead == dwStreamHeaderSize) { if (sid.dwStreamNameSize>0) { //Read the stream name lRead = 0; IntPtr pName = Marshal.AllocHGlobal(sid.dwStreamNameSize); try { Continue = Kernel32.BackupRead(hFile, pName, sid.dwStreamNameSize, ref lRead, false, false, ref Context); char[] bName = new char[sid.dwStreamNameSize]; Marshal.Copy(pName,bName,0,sid.dwStreamNameSize); //Name is of the format ":NAME:$DATA\0" string sName = new string(bName); int i = sName.IndexOf(Kernel32.STREAM_SEP, 1); if (i>-1) sName = sName.Substring(1, i-1); else { //This should never happen. //Truncate the name at the first null char. i = sName.IndexOf('\0'); if (i>-1) sName = sName.Substring(1, i-1); } //Add the stream to the collection base.List.Add(new StreamInfo(this,sName,sid.Size.ToInt64())); } finally { Marshal.FreeHGlobal(pName); } } //Skip the stream contents int l = 0; int h = 0; Continue = Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context); } else break; } } finally { Kernel32.CloseHandle(hFile); } } #endregion #region File /// /// Returns the object for the wrapped file. /// public FileInfo FileInfo { get { return _file; } } /// /// Returns the full path to the wrapped file. /// public string FileName { get { return _file.FullName; } } /// /// Returns the size of the main data stream, in bytes. /// public long FileSize { get {return _file.Length;} } /// /// Returns the size of all streams for the file, in bytes. /// public long Size { get { long size = this.FileSize; foreach (StreamInfo s in this) size += s.Size; return size; } } #endregion #region Open /// /// Opens or creates the default file stream. /// /// public FileStream Open() { return new FileStream(_file.FullName, FileMode.OpenOrCreate); } /// /// Opens or creates the default file stream. /// /// The for the stream. /// public FileStream Open(FileMode Mode) { return new FileStream(_file.FullName, Mode); } /// /// Opens or creates the default file stream. /// /// The for the stream. /// The for the stream. /// public FileStream Open(FileMode Mode, FileAccess Access) { return new FileStream(_file.FullName, Mode, Access); } /// /// Opens or creates the default file stream. /// /// The for the stream. /// The for the stream. /// The for the stream. /// public FileStream Open(FileMode Mode, FileAccess Access, FileShare Share) { return new FileStream(_file.FullName, Mode, Access, Share); } #endregion #region Delete /// /// Deletes the file, and all alternative streams. /// public void Delete() { for (int i=base.List.Count;i>0;i--) { base.List.RemoveAt(i); } _file.Delete(); } #endregion #region Collection operations /// /// Add an alternative data stream to this file. /// /// The name for the stream. /// The index of the new item. public int Add(string Name) { StreamInfo FSI = new StreamInfo(this, Name, 0); int i = base.List.IndexOf(FSI); if (i==-1) i = base.List.Add(FSI); return i; } /// /// Removes the alternative data stream with the specified name. /// /// The name of the string to remove. public void Remove(string Name) { StreamInfo FSI = new StreamInfo(this, Name, 0); int i = base.List.IndexOf(FSI); if (i>-1) base.List.RemoveAt(i); } /// /// Returns the index of the specified object in the collection. /// /// The object to find. /// The index of the object, or -1. public int IndexOf(StreamInfo FSI) { return base.List.IndexOf(FSI); } /// /// Returns the index of the object with the specified name in the collection. /// /// The name of the stream to find. /// The index of the stream, or -1. public int IndexOf(string Name) { return base.List.IndexOf(new StreamInfo(this, Name, 0)); } public StreamInfo this[int Index] { get { return (StreamInfo)base.List[Index]; } } public StreamInfo this[string Name] { get { int i = IndexOf(Name); if (i==-1) return null; else return (StreamInfo)base.List[i]; } } #endregion #region Overrides /// /// Throws an exception if you try to add anything other than a StreamInfo object to the collection. /// protected override void OnInsert(int index, object value) { if (!(value is StreamInfo)) throw new InvalidCastException(); } /// /// Throws an exception if you try to add anything other than a StreamInfo object to the collection. /// protected override void OnSet(int index, object oldValue, object newValue) { if (!(newValue is StreamInfo)) throw new InvalidCastException(); } /// /// Deletes the stream from the file when you remove it from the list. /// protected override void OnRemoveComplete(int index, object value) { try { StreamInfo FSI = (StreamInfo)value; if (FSI != null) FSI.Delete(); } catch {} } public new StreamEnumerator GetEnumerator() { return new StreamEnumerator(this); } #endregion #region StreamEnumerator public class StreamEnumerator : object, IEnumerator { private IEnumerator baseEnumerator; public StreamEnumerator(FileStreams mappings) { this.baseEnumerator = ((IEnumerable)(mappings)).GetEnumerator(); } public StreamInfo Current { get { return ((StreamInfo)(baseEnumerator.Current)); } } object IEnumerator.Current { get { return baseEnumerator.Current; } } public bool MoveNext() { return baseEnumerator.MoveNext(); } bool IEnumerator.MoveNext() { return baseEnumerator.MoveNext(); } public void Reset() { baseEnumerator.Reset(); } void IEnumerator.Reset() { baseEnumerator.Reset(); } } #endregion } } '@ Add-Type -TypeDefinition @' public enum PoshCodeLanguage { asp, bash, csharp, posh, vbnet, xml, text } '@ # SIG # Begin signature block # MIIK0AYJKoZIhvcNAQcCoIIKwTCCCr0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUblhtp8nBiG9rG8Yh20QwrGOH # 4eKgggbEMIIGwDCCBKigAwIBAgIJAKpDRVMtv0LqMA0GCSqGSIb3DQEBBQUAMIHG # MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hl # c3RlcjEaMBgGA1UEChMRSHVkZGxlZE1hc3Nlcy5vcmcxHjAcBgNVBAsTFUNlcnRp # ZmljYXRlIEF1dGhvcml0eTErMCkGA1UEAxMiSm9lbCBCZW5uZXR0IENlcnRpZmlj # YXRlIEF1dGhvcml0eTEnMCUGCSqGSIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNz # ZXMub3JnMB4XDTA4MDcwMjAzNTA1OVoXDTA5MDcwMjAzNTA1OVowgcAxCzAJBgNV # BAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazESMBAGA1UEBxMJUm9jaGVzdGVyMRow # GAYDVQQKExFIdWRkbGVkTWFzc2VzLm9yZzEuMCwGA1UECxMlaHR0cDovL0h1ZGRs # ZWRNYXNzZXMub3JnL0NvZGVDZXJ0LmNydDEVMBMGA1UEAxMMSm9lbCBCZW5uZXR0 # MScwJQYJKoZIhvcNAQkBFhhKYXlrdWxASHVkZGxlZE1hc3Nlcy5vcmcwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXuceXJZYARJbSTU4hoh91goVp2POx # 6Mz/QZ6D5jcT/JNhdW2GwYQ9YUxNj8jkhXg2Ixbgb1djRGMFC/ekgRkgLxyiuhRh # NrVE1IdV4hT4as3idqnvWOi0S3z2R2EGdebqwm2mrRmq9+DbY+FGxuNwLboWZx8Z # roGlLLHRPzt9pabQq/Nu/FIFO+4JzZ8S5ZnEaKTm4dpD0g6j653OWYVvNXJbS/W4 # Dis5aRkHT1q1Gp02dYHh3NTKrpv1nus9BTDlJRwmU/FgGLNQIvnRwqVoBh+I7tVq # NIRnI1RpDTGyFEohbH8mRlwq3z4ijtb6j9boUJEqd8hQshzUMcALoTIR1tN/5APX # u2j4OqGFESM/OG0i2hLKbnP81u581aZT1BfVfQxvDuWrFiurMxllVGY1NvKkXwc8 # aOZktqMQWbWAs2bxZqERbOILXOmkL/mvPdy+e5yQveriHAhrDONu7a79ylreMHBR # XrmYJTK2G/aHvB5vrXjMPw0TBeph0sM2BN2eVzenAAMsIiGlXPXvtKrpKRiBdx5f # 9SV5dyUG2tR8ANDuc2AMB8FKICuMUd8Sx96p4FOBQhXhvF/RZcWZIW5o+A4sHvYE # /s4oiX7LxGrQK2abNiCVs9BDLI/EcSs/TP+ZskBqu7Qb+AVeevoY3T7skihuyC/l # h7EwqjfNpVQ9UwIDAQABo4G0MIGxMB0GA1UdDgQWBBTgB9XYJV/kJAvnkWmKDHsh # 7Cn3PzAfBgNVHSMEGDAWgBQ+5x4ah0JG0o4iUj0TebNd4MCVxTAJBgNVHRMEAjAA # MBEGCWCGSAGG+EIBAQQEAwIEEDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzALBgNV # HQ8EBAMCBsAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp # ZmljYXRlMA0GCSqGSIb3DQEBBQUAA4ICAQAw8B6+s48CZZo5h5tUeKV7OWNXKRG7 # xkyavMkXpEi58BSLutmE3O7smc3uvu3TdCXENNUlGrcq/KQ8y2eEI8QkHgT99VgX # r+v5xu2KnJXiOOIxi65EZybRFFFaGJNodTcrK8L/tY6QLF02ilOlEgfcc1sV/Sj/ # r60JS1iXIMth7nYZVjtWeYXOrsd+I+XwJuoVNJlELNdApOU4ZVNrPEuV+QRNMimj # lqIOv2tn9TDdNGUqaOCI0w+a1XQvapEPWETfQK+o9pvYINTswGDjNeb7Xz8ar2JB # 9IVs2xtxDohHB75kyRrlY1hkoY5j12ZhWOlm0L9Ks6XvmMtXJIjj0/m9Z+3s+9p6 # U7IYjz5NnzmDvtNUn2y9zxB/rUx/JqoUO3BWRKiLX0lvGRWJlzFr9978kH2SXxAD # rsKfzB7YZzMh9hZkGNlJf4T+HTB/OXG1jyfkyqQvhNB/tDAaq+ejDtKNBF4hMS7K # Z0B4vagIxFwMuTiei4UaOjrGzeCfT9w1Bmj6uLJme5ydQVM0V7z3Z6jR3LVq4c4s # Y1dfPmYlw62cbyV9Kb/H2hYw5K0OMX60LfLQZOzIPzAeRJ87NufwZnC1afxsSCmU # bvSx4kCMgRZMXw+d1SHRhh7z+06YTQjnUMmtTGt7DtUkU6I8LKEWF/mAzF7sq/7P # AyhPsbu91X5FuzGCA3YwggNyAgEBMIHUMIHGMQswCQYDVQQGEwJVUzERMA8GA1UE # CBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hlc3RlcjEaMBgGA1UEChMRSHVkZGxl # ZE1hc3Nlcy5vcmcxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTErMCkG # A1UEAxMiSm9lbCBCZW5uZXR0IENlcnRpZmljYXRlIEF1dGhvcml0eTEnMCUGCSqG # SIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNzZXMub3JnAgkAqkNFUy2/QuowCQYF # Kw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkD # MQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJ # KoZIhvcNAQkEMRYEFAofkfwfqeFtWcR9hKS06dZk6WUJMA0GCSqGSIb3DQEBAQUA # BIICADP13OnGPQcOKntTVguGTpRLsXiTeXsZtsV6fa9puWN1dkjmwfwwEQNWA5Pp # il5EwNyQB1zKqPrveEBZ5tZ41xUu07evDFDA+ZCbvPNK9Tvo/wfpre/1IsIbAsMl # +IDZUSLa6sD+gQHwDJyIHc3MmIEafxNSiFjM3mIET85mnKrYlGNDLcYo1OzL1ZGA # iw53p3BgvFFI/anmfmVafWesGfWHc9NqLETZ2MuogsSCxeglnW3Vk+Eq9wlbG1Ve # mb/DukGuyMuaHyXPvmLwXTrwZvxW7hsnsi7nK1TpUiIyxIBrNuJYYlFYnIsDzAUu # cJr95GfuOQ9buKMj8ZxYUsrgIoFXoPhfzG//BIUXCPUWhu3wRDs7OgC16PyBh3PO # R+HksUlh8xM9I/YEyqDWf8w7+xivdlsgZXbkvYmP9AO3iJZnAm4eD8EqX5AI0GwM # JkCRTf0b34Scd1B65U/se/Diz2GHTfM2ESrr54Oj9AZNSH/4K+iXHuZSI2RyZIn9 # fWOkY/WncYOhmhcNL4spoaQfO21xB9MNyokkX1VZwu5A1TKCG91stHwITpuMoTuh # glvUgdG/vr2e28LEpa1UeFX6JxONsB9Hg2oZouw+U9XupYLe5AVVpocpudCHHMsB # kmfAWfhF8skqrtwhrp/ooFUWsj1Ql9ociYC8KqGuGfHjQf8Z # SIG # End signature block