Commit 11e62699 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
Get-ChildItem | Add-ExtendedFileProperties.ps1 | Format-Table Name,"Bit Rate"
#>
begin
{
Set-StrictMode -Version Latest
## Create the Shell.Application COM object that provides this
## functionality
$shellObject = New-Object -Com Shell.Application
## Store the property names and identifiers for all of the shell
## properties
$itemProperties = $null
}
process
{
## 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
if(-not $itemProperties)
{
$itemProperties = @{}
$counter = 0
$columnName = ""
do
{
$columnName = $folderObject.GetDetailsOf(
$folderObject.Items, $counter)
if($columnName) { $itemProperties[$counter] = $columnName }
$counter++
} while($columnName)
}
## 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)
{
$fileItem | Add-Member NoteProperty $itemProperties[$itemProperty] `
$folderObject.GetDetailsOf($item, $itemProperty) -ErrorAction `
SilentlyContinue
}
## Finally, return the file with the extra shell information
$fileItem
}
##############################################################################
##
## 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 Latest
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 }
}
}
##############################################################################
##
## 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 Latest
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 | % { $_ }
}
}
##############################################################################
##
## Add-RelativePathCapture
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Adds a new Out-Default command wrapper that captures relative path
navigation without having to explicitly call 'Set-Location'
.EXAMPLE
PS C:\Users\Lee\Documents>..
PS C:\Users\Lee>...
PS C:\>
.NOTES
This commands builds on New-CommandWrapper, also included in the Windows
PowerShell Cookbook.
#>
Set-StrictMode -Version Latest
New-CommandWrapper Out-Default `
-Process {
if(($_ -is [System.Management.Automation.ErrorRecord]) -and
($_.FullyQualifiedErrorId -eq "CommandNotFoundException"))
{
## Intercept all CommandNotFound exceptions, where the actual
## command consisted solely of dots.
$command = $_.TargetObject
if($command -match '^(\.)+$')
{
## Count the number of dots, and go that many levels (minus
## one) up the directory hierarchy.
$newLocation = "..\" * ($command.Length - 1)
if($newLocation) { Set-Location $newLocation }
## Handle the error
$error.RemoveAt(0)
$_ = $null
}
}
}
##############################################################################
##
## 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
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://terraservice.net/TerraService.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
Add-Type -Assembly 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
}
##############################################################################
##
## 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
"Hello World" | Convert-TextObject
Generates an Object with "P1=Hello" and "P2=World"
.EXAMPLE
"Hello World" | Convert-TextObject -Delimiter "ll"
Generates an Object with "P1=He" and "P2=o World"
.EXAMPLE
"Hello World" | Convert-TextObject -Pattern "He(ll.*o)r(ld)"
Generates an Object with "P1=llo Wo" and "P2=ld"
.EXAMPLE
"Hello World" | Convert-TextObject -PropertyName FirstWord,SecondWord
Generates an Object with "FirstWord=Hello" and "SecondWord=World
.EXAMPLE
"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 Latest
}
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
}
else
{
## Verify that the input contains the delimiter
if(-not ($InputObject -match $delimiter))
{
return
}
## If so, split the input on that delimiter
$matches = $InputObject -split $delimiter
$matchCount = $matches.Length
$startIndex = 0
}
## Go through all of the matches, and add them as notes to the output
## object.
for($counter = $startIndex; $counter -lt $matchCount; $counter++)
{
$currentPropertyName = "P$($counter - $startIndex + 1)"
$currentPropertyType = [string]
## Get the property name
if($counter -lt $propertyName.Length)
{
if($propertyName[$counter])
{
$currentPropertyName = $propertyName[$counter - 1]
}
}
## Get the property value
if($counter -lt $propertyType.Length)
{
if($propertyType[$counter])
{
$currentPropertyType = $propertyType[$counter - 1]
}
}
Add-Member -InputObject $returnObject NoteProperty `
-Name $currentPropertyName `
-Value ($matches[$counter].Trim() -as $currentPropertyType)
}
$returnObject
}
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
param([double] $Fahrenheit)
Set-StrictMode -Version Latest
## Convert Fahrenheit to Celsius
function ConvertFahrenheitToCelsius([double] $fahrenheit)
{
$celsius = $fahrenheit - 32
$celsius = $celsius / 1.8
$celsius
}
$celsius = ConvertFahrenheitToCelsius $fahrenheit
## Output the answer
"$fahrenheit degrees Fahrenheit is $celsius degrees Celsius."
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
param([double] $Fahrenheit)
Set-StrictMode -Version Latest
## Convert it to Celsius
$celsius = $fahrenheit - 32
$celsius = $celsius / 1.8
## Output the answer
"$fahrenheit degrees Fahrenheit is $celsius degrees Celsius."
\ No newline at end of file
##############################################################################
##
## Copy-History
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################