Skip to content

Commit 6bdcc18

Browse files
authored
Fix Test-EntraScript (#1471)
1 parent 51560d3 commit 6bdcc18

File tree

10 files changed

+1090
-30
lines changed

10 files changed

+1090
-30
lines changed

build/Create-EntraModule.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ param (
77

88
. (Join-Path $psscriptroot "/common-functions.ps1")
99
. (Join-Path $psscriptroot "../src/EntraModuleBuilder.ps1")
10+
. (Join-Path $psscriptroot "../src/Get-MissingCmds.ps1")
1011

1112
$moduleBuilder = [EntraModuleBuilder]::new()
1213

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# ------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
# ------------------------------------------------------------------------------
4+
5+
function Test-EntraScript {
6+
[CmdletBinding()]
7+
param (
8+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
9+
[Alias('FullName', 'Name')]
10+
[string[]]
11+
$Path,
12+
13+
[Parameter(ValueFromPipelineByPropertyName = $true)]
14+
[string]
15+
$Content,
16+
17+
[switch]
18+
$Quiet
19+
)
20+
21+
begin {
22+
function Test-ScriptCommand {
23+
[CmdletBinding()]
24+
param (
25+
[Parameter(Mandatory = $true)]
26+
[Alias('FullName')]
27+
[string]
28+
$Name,
29+
30+
[Parameter(Mandatory = $true)]
31+
[string]
32+
$Content,
33+
34+
[switch]
35+
$Quiet,
36+
37+
[AllowEmptyCollection()]
38+
[string[]]
39+
$RequiredCommands,
40+
41+
[AllowEmptyCollection()]
42+
[string[]]
43+
$ForbiddenCommands
44+
)
45+
46+
$ast = [System.Management.Automation.Language.Parser]::ParseInput($Content, [ref]$null, [ref]$null)
47+
$allCommands = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
48+
$allCommandNames = @($allCommands).ForEach{ $_.CommandElements[0].Value }
49+
50+
$findings = @()
51+
foreach ($command in $allCommands) {
52+
if ($command.CommandElements[0].Value -notin $ForbiddenCommands) { continue }
53+
$findings += [PSCustomObject]@{
54+
PSTypeName = 'Microsoft.Entra.CommandRequirement'
55+
Name = $Name
56+
Line = $command.Extent.StartLineNumber
57+
Type = 'UnsupportedCommand'
58+
Command = $command.CommandElements[0].Value
59+
Code = $command.Extent.Text
60+
}
61+
}
62+
foreach ($requiredCommand in $RequiredCommands) {
63+
if ($requiredCommand -notin $allCommandNames) { continue }
64+
$findings += [PSCustomObject]@{
65+
PSTypeName = 'Microsoft.Entra.CommandRequirement'
66+
Name = $Name
67+
Line = -1
68+
Type = 'RequiredCommandMissing'
69+
Command = $requiredCommand
70+
Code = ''
71+
}
72+
}
73+
74+
if (-not $Quiet) {
75+
$findings
76+
return
77+
}
78+
79+
$findings -as [bool]
80+
}
81+
82+
$testParam = @{
83+
Quiet = $Quiet
84+
ForbiddenCommands = $script:MISSING_CMDS
85+
}
86+
}
87+
process {
88+
if ($Path -and $Content) {
89+
Test-ScriptCommand -Name @($Path)[0] -Content $Content
90+
return
91+
}
92+
foreach ($entry in $Path) {
93+
try { $resolvedPaths = Resolve-Path -Path $entry -ErrorAction Stop }
94+
catch {
95+
Write-Error $_
96+
continue
97+
}
98+
99+
foreach ($resolvedPath in $resolvedPaths) {
100+
if (-not (Test-Path -Path $resolvedPath -PathType Leaf)) {
101+
Write-Warning "Not a file: $resolvedPath"
102+
continue
103+
}
104+
105+
$scriptContent = (Get-Content -LiteralPath $resolvedPath) -join "`n"
106+
Test-ScriptCommand -Name $resolvedPath -Content $scriptContent @testParam
107+
}
108+
}
109+
}
110+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# ------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
# ------------------------------------------------------------------------------
4+
5+
function Test-EntraScript {
6+
[CmdletBinding()]
7+
param (
8+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
9+
[Alias('FullName', 'Name')]
10+
[string[]]
11+
$Path,
12+
13+
[Parameter(ValueFromPipelineByPropertyName = $true)]
14+
[string]
15+
$Content,
16+
17+
[switch]
18+
$Quiet
19+
)
20+
21+
begin {
22+
function Test-ScriptCommand {
23+
[CmdletBinding()]
24+
param (
25+
[Parameter(Mandatory = $true)]
26+
[Alias('FullName')]
27+
[string]
28+
$Name,
29+
30+
[Parameter(Mandatory = $true)]
31+
[string]
32+
$Content,
33+
34+
[switch]
35+
$Quiet,
36+
37+
[AllowEmptyCollection()]
38+
[string[]]
39+
$RequiredCommands,
40+
41+
[AllowEmptyCollection()]
42+
[string[]]
43+
$ForbiddenCommands
44+
)
45+
46+
$ast = [System.Management.Automation.Language.Parser]::ParseInput($Content, [ref]$null, [ref]$null)
47+
$allCommands = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
48+
$allCommandNames = @($allCommands).ForEach{ $_.CommandElements[0].Value }
49+
50+
$findings = @()
51+
foreach ($command in $allCommands) {
52+
if ($command.CommandElements[0].Value -notin $ForbiddenCommands) { continue }
53+
$findings += [PSCustomObject]@{
54+
PSTypeName = 'Microsoft.Entra.Beta.CommandRequirement'
55+
Name = $Name
56+
Line = $command.Extent.StartLineNumber
57+
Type = 'UnsupportedCommand'
58+
Command = $command.CommandElements[0].Value
59+
Code = $command.Extent.Text
60+
}
61+
}
62+
foreach ($requiredCommand in $RequiredCommands) {
63+
if ($requiredCommand -notin $allCommandNames) { continue }
64+
$findings += [PSCustomObject]@{
65+
PSTypeName = 'Microsoft.Entra.Beta.CommandRequirement'
66+
Name = $Name
67+
Line = -1
68+
Type = 'RequiredCommandMissing'
69+
Command = $requiredCommand
70+
Code = ''
71+
}
72+
}
73+
74+
if (-not $Quiet) {
75+
$findings
76+
return
77+
}
78+
79+
$findings -as [bool]
80+
}
81+
82+
$testParam = @{
83+
Quiet = $Quiet
84+
ForbiddenCommands = $script:MISSING_CMDS
85+
}
86+
}
87+
process {
88+
if ($Path -and $Content) {
89+
Test-ScriptCommand -Name @($Path)[0] -Content $Content
90+
return
91+
}
92+
foreach ($entry in $Path) {
93+
try { $resolvedPaths = Resolve-Path -Path $entry -ErrorAction Stop }
94+
catch {
95+
Write-Error $_
96+
continue
97+
}
98+
99+
foreach ($resolvedPath in $resolvedPaths) {
100+
if (-not (Test-Path -Path $resolvedPath -PathType Leaf)) {
101+
Write-Warning "Not a file: $resolvedPath"
102+
continue
103+
}
104+
105+
$scriptContent = (Get-Content -LiteralPath $resolvedPath) -join "`n"
106+
Test-ScriptCommand -Name $resolvedPath -Content $scriptContent @testParam
107+
}
108+
}
109+
}
110+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
title: Test-EntraScript
3+
description: This article provides details on the Test-EntraScript command.
4+
5+
ms.topic: reference
6+
ms.date: 07/24/2024
7+
ms.author: eunicewaweru
8+
ms.reviewer: stevemutungi
9+
manager: CelesteDG
10+
author: msewaweru
11+
12+
external help file: Microsoft.Graph.Entra.Beta-help.xml
13+
Module Name: Microsoft.Graph.Entra.Beta
14+
online version: https://learn.microsoft.com/powershell/module/Microsoft.Graph.Entra.Beta/Test-EntraScript
15+
16+
schema: 2.0.0
17+
---
18+
19+
# Test-EntraScript
20+
21+
## Synopsis
22+
23+
Check whether the provided script uses AzureAD commands not supported by Microsoft Entra PowerShell.
24+
25+
## Syntax
26+
27+
```powershell
28+
Test-EntraScript [-Path] <String[]> [[-Content] <String>] [-Quiet] [<CommonParameters>]
29+
```
30+
31+
## Description
32+
33+
Check whether the provided script uses AzureAD commands not supported by Microsoft Entra PowerShell.
34+
35+
## Examples
36+
37+
### Example 1
38+
39+
```powershell
40+
Test-EntraScript -Path .\usercreation.ps1 -Quiet
41+
```
42+
43+
Returns whether the script "usercreation.ps1" could run under Microsoft.Graph.Entra
44+
45+
### Example 2
46+
47+
```powershell
48+
Get-ChildItem -Path \\contoso.com\it\code -Recurse -Filter *.ps1 | Test-EntraScript
49+
```
50+
51+
Returns a list of all scripts that wouldn't run under the Microsoft.Graph.Entra module, listing each issue with line and code.
52+
53+
## Parameters
54+
55+
### -Path
56+
57+
Path to one or more script files to scan.
58+
Or name of the content, when also specifying -Content
59+
60+
```yaml
61+
Type: String[]
62+
Parameter Sets: (All)
63+
Aliases: FullName, Name
64+
65+
Required: True
66+
Position: 1
67+
Default value: None
68+
Accept pipeline input: True (ByPropertyName, ByValue)
69+
Accept wildcard characters: False
70+
```
71+
72+
### -Content
73+
74+
Code content to scan.
75+
Used when scanning code that has no file representation (for example,
76+
straight from a repository).
77+
78+
```yaml
79+
Type: String
80+
Parameter Sets: (All)
81+
Aliases:
82+
83+
Required: False
84+
Position: 2
85+
Default value: None
86+
Accept pipeline input: True (ByPropertyName)
87+
Accept wildcard characters: False
88+
```
89+
90+
### -Quiet
91+
92+
Only return $true or $ false, based on whether the script could run under Microsoft.Graph.Entra ($true) or not ($ false)
93+
94+
```yaml
95+
Type: SwitchParameter
96+
Parameter Sets: (All)
97+
Aliases:
98+
99+
Required: False
100+
Position: Named
101+
Default value: False
102+
Accept pipeline input: False
103+
Accept wildcard characters: False
104+
```
105+
106+
### CommonParameters
107+
108+
This cmdlet supports the common parameters: `-Debug`, `-ErrorAction`, `-ErrorVariable`, `-InformationAction`, `-InformationVariable`, `-OutVariable`, `-OutBuffer`, `-PipelineVariable`, `-Verbose`, `-WarningAction`, and `-WarningVariable`. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216).
109+
110+
## Inputs
111+
112+
## Outputs
113+
114+
## Notes
115+
116+
## Related Links

0 commit comments

Comments
 (0)