From 74d10dd0efdb1b095fdbc6e49363982b93d8695f Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Sat, 11 Jan 2025 11:14:19 -0500 Subject: [PATCH] Add test-hawkglobalobject function and have every public function call it before executing to ensure that hawk global object is fully configured prior to hawk execution. --- ...t-HawkTenantAdminEmailForwardingChange.ps1 | 5 + .../Get-HawkTenantAdminInboxRuleCreation.ps1 | 5 + ...t-HawkTenantAdminInboxRuleModification.ps1 | 6 + .../Get-HawkTenantAdminInboxRuleRemoval.ps1 | 5 + ...HawkTenantAdminMailboxPermissionChange.ps1 | 6 + ...et-HawkTenantAppAndSPNCredentialDetail.ps1 | 3 +- .../Tenant/Get-HawkTenantAuditLog.ps1 | 6 +- .../Tenant/Get-HawkTenantAuthHistory.ps1 | 13 +- .../Tenant/Get-HawkTenantAzureAppAuditLog.ps1 | 10 +- .../Tenant/Get-HawkTenantConfiguration.ps1 | 7 + .../Tenant/Get-HawkTenantConsentGrant.ps1 | 5 + .../Tenant/Get-HawkTenantDomainActivity.ps1 | 7 + .../Get-HawkTenantEDiscoveryConfiguration.ps1 | 4 +- .../Tenant/Get-HawkTenantEDiscoveryLog.ps1 | 7 + .../Tenant/Get-HawkTenantEXOAdmin.ps1 | 5 + .../Tenant/Get-HawkTenantEntraIDAdmin.ps1 | 5 +- .../Tenant/Get-HawkTenantEntraIDUser.ps1 | 5 +- .../Tenant/Get-HawkTenantInboxRule.ps1 | 5 + .../Get-HawkTenantMailItemsAccessed.ps1 | 5 + .../Tenant/Get-HawkTenantRbacChange.ps1 | 5 + .../Tenant/Search-HawkTenantActivityByIP.ps1 | 6 + .../Tenant/Start-HawkTenantInvestigation.ps1 | 7 +- .../functions/User/Get-HawkUserAdminAudit.ps1 | 5 + .../User/Get-HawkUserAuthHistory.ps1 | 6 + Hawk/functions/User/Get-HawkUserAutoReply.ps1 | 5 + .../User/Get-HawkUserConfiguration.ps1 | 4 + .../User/Get-HawkUserEmailForwarding.ps1 | 6 + .../functions/User/Get-HawkUserHiddenRule.ps1 | 6 + Hawk/functions/User/Get-HawkUserInboxRule.ps1 | 6 + .../User/Get-HawkUserMailboxAuditing.ps1 | 5 + .../User/Get-HawkUserMessageTrace.ps1 | 5 + .../User/Get-HawkUserMobileDevice.ps1 | 5 + Hawk/functions/User/Get-HawkUserPWNCheck.ps1 | 189 +++++++++--------- .../User/Start-HawkUserInvestigation.ps1 | 4 + .../functions/Initialize-HawkGlobalObject.ps1 | 51 ++--- .../functions/Text-HawkGlobalObject.ps1 | 37 ++++ 36 files changed, 314 insertions(+), 152 deletions(-) create mode 100644 Hawk/internal/functions/Text-HawkGlobalObject.ps1 diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 index 6809f9b..bea58fd 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 @@ -37,6 +37,11 @@ Function Get-HawkTenantAdminEmailForwardingChange { [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + # Test the Exchange Online connection to ensure the environment is ready for operations. Test-EXOConnection # Log the execution of the function for audit and telemetry purposes. diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 index 5add1dc..fdae3d0 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 @@ -42,6 +42,11 @@ Function Get-HawkTenantAdminInboxRuleCreation { [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 index b91c5d1..bb67e79 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 @@ -45,6 +45,12 @@ Function Get-HawkTenantAdminInboxRuleModification { [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 index 25fd78e..29785fd 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 @@ -38,6 +38,11 @@ Function Get-HawkTenantAdminInboxRuleRemoval { [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 index f46d86d..b3b4134 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 @@ -29,6 +29,12 @@ Function Get-HawkTenantAdminMailboxPermissionChange { [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantAppAndSPNCredentialDetail.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAppAndSPNCredentialDetail.ps1 index bf29009..6c0350c 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAppAndSPNCredentialDetail.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAppAndSPNCredentialDetail.ps1 @@ -23,7 +23,8 @@ param() BEGIN { - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } diff --git a/Hawk/functions/Tenant/Get-HawkTenantAuditLog.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAuditLog.ps1 index 11273cf..4569c66 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAuditLog.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAuditLog.ps1 @@ -22,10 +22,12 @@ https://docs.microsoft.com/en-us/graph/api/resources/auditlog?view=graph-rest-1. #> BEGIN{ - #Initializing Hawk Object if not present - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { + + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } + Out-LogFile "Gathering Azure AD Audit Logs events" -Action } PROCESS{ diff --git a/Hawk/functions/Tenant/Get-HawkTenantAuthHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAuthHistory.ps1 index 0ecdea5..28a4428 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAuthHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAuthHistory.ps1 @@ -27,15 +27,12 @@ [int]$IntervalMinutes = 15 ) - # # Try to convert the submitted date into [datetime] format - # try { - # [datetime]$DateToStartSearch = Get-Date $StartDate - # } - # catch { - # Out-Logfile "[ERROR] - Unable to convert submitted date" - # break - # } + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + # Make sure the start date isn't more than 90 days in the past if ((Get-Date).adddays(-91) -gt $StartDate) { Out-Logfile "Start date is over 90 days in the past" -isError diff --git a/Hawk/functions/Tenant/Get-HawkTenantAzureAppAuditLog.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAzureAppAuditLog.ps1 index c00c705..d966844 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAzureAppAuditLog.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAzureAppAuditLog.ps1 @@ -21,9 +21,13 @@ #> Begin { #Initializing Hawk Object if not present - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { - Initialize-HawkGlobalObject - } + # Check if Hawk object exists and is fully initialized + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Out-LogFile "Gathering Tenant information" -Action Test-EXOConnection }#End BEGIN diff --git a/Hawk/functions/Tenant/Get-HawkTenantConfiguration.ps1 b/Hawk/functions/Tenant/Get-HawkTenantConfiguration.ps1 index a312581..a73fd91 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantConfiguration.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantConfiguration.ps1 @@ -58,6 +58,13 @@ .NOTES TODO: Put in some analysis ... flag some key things that we know we should #> + + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantConsentGrant.ps1 b/Hawk/functions/Tenant/Get-HawkTenantConsentGrant.ps1 index 5e5e682..5be6e33 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantConsentGrant.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantConsentGrant.ps1 @@ -25,6 +25,11 @@ [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Out-LogFile "Gathering OAuth / Application Grants" -Action Test-GraphConnection diff --git a/Hawk/functions/Tenant/Get-HawkTenantDomainActivity.ps1 b/Hawk/functions/Tenant/Get-HawkTenantDomainActivity.ps1 index 119c83a..ea78c43 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantDomainActivity.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantDomainActivity.ps1 @@ -27,6 +27,13 @@ Function Get-HawkTenantDomainActivity { Searches for all Domain configuration actions #> BEGIN{ + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + + Test-EXOConnection Send-AIEvent -Event "CmdRun" Out-LogFile "Gathering any changes to Domain configuration settings" -action diff --git a/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryConfiguration.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryConfiguration.ps1 index d342632..9277823 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryConfiguration.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryConfiguration.ps1 @@ -59,10 +59,12 @@ #TO DO: UPDATE THIS FUNCTION TO FIND E-Discovery roles created via the graph API BEGIN { - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryLog.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryLog.ps1 index 73607e8..5c015bf 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryLog.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEDiscoveryLog.ps1 @@ -41,6 +41,13 @@ - Cmdlet: Command that was executed (if applicable) #> # Search UAL audit logs for any Domain configuration changes + + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantEXOAdmin.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEXOAdmin.ps1 index 6cd04ca..770a59a 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEXOAdmin.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEXOAdmin.ps1 @@ -14,6 +14,11 @@ .NOTES #> BEGIN{ + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Out-LogFile "Gathering Exchange Online Administrators" -Action Test-EXOConnection diff --git a/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 index c278470..502de1c 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 @@ -20,10 +20,11 @@ param() BEGIN { - # Initializing Hawk Object if not present - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } + Out-LogFile "Gathering Microsoft Entra ID Administrators" -Action # Verify Graph API connection diff --git a/Hawk/functions/Tenant/Get-HawkTenantEntraIDUser.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEntraIDUser.ps1 index 17082fa..576bcf0 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEntraIDUser.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEntraIDUser.ps1 @@ -20,10 +20,11 @@ Properties selected for DFIR relevance. #> BEGIN { - # Initialize the Hawk environment if not already done - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } + Out-LogFile "Gathering Entra ID Users" -Action # Ensure we have a valid Graph connection diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRule.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRule.ps1 index b9ff844..0a85c42 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRule.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRule.ps1 @@ -55,6 +55,11 @@ [Parameter(Mandatory = $true)] [string]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Get-HawkTenantMailItemsAccessed.ps1 b/Hawk/functions/Tenant/Get-HawkTenantMailItemsAccessed.ps1 index 4ce4025..bf42c3e 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantMailItemsAccessed.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantMailItemsAccessed.ps1 @@ -33,6 +33,11 @@ ) BEGIN { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Out-LogFile "Starting Unified Audit Log (UAL) search for 'MailItemsAccessed'" -Action }#End Begin diff --git a/Hawk/functions/Tenant/Get-HawkTenantRbacChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantRbacChange.ps1 index ca050b8..c3f3c4d 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantRbacChange.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantRbacChange.ps1 @@ -37,6 +37,11 @@ #> [CmdletBinding()] param() + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + # Verify EXO connection and send telemetry Test-EXOConnection diff --git a/Hawk/functions/Tenant/Search-HawkTenantActivityByIP.ps1 b/Hawk/functions/Tenant/Search-HawkTenantActivityByIP.ps1 index ccf962d..1b68a71 100644 --- a/Hawk/functions/Tenant/Search-HawkTenantActivityByIP.ps1 +++ b/Hawk/functions/Tenant/Search-HawkTenantActivityByIP.ps1 @@ -44,6 +44,12 @@ [string]$IpAddress ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index f3c398d..487bda2 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -33,9 +33,10 @@ [CmdletBinding(SupportsShouldProcess)] param() - if ([string]::IsNullOrEmpty($Hawk.FilePath)) { - Initialize-HawkGlobalObject - } + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } Out-LogFile "Starting Tenant Sweep" -action Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserAdminAudit.ps1 b/Hawk/functions/User/Get-HawkUserAdminAudit.ps1 index d829fed..2b9576d 100644 --- a/Hawk/functions/User/Get-HawkUserAdminAudit.ps1 +++ b/Hawk/functions/User/Get-HawkUserAdminAudit.ps1 @@ -35,6 +35,11 @@ [Parameter(Mandatory = $true)] [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserAuthHistory.ps1 b/Hawk/functions/User/Get-HawkUserAuthHistory.ps1 index 8996f10..738897e 100644 --- a/Hawk/functions/User/Get-HawkUserAuthHistory.ps1 +++ b/Hawk/functions/User/Get-HawkUserAuthHistory.ps1 @@ -38,6 +38,12 @@ [switch]$ResolveIPLocations ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserAutoReply.ps1 b/Hawk/functions/User/Get-HawkUserAutoReply.ps1 index be81c5d..e1cd318 100644 --- a/Hawk/functions/User/Get-HawkUserAutoReply.ps1 +++ b/Hawk/functions/User/Get-HawkUserAutoReply.ps1 @@ -30,6 +30,11 @@ ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserConfiguration.ps1 b/Hawk/functions/User/Get-HawkUserConfiguration.ps1 index f7df349..2302de4 100644 --- a/Hawk/functions/User/Get-HawkUserConfiguration.ps1 +++ b/Hawk/functions/User/Get-HawkUserConfiguration.ps1 @@ -43,6 +43,10 @@ [Parameter(Mandatory = $true)] [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserEmailForwarding.ps1 b/Hawk/functions/User/Get-HawkUserEmailForwarding.ps1 index 294a6e5..ffe2d0c 100644 --- a/Hawk/functions/User/Get-HawkUserEmailForwarding.ps1 +++ b/Hawk/functions/User/Get-HawkUserEmailForwarding.ps1 @@ -38,6 +38,12 @@ [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserHiddenRule.ps1 b/Hawk/functions/User/Get-HawkUserHiddenRule.ps1 index b8f477d..c184a7f 100644 --- a/Hawk/functions/User/Get-HawkUserHiddenRule.ps1 +++ b/Hawk/functions/User/Get-HawkUserHiddenRule.ps1 @@ -46,6 +46,12 @@ [System.Management.Automation.PSCredential]$EWSCredential ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserInboxRule.ps1 b/Hawk/functions/User/Get-HawkUserInboxRule.ps1 index 9040e42..acf94d2 100644 --- a/Hawk/functions/User/Get-HawkUserInboxRule.ps1 +++ b/Hawk/functions/User/Get-HawkUserInboxRule.ps1 @@ -40,6 +40,12 @@ Function Get-HawkUserInboxRule { ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserMailboxAuditing.ps1 b/Hawk/functions/User/Get-HawkUserMailboxAuditing.ps1 index e0e73bf..4af71af 100644 --- a/Hawk/functions/User/Get-HawkUserMailboxAuditing.ps1 +++ b/Hawk/functions/User/Get-HawkUserMailboxAuditing.ps1 @@ -77,6 +77,11 @@ [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserMessageTrace.ps1 b/Hawk/functions/User/Get-HawkUserMessageTrace.ps1 index feea71b..10b6a35 100644 --- a/Hawk/functions/User/Get-HawkUserMessageTrace.ps1 +++ b/Hawk/functions/User/Get-HawkUserMessageTrace.ps1 @@ -27,6 +27,11 @@ Single UPN of a user, commans seperated list of UPNs, or array of objects that c [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserMobileDevice.ps1 b/Hawk/functions/User/Get-HawkUserMobileDevice.ps1 index a36249e..b16a1f5 100644 --- a/Hawk/functions/User/Get-HawkUserMobileDevice.ps1 +++ b/Hawk/functions/User/Get-HawkUserMobileDevice.ps1 @@ -31,6 +31,11 @@ [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + Test-EXOConnection Send-AIEvent -Event "CmdRun" diff --git a/Hawk/functions/User/Get-HawkUserPWNCheck.ps1 b/Hawk/functions/User/Get-HawkUserPWNCheck.ps1 index c66c3ea..bd71dd5 100644 --- a/Hawk/functions/User/Get-HawkUserPWNCheck.ps1 +++ b/Hawk/functions/User/Get-HawkUserPWNCheck.ps1 @@ -1,93 +1,100 @@ Function Get-HawkUserPWNCheck { - <# - .SYNOPSIS - Checks an email address against haveibeenpwned.com - .DESCRIPTION - Checks a single email address against HaveIBeenPwned. An API key is required and can be obtained from https://haveibeenpwned.com/API/Key for $3.50 a month. - This script will prompt for the key if $hibpkey is not set as a variable. - .PARAMETER EmailAddress - Accepts since EMail address or array of Email address strings. - DOES NOT Accept an array of objects (it will end up checked the UPN and not the email address) - .OUTPUTS - File: Have_I_Been_Pwned.txt - Path: \ - Description: Information returned from the pwned database - .EXAMPLE - Get-HawkUserPWNCheck -EmailAddress user@company.com - - Returns the pwn state of the email address provided - #> - - param( - [string[]]$EmailAddress - ) - - # if there is no value of hibpkey then we need to get it from the user - BEGIN {if ($null -eq $hibpkey) { - - Write-Host -ForegroundColor Green " - - HaveIBeenPwned.com now requires an API access key to gather Stats with from their API. - - Please purchase an API key for `$3.95 a month from get a Free access key from https://haveibeenpwned.com/API/Key and provide it below. - - " - - # get the access key from the user - Out-LogFile "haveibeenpwned.com apikey" -isPrompt -NoNewLine - $hibpkey = Read-Host - } - }#End of BEGIN block - - # Verify our UPN input - PROCESS {[array]$UserArray = Test-UserObject -ToTest $EmailAddress - $headers=@{'hibp-api-key' = $hibpkey} - - foreach ($Object in $UserArray) { - - [string]$User = $Object.UserPrincipalName - - # Convert the email to URL encoding - $uriEncodeEmail = [uri]::EscapeDataString($($user)) - - # Build and invoke the URL - $InvokeURL = 'https://haveibeenpwned.com/api/v3/breachedaccount/' + $uriEncodeEmail + '?truncateResponse=false' - $Error.clear() - #Will catch the error if the email is not found. 404 error means that the email is not found in the database. - #https://haveibeenpwned.com/API/v3#ResponseCodes contains the response codes for the API - try { - $Result = Invoke-WebRequest -Uri $InvokeURL -Headers $headers -userAgent 'Hawk' -ErrorAction Stop - } - catch { - $StatusCode = $_.Exception.Response.StatusCode - $ErrorMessage = $_.Exception.Message - switch ($StatusCode) { - NotFound{ - write-host "Email Provided Not Found in Pwned Database" - return - } - Unauthorized{ - write-host "Unauthorised Access - API key provided is not valid or has expired" - return - } - Default { - write-host $ErrorMessage - return - } - } - } - - # Convert the result into a PS custgom object - $Pwned = $Result.content | ConvertFrom-Json - - # Output the value - Out-LogFile ("Email Address found in " + $pwned.count) - $Pwned | Out-MultipleFileType -FilePreFix "Have_I_Been_Pwned" -user $user -txt - - - } - }#End of PROCESS block - END { - Start-Sleep -Milliseconds 1500 - }#End of END block + <# + .SYNOPSIS + Checks an email address against haveibeenpwned.com + .DESCRIPTION + Checks a single email address against HaveIBeenPwned. An API key is required and can be obtained from https://haveibeenpwned.com/API/Key for $3.50 a month. + This script will prompt for the key if $hibpkey is not set as a variable. + .PARAMETER EmailAddress + Accepts since EMail address or array of Email address strings. + DOES NOT Accept an array of objects (it will end up checked the UPN and not the email address) + .OUTPUTS + File: Have_I_Been_Pwned.txt + Path: \ + Description: Information returned from the pwned database + .EXAMPLE + Get-HawkUserPWNCheck -EmailAddress user@company.com + + Returns the pwn state of the email address provided + #> + + param( + [string[]]$EmailAddress + ) + + BEGIN { + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } + + if ($null -eq $hibpkey) { + Write-Host -ForegroundColor Green " + + HaveIBeenPwned.com now requires an API access key to gather Stats with from their API. + + Please purchase an API key for `$3.95 a month from get a Free access key from https://haveibeenpwned.com/API/Key and provide it below. + + " + + # get the access key from the user + Out-LogFile "haveibeenpwned.com apikey" -isPrompt -NoNewLine + $hibpkey = Read-Host + } + }#End of BEGIN block + + # Verify our UPN input + PROCESS { + # Used to silence PSSA parameter usage warning + if ($null -eq $EmailAddress) { return } + [array]$UserArray = Test-UserObject -ToTest $EmailAddress + $headers=@{'hibp-api-key' = $hibpkey} + + foreach ($Object in $UserArray) { + + [string]$User = $Object.UserPrincipalName + + # Convert the email to URL encoding + $uriEncodeEmail = [uri]::EscapeDataString($($user)) + + # Build and invoke the URL + $InvokeURL = 'https://haveibeenpwned.com/api/v3/breachedaccount/' + $uriEncodeEmail + '?truncateResponse=false' + $Error.clear() + #Will catch the error if the email is not found. 404 error means that the email is not found in the database. + #https://haveibeenpwned.com/API/v3#ResponseCodes contains the response codes for the API + try { + $Result = Invoke-WebRequest -Uri $InvokeURL -Headers $headers -userAgent 'Hawk' -ErrorAction Stop + } + catch { + $StatusCode = $_.Exception.Response.StatusCode + $ErrorMessage = $_.Exception.Message + switch ($StatusCode) { + NotFound{ + write-host "Email Provided Not Found in Pwned Database" + return + } + Unauthorized{ + write-host "Unauthorised Access - API key provided is not valid or has expired" + return + } + Default { + write-host $ErrorMessage + return + } + } + } + + # Convert the result into a PS custgom object + $Pwned = $Result.content | ConvertFrom-Json + + # Output the value + Out-LogFile ("Email Address found in " + $pwned.count) + $Pwned | Out-MultipleFileType -FilePreFix "Have_I_Been_Pwned" -user $user -txt + + } + }#End of PROCESS block + + END { + Start-Sleep -Milliseconds 1500 + }#End of END block }#End of Function Get-HawkUserPWNCheck \ No newline at end of file diff --git a/Hawk/functions/User/Start-HawkUserInvestigation.ps1 b/Hawk/functions/User/Start-HawkUserInvestigation.ps1 index 2a332f0..d295c90 100644 --- a/Hawk/functions/User/Start-HawkUserInvestigation.ps1 +++ b/Hawk/functions/User/Start-HawkUserInvestigation.ps1 @@ -49,6 +49,10 @@ [Parameter(Mandatory = $true)] [array]$UserPrincipalName ) + # Check if Hawk object exists and is fully initialized + if (Test-HawkGlobalObject) { + Initialize-HawkGlobalObject + } # Check if the logging filepath is set diff --git a/Hawk/internal/functions/Initialize-HawkGlobalObject.ps1 b/Hawk/internal/functions/Initialize-HawkGlobalObject.ps1 index 65d78fb..fd26ac9 100644 --- a/Hawk/internal/functions/Initialize-HawkGlobalObject.ps1 +++ b/Hawk/internal/functions/Initialize-HawkGlobalObject.ps1 @@ -46,47 +46,20 @@ [string]$FilePath ) - # Validation to handle interrupted initialization states - # If Hawk initialization was interrupted (e.g., by CTRL+C during path input), - # it can leave behind a partially initialized Hawk object. This causes - # recursion errors on subsequent runs due to the partial state. - # - # Two cleanup scenarios: - # 1. Force parameter: Always remove any existing Hawk object - # 2. Incomplete object: Remove if missing essential properties - # (FilePath, StartDate, EndDate) - # - # This validation runs before any function definitions or calls to prevent - # call depth overflow errors from recursion. - # Attempted to put in its own function, but resulted in issues due to order of the call stack - -# Validation to handle interrupted initialization states -# If Hawk initialization was interrupted (e.g., by CTRL+C during path input), -# it can leave behind a partially initialized Hawk object. This causes -# recursion errors on subsequent runs due to the partial state. -# -# Two cleanup scenarios: -# 1. Force parameter: Always remove any existing Hawk object -# 2. Incomplete object: Remove if missing essential properties -# (FilePath, StartDate, EndDate) -# -# This validation runs before any function definitions or calls to prevent -# call depth overflow errors from recursion. -# Attempted to put in its own function, but resulted in issues due to order of the call stack if ($Force) { Remove-Variable -Name Hawk -Scope Global -ErrorAction SilentlyContinue } - # Then check if the Hawk object exists but is incomplete - if ($null -ne (Get-Variable -Name Hawk -ErrorAction SilentlyContinue) -and - ($null -eq $Hawk.FilePath -or - $null -eq $Hawk.StartDate -or - $null -eq $Hawk.EndDate -or - # Add additional checks for partially initialized date properties - ($Hawk.PSObject.Properties.Name -contains 'StartDate' -and $null -eq $Hawk.StartDate) -or - ($Hawk.PSObject.Properties.Name -contains 'EndDate' -and $null -eq $Hawk.EndDate))) { - Remove-Variable -Name Hawk -Scope Global -ErrorAction SilentlyContinue + # Check for incomplete/interrupted initialization and force a fresh start + if ($null -ne (Get-Variable -Name Hawk -ErrorAction SilentlyContinue)) { + if (Test-HawkGlobalObject) { + Remove-Variable -Name Hawk -Scope Global -ErrorAction SilentlyContinue + + # Remove other related global variables that might exist + Remove-Variable -Name IPlocationCache -Scope Global -ErrorAction SilentlyContinue + Remove-Variable -Name MSFTIPList -Scope Global -ErrorAction SilentlyContinue + } } Function Test-LoggingPath { @@ -216,9 +189,9 @@ # Create the global $Hawk variable immediately with minimal properties $Global:Hawk = [PSCustomObject]@{ FilePath = $null # Will be set shortly - DaysToLookBack = 90 - StartDate = ((Get-Date).ToUniversalTime().AddDays(-90)).Date # 90 days back in UTC - EndDate = (Get-Date).ToUniversalTime().Date # Today's date in UTC + DaysToLookBack = $null + StartDate = $null + EndDate = $null WhenCreated = $null } diff --git a/Hawk/internal/functions/Text-HawkGlobalObject.ps1 b/Hawk/internal/functions/Text-HawkGlobalObject.ps1 new file mode 100644 index 0000000..f27c63a --- /dev/null +++ b/Hawk/internal/functions/Text-HawkGlobalObject.ps1 @@ -0,0 +1,37 @@ +Function Test-HawkGlobalObject { + <# + .SYNOPSIS + Tests if the Hawk global object exists and is properly initialized. + + .DESCRIPTION + This is an internal helper function that verifies whether the Hawk global object + exists and contains all required properties properly initialized. It checks for: + - FilePath property existence and value + - StartDate property existence and value + - EndDate property existence and value + + .EXAMPLE + Test-HawkGlobalObject + Returns $true if Hawk object is properly initialized, $false otherwise. + + .OUTPUTS + Boolean indicating if reinitialization is needed + #> + [CmdletBinding()] + [OutputType([bool])] + param() + + # Return true (needs initialization) if: + # - Hawk object doesn't exist + # - Any required property is missing or null + if ([string]::IsNullOrEmpty($Hawk.FilePath) -or + $null -eq $Hawk.StartDate -or + $null -eq $Hawk.EndDate -or + ($Hawk.PSObject.Properties.Name -contains 'StartDate' -and $null -eq $Hawk.StartDate) -or + ($Hawk.PSObject.Properties.Name -contains 'EndDate' -and $null -eq $Hawk.EndDate)) { + return $true + } + + # Hawk object exists and is properly initialized + return $false +} \ No newline at end of file