Category Archives: PowerBI

Average device daily usage report in PowerBI

A customer wanted to know how many hours on average their devices were being used, without modifying their configuration.

This to help target replacements, upgrades, #desks per location, #shared devices per location etc.

At first I figured it’d be a simple task, just getting the right event ID’s from the local eventlog, but no, that required additional auditing to be enabled and how would the data flow to PowerBI?

The next attempted data source was much better; Defender Advanced Hunting. Especially the DeviceLogonEvents table, which contains cached and interactive logons to all monitored devices.

Using logon events, we can get an idea of a device’s relative use in the fleet. It won’t be exact as measuring the time between pure lock/unlock/signin/signout events.

This was fine for the customer’s purpose and checking their data the number of daily logon events (7-9) was actually much higher than the expected 2-3 per device per day (at least on Windows 11, our target OS).

Getting that data into PowerBI turned out to be even easier 🙂

Option 1: use my PowerBI template

Option 2: build your own report using below steps:

  1. Open up PowerBI and click Blank Query
  1. Open the Advanced Editor
  1. Paste the KQL query and click done

KQL:

 let
        AdvancedHuntingQuery = "DeviceLogonEvents
| where Timestamp between (ago(28d) .. now())
| where ActionType == ""LogonSuccess""
| where LogonType == ""Interactive""
| extend LogonDate = startofday(Timestamp)
| where LogonDate < startofday(now())  
| summarize 
    FirstLogon = min(Timestamp), 
    LastLogon = max(Timestamp)
    by DeviceName, LogonDate
| extend UsageDuration = LastLogon - FirstLogon
| project DeviceName, LogonDate, FirstLogon, LastLogon, UsageDuration
| order by DeviceName asc, LogonDate desc",

        HuntingUrl = "https://api.security.microsoft.com/api/advancedqueries",

        Response = Json.Document(Web.Contents(HuntingUrl, [Query=[key=AdvancedHuntingQuery]])),

        TypeMap = #table(
            { "Type", "PowerBiType" },
            {
                { "Double",   Double.Type },
                { "Int64",    Int64.Type },
                { "Int32",    Int32.Type },
                { "Int16",    Int16.Type },
                { "UInt64",   Number.Type },
                { "UInt32",   Number.Type },
                { "UInt16",   Number.Type },
                { "Byte",     Byte.Type },
                { "Single",   Single.Type },
                { "Decimal",  Decimal.Type },
                { "TimeSpan", Duration.Type },
                { "DateTime", DateTimeZone.Type },
                { "String",   Text.Type },
                { "Boolean",  Logical.Type },
                { "SByte",    Logical.Type },
                { "Guid",     Text.Type }
            }),

        Schema = Table.FromRecords(Response[Schema]),
        TypedSchema = Table.Join(Table.SelectColumns(Schema, {"Name", "Type"}), {"Type"}, TypeMap , {"Type"}),
        Results = Response[Results],
        Rows = Table.FromRecords(Results, Schema[Name]),
        Table = Table.TransformColumnTypes(Rows, Table.ToList(TypedSchema, (c) => {c{0}, c{2}}))

    in Table
  1. Edit your credentials and sign in

Now you’ve got the data connected, and just need to create a table with the fields you want.

M365Permissions v1.2.3

Performance improvements and Onenote Notebooks.

Today’s release has a ‘special guest’; Morten (blog)! He completely rewrote the entra user and group retrieval code, greatly improving both performance and total capacity!

Other changes of note:

  1. Add support for Onenote Notebook sharing permissions
  2. Treat anonymous sharing links as ‘deleted’ if the sharing level at the site forbids anonymous sharing

Full changelog here

Download / Use:

M365Permissions module page | Github | PSGallery

M365Permissions v1.2.2

Are you also curious about all those PowerApps and Flows in your environment? Orphaned ones maybe? Or when someone leaves the company?

1.2.2 adds scanning of PowerApps and Flows! Only when using SPN auth. (setup instructions)

In addition to that, I’ve also added provisional support for scans of tenants in USGOV, USDOD and China. Since I don’t have a test tenant there, I’ll have to rely on you to test how it performs there.

Full changelog here

Download / Use:

M365Permissions module page | Github | PSGallery

M365Permissions v1.2.1

Yes, we finally have Microsoft Azure! All active and eligible permissions are in scope from the subscription level and below.

If you use a service principal for scanning, be sure to assign read permissions for it to all subscriptions (or lower level resource groups) you want it to index.

Full changelog here

Download / Use:

M365Permissions module page | Github | PSGallery

M365Permissions v1.1.6

1.1.6 brings all separate catagories we scan in line by making the report columns the same (=Common Data Mode). This makes comparing and pivoting a LOT easier 🙂

Also, added Partner Permissions and Entra Devices (including Cloud PC’s).

Main changes:

  • [Feature] Add partner relationships
  • [Feature] Add entra devices & cloud pc’s
  • [Feature] Remove group enumeration for all entra type groups
  • [Feature] Implement Common Data Model
  • [BugFix] Don’t scan Teams Channels twice
  • [BugFix] Do not retry when getting 404 errors
  • [BugFix] Properly restore site lock state if modified

Full changelog here

Download / Use:

M365Permissions module page | Github | PSGallery