Commit 61f69f13 by O'Reilly Media, Inc

Initial commit

parents
##############################################################################
##
## Add-ExtendedFileProperties
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Add the extended file properties normally shown in Exlorer's
"File Properties" tab.
.EXAMPLE
PS > Get-ChildItem | Add-ExtendedFileProperties.ps1 | Format-Table Name,"Bit Rate"
#>
begin
{
Set-StrictMode -Version 3
## Create the Shell.Application COM object that provides this
## functionality
$shellObject = New-Object -Com Shell.Application
## Remember the column property mappings
$columnMappings = @{}
}
process
{
## Store the property names and identifiers for all of the shell
## properties
$itemProperties = @{}
## Get the file from the input pipeline. If it is just a filename
## (rather than a real file,) piping it to the Get-Item cmdlet will
## get the file it represents.
$fileItem = $_ | Get-Item
## Don't process directories
if($fileItem.PsIsContainer)
{
$fileItem
return
}
## Extract the file name and directory name
$directoryName = $fileItem.DirectoryName
$filename = $fileItem.Name
## Create the folder object and shell item from the COM object
$folderObject = $shellObject.NameSpace($directoryName)
$item = $folderObject.ParseName($filename)
## Populate the item properties
$counter = 0
$columnName = ""
do
{
if(-not $columnMappings[$counter])
{
$columnMappings[$counter] = $folderObject.GetDetailsOf(
$folderObject.Items, $counter)
}
$columnName = $columnMappings[$counter]
if($columnName)
{
$itemProperties[$columnName] =
$folderObject.GetDetailsOf($item, $counter)
}
$counter++
} while($columnName)
## Process extended properties
foreach($name in
$item.ExtendedProperty('System.PropList.FullDetails').Split(';'))
{
$name = $name.Replace("*","")
$itemProperties[$name] = $item.ExtendedProperty($name)
}
## Now, go through each property and add its information as a
## property to the file we are about to return
foreach($itemProperty in $itemProperties.Keys)
{
$value = $itemProperties[$itemProperty]
if($value)
{
$fileItem | Add-Member NoteProperty $itemProperty `
$value -ErrorAction `
SilentlyContinue
}
}
## Finally, return the file with the extra shell information
$fileItem
}
\ No newline at end of file
##############################################################################
##
## Add-FormatData
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Adds a table formatting definition for the specified type name.
.EXAMPLE
PS > $r = [PSCustomObject] @{
Name = "Lee";
Phone = "555-1212";
SSN = "123-12-1212"
}
PS > $r.PSTypeNames.Add("AddressRecord")
PS > Add-FormatData -TypeName AddressRecord -TableColumns Name, Phone
PS > $r
Name Phone
---- -----
Lee 555-1212
#>
param(
## The type name (or PSTypeName) that the table definition should
## apply to.
$TypeName,
## The columns to be displayed by default
[string[]] $TableColumns
)
Set-StrictMode -Version 3
## Define the columns within a table control row
$rowDefinition = New-Object Management.Automation.TableControlRow
## Create left-aligned columns for each provided column name
foreach($column in $TableColumns)
{
$rowDefinition.Columns.Add(
(New-Object Management.Automation.TableControlColumn "Left",
(New-Object Management.Automation.DisplayEntry $column,"Property")))
}
$tableControl = New-Object Management.Automation.TableControl
$tableControl.Rows.Add($rowDefinition)
## And then assign the table control to a new format view,
## which we then add to an extended type definition. Define this view for the
## supplied custom type name.
$formatViewDefinition = New-Object Management.Automation.FormatViewDefinition "TableView",$tableControl
$extendedTypeDefinition = New-Object Management.Automation.ExtendedTypeDefinition $TypeName
$extendedTypeDefinition.FormatViewDefinition.Add($formatViewDefinition)
## Add the definition to the session, and refresh the format data
[Runspace]::DefaultRunspace.InitialSessionState.Formats.Add($extendedTypeDefinition)
Update-FormatData
\ No newline at end of file
##############################################################################
##
## Add-FormatTableIndexParameter
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Adds a new -IncludeIndex switch parameter to the Format-Table command
to help with array indexing.
.NOTES
This commands builds on New-CommandWrapper, also included in the Windows
PowerShell Cookbook.
.EXAMPLE
PS > $items = dir
PS > $items | Format-Table -IncludeIndex
PS > $items[4]
#>
Set-StrictMode -Version 3
New-CommandWrapper Format-Table `
-AddParameter @{
@{
Name = 'IncludeIndex';
Attributes = "[Switch]"
} = {
function Add-IndexParameter {
begin
{
$psIndex = 0
}
process
{
## If this is the Format-Table header
if($_.GetType().FullName -eq `
"Microsoft.PowerShell.Commands.Internal." +
"Format.FormatStartData")
{
## Take the first column and create a copy of it
$formatStartType =
$_.shapeInfo.tableColumnInfoList[0].GetType()
$clone =
$formatStartType.GetConstructors()[0].Invoke($null)
## Add a PSIndex property
$clone.PropertyName = "PSIndex"
$clone.Width = $clone.PropertyName.Length
## And add its information to the header information
$_.shapeInfo.tableColumnInfoList.Insert(0, $clone)
}
## If this is a Format-Table entry
if($_.GetType().FullName -eq `
"Microsoft.PowerShell.Commands.Internal." +
"Format.FormatEntryData")
{
## Take the first property and create a copy of it
$firstField =
$_.formatEntryInfo.formatPropertyFieldList[0]
$formatFieldType = $firstField.GetType()
$clone =
$formatFieldType.GetConstructors()[0].Invoke($null)
## Set the PSIndex property value
$clone.PropertyValue = $psIndex
$psIndex++
## And add its information to the entry information
$_.formatEntryInfo.formatPropertyFieldList.Insert(
0, $clone)
}
$_
}
}
$newPipeline = { __ORIGINAL_COMMAND__ | Add-IndexParameter }
}
}
\ No newline at end of file
##############################################################################
##
## Add-ObjectCollector
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Adds a new Out-Default command wrapper to store up to 500 elements from
the previous command. This wrapper stores output in the $ll variable.
.EXAMPLE
PS > Get-Command $pshome\powershell.exe
CommandType Name Definition
----------- ---- ----------
Application powershell.exe C:\Windows\System32\Windo...
PS > $ll.Definition
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
.NOTES
This command builds on New-CommandWrapper, also included in the Windows
PowerShell Cookbook.
#>
Set-StrictMode -Version 3
New-CommandWrapper Out-Default `
-Begin {
$cachedOutput = New-Object System.Collections.ArrayList
} `
-Process {
## If we get an input object, add it to our list of objects
if($_ -ne $null) { $null = $cachedOutput.Add($_) }
while($cachedOutput.Count -gt 500) { $cachedOutput.RemoveAt(0) }
} `
-End {
## Be sure we got objects that were not just errors (
## so that we don't wipe out the saved output when we get errors
## trying to work with it.)
## Also don't caputre formatting information, as those objects
## can't be worked with.
$uniqueOutput = $cachedOutput | Foreach-Object {
$_.GetType().FullName } | Select -Unique
$containsInterestingTypes = ($uniqueOutput -notcontains `
"System.Management.Automation.ErrorRecord") -and
($uniqueOutput -notlike `
"Microsoft.PowerShell.Commands.Internal.Format.*")
## If we actually had output, and it was interesting information,
## save the output into the $ll variable
if(($cachedOutput.Count -gt 0) -and $containsInterestingTypes)
{
$GLOBAL:ll = $cachedOutput | % { $_ }
}
}
\ No newline at end of file
##############################################################################
##
## Add-RelativePathCapture
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Adds a new CommandNotFound handler that captures relative path
navigation without having to explicitly call 'Set-Location'
.EXAMPLE
PS C:\Users\Lee\Documents>..
PS C:\Users\Lee>...
PS C:\>
#>
Set-StrictMode -Version 3
$executionContext.SessionState.InvokeCommand.CommandNotFoundAction = {
param($CommandName, $CommandLookupEventArgs)
## If the command is only dots
if($CommandName -match '^\.+$')
{
## Associate a new command that should be invoked instead
$CommandLookupEventArgs.CommandScriptBlock = {
## Count the number of dots, and run "Set-Location .." one
## less time.
for($counter = 0; $counter -lt $CommandName.Length - 1; $counter++)
{
Set-Location ..
}
## We call GetNewClosure() so that the reference to $CommandName can
## be used in the new command.
}.GetNewClosure()
## Stop going through the command resolution process. This isn't
## strictly required in the CommandNotFoundAction.
$CommandLookupEventArgs.StopSearch = $true
}
}
\ No newline at end of file
##############################################################################
##
## Compare-Property
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Compare the property you provide against the input supplied to the script.
This provides the functionality of simple Where-Object comparisons without
the syntax required for that cmdlet.
.EXAMPLE
PS Get-Process | Compare-Property Handles gt 1000
.EXAMPLE
PS > Set-Alias ?? Compare-Property
PS > dir | ?? PsIsContainer
#>
param(
## The property to compare
$Property,
## The operator to use in the comparison
$Operator = "eq",
## The value to compare with
$MatchText = "$true"
)
Begin { $expression = "`$_.$property -$operator `"$matchText`"" }
Process { if(Invoke-Expression $expression) { $_ } }
\ No newline at end of file
##############################################################################
##
## Connect-WebService
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
## Connect to a given web service, and create a type that allows you to
## interact with that web service. In PowerShell version two, use the
## New-WebserviceProxy cmdlet.
##
## Example:
##
## $wsdl = "http://www.terraserver-usa.com/TerraService2.asmx?WSDL"
## $terraServer = Connect-WebService $wsdl
## $place = New-Object Place
## $place.City = "Redmond"
## $place.State = "WA"
## $place.Country = "USA"
## $facts = $terraserver.GetPlaceFacts($place)
## $facts.Center
##
##############################################################################
param(
## The URL that contains the WSDL
[string] $WsdlLocation = $(throw "Please specify a WSDL location"),
## The namespace to use to contain the web service proxy
[string] $Namespace,
## Switch to identify web services that require authentication
[Switch] $RequiresAuthentication
)
## Create the web service cache, if it doesn't already exist
if(-not (Test-Path Variable:\Lee.Holmes.WebServiceCache))
{
${GLOBAL:Lee.Holmes.WebServiceCache} = @{}
}
## Check if there was an instance from a previous connection to
## this web service. If so, return that instead.
$oldInstance = ${GLOBAL:Lee.Holmes.WebServiceCache}[$wsdlLocation]
if($oldInstance)
{
$oldInstance
return
}
## Load the required Web Services DLL
$null = [Reflection.Assembly]::LoadWithPartialName("System.Web.Services")
## Download the WSDL for the service, and create a service description from
## it.
$wc = New-Object System.Net.WebClient
if($requiresAuthentication)
{
$wc.UseDefaultCredentials = $true
}
$wsdlStream = $wc.OpenRead($wsdlLocation)
## Ensure that we were able to fetch the WSDL
if(-not (Test-Path Variable:\wsdlStream))
{
return
}
$serviceDescription =
[Web.Services.Description.ServiceDescription]::Read($wsdlStream)
$wsdlStream.Close()
## Ensure that we were able to read the WSDL into a service description
if(-not (Test-Path Variable:\serviceDescription))
{
return
}
## Import the web service into a CodeDom
$serviceNamespace = New-Object System.CodeDom.CodeNamespace
if($namespace)
{
$serviceNamespace.Name = $namespace
}
$codeCompileUnit = New-Object System.CodeDom.CodeCompileUnit
$serviceDescriptionImporter =
New-Object Web.Services.Description.ServiceDescriptionImporter
$serviceDescriptionImporter.AddServiceDescription(
$serviceDescription, $null, $null)
[void] $codeCompileUnit.Namespaces.Add($serviceNamespace)
[void] $serviceDescriptionImporter.Import(
$serviceNamespace, $codeCompileUnit)
## Generate the code from that CodeDom into a string
$generatedCode = New-Object Text.StringBuilder
$stringWriter = New-Object IO.StringWriter $generatedCode
$provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$provider.GenerateCodeFromCompileUnit($codeCompileUnit, $stringWriter, $null)
## Compile the source code.
$references = @("System.dll", "System.Web.Services.dll", "System.Xml.dll")
$compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
$compilerParameters.ReferencedAssemblies.AddRange($references)
$compilerParameters.GenerateInMemory = $true
$compilerResults =
$provider.CompileAssemblyFromSource($compilerParameters, $generatedCode)
## Write any errors if generated.
if($compilerResults.Errors.Count -gt 0)
{
$errorLines = ""
foreach($error in $compilerResults.Errors)
{
$errorLines += "`n`t" + $error.Line + ":`t" + $error.ErrorText
}
Write-Error $errorLines
return
}
## There were no errors. Create the webservice object and return it.
else
{
## Get the assembly that we just compiled
$assembly = $compilerResults.CompiledAssembly
## Find the type that had the WebServiceBindingAttribute.
## There may be other "helper types" in this file, but they will
## not have this attribute
$type = $assembly.GetTypes() |
Where-Object { $_.GetCustomAttributes(
[System.Web.Services.WebServiceBindingAttribute], $false) }
if(-not $type)
{
Write-Error "Could not generate web service proxy."
return
}
## Create an instance of the type, store it in the cache,
## and return it to the user.
$instance = $assembly.CreateInstance($type)
## Many services that support authentication also require it on the
## resulting objects
if($requiresAuthentication)
{
if(@($instance.PsObject.Properties |
where { $_.Name -eq "UseDefaultCredentials" }).Count -eq 1)
{
$instance.UseDefaultCredentials = $true
}
}
${GLOBAL:Lee.Holmes.WebServiceCache}[$wsdlLocation] = $instance
$instance
}
\ No newline at end of file
##############################################################################
##
## Convert-TextObject
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Convert a simple string into a custom PowerShell object.
.EXAMPLE
PS > "Hello World" | Convert-TextObject
Generates an Object with "P1=Hello" and "P2=World"
.EXAMPLE
PS > "Hello World" | Convert-TextObject -Delimiter "ll"
Generates an Object with "P1=He" and "P2=o World"
.EXAMPLE
PS > "Hello World" | Convert-TextObject -Pattern "He(ll.*o)r(ld)"
Generates an Object with "P1=llo Wo" and "P2=ld"
.EXAMPLE
PS > "Hello World" | Convert-TextObject -PropertyName FirstWord,SecondWord
Generates an Object with "FirstWord=Hello" and "SecondWord=World
.EXAMPLE
PS > "123 456" | Convert-TextObject -PropertyType $([string],[int])
Generates an Object with "Property1=123" and "Property2=456"
The second property is an integer, as opposed to a string
.EXAMPLE
PS > $ipAddress = (ipconfig | Convert-TextObject -Delim ": ")[2].P2
PS > $ipAddress
192.168.1.104
#>
[CmdletBinding(DefaultParameterSetName = "ByDelimiter")]
param(
## If specified, gives the .NET Regular Expression with which to
## split the string. The script generates properties for the
## resulting object out of the elements resulting from this split.
## If not specified, defaults to splitting on the maximum amount
## of whitespace: "\s+", as long as Pattern is not
## specified either.
[Parameter(ParameterSetName = "ByDelimiter", Position = 0)]
[string] $Delimiter = "\s+",
## If specified, gives the .NET Regular Expression with which to
## parse the string. The script generates properties for the
## resulting object out of the groups captured by this regular
## expression.
[Parameter(Mandatory = $true,
ParameterSetName = "ByPattern",
Position = 0)]
[string] $Pattern,
## If specified, the script will pair the names from this object
## definition with the elements from the parsed string. If not
## specified (or the generated object contains more properties
## than you specify,) the script uses property names in the
## pattern of P1,P2,...,PN
[Parameter(Position = 1)]
[Alias("PN")]
[string[]] $PropertyName = @(),
## If specified, the script will pair the types from this list with
## the properties from the parsed string. If not specified (or the
## generated object contains more properties than you specify,) the
## script sets the properties to be of type [string]
[Parameter(Position = 2)]
[Alias("PT")]
[type[]] $PropertyType = @(),
## The input object to process
[Parameter(ValueFromPipeline = $true)]
[string] $InputObject
)
begin {
Set-StrictMode -Version 3
}
process {
$returnObject = New-Object PSObject
$matches = $null
$matchCount = 0
if($PSBoundParameters["Pattern"])
{
## Verify that the input contains the pattern
## Populates the matches variable by default
if(-not ($InputObject -match $pattern))
{
return
}
$matchCount = $matches.Count
$startIndex = 1