@@ -224,84 +224,167 @@ function Measure-RequiresModules
224
224
}
225
225
}
226
226
227
- <#
228
- . SYNOPSIS
229
- You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
230
- . DESCRIPTION
231
- When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
232
- To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
233
- $namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
234
- . EXAMPLE
235
- Measure-LongClassName -CommandAst $CommandAst
236
- . INPUTS
237
- [System.Management.Automation.Language.CommandAst]
238
- . OUTPUTS
239
- [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
240
- . NOTES
241
- Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
242
- #>
243
- function Measure-LongClassName
244
- {
245
- [CmdletBinding ()]
246
- [OutputType ([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord []])]
247
- Param
248
- (
249
- [Parameter (Mandatory = $true )]
250
- [ValidateNotNullOrEmpty ()]
251
- [System.Management.Automation.Language.CommandAst ]
252
- $CommandAst
253
- )
254
-
255
- Process
256
- {
257
- $results = @ ()
258
227
259
- # The StaticParameterBinder help us to find the argument of TypeName.
260
- $spBinder = [System.Management.Automation.Language.StaticParameterBinder ]
261
-
262
- # Checks New-Object without ComObject parameter command only.
263
- if ($null -ne $CommandAst.GetCommandName ())
264
- {
265
- if ($CommandAst.GetCommandName () -ne " new-object" )
266
- {
267
- return $results
268
- }
269
- }
270
- else
271
- {
272
- return $results
273
- }
274
-
275
- try
276
- {
277
- [System.Management.Automation.Language.StaticBindingResult ]$sbResults = $spBinder ::BindCommand($CommandAst , $true )
278
- foreach ($sbResult in $sbResults )
279
- {
280
- # TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
281
- if ($null -eq $sbResult.BoundParameters [" TypeName" ].ConstantValue) { continue }
282
-
283
- if ($sbResult.BoundParameters [" TypeName" ].ConstantValue.ToString().Split(' .' ).Length -ge 3 )
284
- {
285
- # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
286
- $result = New-Object `
287
- - Typename " Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
288
- - ArgumentList $Messages.MeasureLongClassName , $sbResult.BoundParameters [" TypeName" ].Value.Extent, $PSCmdlet.MyInvocation.InvocationName , Information, $null
289
-
290
- $results += $result
291
- }
292
- }
293
-
294
- return $results
295
- }
296
- catch
297
- {
298
- $PSCmdlet.ThrowTerminatingError ($PSItem )
299
- }
228
+ # The two rules in the following if block use StaticParameterBinder class.
229
+ # StaticParameterBinder class was introduced in PSv4.
230
+ if ($PSVersionTable.PSVersion -ge [Version ]' 4.0' )
231
+ {
232
+ <#
233
+ . SYNOPSIS
234
+ You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
235
+ . DESCRIPTION
236
+ When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
237
+ To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
238
+ $namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
239
+ . EXAMPLE
240
+ Measure-LongClassName -CommandAst $CommandAst
241
+ . INPUTS
242
+ [System.Management.Automation.Language.CommandAst]
243
+ . OUTPUTS
244
+ [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
245
+ . NOTES
246
+ Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
247
+ #>
248
+ function Measure-LongClassName
249
+ {
250
+ [CmdletBinding ()]
251
+ [OutputType ([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord []])]
252
+ Param
253
+ (
254
+ [Parameter (Mandatory = $true )]
255
+ [ValidateNotNullOrEmpty ()]
256
+ [System.Management.Automation.Language.CommandAst ]
257
+ $CommandAst
258
+ )
259
+
260
+ Process
261
+ {
262
+ $results = @ ()
263
+
264
+ # The StaticParameterBinder help us to find the argument of TypeName.
265
+ $spBinder = [System.Management.Automation.Language.StaticParameterBinder ]
266
+
267
+ # Checks New-Object without ComObject parameter command only.
268
+ if ($null -ne $CommandAst.GetCommandName ())
269
+ {
270
+ if ($CommandAst.GetCommandName () -ne " new-object" )
271
+ {
272
+ return $results
273
+ }
274
+ }
275
+ else
276
+ {
277
+ return $results
278
+ }
279
+
280
+ try
281
+ {
282
+ [System.Management.Automation.Language.StaticBindingResult ]$sbResults = $spBinder ::BindCommand($CommandAst , $true )
283
+ foreach ($sbResult in $sbResults )
284
+ {
285
+ # TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
286
+ if ($null -eq $sbResult.BoundParameters [" TypeName" ].ConstantValue) { continue }
287
+
288
+ if ($sbResult.BoundParameters [" TypeName" ].ConstantValue.ToString().Split(' .' ).Length -ge 3 )
289
+ {
290
+ # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
291
+ $result = New-Object `
292
+ - Typename " Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
293
+ - ArgumentList $Messages.MeasureLongClassName , $sbResult.BoundParameters [" TypeName" ].Value.Extent, $PSCmdlet.MyInvocation.InvocationName , Information, $null
294
+
295
+ $results += $result
296
+ }
297
+ }
298
+
299
+ return $results
300
+ }
301
+ catch
302
+ {
303
+ $PSCmdlet.ThrowTerminatingError ($PSItem )
304
+ }
305
+
306
+
307
+ }
308
+ }
309
+
310
+ <#
311
+ . SYNOPSIS
312
+ Please do not use COM objects when calling New-Object.
313
+ . DESCRIPTION
314
+ If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand.
315
+ They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
316
+ To fix a violation of this rule, please do not use COM objects when calling New-Object.
317
+ . EXAMPLE
318
+ Measure-ComObject -CommandAst $CommandAst
319
+ . INPUTS
320
+ [System.Management.Automation.Language.CommandAst]
321
+ . OUTPUTS
322
+ [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
323
+ . NOTES
324
+ Reference: The Purity Laws, The Community Book of PowerShell Practices.
325
+ #>
326
+ function Measure-ComObject
327
+ {
328
+ [CmdletBinding ()]
329
+ [OutputType ([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord []])]
330
+ Param
331
+ (
332
+ [Parameter (Mandatory = $true )]
333
+ [ValidateNotNullOrEmpty ()]
334
+ [System.Management.Automation.Language.CommandAst ]
335
+ $CommandAst
336
+ )
337
+
338
+ Process
339
+ {
340
+ $results = @ ()
341
+
342
+ # The StaticParameterBinder help us to find the argument of TypeName.
343
+ $spBinder = [System.Management.Automation.Language.StaticParameterBinder ]
344
+
345
+ # Checks New-Object without ComObject parameter command only.
346
+ if ($null -ne $CommandAst.GetCommandName ())
347
+ {
348
+ if ($CommandAst.GetCommandName () -ne " new-object" )
349
+ {
350
+ return $results
351
+ }
352
+ }
353
+ else
354
+ {
355
+ return $results
356
+ }
357
+
358
+ try
359
+ {
360
+ [System.Management.Automation.Language.StaticBindingResult ]$sbResults = $spBinder ::BindCommand($CommandAst , $true )
361
+ foreach ($sbResult in $sbResults )
362
+ {
363
+ if ($sbResults.BoundParameters.ContainsKey (" ComObject" ))
364
+ {
365
+ # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
366
+ $result = New-Object `
367
+ - Typename " Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
368
+ - ArgumentList $Messages.MeasureComObject , $sbResult.BoundParameters [" ComObject" ].Value.Extent, $PSCmdlet.MyInvocation.InvocationName , Warning, $null
369
+
370
+ $results += $result
371
+ }
372
+ }
373
+
374
+ return $results
375
+ }
376
+ catch
377
+ {
378
+ $PSCmdlet.ThrowTerminatingError ($PSItem )
379
+ }
380
+
381
+
382
+ }
383
+ }
384
+
385
+ } # end if ($PSVersionTable.PSVersion -ge [Version]'4.0')
300
386
301
387
302
- }
303
- }
304
-
305
388
<#
306
389
. SYNOPSIS
307
390
Do not use deprecated WMI class in your script.
@@ -357,81 +440,6 @@ function Measure-DeprecatedWMIClass
357
440
}
358
441
}
359
442
360
- <#
361
- . SYNOPSIS
362
- Please do not use COM objects when calling New-Object.
363
- . DESCRIPTION
364
- If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand.
365
- They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
366
- To fix a violation of this rule, please do not use COM objects when calling New-Object.
367
- . EXAMPLE
368
- Measure-ComObject -CommandAst $CommandAst
369
- . INPUTS
370
- [System.Management.Automation.Language.CommandAst]
371
- . OUTPUTS
372
- [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
373
- . NOTES
374
- Reference: The Purity Laws, The Community Book of PowerShell Practices.
375
- #>
376
- function Measure-ComObject
377
- {
378
- [CmdletBinding ()]
379
- [OutputType ([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord []])]
380
- Param
381
- (
382
- [Parameter (Mandatory = $true )]
383
- [ValidateNotNullOrEmpty ()]
384
- [System.Management.Automation.Language.CommandAst ]
385
- $CommandAst
386
- )
387
-
388
- Process
389
- {
390
- $results = @ ()
391
-
392
- # The StaticParameterBinder help us to find the argument of TypeName.
393
- $spBinder = [System.Management.Automation.Language.StaticParameterBinder ]
394
-
395
- # Checks New-Object without ComObject parameter command only.
396
- if ($null -ne $CommandAst.GetCommandName ())
397
- {
398
- if ($CommandAst.GetCommandName () -ne " new-object" )
399
- {
400
- return $results
401
- }
402
- }
403
- else
404
- {
405
- return $results
406
- }
407
-
408
- try
409
- {
410
- [System.Management.Automation.Language.StaticBindingResult ]$sbResults = $spBinder ::BindCommand($CommandAst , $true )
411
- foreach ($sbResult in $sbResults )
412
- {
413
- if ($sbResults.BoundParameters.ContainsKey (" ComObject" ))
414
- {
415
- # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
416
- $result = New-Object `
417
- - Typename " Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
418
- - ArgumentList $Messages.MeasureComObject , $sbResult.BoundParameters [" ComObject" ].Value.Extent, $PSCmdlet.MyInvocation.InvocationName , Warning, $null
419
-
420
- $results += $result
421
- }
422
- }
423
-
424
- return $results
425
- }
426
- catch
427
- {
428
- $PSCmdlet.ThrowTerminatingError ($PSItem )
429
- }
430
-
431
-
432
- }
433
- }
434
-
435
443
<#
436
444
. SYNOPSIS
437
445
Adds end-of-line comment after closing curly bracket for deeply nested structures.
@@ -498,8 +506,8 @@ function Measure-CurlyBracket
498
506
foreach ($ast in $asts )
499
507
{
500
508
# Checks nesting structures
501
- $nestingASTs = $asts. Where ( {($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber ) -and
502
- ($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber )})
509
+ $nestingASTs = $asts | Where-Object {($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber ) -and
510
+ ($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber )}
503
511
504
512
# If one AST have end-of-line comments, we should skip it.
505
513
[bool ]$needComment = $ast.Extent.EndScriptPosition.Line.Trim ().EndsWith(" }" )
@@ -629,7 +637,7 @@ function Measure-Backtick
629
637
try
630
638
{
631
639
# Finds LineContinuation tokens
632
- $lcTokens = $Token. Where ( {$PSItem.Kind -eq [System.Management.Automation.Language.TokenKind ]::LineContinuation})
640
+ $lcTokens = $Token | Where-Object {$PSItem.Kind -eq [System.Management.Automation.Language.TokenKind ]::LineContinuation}
633
641
634
642
foreach ($lcToken in $lcTokens )
635
643
{
@@ -830,7 +838,7 @@ function Measure-QuestionVariable
830
838
$sbAst = [System.Management.Automation.Language.Parser ]::ParseInput($ScriptBlockAst , [ref ]$tokens , [ref ]$errors )
831
839
832
840
# Gets question variables
833
- $questionVariables = $tokens. Where ( {$PSItem.Name -eq ' ?' })
841
+ $questionVariables = $tokens | Where-Object {$PSItem.Name -eq ' ?' }
834
842
835
843
foreach ($questionVariable in $questionVariables )
836
844
{
0 commit comments