# encoding: ascii
# api: powershell
# title: ConvertTo-PseudoType
# description: Converts objects to custom PSObjects with robust type support. Allows converting data from Import-CSV etc into type-safe pseudo structs …
# version: 0.1
# type: function
# author: Joel Bennett
# license: CC0
# function: ConvertTo-PseudoType
# x-poshcode-id: 2640
# x-archived: 2015-01-03T07:42:16
# x-published: 2012-04-27T23:06:00
#
# Fixed the example to show setting Selected.System.IO.FileInfo and System.IO.FileInfo (for formatting).
# Next step is to add a function to generate the Mapping for you from a Type (via [Type].GetProperties()) or from a sample object …
# And then add a couple of overrides to ConvertTo-PseudotType which would call that generator for you.
#
#function ConvertTo-PseudoType {
<#
.Synopsis
Convert an object to a custom PSObject wiith robust type information
.Parameter TypeName
The name(s) of the PseudoType(s) to be inserted into the objects for the sake of formatting
.Parameter Mapping
A Hashtable of property names to types (or conversion scripts)
.Parameter InputObject
An object to convert.
.Example
Get-ChildItem | Where { !$_.PsIsContainer } | Export-CSV files.csv
## Given that a CSV file of file information exists,
## And we want to rehydrate it and be able to compare things...
## We need to create a mapping of properties to types
## Optionally, we can provide scriptblocks to convert instances
$Mapping = @{
Attributes = [System.IO.FileAttributes]
CreationTime = [System.DateTime]
CreationTimeUtc = [System.DateTime]
Directory = [System.IO.DirectoryInfo]
DirectoryName = [System.String]
Exists = [System.Boolean]
Extension = [System.String]
FullName = [System.String]
IsReadOnly = [System.Boolean]
LastAccessTime = [System.DateTime]
LastAccessTimeUtc = [System.DateTime]
LastWriteTime = [System.DateTime]
LastWriteTimeUtc = [System.DateTime]
Length = [System.Int64]
Name = [System.String]
PSChildName = [System.String]
PSDrive = [System.Management.Automation.PSDriveInfo]
PSIsContainer = [System.Boolean]
PSParentPath = [System.String]
PSPath = [System.String]
PSProvider = { Get-PSProvider $_ }
ReparsePoint = [System.Management.Automation.PSCustomObject]
VersionInfo = [System.Diagnostics.FileVersionInfo]
}
## Selected.System.IO.FileInfo is what you'd get from | Select *
## But we'll ALSO specify System.IO.FileInfo to get formatted output
Import-CSV | ConvertTo-PseudoType Selected.System.IO.FileInfo, System.IO.FileInfo $Mapping
## That way, the output will look as though you had run:
Get-ChildItem | Where { !$_.PsIsContainer } | Select *
NOTE: Not all types are rehydrateable from CSV output -- the "VersionInfo" will be hydrated as a string...
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true, Position=0)]
[Alias("Name","Tn")]
[String[]]$TypeName
,
[Parameter(Mandatory=$true, Position=1)]
[Hashtable]$Mapping
,
[Parameter(Mandatory=$true, Position=99, ValueFromPipeline=$true)]
[PSObject[]]$InputObject
)
begin {
$MappingFunction = @{}
foreach($key in $($Mapping.Keys)) {
$MappingFunction.$Key = {$_.$Key -as $Mapping.$Key}
}
[Array]::Reverse($TypeName)
}
process {
foreach($IO in $InputObject) {
$Properties = @{}
foreach($key in $($Mapping.Keys)) {
if($Mapping.$Key -is [ScriptBlock]) {
$Properties.$Key = $IO.$Key | ForEach-Object $Mapping.$Key
} elseif($Mapping.$Key -is [Type]) {
if($Value = $IO.$Key -as $Mapping.$Key) {
$Properties.$Key = $Value
} else {
$Properties.$Key = $IO.$Key
}
} else {
$Properties.$Key = [PSObject]$IO.$Key
}
}
New-Object PSObject -Property $Properties | %{ foreach($type in $TypeName) { $_.PSTypeNames.Insert(0, $type) } $_ }
}
}
#}