#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