-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix PSSA Analyzer script issues with plural noun in Get-HawkTenantAZA…
…dmins, renaming it to Get-HawkTenantAZAdmin. Added PSSA Exception for global vars as old tests include global vars.
- Loading branch information
1 parent
cec3205
commit c9c2795
Showing
7 changed files
with
261 additions
and
118 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
Function Get-HawkTenantAZAdmin { | ||
<# | ||
.SYNOPSIS | ||
Tenant Azure Active Directory Administrator export using Microsoft Graph. | ||
.DESCRIPTION | ||
Tenant Azure Active Directory Administrator export. Reviewing administrator access is key to knowing who can make changes | ||
to the tenant and conduct other administrative actions to users and applications. | ||
.EXAMPLE | ||
Get-HawkTenantAZAdmin | ||
Gets all Azure AD Admins | ||
.OUTPUTS | ||
AzureADAdministrators.csv | ||
.LINK | ||
https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.directorymanagement/get-mgdirectoryrole | ||
.NOTES | ||
Requires Microsoft.Graph.Identity.DirectoryManagement module | ||
#> | ||
[CmdletBinding()] | ||
param() | ||
|
||
BEGIN { | ||
# Initializing Hawk Object if not present | ||
if ([string]::IsNullOrEmpty($Hawk.FilePath)) { | ||
Initialize-HawkGlobalObject | ||
} | ||
Out-LogFile "Gathering Azure AD Administrators" | ||
|
||
Test-GraphConnection | ||
Send-AIEvent -Event "CmdRun" | ||
} | ||
|
||
PROCESS { | ||
try { | ||
# Get all directory roles | ||
$directoryRoles = Get-MgDirectoryRole -ErrorAction Stop | ||
Out-LogFile "Retrieved $(($directoryRoles | Measure-Object).Count) directory roles" | ||
|
||
$roles = foreach ($role in $directoryRoles) { | ||
# Get members for each role | ||
$members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -ErrorAction Stop | ||
|
||
if (-not $members) { | ||
[PSCustomObject]@{ | ||
AdminGroupName = $role.DisplayName | ||
Members = "No Members" | ||
MemberType = "None" # Added member type for better analysis | ||
MemberId = $null | ||
} | ||
} | ||
else { | ||
foreach ($member in $members) { | ||
# Determine member type and get appropriate properties | ||
if ($member.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.user") { | ||
[PSCustomObject]@{ | ||
AdminGroupName = $role.DisplayName | ||
Members = $member.AdditionalProperties.userPrincipalName | ||
MemberType = "User" | ||
MemberId = $member.Id | ||
} | ||
} | ||
else { | ||
# Groups or Service Principals | ||
[PSCustomObject]@{ | ||
AdminGroupName = $role.DisplayName | ||
Members = $member.AdditionalProperties.displayName | ||
MemberType = ($member.AdditionalProperties.'@odata.type' -replace '#microsoft.graph.', '') | ||
MemberId = $member.Id | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
if ($roles) { | ||
$roles | Out-MultipleFileType -FilePrefix "AzureADAdministrators" -csv -json | ||
Out-LogFile "Successfully exported Azure AD Administrators data" | ||
} | ||
else { | ||
Out-LogFile "No administrator roles found or accessible" -notice | ||
} | ||
} | ||
catch { | ||
Out-LogFile "Error retrieving Azure AD Administrators: $($_.Exception.Message)" -notice | ||
Write-Error -ErrorRecord $_ -ErrorAction Continue | ||
} | ||
} | ||
|
||
END { | ||
Out-LogFile "Completed exporting Azure AD Admins" | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,147 @@ | ||
# Load Pester module if not already loaded | ||
Import-Module -Name Pester -ErrorAction Stop | ||
|
||
# Log function for consistent output | ||
function Log { | ||
param( | ||
[string]$Message, | ||
[string]$Level = "Info" | ||
) | ||
$timestamp = Get-Date -Format "HH:mm:ss" | ||
Write-Output "[$timestamp][$Level] $Message" | ||
} | ||
|
||
# Start of test execution | ||
Log "Starting Tests" | ||
|
||
# Define the tests directory | ||
$testDirectory = "$PSScriptRoot" | ||
|
||
# Get all test files in the directory, excluding specific ones | ||
$testFiles = Get-ChildItem -Path $testDirectory -Recurse -Include *.Tests.ps1 | | ||
Where-Object { $_.Name -notin @('pester.ps1', 'Run-PesterTests.ps1') } | ||
|
||
# Ensure we found test files | ||
if (-not $testFiles) { | ||
Log "No test files found to execute." "Error" | ||
exit 1 | ||
} | ||
|
||
# Loop through each test file | ||
foreach ($testFile in $testFiles) { | ||
Log "Executing $($testFile.FullName)" "Info" | ||
try { | ||
# Run tests with minimal output | ||
Invoke-Pester -Path $testFile.FullName -Output Minimal -PassThru | Out-Null | ||
} catch { | ||
Log "Error running $($testFile.FullName): $_" "Error" | ||
} | ||
} | ||
<# | ||
.NOTES | ||
The original test this is based upon was written by June Blender. | ||
After several rounds of modifications it stands now as it is, but the honor remains hers. | ||
Thank you June, for all you have done! | ||
.DESCRIPTION | ||
This test evaluates the help for all commands in a module. | ||
.PARAMETER SkipTest | ||
Disables this test. | ||
.PARAMETER CommandPath | ||
List of paths under which the script files are stored. | ||
This test assumes that all functions have their own file that is named after themselves. | ||
These paths are used to search for commands that should exist and be tested. | ||
Will search recursively and accepts wildcards, make sure only functions are found | ||
.PARAMETER ModuleName | ||
Name of the module to be tested. | ||
The module must already be imported | ||
.PARAMETER ExceptionsFile | ||
File in which exceptions and adjustments are configured. | ||
In it there should be two arrays and a hashtable defined: | ||
$global:FunctionHelpTestExceptions | ||
$global:HelpTestEnumeratedArrays | ||
$global:HelpTestSkipParameterType | ||
These can be used to tweak the tests slightly in cases of need. | ||
See the example file for explanations on each of these usage and effect. | ||
#> | ||
[CmdletBinding()] | ||
Param ( | ||
[switch] | ||
$SkipTest, | ||
|
||
[string[]] | ||
$CommandPath = @("$global:testroot\..\functions", "$global:testroot\..\internal\functions"), | ||
|
||
[string] | ||
$ModuleName = "Hawk", | ||
|
||
[string] | ||
$ExceptionsFile = "$global:testroot\general\Help.Exceptions.ps1" | ||
) | ||
if ($SkipTest) { return } | ||
. $ExceptionsFile | ||
|
||
$includedNames = (Get-ChildItem $CommandPath -Recurse -File | Where-Object Name -like "*.ps1").BaseName | ||
$commandTypes = @('Cmdlet', 'Function') | ||
if ($PSVersionTable.PSEdition -eq 'Desktop' ) { $commandTypes += 'Workflow' } | ||
$commands = Get-Command -Module (Get-Module $ModuleName) -CommandType $commandTypes | Where-Object Name -In $includedNames | ||
|
||
## When testing help, remember that help is cached at the beginning of each session. | ||
## To test, restart session. | ||
|
||
|
||
foreach ($command in $commands) { | ||
$commandName = $command.Name | ||
|
||
# Skip all functions that are on the exclusions list | ||
if ($global:FunctionHelpTestExceptions -contains $commandName) { continue } | ||
|
||
Log "All tests executed successfully!" "Success" | ||
# The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets | ||
$Help = Get-Help $commandName -ErrorAction SilentlyContinue | ||
|
||
Describe "Test help for $commandName" { | ||
|
||
# If help is not found, synopsis in auto-generated help is the syntax diagram | ||
It "should not be auto-generated" -TestCases @{ Help = $Help } { | ||
$Help.Synopsis | Should -Not -BeLike '*`[`<CommonParameters`>`]*' | ||
} | ||
|
||
# Should be a description for every function | ||
It "gets description for $commandName" -TestCases @{ Help = $Help } { | ||
$Help.Description | Should -Not -BeNullOrEmpty | ||
} | ||
|
||
# Should be at least one example | ||
It "gets example code from $commandName" -TestCases @{ Help = $Help } { | ||
($Help.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty | ||
} | ||
|
||
# Should be at least one example description | ||
It "gets example help from $commandName" -TestCases @{ Help = $Help } { | ||
($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should -Not -BeNullOrEmpty | ||
} | ||
|
||
Context "Test parameter help for $commandName" { | ||
|
||
$common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' | ||
|
||
$parameters = $command.ParameterSets.Parameters | Sort-Object -Property Name -Unique | Where-Object Name -notin $common | ||
$parameterNames = $parameters.Name | ||
$HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique | ||
foreach ($parameter in $parameters) { | ||
$parameterName = $parameter.Name | ||
$parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName | ||
|
||
# Should be a description for every parameter | ||
It "gets help for parameter: $parameterName : in $commandName" -TestCases @{ parameterHelp = $parameterHelp } { | ||
$parameterHelp.Description.Text | Should -Not -BeNullOrEmpty | ||
} | ||
|
||
$codeMandatory = $parameter.IsMandatory.toString() | ||
It "help for $parameterName parameter in $commandName has correct Mandatory value" -TestCases @{ parameterHelp = $parameterHelp; codeMandatory = $codeMandatory } { | ||
$parameterHelp.Required | Should -Be $codeMandatory | ||
} | ||
|
||
if ($HelpTestSkipParameterType[$commandName] -contains $parameterName) { continue } | ||
|
||
$codeType = $parameter.ParameterType.Name | ||
|
||
if ($parameter.ParameterType.IsEnum) { | ||
# Enumerations often have issues with the typename not being reliably available | ||
$names = $parameter.ParameterType::GetNames($parameter.ParameterType) | ||
# Parameter type in Help should match code | ||
It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ parameterHelp = $parameterHelp; names = $names } { | ||
$parameterHelp.parameterValueGroup.parameterValue | Should -be $names | ||
} | ||
} | ||
elseif ($parameter.ParameterType.FullName -in $HelpTestEnumeratedArrays) { | ||
# Enumerations often have issues with the typename not being reliably available | ||
$names = [Enum]::GetNames($parameter.ParameterType.DeclaredMembers[0].ReturnType) | ||
It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ parameterHelp = $parameterHelp; names = $names } { | ||
$parameterHelp.parameterValueGroup.parameterValue | Should -be $names | ||
} | ||
} | ||
else { | ||
# To avoid calling Trim method on a null object. | ||
$helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } | ||
# Parameter type in Help should match code | ||
It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ helpType = $helpType; codeType = $codeType } { | ||
$helpType | Should -be $codeType | ||
} | ||
} | ||
} | ||
foreach ($helpParm in $HelpParameterNames) { | ||
# Shouldn't find extra parameters in help. | ||
It "finds help parameter in code: $helpParm" -TestCases @{ helpParm = $helpParm; parameterNames = $parameterNames } { | ||
$helpParm -in $parameterNames | Should -Be $true | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.