# encoding: ascii
# api: csharp
# title: ScriptTransforms module
# description: PowerShell module that allows scripters to define argument transformation attributes in simple PowerShell syntax.  This is an extension developed by beefarino of my ScriptTransform example at http://huddledmasses.org/more-custom-attributes-for-powershell-parameters/ and now supports re-defining transforms without restarting PowerShell.
# version: 1.4
# type: function
# author: Joel Bennett
# license: CC0
# function: New-ParameterTransform
# x-poshcode-id: 3029
# x-archived: 2012-12-23T23:40:23
# x-published: 2012-10-27T21:56:00
#
# Note: It is now possible to redefine transforms by name by running the New-ParameterTransform command again, but type aliases that are generated are bound at function definition time, so any functions that are using the transform before it is redefined must also be redefined to take advantage of the new transform definition.
# Example usage:
# import-module ScriptTransforms;
# Transform NormalizeWhitespace {
# $string = $args[0].Trim()
# do { 
# $before = $string
# $string = $string -replace " + |`t"," "
# } while($before -ne $string)
# $string
# }
# function Test ( [NormalizeWhitespace()] $z ) { $z }
# Now, when you run:
# PS> Test " This is`tnot`tnormal.  At all.   "
# This is not normal. At all. 
# v 1.4 Fixes crashes when the transform output is null
# v 1.3 Fixes an ascii paste bug in the class name randomization
# v 1.2 Randomization of class names with type accelerators 
# v 1.1 Modularization by beefarino
# v 1.0 Original code from Joel’s blog
#
function New-ParameterTransform {
#.Synopsis
#	Generates Parameter Transformation Attributes in simple PowerShell syntax
#.Description
#	New-ParameterTransform allows the creation of .Net Attribute classes which can be applied to PowerShell parameters to transform or manipulate data as it's being passed in.
#.Example
#	Transform TrimBraces {
#		param($string) 
#		if($string -is [String] -and $string.Length -gt 2 -and $string[0] -eq '[' -and $string[-1] -eq ']') { 
#			$string.SubString(1, $string.Length-2) 
#		} else { 
#			$string
#		} 
#	}
#
#	function Where-Type {
#		param(
#			[Type][TrimBraces()][String]
#			[Parameter(Mandatory=$true, Position=0)]
#			$Type,
#			
#			[Parameter(ValueFromPipeline=$true)]
#			$InputObject
#		)
#		process {
#			if($InputObject -is $Type) { $InputObject }
#		}
#	}
#
#   Description
#   -----------
#	This example allows us to pass the "Type" to Where-Type with or without the [Braces] which would normally cause an exception when casting to a type:
#
#	Get-ChildItem | Where-Type IO.FileInfo
#
#	Get-ChildItem | Where-Type [IO.FileInfo]
#
#	Get-ChildItem | Where-Type ([IO.FileInfo])
#
#.Notes
#   It is possible to redefine transforms by name by running the New-ParameterTransform command again, but the type aliases that are generated are bound at function definition time, so any functions that are using the transform before it is redefined must also be redefined to take advantage of the new transform definition.
#
#   v 1.4 Fixes crashes when the transform output is null
#   v 1.3 Fixes an ascii paste bug in the class name randomization
#   v 1.2 Randomization of class names with type accelerators 
#   v 1.1 Modularization by "beefarino":http://poshcode.org/author/beefarino
#   v 1.0 Original code from Joel's blog
	[cmdletbinding()]
	param(
		# The name of the parameter transform to generate
		[Parameter(Mandatory=$true,Position=0)]
		[string] $name,
		# The script definition of the parameter transform
		[Parameter(Mandatory=$true, Position=1)]
		[scriptblock] $script
	)

end {
	$className = [Convert]::ToBase64String( ([Guid]::NewGuid().ToByteArray()) ).Replace('+',([char]241)).Replace('/',([char]223)).TrimEnd('=')

	$Type = Add-Type -Passthru -TypeDefinition @"
using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Collections.ObjectModel;

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ${name}Attribute${className} : ArgumentTransformationAttribute {
   private ScriptBlock _scriptblock;
   private string _noOutputMessage = "Transform Script had no output.";

   public ${name}Attribute${className}() {
      this.Script = ScriptBlock.Create( @"
	  	$($script.ToString() -replace '"','""' )
" );
   }
   public override string ToString() {
      return Script.ToString();
   }
   
   public override Object Transform( EngineIntrinsics engine, Object inputData) {
      Collection<PSObject> output;
      try {
         output = engine.InvokeCommand.InvokeScript( engine.SessionState, Script, inputData );
      } catch (ArgumentTransformationMetadataException) {
         throw;
      } catch (Exception e) {
         throw new ArgumentTransformationMetadataException(
            string.Format("Transform Script threw an exception ('{0}'). See `$Error[0].Exception.InnerException.InnerException for more details.", e.Message),
            e);
      }
      if(output == null || output.Count == 0 ) { 
         throw new ArgumentTransformationMetadataException(NoOutputMessage);
      }
      
      if(output.Count > 1) 
      {
         Object[] transformed = new Object[output.Count];
         for(int i =0; i < output.Count;i++) {
            if(output[i] == null) {
               transformed[i] = null;
            } else {
               transformed[i] = output[i].BaseObject;
            }
         }
         return transformed;
      }
      else // (output.Count == 1) 
      {
         if(output[0] == null) {
            return null;
         }
         return output[0].BaseObject;
      }
   }
   
   public ScriptBlock Script {
      get { return _scriptblock; }
      set { _scriptblock = value; }
   }
   
   public string NoOutputMessage {
      get { return _noOutputMessage; }
      set { _noOutputMessage = value; }
   }  
}
"@

	$xlr8r = [psobject].assembly.gettype("System.Management.Automation.TypeAccelerators")
	if($xlr8r::AddReplace) { 
		$xlr8r::AddReplace( ${name}, $Type) 
	} else {
		$null = $xlr8r::Remove( ${name} )
		$xlr8r::Add( ${name}, $Type)
	}
}}

New-Alias -Name Transform -Value New-ParameterTransform;
Export-ModuleMember -Alias Transform -Function *
# SIG # Begin signature block
# MIIRDAYJKoZIhvcNAQcCoIIQ/TCCEPkCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUiseSTw8ZDs4/WyAi4TlGsBiB
# yUWggg5CMIIHBjCCBO6gAwIBAgIBFTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQG
# EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp
# Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy
# dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjIwMTQ1WhcNMTIxMDI0MjIw
# MTQ1WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp
# BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV
# BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgT2JqZWN0
# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiOLIjUemqAbPJ1J
# 0D8MlzgWKbr4fYlbRVjvhHDtfhFN6RQxq0PjTQxRgWzwFQNKJCdU5ftKoM5N4YSj
# Id6ZNavcSa6/McVnhDAQm+8H3HWoD030NVOxbjgD/Ih3HaV3/z9159nnvyxQEckR
# ZfpJB2Kfk6aHqW3JnSvRe+XVZSufDVCe/vtxGSEwKCaNrsLc9pboUoYIC3oyzWoU
# TZ65+c0H4paR8c8eK/mC914mBo6N0dQ512/bkSdaeY9YaQpGtW/h/W/FkbQRT3sC
# pttLVlIjnkuY4r9+zvqhToPjxcfDYEf+XD8VGkAqle8Aa8hQ+M1qGdQjAye8OzbV
# uUOw7wIDAQABo4ICfzCCAnswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYD
# VR0OBBYEFNBOD0CZbLhLGW87KLjg44gHNKq3MIGoBgNVHSMEgaAwgZ2AFE4L7xqk
# QFulF2mHMMo0aEPQQa7yoYGBpH8wfTELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0
# YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRl
# IFNpZ25pbmcxKTAnBgNVBAMTIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
# aXR5ggEBMAkGA1UdEgQCMAAwPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzAChiFo
# dHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQwYAYDVR0fBFkwVzAsoCqg
# KIYmaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3Nmc2NhLWNybC5jcmwwJ6AloCOG
# IWh0dHA6Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDCBggYDVR0gBHsweTB3
# BgsrBgEEAYG1NwEBBTBoMC8GCCsGAQUFBwIBFiNodHRwOi8vY2VydC5zdGFydGNv
# bS5vcmcvcG9saWN5LnBkZjA1BggrBgEFBQcCARYpaHR0cDovL2NlcnQuc3RhcnRj
# b20ub3JnL2ludGVybWVkaWF0ZS5wZGYwEQYJYIZIAYb4QgEBBAQDAgABMFAGCWCG
# SAGG+EIBDQRDFkFTdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRl
# IE9iamVjdCBTaWduaW5nIENlcnRpZmljYXRlczANBgkqhkiG9w0BAQUFAAOCAgEA
# UKLQmPRwQHAAtm7slo01fXugNxp/gTJY3+aIhhs8Gog+IwIsT75Q1kLsnnfUQfbF
# pl/UrlB02FQSOZ+4Dn2S9l7ewXQhIXwtuwKiQg3NdD9tuA8Ohu3eY1cPl7eOaY4Q
# qvqSj8+Ol7f0Zp6qTGiRZxCv/aNPIbp0v3rD9GdhGtPvKLRS0CqKgsH2nweovk4h
# fXjRQjp5N5PnfBW1X2DCSTqmjweWhlleQ2KDg93W61Tw6M6yGJAGG3GnzbwadF9B
# UW88WcRsnOWHIu1473bNKBnf1OKxxAQ1/3WwJGZWJ5UxhCpA+wr+l+NbHP5x5XZ5
# 8xhhxu7WQ7rwIDj8d/lGU9A6EaeXv3NwwcbIo/aou5v9y94+leAYqr8bbBNAFTX1
# pTxQJylfsKrkB8EOIx+Zrlwa0WE32AgxaKhWAGho/Ph7d6UXUSn5bw2+usvhdkW4
# npUoxAk3RhT3+nupi1fic4NG7iQG84PZ2bbS5YxOmaIIsIAxclf25FwssWjieMwV
# 0k91nlzUFB1HQMuE6TurAakS7tnIKTJ+ZWJBDduUbcD1094X38OvMO/++H5S45Ki
# 3r/13YTm0AWGOvMFkEAF8LbuEyecKTaJMTiNRfBGMgnqGBfqiOnzxxRVNOw2hSQp
# 0B+C9Ij/q375z3iAIYCbKUd/5SSELcmlLl+BuNknXE0wggc0MIIGHKADAgECAgFR
# MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRD
# b20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln
# bmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3MgMiBQcmltYXJ5IEludGVybWVk
# aWF0ZSBPYmplY3QgQ0EwHhcNMDkxMTExMDAwMDAxWhcNMTExMTExMDYyODQzWjCB
# qDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMRcwFQYDVQQHEw5XZXN0
# IEhlbnJpZXR0YTEtMCsGA1UECxMkU3RhcnRDb20gVmVyaWZpZWQgQ2VydGlmaWNh
# dGUgTWVtYmVyMRUwEwYDVQQDEwxKb2VsIEJlbm5ldHQxJzAlBgkqhkiG9w0BCQEW
# GEpheWt1bEBIdWRkbGVkTWFzc2VzLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEP
# ADCCAQoCggEBAMfjItJjMWVaQTECvnV/swHQP0FTYUvRizKzUubGNDNaj7v2dAWC
# rAA+XE0lt9JBNFtCCcweDzphbWU/AAY0sEPuKobV5UGOLJvW/DcHAWdNB/wRrrUD
# dpcsapQ0IxxKqpRTrbu5UGt442+6hJReGTnHzQbX8FoGMjt7sLrHc3a4wTH3nMc0
# U/TznE13azfdtPOfrGzhyBFJw2H1g5Ag2cmWkwsQrOBU+kFbD4UjxIyus/Z9UQT2
# R7bI2R4L/vWM3UiNj4M8LIuN6UaIrh5SA8q/UvDumvMzjkxGHNpPZsAPaOS+RNmU
# Go6X83jijjbL39PJtMX+doCjS/lnclws5lUCAwEAAaOCA4EwggN9MAkGA1UdEwQC
# MAAwDgYDVR0PAQH/BAQDAgeAMDoGA1UdJQEB/wQwMC4GCCsGAQUFBwMDBgorBgEE
# AYI3AgEVBgorBgEEAYI3AgEWBgorBgEEAYI3CgMNMB0GA1UdDgQWBBR5tWPGCLNQ
# yCXI5fY5ViayKj6xATCBqAYDVR0jBIGgMIGdgBTQTg9AmWy4SxlvOyi44OOIBzSq
# t6GBgaR/MH0xCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSsw
# KQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYD
# VQQDEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eYIBFTCCAUIGA1Ud
# IASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgEwggEgMC4GCCsGAQUFBwIBFiJodHRw
# Oi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIBFihodHRw
# Oi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3BggrBgEFBQcC
# AjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJpbGl0eSwg
# c2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3RhcnRDb20g
# Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBhdCBodHRw
# Oi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGMGA1UdHwRcMFowK6ApoCeG
# JWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydGMyLWNybC5jcmwwK6ApoCeGJWh0
# dHA6Ly9jcmwuc3RhcnRzc2wuY29tL2NydGMyLWNybC5jcmwwgYkGCCsGAQUFBwEB
# BH0wezA3BggrBgEFBQcwAYYraHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9j
# bGFzczIvY29kZS9jYTBABggrBgEFBQcwAoY0aHR0cDovL3d3dy5zdGFydHNzbC5j
# b20vY2VydHMvc3ViLmNsYXNzMi5jb2RlLmNhLmNydDAjBgNVHRIEHDAahhhodHRw
# Oi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEBACY+J88ZYr5A
# 6lYz/L4OGILS7b6VQQYn2w9Wl0OEQEwlTq3bMYinNoExqCxXhFCHOi58X6r8wdHb
# E6mU8h40vNYBI9KpvLjAn6Dy1nQEwfvAfYAL8WMwyZykPYIS/y2Dq3SB2XvzFy27
# zpIdla8qIShuNlX22FQL6/FKBriy96jcdGEYF9rbsuWku04NqSLjNM47wCAzLs/n
# FXpdcBL1R6QEK4MRhcEL9Ho4hGbVvmJES64IY+P3xlV2vlEJkk3etB/FpNDOQf8j
# RTXrrBUYFvOCv20uHsRpc3kFduXt3HRV2QnAlRpG26YpZN4xvgqSGXUeqRceef7D
# dm4iTdHK5tIxggI0MIICMAIBATCBkjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoT
# DVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmlj
# YXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJ
# bnRlcm1lZGlhdGUgT2JqZWN0IENBAgFRMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3
# AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG
# AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEWMCMGCSqGSIb3DQEJBDEWBBTNfKnuBQMU
# THK1FpgQp3lahPwKODANBgkqhkiG9w0BAQEFAASCAQBy/tVZJPNVzpSJhoW28FmA
# QF+7mZTBatgkRnvfEJ1QwMI7TkUZF3C0woOwmkNUfRuxLOITq9ZFE5zIDiQ3ijS1
# p6dpmH0EmBh2kBGBvJdw41/H/v3dyVRHMJgClXR2dL++j9bdFzsIHLhsQMuJSks/
# dX6a2ETq6+IMJ3TQA/qdLEJTUGvzfHGComW7pAI92ErM+SMQBbTeVtWOr4cbQxCW
# 1+489NSS7FpWjyLyCazTUPFPHzv+gEmryNa6nBOKOJ4urXw9x08GSWqM8G821YVe
# eYbbVSce5o1eu8vEREGpJMUotZCNmql8fOYN4TGXG7CNtfKojbeCzKyvE0GW1qd/
# SIG # End signature block
