• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Clatent

Technology | Fitness | Food

  • About
  • Resources
  • Contact

365

EntraFIDOFinder – New PowerShell Module

September 30, 2024 by ClaytonT Leave a Comment

After so much interest from my post on Friday, I figured I’d do one better and make a PowerShell module that does it for you. So now you will be able to find which FIDO2 keys are attestation compatible with Entra right from your terminal. In the very near future I will have individual functions for exporting to Excel, CSV, Markdown, and PDF, but know a lot of people like to customize that themselves. I even put a few quick pointers on GitHub for it too, but will be doing tutorials shortly as well.

I’m still cleaning up the GitHub, but it is in the PowerShell Gallery and on GitHub at the links below.

You are able to search by Brand and/or device type such as USB, NFC, BLE, or BIO. These values are all parameter validated so if you do not see a brand that you have, then currently it is not compatible. Here is also the original link I shared on Friday Microsoft Learn FIDO2 Hardware Attestation.

Let me know what you think and do you find it useful. There are a few other features I want to add, but open to any other suggestions or do you think it is good as is?

And don’t forget the mid Oct deadline is coming up quickly for Entra admin portals, good luck!

PowerShell Gallery: EntraFIDOFinder
GitHub: EntraFIDOFinder

Tagged With: 365, Automation, AzureAD, Entra, MFA, PowerShell, Security, SSO

October 15, 2024: Microsoft Azure and Admin Portal MFA Requirement

September 23, 2024 by ClaytonT Leave a Comment

Are you ready for October 15, 2024 where accessing Azure Portal, Entra admin, Intune admin, and 365 Admin center portals will require MFA? It’s less than a month away. It does look like you can push it out to March 2025 if you absolutely have to, but I wouldn’t recommend it unless you have an extreme case.

Below is a great link from Microsoft Learn to check out to see how you’ll be affected and how to plan for it if you haven’t made the necessary changes. If you need any help migrating or any questions regarding it, I’d be glad to help out.

Microsoft Mandatory MFA Requirement

Tagged With: 365, Azure, PowerShell

Simple Tip for GitHub Copilot

September 20, 2024 by ClaytonT 2 Comments

If you have GitHub Copilot, you may or may not know about this little tip, but wanted to let you know just in case. It has saved me so much time and it can be applied to a lot of scenarios.

Here is the prompt, “Can you add the export to markdown capability from #file:Test-365ACCompanyName.ps1 to #file:Test-365ACStreetAddress.ps1”

And what this does is it adds the functionality of exporting to markdown to the new file the same I did in CompanyName, but adapts it to fit StreetAddress. Further more, it adds Help for it and creates the parameter for it(with ValidatePattern).

From this:

<#
.SYNOPSIS
    Tests whether users have a street address and generates a report.

.DESCRIPTION
    The Test-365ACStreetAddress function tests whether users have a street address and generates a report. 
    It takes a list of users as input and checks if each user has a street address. 
    The function generates a report that includes the user's display name and whether they have a street address.
    The report can be exported to an Excel file or an HTML file.

.PARAMETER Users
    Specifies the list of users to test. If not provided, it retrieves all users from the Microsoft Graph API.

.PARAMETER TenantID
    The ID of the tenant to connect to. Required if using app-only authentication.

.PARAMETER ClientID
    The ID of the client to use for app-only authentication. Required if using app-only authentication.

.PARAMETER CertificateThumbprint
    The thumbprint of the certificate to use for app-only authentication. Required if using app-only authentication.

.PARAMETER AccessToken
    The access token to use for authentication. Required if using app-only authentication.

.PARAMETER InteractiveLogin
    Specifies whether to use interactive login. If this switch is present, interactive login will be used. Otherwise, app-only authentication will be used.

.PARAMETER OutputExcelFilePath
    Specifies the file path to export the report as an Excel file. The file must have a .xlsx extension.

.PARAMETER OutputHtmlFilePath
    Specifies the file path to export the report as an HTML file. The file must have a .html extension.

.PARAMETER TestedProperty
    Specifies the name of the property being tested. Default value is 'Has Street Address'.

.EXAMPLE
    Test-365ACStreetAddress -Users $users -OutputExcelFilePath "C:\\Reports\\StreetAddressReport.xlsx"

    This example tests the specified list of users for street addresses and exports the report to an Excel file.

.EXAMPLE
    Test-365ACStreetAddress -OutputExcelFilePath "C:\\Reports\\StreetAddressReport.xlsx"

    This example retrieves all users from the Microsoft Graph API, tests them for street addresses, and exports the report to an Excel file.

#>

Function Test-365ACStreetAddress {
    [CmdletBinding()]
    param
    (
        [Parameter(ValueFromPipeline = $true)]
        [array]$Users = (Get-MgUser -All -Property DisplayName, StreetAddress | Select-Object DisplayName, StreetAddress),
        
        [Parameter(Mandatory = $false)]
        [string]$TenantID,
        
        [Parameter(Mandatory = $false)]
        [string]$ClientID,
        
        [Parameter(Mandatory = $false)]
        [string]$CertificateThumbprint,
        
        [Parameter(Mandatory = $false)]
        [string]$AccessToken,
        
        [Parameter(Mandatory = $false)]
        [switch]$InteractiveLogin,

        [ValidatePattern('\\.xlsx$')]
        [string]$OutputExcelFilePath,
        
        [ValidatePattern('\\.html$')]
        [string]$OutputHtmlFilePath,
        
        [string]$TestedProperty = 'Has Street Address'
    )
    BEGIN {
        if ($InteractiveLogin) {
            Write-PSFMessage "Using interactive login..." -Level Host
            Connect-MgGraph -Scopes "User.Read.All", "AuditLog.read.All"  -NoWelcome
        }
        else {
            Write-PSFMessage "Using app-only authentication..." -Level Host
            Connect-MgGraph -ClientId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint -Scopes "User.Read.All", "AuditLog.Read.All"
        }
        
        $results = @()
    }
    PROCESS {
        foreach ($user in $Users) {
            $hasStreetAddress = [bool]($user.StreetAddress)
            $result = [PSCustomObject]@{
                'User Display Name' = $user.DisplayName
                $TestedProperty     = $hasStreetAddress
            }
            $results += $result
        }
    }
    END {
        $totalTests = $results.Count
        $passedTests = ($results | Where-Object { $_.$TestedProperty }).Count
        $failedTests = $totalTests - $passedTests
        if ($OutputExcelFilePath) {
            Export-365ACResultToExcel -Results $results -OutputExcelFilePath $OutputExcelFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
        }
        elseif ($OutputHtmlFilePath) {
            Export-365ACResultToHtml -Results $results -OutputHtmlFilePath $OutputHtmlFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
        }
        else {
            Write-Output $results
        }
    }
}

To this:

<#
.SYNOPSIS
    Tests whether users have a street address and generates a report.
.DESCRIPTION
    The Test-365ACStreetAddress function tests whether users have a street address and generates a report. 
    It takes a list of users as input and checks if each user has a street address. 
    The function generates a report that includes the user's display name and whether they have a street address.
    The report can be exported to an Excel file, an HTML file, or a Markdown file.
.PARAMETER Users
    Specifies the list of users to test. If not provided, it retrieves all users from the Microsoft Graph API.
.PARAMETER TenantID
    The ID of the tenant to connect to. Required if using app-only authentication.
.PARAMETER ClientID
    The ID of the client to use for app-only authentication. Required if using app-only authentication.
.PARAMETER CertificateThumbprint
    The thumbprint of the certificate to use for app-only authentication. Required if using app-only authentication.
.PARAMETER AccessToken
    The access token to use for authentication. Required if using app-only authentication.
.PARAMETER InteractiveLogin
    Specifies whether to use interactive login. If this switch is present, interactive login will be used. Otherwise, app-only authentication will be used.
.PARAMETER OutputExcelFilePath
    Specifies the file path to export the report as an Excel file. The file must have a .xlsx extension.
.PARAMETER OutputHtmlFilePath
    Specifies the file path to export the report as an HTML file. The file must have a .html extension.
.PARAMETER OutputMarkdownFilePath
    Specifies the file path to export the report as a Markdown file. The file must have a .md extension.
.PARAMETER TestedProperty
    Specifies the name of the property being tested. Default value is 'Has Street Address'.
.EXAMPLE
    Test-365ACStreetAddress -Users $users -OutputExcelFilePath "C:\\Reports\\StreetAddressReport.xlsx"
    This example tests the specified list of users for street addresses and exports the report to an Excel file.
.EXAMPLE
    Test-365ACStreetAddress -OutputExcelFilePath "C:\\Reports\\StreetAddressReport.xlsx"
    This example retrieves all users from the Microsoft Graph API, tests them for street addresses, and exports the report to an Excel file.
#>
Function Test-365ACStreetAddress {
[CmdletBinding()]
param
(
    [Parameter(ValueFromPipeline = $true)]
    [array]$Users = (Get-MgUser -All -Property DisplayName, StreetAddress | Select-Object DisplayName, StreetAddress),
    
    [Parameter(Mandatory = $false)]
    [string]$TenantID,
    
    [Parameter(Mandatory = $false)]
    [string]$ClientID,
    
    [Parameter(Mandatory = $false)]
    [string]$CertificateThumbprint,
    
    [Parameter(Mandatory = $false)]
    [string]$AccessToken,
    
    [Parameter(Mandatory = $false)]
    [switch]$InteractiveLogin,
    
    [ValidatePattern('\\.xlsx$')]
    [string]$OutputExcelFilePath,
    
    [ValidatePattern('\\.html$')]
    [string]$OutputHtmlFilePath,
    
    [ValidatePattern('\\.md$')]
    [string]$OutputMarkdownFilePath,
    
    [string]$TestedProperty = 'Has Street Address'
)
BEGIN {
    if ($InteractiveLogin) {
        Write-PSFMessage "Using interactive login..." -Level Host
        Connect-MgGraph -Scopes "User.Read.All", "AuditLog.read.All"  -NoWelcome
    }
    else {
        Write-PSFMessage "Using app-only authentication..." -Level Host
        Connect-MgGraph -ClientId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint -Scopes "User.Read.All", "AuditLog.Read.All"
    }
    
    $results = @()
}
PROCESS {
    foreach ($user in $Users) {
        $hasStreetAddress = [bool]($user.StreetAddress)
        $result = [PSCustomObject]@{
            'User Display Name' = $user.DisplayName
            $TestedProperty     = $hasStreetAddress
        }
        $results += $result
    }
}
END {
    $totalTests = $results.Count
    $passedTests = ($results | Where-Object { $_.$TestedProperty }).Count
    $failedTests = $totalTests - $passedTests
    if ($OutputExcelFilePath) {
        Export-365ACResultToExcel -Results $results -OutputExcelFilePath $OutputExcelFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
        Write-PSFMessage "Excel report saved to $OutputExcelFilePath" -Level Host
    }
    elseif ($OutputHtmlFilePath) {
        Export-365ACResultToHtml -Results $results -OutputHtmlFilePath $OutputHtmlFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
        Write-PSFMessage "HTML report saved to $OutputHtmlFilePath" -Level Host
    }
    elseif ($OutputMarkdownFilePath) {
        Export-365ACResultToMarkdown -Results $results -OutputMarkdownFilePath $OutputMarkdownFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
        Write-PSFMessage "Markdown report saved to $OutputMarkdownFilePath" -Level Host
    }
    else {
        Write-PSFMessage -Level Output -Message ($results | Out-String)
    }
}
}

And here is the source Test-365ACCompanyName.ps1 code

<#
.SYNOPSIS
Tests if users have a company name property and generates test results.

.DESCRIPTION
The Test-365ACCompanyName function tests if users have a company name property and generates test results. It takes an array of users as input and checks if each user has a company name property. The test results are stored in an array of custom objects, which include the user's display name and the result of the test.

.PARAMETER Users
Specifies the array of users to test. Each user should have a DisplayName and CompanyName property.

.PARAMETER TenantID
The ID of the tenant to connect to. Required if using app-only authentication.

.PARAMETER ClientID
The ID of the client to use for app-only authentication. Required if using app-only authentication.

.PARAMETER CertificateThumbprint
The thumbprint of the certificate to use for app-only authentication. Required if using app-only authentication.

.PARAMETER AccessToken
The access token to use for authentication. Required if using app-only authentication.

.PARAMETER InteractiveLogin
Specifies whether to use interactive login. If this switch is present, interactive login will be used. Otherwise, app-only authentication will be used.

.PARAMETER OutputExcelFilePath
Specifies the path to the output Excel file. If provided, the test results will be exported to an Excel file.

.PARAMETER OutputHtmlFilePath
Specifies the path to the output HTML file. If provided, the test results will be exported to an HTML file.

.PARAMETER OutputMarkdownFilePath
Specifies the path to the output Markdown file. If provided, the test results will be exported to a Markdown file.

.PARAMETER TestedProperty
Specifies the name of the tested property. Default value is 'Has Company Name'.

.INPUTS
An array of users with DisplayName and CompanyName properties.

.OUTPUTS
If OutputExcelFilePath or OutputHtmlFilePath is not provided, the function outputs an array of custom objects with the user's display name and the result of the test.

.EXAMPLE
$users = Get-MgUser -All -Property DisplayName, CompanyName | Select-Object DisplayName, CompanyName
Test-365ACCompanyName -Users $users -OutputExcelFilePath 'C:\\TestResults.xlsx'
This example tests if the users have a company name property and exports the test results to an Excel file.
#>
Function Test-365ACCompanyName {
    [CmdletBinding()]
    param
    (
        [Parameter(ValueFromPipeline = $true)]
        [array]$Users = (Get-MgUser -All -Property DisplayName, CompanyName | Select-Object DisplayName, CompanyName),
        
        [Parameter(Mandatory = $false)]
        [string]$TenantID,
        
        [Parameter(Mandatory = $false)]
        [string]$ClientID,
        
        [Parameter(Mandatory = $false)]
        [string]$CertificateThumbprint,
        
        [Parameter(Mandatory = $false)]
        [string]$AccessToken,
        
        [Parameter(Mandatory = $false)]
        [switch]$InteractiveLogin,
        
        [ValidatePattern('\\.xlsx$')]
        [string]$OutputExcelFilePath,
        
        [ValidatePattern('\\.html$')]
        [string]$OutputHtmlFilePath,
        
        [ValidatePattern('\\.md$')]
        [string]$OutputMarkdownFilePath,
        
        [string]$TestedProperty = 'Has Company Name'
    )
    BEGIN {
        if ($InteractiveLogin) {
            Write-PSFMessage "Using interactive login..." -Level Host
            Connect-MgGraph -Scopes "User.Read.All", "AuditLog.read.All"  -NoWelcome
        }
        else {
            Write-PSFMessage "Using app-only authentication..." -Level Host
            Connect-MgGraph -ClientId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint -Scopes "User.Read.All", "AuditLog.Read.All"
        }
        $results = @()
    }
    PROCESS {
        foreach ($user in $Users) {
            $hasCompanyName = [bool]($user.CompanyName)
            $result = [PSCustomObject]@{
                'User Display Name' = $user.DisplayName
                $TestedProperty     = $hasCompanyName
            }
            $results += $result
        }
    }
    END {
        $totalTests = $results.Count
        $passedTests = ($results | Where-Object { $_.$TestedProperty }).Count
        $failedTests = $totalTests - $passedTests
        if ($OutputExcelFilePath) {
            Export-365ACResultToExcel -Results $results -OutputExcelFilePath $OutputExcelFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
            Write-PSFMessage "Excel report saved to $OutputExcelFilePath" -Level Host
        }
        elseif ($OutputHtmlFilePath) {
            Export-365ACResultToHtml -Results $results -OutputHtmlFilePath $OutputHtmlFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
            Write-PSFMessage "HTML report saved to $OutputHtmlFilePath" -Level Host
        }
        elseif ($OutputMarkdownFilePath) {
            Export-365ACResultToMarkdown -Results $results -OutputMarkdownFilePath $OutputMarkdownFilePath -TotalTests $totalTests -PassedTests $passedTests -FailedTests $failedTests -TestedProperty $TestedProperty
            Write-PSFMessage "Markdown report saved to $OutputMarkdownFilePath" -Level Host
        }
        else {
            Write-PSFMessage -Level Output -Message ($results | Out-String)
        }
    }
}

And yes, it did write out the whole function again, I didn’t manipulate it at all, so after reviewing you can literally just copy it in, and not have to worry about forgetting a “(” or “{”. I know it’s not a huge lift, but you can also do “Can you also do this for #file:Test-365ACZipcode.ps1” and it will.

I’ve used this prompt syntax for other functions as well with great results. Have you used anything like this before?

You can see more uses of it at GitHub – 365AutomatedCheck

Tagged With: AI, Automation, GitHub Copilot, PowerShell, Templates

1k Downloads and more

September 16, 2024 by ClaytonT Leave a Comment

Wow, can’t believe it! 1,000 downloads of 365AutomatedLab! Thank you all! And I just want to start out saying apologies for not updating it more. Big work projects, summer, and life got in the way, but learned a lot and can’t wait to spread that info.

Still saddened that Microsoft hasn’t brought back the free Developer tenant program, but you can still use these in production to standardize adding and removing objects when dynamic groups aren’t an option. Please let me know if there are any features you wish it had, and I’ll see what I can do.

I did make a quick update to the module due to the PnP.PowerShell module changes where I removed the Connect-PnP in functions as you cannot use the old way anymore. I didn’t want you or others to be blocked from using those functions because of it, but will be adding back the newer way in the near future, I just want to find the best way to give you options to connect. If you already have a working function, I’d be glad to add it as well.

In addition to 365AutomatedLab, I’d been working on 365AutomatedCheck which is still in beta, but it checks if your 365 tenant is formatted and/or configured correctly to your company standards. Some of its capabilities are making sure that field values follow company standards, making sure phone numbers are filled in, and even on the fly correcting of those fields. This isn’t a Maester replacement, in fact all of the Pester tests work in Maester, and encourage you to add these to your Maester setup, but as of right now the auto correct fields function doesn’t work. Maybe we can make that happen!

Again, thank you for using 365AutomatedLab, as this is a fun side project for me, and never thought it would get this much traction. It’s a dream come true, and can’t wait to start working on it again!

Hope you have a great day!

365AutomatedLab
PowerShell Gallery: https://www.powershellgallery.com/packages/365AutomatedLab/2.11.0
GitHub: https://github.com/DevClate/365AutomatedLab

365AutomatedCheck
PowerShell Gallery: https://www.powershellgallery.com/packages/365AutomatedCheck/0.0.11
GitHub: https://github.com/DevClate/365AutomatedCheck

Maester
PowerShell Gallery: https://www.powershellgallery.com/packages/Maester/0.3.0
GitHub: https://github.com/maester365/maester

PnP.PowerShell Announcement
https://github.com/pnp/powershell/issues/4250

Tagged With: 365, 365AutomatedCheck, 365AutomatedLab, Automation, Entra, PowerShell, Reporting

365AutomatedLab and new companion module coming soon

June 28, 2024 by ClaytonT Leave a Comment

365AutomatedLab and new companion module coming soon

I promise I haven’t forgotten about 365AutomatedLab, but I’ll be honest after Microsoft made the announcement of no more new Dev tenants it hurt a bit as I know how useful they are on learning and testing features and PowerShell without hurting your production environment. 365AutomatedLab will still be used for people that have Dev tenants whether they are free or not, but you can use these functions in production as well.

Now about the new module, it hasn’t been released yet, but finishing cleaning it up to at least beta stage. I won’t say exactly what it does yet, but it is a companion to 365AutomatedLab in that it helps you keep your 365 tenant organized. A little teaser though, is that some of the parts will work with the amazing module Maester and if you don’t already use it, go install it now. Seriously, go do that and while that is downloading, think of ways you would like to see 365AutomatedLab improved.

Maester.dev – Test Automation Framework to keep control of your 365 security configuration
365AutomatedLab – Setup a 365 Tenant from an Excel Workbook

As always, thank you for taking the time and have a great day!

Tagged With: 365, 365AutomatedLab, Automation, Maester, PowerShell, Reporting, Testing

365Automatedlab V2.10.1 Released!

April 26, 2024 by ClaytonT Leave a Comment

I know I said every 2 weeks, but I lied. I wanted to get this out! It is now possible to add a manager when creating a new user. Also added a feature so that when you use the parameter -UseDeveloperPackE5 when creating new users and it will add the Developer license to all added users.

New-CTUser

  • Added “Add Manager” when creating new user
  • Add only Dev licenses option
  • Updated help
  • Allow some parameters to be empty

Added “Discussions” in GitHub for feature requests and general discussions

Let me know what you think and if you have any feedback or suggestions!

Have a great day!

PowerShell Gallery: https://www.powershellgallery.com/packages/365AutomatedLab/2.10.1
GitHub: https://github.com/DevClate/365AutomatedLab

Tagged With: 365, 365AutomatedLab, Automation, Onboarding, PowerShell, Sharepoint, Teams

  • « Go to Previous Page
  • Page 1
  • Interim pages omitted …
  • Page 3
  • Page 4
  • Page 5
  • Page 6
  • Page 7
  • Interim pages omitted …
  • Page 10
  • Go to Next Page »

Primary Sidebar

Clayton Tyger

Tech enthusiast dad who has lost 100lbs and now sometimes has crazy running/biking ideas. Read More…

Find Me On

  • Email
  • GitHub
  • Instagram
  • LinkedIn
  • Twitter

Recent Posts

  • Learning ValidateSet in PowerShell: Valid Values Only
  • Teams Chat and PowerShell – How to add value!
  • EntraFIDOFinder: New Web UI and Over 70 New Authenticators
  • January 19, 2026 Updates to EntraFIDOFinder
  • v0.0.20 EntraFIDOFinder is out

Categories

  • 365
  • Active Directory
  • AI
  • AzureAD
  • BlueSky
  • Cim
  • Dashboards
  • Documentation
  • Entra
  • Get-WMI
  • Learning
  • Module Monday
  • Nutanix
  • One Liner Wednesday
  • Passwords
  • PDF
  • Planner
  • PowerShell
  • Read-Only Friday
  • Reporting
  • Security
  • Uncategorized
  • Windows
  • WSUS

© 2026 Clatent