From 1b38db7da52d009b7c2b9d7ef37dfbec95adf285 Mon Sep 17 00:00:00 2001 From: Dylan <57426223+kDylanHayes@users.noreply.github.com> Date: Sat, 7 Oct 2023 09:08:23 -0400 Subject: [PATCH 1/3] Update to use Microsoft Graph Powershell Module + PowerShell 7 Support - Replaced AzureAD module with Microsoft.Graph - It proceeds the same XML output as the AzureAD version but the ObjectID, Name, Displayname lines might not be needed - Cleaned up code including removing unnecessary CSV temp files and catch-try for connecting as most do not need it or use it --- Save-AzureADUser.ps1 | 79 +++++++++++++------------------------------- 1 file changed, 23 insertions(+), 56 deletions(-) diff --git a/Save-AzureADUser.ps1 b/Save-AzureADUser.ps1 index cf99c03..6927e43 100644 --- a/Save-AzureADUser.ps1 +++ b/Save-AzureADUser.ps1 @@ -1,53 +1,28 @@ - -# Check that AzureAD is installed -if (-Not (Get-Module -ListAvailable -Name AzureAD)) { +# Check that Microsoft.Graph is installed +if (-Not (Get-Module -ListAvailable -Name Microsoft.Graph)) { - $install = Read-Host 'The AzureAD PowerShell module is not installed. Do you want to install it now? (Y/n)' + $install = Read-Host 'The Microsoft Graph PowerShell module is not installed. Do you want to install it now? (Y/n)' - if($install -eq '' -Or $install -eq 'Y' -Or $install -eq 'Yes'){ - If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) - { - Write-Warning "Administrator permissions are needed to install the AzureAD PowerShell module.`nPlease re-run this script as an Administrator." + if ($install -eq '' -Or $install -eq 'Y' -Or $install -eq 'Yes') { + If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { + Write-Warning "Administrator permissions are needed to install the Microsoft Graph PowerShell module.`nPlease re-run this script as an Administrator." Exit } - - write-host "Installing" - Install-Module -Name AzureAD + Write-Host "Installing" + Install-Module -Name Microsoft.Graph } else { exit } } - -# Create a temporary file to hold the unformatted results of our Get-AzureADUser query -$TempFile = New-TemporaryFile - -#Go ahead and attempt to get the Azure AD user IDs, but catch the error if there is no existing connection to Azure AD -Try -{ - Get-AzureADUser -All:$true | Export-Csv -Path $TempFile -NoTypeInformation -encoding Utf8 -} -Catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException] -{ - #Connect to Azure AD. This will show a prompt. - Connect-AzureAD | Out-Null - - #Try again - Get-AzureADUser -All:$true | Export-Csv -Path $TempFile -NoTypeInformation -encoding Utf8 -} - - -# Get the tennant details -$Tenant = Get-AzureADTenantDetail - -# Get the unformatted data from the temporary file -$azureADUsers = import-csv $TempFile +#Connect to Microsoft Graph and get all users +Connect-MgGraph -Scopes Directory.Read.All -NoWelcome +$EntraUsers = Get-MgUser -All # Create the XML file $xmlsettings = New-Object System.Xml.XmlWriterSettings $xmlsettings.Indent = $true $xmlsettings.IndentChars = " " - $XmlWriter = [System.XML.XmlWriter]::Create("$((Get-Location).Path)\ForensiTAzureID.xml", $xmlsettings) # Write the XML Declaration and set the XSL @@ -57,34 +32,26 @@ $xmlWriter.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='s # Start the Root Element $xmlWriter.WriteStartElement("ForensiTAzureID") -# Write the Azure AD domain details as attributes -$xmlWriter.WriteAttributeString("ObjectId", $($Tenant.ObjectId)) -$xmlWriter.WriteAttributeString("Name", $($Tenant.VerifiedDomains.Name)); -$xmlWriter.WriteAttributeString("DisplayName", $($Tenant.DisplayName)); - +# Write the Entra ID domain details as attributes +$Context = Get-MgContext +$xmlWriter.WriteAttributeString("ObjectId", $Context.TenantId) +$xmlWriter.WriteAttributeString("Name", (get-MgDomain).id); +$TenantName = (Invoke-RestMethod -UseBasicParsing -Uri ("https://login.microsoftonline.com/GetUserRealm.srf?login=$($Context.Account)")).FederationBrandName +$xmlWriter.WriteAttributeString("DisplayName", $TenantName); #Parse the data -ForEach ($azureADUser in $azureADUsers){ +ForEach ($EntraUser in $EntraUsers) { $xmlWriter.WriteStartElement("User") - - $xmlWriter.WriteElementString("UserPrincipalName",$($azureADUser.UserPrincipalName)) - $xmlWriter.WriteElementString("ObjectId",$($azureADUser.ObjectId)) - $xmlWriter.WriteElementString("DisplayName",$($azureADUser.DisplayName)) - + $xmlWriter.WriteElementString("UserPrincipalName", $($EntraUser.UserPrincipalName)) + $xmlWriter.WriteElementString("ObjectId", $($EntraUser.Id)) + $xmlWriter.WriteElementString("DisplayName", $($EntraUser.DisplayName)) $xmlWriter.WriteEndElement() - } +} $xmlWriter.WriteEndElement() - # Close the XML Document $xmlWriter.WriteEndDocument() $xmlWriter.Flush() $xmlWriter.Close() - - -# Clean up -Remove-Item $TempFile - -write-host "Azure user ID file created: $((Get-Location).Path)\ForensiTAzureID.xml" - +write-host "Entra ID user file created: $((Get-Location).Path)\ForensiTAzureID.xml" From 644f05333339fbfad6426ac4a5aa296bdcae27d8 Mon Sep 17 00:00:00 2001 From: Dylan <57426223+kDylanHayes@users.noreply.github.com> Date: Sat, 7 Oct 2023 10:58:25 -0400 Subject: [PATCH 2/3] Updated to only install needed Graph modules - Limit what is installed to speed up the process - Use compare objects to check if modules are installed and only try installing what is missing - Updated capital casing --- Save-AzureADUser.ps1 | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Save-AzureADUser.ps1 b/Save-AzureADUser.ps1 index 6927e43..35af4b4 100644 --- a/Save-AzureADUser.ps1 +++ b/Save-AzureADUser.ps1 @@ -1,18 +1,18 @@ -# Check that Microsoft.Graph is installed -if (-Not (Get-Module -ListAvailable -Name Microsoft.Graph)) { - - $install = Read-Host 'The Microsoft Graph PowerShell module is not installed. Do you want to install it now? (Y/n)' - - if ($install -eq '' -Or $install -eq 'Y' -Or $install -eq 'Yes') { +# Check that the needed Microsoft Graph Modules are installed and install only if needed +$Modules = "Microsoft.Graph.Authentication", "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.Users" +$ToInstall = Compare-Object (Get-Module -ListAvailable -Name $Modules) $Modules +if ($ToInstall) { + $Install = Read-Host 'The Microsoft Graph PowerShell module is not installed. Do you want to install it now? (Y/n)' + if ($Install -eq '' -Or $Install -eq 'Y' -Or $Install -eq 'Yes') { If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Warning "Administrator permissions are needed to install the Microsoft Graph PowerShell module.`nPlease re-run this script as an Administrator." Exit } - Write-Host "Installing" - Install-Module -Name Microsoft.Graph + Write-Host "Installing: $($ToInstall.InputObject)" + Install-Module $ToInstall.InputObject } else { - exit + Exit } } #Connect to Microsoft Graph and get all users @@ -20,38 +20,38 @@ Connect-MgGraph -Scopes Directory.Read.All -NoWelcome $EntraUsers = Get-MgUser -All # Create the XML file -$xmlsettings = New-Object System.Xml.XmlWriterSettings -$xmlsettings.Indent = $true -$xmlsettings.IndentChars = " " -$XmlWriter = [System.XML.XmlWriter]::Create("$((Get-Location).Path)\ForensiTAzureID.xml", $xmlsettings) +$XMLSettings = New-Object System.Xml.XmlWriterSettings +$XMLSettings.Indent = $true +$XMLSettings.IndentChars = " " +$XMLWriter = [System.XML.XmlWriter]::Create("$((Get-Location).Path)\ForensiTAzureID.xml", $XMLSettings) # Write the XML Declaration and set the XSL -$xmlWriter.WriteStartDocument() -$xmlWriter.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='style.xsl'") +$XMLWriter.WriteStartDocument() +$XMLWriter.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='style.xsl'") # Start the Root Element -$xmlWriter.WriteStartElement("ForensiTAzureID") +$XMLWriter.WriteStartElement("ForensiTAzureID") # Write the Entra ID domain details as attributes $Context = Get-MgContext -$xmlWriter.WriteAttributeString("ObjectId", $Context.TenantId) -$xmlWriter.WriteAttributeString("Name", (get-MgDomain).id); +$XMLWriter.WriteAttributeString("ObjectId", $Context.TenantId) +$XMLWriter.WriteAttributeString("Name", (Get-MgDomain).Id); $TenantName = (Invoke-RestMethod -UseBasicParsing -Uri ("https://login.microsoftonline.com/GetUserRealm.srf?login=$($Context.Account)")).FederationBrandName -$xmlWriter.WriteAttributeString("DisplayName", $TenantName); +$XMLWriter.WriteAttributeString("DisplayName", $TenantName); #Parse the data ForEach ($EntraUser in $EntraUsers) { - $xmlWriter.WriteStartElement("User") - $xmlWriter.WriteElementString("UserPrincipalName", $($EntraUser.UserPrincipalName)) - $xmlWriter.WriteElementString("ObjectId", $($EntraUser.Id)) - $xmlWriter.WriteElementString("DisplayName", $($EntraUser.DisplayName)) - $xmlWriter.WriteEndElement() + $XMLWriter.WriteStartElement("User") + $XMLWriter.WriteElementString("UserPrincipalName", $($EntraUser.UserPrincipalName)) + $XMLWriter.WriteElementString("ObjectId", $($EntraUser.Id)) + $XMLWriter.WriteElementString("DisplayName", $($EntraUser.DisplayName)) + $XMLWriter.WriteEndElement() } -$xmlWriter.WriteEndElement() +$XMLWriter.WriteEndElement() # Close the XML Document -$xmlWriter.WriteEndDocument() -$xmlWriter.Flush() -$xmlWriter.Close() +$XMLWriter.WriteEndDocument() +$XMLWriter.Flush() +$XMLWriter.Close() write-host "Entra ID user file created: $((Get-Location).Path)\ForensiTAzureID.xml" From cf5964e86b4f2f2b1f3df7b9676a8e143d4805f8 Mon Sep 17 00:00:00 2001 From: Dylan <57426223+kDylanHayes@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:19:36 -0400 Subject: [PATCH 3/3] Update Save-AzureADUser.ps1 Handle null inputs when no modules are installed https://stackoverflow.com/questions/15487623/compare-object-on-null-array --- Save-AzureADUser.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Save-AzureADUser.ps1 b/Save-AzureADUser.ps1 index 35af4b4..69edd05 100644 --- a/Save-AzureADUser.ps1 +++ b/Save-AzureADUser.ps1 @@ -1,6 +1,7 @@ # Check that the needed Microsoft Graph Modules are installed and install only if needed $Modules = "Microsoft.Graph.Authentication", "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.Users" -$ToInstall = Compare-Object (Get-Module -ListAvailable -Name $Modules) $Modules +$CurrentModules = Get-Module -ListAvailable -Name $Modules +$ToInstall = Compare-Object -ReferenceObject @($CurrentModules | Select-Object) -DifferenceObject $Modules if ($ToInstall) { $Install = Read-Host 'The Microsoft Graph PowerShell module is not installed. Do you want to install it now? (Y/n)' if ($Install -eq '' -Or $Install -eq 'Y' -Or $Install -eq 'Yes') {