@@ -57,6 +57,48 @@ $NoBlock,
5757[switch ]
5858$NoParameter ,
5959
60+ # If set, will ensure that the script block contains types in this list.
61+ # Passing -IncludeType without -ExcludeType will make -ExcludeType default to *.
62+ [ValidateScript ({
63+ $validTypeList = [System.String ], [System.String []], [System.Text.RegularExpressions.Regex ], [System.Type ], [System.Type []]
64+ $thisType = $_.GetType ()
65+ $IsTypeOk =
66+ $ (@ ( foreach ($validType in $validTypeList ) {
67+ if ($_ -as $validType ) {
68+ $true ;break
69+ }
70+ }))
71+ if (-not $isTypeOk ) {
72+ throw " Unexpected type '$ ( @ ($thisType )[0 ]) '. Must be 'string','string[]','regex','type','type[]'."
73+ }
74+ return $true
75+ })]
76+ $IncludeType ,
77+
78+ # If set, will ensure that the script block does not use the types in this list.
79+ # Passing -IncludeType without -ExcludeType will make -ExcludeType default to *.
80+ [ValidateScript ({
81+ $validTypeList = [System.String ], [System.String []], [System.Text.RegularExpressions.Regex ], [System.Type ], [System.Type []]
82+ $thisType = $_.GetType ()
83+ $IsTypeOk =
84+ $ (@ ( foreach ($validType in $validTypeList ) {
85+ if ($_ -as $validType ) {
86+ $true ;break
87+ }
88+ }))
89+ if (-not $isTypeOk ) {
90+ throw " Unexpected type '$ ( @ ($thisType )[0 ]) '. Must be 'string','string[]','regex','type','type[]'."
91+ }
92+ return $true
93+ })]
94+ $ExcludeType ,
95+
96+ # One or more AST conditions to validate.
97+ # If no results are found or the condition throws, the script block will be considered invalid.
98+ [Alias (' AstConditions' , ' IfAst' )]
99+ [Scriptblock []]
100+ $AstCondition ,
101+
60102# A VariableExpression. If provided, the Validation attributes will apply to this variable.
61103[Parameter (Mandatory , ValueFromPipeline , ParameterSetName = ' VariableExpressionAST' )]
62104[Management.Automation.Language.VariableExpressionAST ]
@@ -118,7 +160,123 @@ $validateScripts = @(
118160 return $true
119161})]
120162'@
121- }
163+ }
164+
165+ # If -IncludeType or -ExcludeType were provided
166+ if ($IncludeType -or $ExcludeType ) {
167+ if (-not $ExcludeType ) {
168+ $ExcludeType = ' *'
169+ }
170+
171+ if (-not $IncludeType -and $ExcludeType -eq ' *' ) {
172+ $AstCondition += {
173+ param ($ast )
174+ if ($ast -is [Management.Automation.Language.TypeExpressionAst ]) {
175+ throw " AST cannot contain types"
176+ }
177+ return $true }
178+ }
179+ else {
180+ $AstCondition += [ScriptBlock ]::Create(@"
181+ param(`$ ast)
182+ `$ included = $ (
183+ if (-not $IncludeType ) { ' $null' }
184+ @ ($ (foreach ($incT in $IncludeType ) {
185+ if ($incT -is [string ]) {
186+ " '$ ( $incT -replace " '" , " ''" ) '"
187+ }
188+ elseif ($incT -is [type ]) {
189+ " [$ ( $incT.FullName -replace ' ^System\.' ) ]"
190+ }
191+ elseif ($incT -is [regex ]) {
192+ " [Regex]::new('$ ( $incT.ToString ().Replace(" '" , " ''" )) ','$ ( $incT.Options ) ','$ ( $incT.MatchTimeout ) ')"
193+ }
194+ })) -join ' ,' )
195+ `$ excluded = $ ( @ (
196+ if (-not $ExcludeType ) { ' $null' }
197+ $ (foreach ($excT in $ExcludeType ) {
198+ if ($excT -is [string ]) {
199+ " '$ ( $excT -replace " '" , " ''" ) '"
200+ }
201+ elseif ($excT -is [type ]) {
202+ " [$ ( $excT.FullName -replace ' ^System\.' ) ]"
203+ }
204+ elseif ($excT -is [regex ]) {
205+ " [Regex]::new('$ ( $excT.ToString ().Replace(" '" , " ''" )) ','$ ( $excT.Options ) ','$ ( $excT.MatchTimeout ) ')"
206+ }
207+ })) -join ' ,' )
208+ if (`$ ast -is [Management.Automation.Language.TypeExpressionAst]) {
209+ $ ( if ($IncludeType ) {
210+ {
211+ foreach ($inc in $included ) {
212+ if ($inc -is [string ] -and $ast.TypeName -like $inc ) {
213+ return $true
214+ }
215+ elseif ($inc -is [Regex ] -and $ast.TypeName -match $inc ) {
216+ return $true
217+ }
218+ elseif ($inc -is [type ]){
219+ $reflectionType = $ast.TypeName.GetReflectionType ()
220+ if ($inc -eq $reflectionType ) { return $true }
221+ if ($inc.IsSubclassOf ($reflectionType ) -or $reflectionType.IsSubclassOf ($inc )) {
222+ return $true
223+ }
224+ if ($inc.IsInterface -and $reflectionType.getInterFace ($inc )) {
225+ return $true
226+ }
227+ if ($reflectionType.IsInterface -and $inc.getInterFace ($reflectionType )) {
228+ return $true
229+ }
230+ }
231+ }
232+ }})
233+ $ ( {
234+ $throwMessage = " [$ ( $ast.Typename ) ] is not allowed"
235+ foreach ($exc in $excluded ) {
236+ if ($exc -is [string ] -and $ast.TypeName -like $exc ) {
237+ throw $throwMessage
238+ }
239+ elseif ($exc -is [regex ] -and $ast.TypeName -match $exc ) {
240+ throw $throwMessage
241+ }
242+ elseif ($exc -is [type ]) {
243+ $reflectionType = $ast.TypeName.GetReflectionType ()
244+ if ($ecx -eq $reflectionType ) {
245+ throw $throwMessage
246+ }
247+ elseif ($exc.IsSubclassOf ($reflectionType ) -or $reflectionType.IsSubclassOf ($exc )) {
248+ throw $throwMessage
249+ }
250+ elseif ($exc.IsInterface -and $reflectionType.getInterFace ($exc )) {
251+ throw $throwMessage
252+ }
253+ elseif ($reflectionType.IsInterface -and $exc.getInterFace ($reflectionType )) {
254+ throw $throwMessage
255+ }
256+ }
257+ }
258+ })
259+
260+ }
261+ return `$ true
262+ "@ )
263+ }
264+ }
265+
266+ if ($AstCondition ) {
267+ @"
268+ [ValidateScript({
269+ if (`$ _ -isnot [ScriptBlock]) { return `$ true }
270+ `$ astConditions = {$ ( $AstCondition -join ' } , {' ) }
271+ `$ scriptBlockAst = `$ _.Ast
272+ foreach (`$ astCondition in `$ astConditions) {
273+ `$ foundResults = `$ scriptBlockAst.FindAll(`$ astCondition, `$ true)
274+ if (-not `$ foundResults) { return `$ false}
275+ }
276+ return `$ true
277+ })]
278+ "@
279+ }
122280)
123281 if (-not $validateScripts ) { return }
124282
0 commit comments