Last active
August 29, 2015 14:15
-
-
Save altrive/43e3a149259e9c681efb to your computer and use it in GitHub Desktop.
Enable [OutputType] validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Set-OutputTypeValidationMode | |
function Main | |
{ | |
Test-ShouldReturnInt32 | |
Test-ShouldReturnVoid | |
} | |
#region function definitions | |
function Test-ShouldReturnInt32 | |
{ | |
[OutputType([int])] | |
param () | |
#Warning: Should return [int] | |
return [long] 1 | |
} | |
function Test-ShouldReturnVoid | |
{ | |
[OutputType([void])] | |
param () | |
#Warning: Should not return object | |
return 1 | |
} | |
Main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Set-OutputTypeValidationMode | |
{ | |
[OutputType([void])] | |
[CmdletBinding(DefaultParameterSetName = 'Strict')] | |
param ( | |
#[Parameter(Mandatory, ParameterSetName = 'Off')] | |
#[switch] $Off, | |
#[Parameter(ParameterSetName = 'Strict')] | |
#[switch] $Strict = $false, | |
#[switch] $Exclude | |
) | |
Set-StrictMode -Version Latest | |
$ErrorActionPreference = "Stop" | |
$ExecutionContext.InvokeCommand.PostCommandLookupAction = { | |
param ( | |
$CommandName, | |
$CommandLookupEventArgs | |
) | |
#Don't need to handle internal command | |
if ($CommandLookupEventArgs.CommandOrigin -eq [System.Management.Automation.CommandOrigin]::Internal){ | |
return | |
} | |
#Skip prompt command | |
if ($CommandName -eq 'prompt'){ | |
return | |
} | |
#Retrive OutputType informations from command | |
[Type[]] $outputTypes = [Linq.Enumerable]::ToArray($CommandLookupEventArgs.Command.OutputType).Type | where { $_ -ne $null } | |
[string[]] $outputTypeNames = [Linq.Enumerable]::ToArray($CommandLookupEventArgs.Command.OutputType).Name | |
#If [OutputType] attribute is not specified. skip validation | |
if ($null -eq $outputTypeNames){ | |
return | |
} | |
#TODO:Support function parametersets | |
#TODO:Support -Passthru parameter | |
#$supportPassThru = $CommandLookupEventArgs.Command.Parameters.ContainsKey('Passthru') | |
#TODO: Need to handle ParameterSetName overloads([OutputType([<TypeLiteral>], ParameterSetName="<Name>")]) | |
[bool] $shouldReturnVoid = ($outputTypeNames[0] -eq [void].FullName) #Explicitly declare funtion with [OutputType([void])] | |
[bool] $shouldNotReturnVoid = ($outputTypeNames[0] -ne [void].FullName) #Don't contains [OutputType([void])] declaration | |
#$CommandLookupEventArgs.StopSearch = $true | |
$CommandLookupEventArgs.CommandScriptBlock = { | |
[long] $count = 0 | |
#TODO:Convert to filter instead of foreach-object | |
& $CommandName @args | foreach { | |
#Write object to output stream | |
Write-Output -InputObject $_ | |
$returnObjectType = $_.GetType() | |
++$count | |
$isValid = ($outputTypes | foreach { $_.IsAssignableFrom($returnObjectType)}) -eq $true | |
if (!$isValid) | |
{ | |
Write-Warning ("FunctionName = {0}`r`n`tReturn = {1}`r`n`tExpected = {2}" -f $CommandName, $returnObjectType.FullName, [String]::Join(', ', $outputTypeNames)) | |
#TODO: Need to suppress warning for large pipeline inputs | |
} | |
} | |
if ($shouldReturnVoid -and ($count -gt 0)){ | |
Write-Warning ("Function should not return object!,CommandName={0}" -f $CommandName) | |
return | |
} | |
if ($shouldNotReturnVoid -and ($count -eq 0)){ | |
Write-Warning ("Function should return object!,CommandName={0}" -f $CommandName) | |
return | |
} | |
#Output Validation is successfully completed. | |
}.GetNewClosure() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment