A few years ago I wrote an article named "Exchange Meeting Room Statistics" about a script to gather statistics regarding Exchange meeting room usage for MSExchange.org (now techgenix.com). For this script to work, we have to give ourselves FullAccess to the meeting rooms’ mailbox, add them into our Outlook profile, and then use an Outlook COM Object to connect to Outlook and gather this information. Far from ideal, especially when trying to analyse dozens of rooms!
A couple of years after, I wrote a new version that uses Exchange Web Services to gather the same information, plus some further stats. However, this script wasn't very reliable with Exchange Online as it would work in some environments, but not in other.
I have finally written this newer version, specifically targeted at Exchange Online only, this time using Graph API!
IMPORTANT:
- To analyze a particular meeting room, specify one or more primary SMTP addresses in the format: "room1@domain.com, room2@domain.com". Alternatively, analyze all meeting rooms by using the "-All" switch;
- You will need to have, or create, an 'app registration' in Azure and user digital certificate for authentication (you can update the script to use 'client secret' instead);
- The app registration will need the following API permissions to Graph API: 'User.Read.All', 'Calendars.Read', and 'Place.Read.All', all of type 'Application';
- Maximum range to search is 1825 days (5 years);
- You can enter the dates in the format "22/02/2020", "22/02/2020 15:00", or in ISO 8601 format such as "2020-02-22T15:00:00", or even "2020-02-22T15:00:00-08:00" to specify an offset to UTC (time zone).
The most basic way of running the script is as follows (more examples in the script itself):
.\Get-MeetingRoomStats_GraphAPI.ps1 -All -From "01/01/2020" -To "01/02/2020"
The script gathers and exports the following stats for each meeting room for the given date range:
- RoomName: the display name of the meeting room (when using -All). When using -RoomListSMTP, this will be the room's SMTP address;
- RoomSMTP: the SMTP address of the meeting room;
- From: the start of the date range to search the calendar;
- To: the end of the date range to search the calendar;
- totalMeetings: the total number of meetings;
- totalDuration: the total number of minutes for all meetings;
- totalAttendees: the total number of attendees invited across all meetings;
- totalUniqueOrganizers: the number of unique meeting organizers;
- totalUniqueAttendees: the number of unique attendees;
- totalReqAttendees: the total number of required attendees;
- totalOptAttendees: the total number of optional attendees;
- Top5Organizers: the email address of the top 5 meeting organizers, and how many meetings each scheduled;
- Top5Attendees: the email address of the top 5 meeting attendees, and how many meetings each attended;
- totalAllDay: the total number of 'all-day' meetings;
- totalAM: the total number of meetings that started in the morning (this excludes all-day meetings);
- totalPM: the total number of meetings that started in the afternoon;
- totalRecurring: the total number of recurring meetings;
- totalSingle: the total number of non-recurring meetings (single instance/occurrence).
Where do I run this PS? Do I use Exchange online PS or AzureAD PS?
ReplyDeleteHi Steve,
DeleteYou can run it from a "normal" PowerShell console. The script uses Graph API, so it doesn't need to be connected to Exchange Online or Azure AD :)
Best regards,
Nuno
\GetMeetingRoomStats_GraphAPI_v0.2.ps1 : Cannot process argument transformation on parameter 'All'. Cannot convert value "System.String" to type
Delete"System.Management.Automation.SwitchParameter". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.
Can you show me exactly how are you calling the script?
DeleteI am trying to collect the information about each meeting which have been booked rather than just the overall number based on the room. I have taken the # out from the part about getting the information about each meeting but the output is only giving me 1 result per room rather than every meeting in the room
ReplyDeleteHi. Did you export that PSCustomObject to a file for example?
Deletecan you confirm if we can store the email addresses in a csv and import the csv as at the moment we are having to run a query on 400+ calendars
ReplyDeleteI'm afraid you can't with the script as is...
Deleteexport all of your resource mailboxes onto a csv, extract all of their smtp's to a simple file and run this command.
Deleteimport-csv c:\user\username\desktop\smtp.csv | foreach { .\getmeetingroomstats_graphapi.ps1 -roomlistsmtp $_.PrimarySmtpAddress}
Hi, I read that there is a new Places api that is supposed to replace findRooms or findRoomLists. It can list more than 100 rooms https://docs.microsoft.com/en-us/graph/api/resources/place?view=graph-rest-beta
ReplyDeleteCan you please suggest how to modify your script in order to use the new Places api?
Hi Agnese,
DeleteThank you for letting me know! I just tested it and it seems to work great! :) Unfortunately I don't have a tenant with more than 100 meeting rooms, but it worked fine in a smaller tenant.
All you have to do is ensure your app registration has the required permissions as per the article and update the following line from:
$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/users/$user/findRooms" -Token $token
To:
$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room" -Token $token
Then, find and replace all "$room.address" with "$room.emailAddress", and "$room.name" with "$room.nickname"
That should do it! :)
Regards,
Nuno
Hi Nuno,
ReplyDeletenice work.
Where i can find your script. Microsoft delete all of the scirpts :(
https://gallery.technet.microsoft.com/scriptcenter/Exchange-Online-Meeting-4894b38f is not working anymore.
Kind regards,
Neon
Thanks! I know, I need to move these scripts to GitHub or something... :( I will update the post once I do
DeleteHi Steve, too I am in urgent neefnedyou r script od you upload it ploan it plel yo..e. pelase?
DeletePlease let us know when you do, this looks perfect!
DeleteThis would be great!
DeleteHere it is! https://github.com/NunoFilipeMota/PublicScripts/blob/main/GetMeetingRoomStats_GraphAPI.ps1
DeleteHi Nuno,
ReplyDeleteHope your well, would appreciate if you can share the script.
Many Thanks
Hi! Sorry for the delay. Here it is! https://github.com/NunoFilipeMota/PublicScripts/blob/main/GetMeetingRoomStats_GraphAPI.ps1
DeleteDo you still have the script for on prem .. the scripts looks good but I need for exchange 2016 on prem
ReplyDeleteHi Brijesh,
DeleteSure, you can find it here: https://github.com/NunoFilipeMota/PublicScripts/blob/main/GetMeetingRoomStats_EWS.ps1
Regards,
Nuno
Hi Nuno mota can you help me ? do oyu have script for exchange on premise ? i need room occupancy per hour some help ?
ReplyDeleteSure! You can find it here: https://letsexchange.blogspot.com/2017/05/exchange-meeting-room-statistics.html
DeleteHi Nuno,
ReplyDeleteThank you for publishing the script. I am receiving the following error while running it:
Unable to get token: 'The remote server returned an error: (401) Unauthorized.'
.\GetMeetingRoomStats_GraphAPI.ps1 -All -From "01/05/2021" -To "18/05/2021"
Can you please suggest. Please note I have registered the app in azure and provide the client ID and client serest details in the script.
Hi!
DeleteAre you sure the script has the correct information about the app registration? The error seems to be when you are trying to get the auth token. Also, please double-check the app registration has the correct API permissions!
Regards, Nuno
I can second this error. Script works when I specify a meeting room but not when I use -All parameter. Is there any additional API permission required to pull the list of rooms in the first place?
DeleteApologies, I updated the code to use "list places" instead of "findRooms" and didn't update the description... You will also need "Place.Read.All" application permissions. Apologies for the error. I will update GitHub soon!
DeleteHi Nuno,
ReplyDeleteThank-you for this script - just what I need, but cant get it to work. It seems EWS Managed API isn't available anymore. Has anyone been able to download it from somewhere? I see reference to nuget, but have no idea how to use it!
Hi! Aren't you able to use the Graph API version?
DeleteHi Nuno, i am receiving the following error... Retrieved OAuth Token
ReplyDeleteUnable to query Graph API: 'Der Remoteserver hat einen Fehler zurückgegeben: (401) Nicht autorisiert.' I run this script from my local client without globaladmin rights.
Hi. It seems to me the app registration is not configured correctly. Does the app registration have the required permissions, and do you have the correct app registration details in the script?
DeleteHi Nuno, thanks for creating this.
ReplyDeleteI get this error when running the script: You must use the -ClientID -ClientSecret AND -TenantID parameters. Exiting Script.
Hi Lynn. Are you using those parameters when running the script? If not, please update them with the corresponding Azure application details at the beginning of the script.
DeleteHi Nino, Thanks for your response, I have fixed the settings in the script but I am getting a new error: Unable to get token: 'The remote server returned an error: (400) Bad Request.' -- Did I miss a setting in the script?
DeleteHi Lynn. Have you updated all three parameters and is the app registration configured correctly?
DeleteHi Nuno, Thank you for this.
ReplyDeleteWhen I run the script with the -All parameter, The output shows that it retrieved 6 meeting rooms but the output shows stats for only 1 meeting room. can you please advise?
Hi. Are you running the latest version that uses Graph API?
DeleteHi Nuno. I've tried to use updated the script, but it seems retrieving only 100 rooms. Could you please advise how to fix it?
ReplyDeleteHi Russel. Are you using the latest version with Graph API?
DeleteHello Nuno. Yes, the version of Graph API 1.6.1
DeleteHi Russel,
DeleteApologies. Please use the following instead:
$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room?top=999" -Token $token
I've updated the code on GitHub with this change.
Regards,
Nuno
Hello,
ReplyDeleteThank you very much for your script which was really helpful for our need. The only problem we had was about limitation of first 100Th room mailboxes despite switching to -All and using pagination through https://docs.microsoft.com/en-us/graph/paging.
Still helpful anyway.
Hi,
DeleteApologies. Please use the following instead:
$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room?top=999" -Token $token
I've updated the code on GitHub with this change.
Regards,
Nuno
im getting this error
ReplyDeletePlease use -All or -RoomListSMTP parameters. Exiting Script.
HELP!
Hi Abmiester,
DeleteYou have to use one of those parameters when running the scripy.
Regards,
Nuno
hi Nuno..can you assist. i double checked the creds and this is what i'm getting
ReplyDeleteRetrieved OAuth Token
Unable to query Graph API: 'The remote server returned an error: (401) Unauthorized.'
END.
Hi Abmiester. That means the app registration you created does not have the required permissions. Have you assigned it 'User.Read.All', 'Calendars.Read', and 'Place.Read.All' (all of type 'Application')?
DeleteHi, I'm getting the same, the app registration has the following permissions 'User.Read.All', 'Calendars.Read', and 'Place.Read.All' all of them type Application.
DeleteI am using the secret ID, Tennant ID and Application ID parameters.
Hi Nuno, I have one doubt in your script. It is working fine. I booked a meeting room on 26th Sep. When I run the script today by passing only Sep month date, it is not giving me the details about the meeting which I have booked on 26th Sep.
ReplyDeleteCan you please assist?
Hi Nuno,
ReplyDeleteAfter using this '$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room" -Token $token' also, powershell script is displaying only 100 meeting rooms.
Can you please assist ?
Thanks.
Hi Vidhya,
DeleteApologies. Please use the following instead:
$allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room?top=999" -Token $token
I've updated the code on GitHub.
Regards,
Nuno
Thank you so much Nuno for your help. It worked :)
DeleteExcellent! :) Thank you for the update.
DeleteGreat script and thank you so much this has helped me.
ReplyDeleteI want to see all the attendees in a certain timeframe not top 5, how can i change this?
Thank you
Thank you! :)
DeleteSimply update the following line which selects only the top 5:
Top5Attendees = If ($topAttendees) {($topAttendees.GetEnumerator() | Sort -Property Value -Descending | Select -First 5 | % {"$($_.Key) ($($_.Value))"}) -Join ", "} Else {""}
If you want more than 5, simply update the Select statement, or remove it completely to get ALL of the attendees.
Regards,
Nuno
I continue to get Unable to get token: 'The remote server returned an error: (401) Unauthorized.' I have made sure application permissions are assigned
ReplyDeleteJust an fyi if anyone else is in a GCC High environment like myself make sure to change all .com to .us throughout the script.
ReplyDeleteexample
https://login.microsoftonline.us/$TenantID/oauth2/v2.0/token
https://graph.microsoft.us/
Thanks for the tip!!
DeleteHi Nuno, great work! All objects returned are ResourceType 'Room' (understandable as that's what is targeted by the Graph API). Do you know if a similar report can be produced for objects with ResourceType 'Workspace'?
ReplyDeleteThanks.
Thanks! I don't I'm afraid, I never looked into that specifically...
DeleteOk here is a SIMPLE GUIDE if you have problems running the script
ReplyDeletein the end you should have something like this
syntax
.\Get-MeetingRoomStats_GraphAPI.ps1 -ClientID randomid-generated-from-azure-ad -ClientSecret generatedpasswordfromazuread -TenantID generated-idf-from-azure-id -RoomListSMTP "yourroomname@yourdomainname.com" -From "01/10/2021" -To "01/12/2021"
get -ClientID from
https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
app registrations
new registration
clientid
and tenant id are gonna show up here
then go to certificates and secrets get new client secret
copy the secret/password because it will be hidden later.
-ClientSecret
this will expire after set time
go to the app and view permissions
add application permission for
Calendars.Read
Place.Read
Place.Read.All
User.Read
User.Read.All
and allow access/grant admin consent
hopefully it will work
Thanks a lot for helping everyone! :)
DeleteThank you these two guys!
DeleteHello. Does this work on workspaces?
ReplyDeleteHello Nuno,
ReplyDeleteThank you very much for making this script. I am using it on a tenant with more than 300 room mailboxes. One thing I can't really understand is that it stops processing far before it reaches the total number of room mailboxes. It also doesn;t show any mailboxes with 0 meetings. Could it be that it skips these and also doesn't count it in the total number of processed mailboxes?
Hi Stefan,
DeleteYes, at is, it will skip the room if there are no meetings. You will find that in the following part of the code:
$totalMeetings = ($allMeetings | Measure).Count
If ($totalMeetings -eq 0) {
Write-Log -Type "WRN" -Message "0 meetings retrieved from '$($room.nickname)'"
Continue
} Else {
Write-Log -Type "INF" -Message "$totalMeetings meetings retrieved from '$($room.nickname)'"
}
When this happens, you should see a WRN entry in the log for that particular meeting room as per the code above.
As to the number of rooms, yes, it should return all of them.
I've just started working on a version of this script that uses the Graph API SDK instead, which should greatly simplify the script! Hopefully it will be published soon :)
Regards,
Nuno
Hi Nuno,
DeleteThank you for the very quick response. For some reason when I use it, it shows that there are 335 room mailboxes in the status bar, but when it reaches about 175 it stops with the "END." message. This is wile using From: 1-02-2022 and To: 15-02-2022. So I only get 175 mailboxes in the export and none of them has 0 meetings. When I use From: 1-11-2019 and To: 30-11-2019 it also shows 335 mailboxes in the status bar but stops at 115. Do you maybe know a reason why this could happen?
Regards,
Stefan
Are you sure those missing ones are not rooms with 0 meetings? Have you checked the log for "0 meetings retrieved from" to see how many entries there are?
DeleteYou can try commenting the "Continue" statement, but nothing will be added to the export if there are no meetings for the room...
I am experiencing same issue where not all meeting rooms data is retrieved even though meeting rooms definitely have meetings, is there a fix for this yet?
DeleteSo is it actually possible to export also rooms with 0 meetings?
DeleteIn order to see warning messages in the log and in the export file you need to comment out both "Continue" statements. Thank you Nuno for the perfect script. Really appreciate it.
DeleteThe script is great. Thanks for doing this. I see a place to uncomment lines and get individual meeting details as well. I did that and it puts that out to screen, but does not append to the csv output. Is there a way to get it to put the meeting details in the csv as well?
ReplyDeleteThank you! :) Yes, it will output it to the screen. If you want it into a CSV, simply add something like " | Export-CSV file.csv -NoType -Append" after that block's }
DeleteTrying your script for the first time, and I am also seeing "Unable to get token: 'The remote server returned an error: (401) Unauthorized.'". Verified that the application has the following rights:
ReplyDeleteCalendars.Read,
Place.Read.All
User.Read
User.Read.All
any thoughts?
Have you checked that the permissions have actually been granted for the organisation? They will require admin consent.
DeleteFirst of all I'd like to thank you for taking your time to write the script. It's really nice to have an adaptation which now works via Graph API.
ReplyDeleteSecond, do you know how recurring calendar elements are read by Graph API/your script ? I'm running an export right now and I'm getting several timeouts. When investigating further I see mailboxes with 22 items in the calendar cause 30+ min delays where it simply says "Processed (0 / 1). Current calendar: ''". 22 items shouldn't take that long. Checking the calendar I see some Outlook super users (not) creating 17 recurring events on a single day (due to mailbox full access thus skipping calendarprocessing limitations) and not setting an end date.
For this particular mailbox it takes about 80 seconds to export data for 1 month. So it should take about 16 minutes for 2021 but that's not what I'm experiencing. Seems like I'm hitting some hidden timeout/retry not being printed to screen until it times out.
Thnx for the script and for providing it to us, it really helps alot.
ReplyDeleteIf I run the script called 'GetMeetingRoomStats_GraphAPI_v0.1.ps1' everything runs fine but when I use the script called 'Update GetMeetingRoomStats_GraphAPI.ps1' there is a problem.
If I use the -RoomListSMTP parameter it runs fine and I can run it on all rooms, but when I use the -All parameter I just get 'Unable to query Graph API: The remote server returned an error: (401) No permission'
I haven't made any changes to the script. What am I missing here?
Hi Richard. Glad to hear that! :)
DeleteWhat do you mean when you run it like 'Update GetMeetingRoomStats_GraphAPI.ps1'? Did you rename it and added a space to the script name?
As to using "-All", please make sure the app registration has all the permissions, as that parameter requires 'Place.Read.All' permissions.
Hello Nuno,
ReplyDeleteSorry for the lame problem, but I see the EWS Managed API is no longer available. What can i do? How can i install the api? I have already checked the github but I cannot see any installable version of the API.
I just would like to know what is the usage of the meeting rooms (percentage of free-reserved times) in my workplace. Your ps script seems to be the best solution for this but in this case I cannot use it :(
Hi Zoltan. You can get v2.2 from here: https://www.nuget.org/packages/Microsoft.Exchange.WebServices/
DeleteHowever, I suggest you use the script I wrote that uses Graph API (the one in this post) instead of EWS.
Hey
ReplyDeleteI tried running the script and also gave permissions of API permissions but I still encountered such an error message:
"You must use the -ClientID -ClientSecret AND -TenantID parameters. Exiting Script."
Would appreciate help. Thanks!
Hi. How exactly are you calling/running the script?
DeleteHi,
ReplyDeletefor AM/PM meeting counters, i changed to this
If ($meeting.isAllDay) {$totalAllDay++} Else {If ((Get-Date $meeting.start.dateTime -format "HH") -lt "12") {$totalAM++} Else {$totalPM++}}
for country having 24h format, also it wont count meetings in the mornings
That's a great approach as well! But my one works fine for me, even with 24h format, so that's strange...
DeleteNuno!
ReplyDeleteYou are a scholar and a gentleman! Thank you for creating this script.
Quick question,
Is it possible to use this script with Certificate Based Authentication?
If so, can you point me in the direction of how I can incorporate that with your script instead of using the client secret?
Much thanks and keep up the great work!
Hi Tom,
DeleteThank you for the kind comment! :)
Yes! Just replace the Get-OAuthToken function with the following, which uses a cert installed under the machine or user scope (update accordingly with the details of your cert):
Function Get-OAuthToken {
Param ($ClientID, $TenantID, $CertThumprint)
Try {
Import-Module MSAL.PS -ErrorAction Stop
} Catch {
Write-Log -Type "ERR" -Message "Unable to import MSAL PowerShell module: '$($_.Exception.Message)'"
Return $False
}
# Get OAuth Token
Try {
$ClientCertificate = Get-Item "Cert:\CurrentUser\My\$CertThumprint"
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientCertificate $ClientCertificate
Return $token.AccessToken
} Catch {
Write-Log -Type "ERR" -Message "Unable to get OAuth token using MSAL: '$($_.Exception.Message)'"
}
}
Hope it helps!
Regards,
Nuno
Nuno - Great script and so useful. It ran successfully on the first try. Thank you so much for writing and sharing this.
ReplyDeleteI also ran into the issue of rooms with 0 meetings being completely omitted, both from the log file and the csv file and had to comment out the line "If (!$allMeetings) {Continue}" since that caused those rooms to be skipped for both.
What I was not able to accomplish, was to add other attributes to the export. For example, the rooms' DisplayName, city, address, etc., which would be very helpful. Could you help with that?
Thank you for the feedback :) Please check the latest version of the script I have just uploaded. It now exports meeting rooms with 0 meetings :)
Deletewhen i run the script to get the meeting room calendar events information for 10 to 15 room mailboxes , i am not getting all events information(issue number 1) and for some events i am not getting meeting room name
ReplyDeleteHi. Please try the newer version I have just uploaded as it now uses MSAL to retrieve the token. Please note that it requires a certificate for authentication, but you can change the function to use a Client Secret instead if you want.
DeleteHi! I would like to use this script with an imported csv file with the meeting rooms, is this possible?
ReplyDeleteThe thing is we have over 600 meeting rooms and i would just like to use it on 60-80 meeting rooms, it takes too long to write with "roomlistSMTP". I Could ofc use it on all and just filter it out to the ones i want but it would be lovely to use it with imported CSV file instead.
Hi Markus. I'm afraid you'd need to update the code yourself in order to work that way. I'll try to incorporate that in the next version, but not sure when that will be...
DeleteThis still seemingly even with the current changes to $allRooms = Query-GraphAPI -URI "https://graph.microsoft.com/beta/places/microsoft.graph.room?top=999"
ReplyDeleteimmediately stops processing whenever it hits the 100th mailbox no matter how you shake it out.
Did you ever figure out what was causing that?
That is strange... For me, it is exporting over 700 meetings in one go in my environment. Please try the latest version I have just uploaded (but that part of the code is exactly the same...)
DeleteHey Nuno, When i run the script it does not error out, i have added the options for -ClientID, -TenantID, -ClientSecret. (I created the app in azure and granted permisisons). However the script only reports 1 meeting.
ReplyDeleteIf i set the from/to on the script to "2020-01-01" and "2022-08-17" - It reports the SINGLE Meeting as a from/date of:
From : 1/1/2020 12:00:00 AM To : 8/17/2022 12:00:00 AM
If i set start date to different date the above results change to that date as well. Also if i run the scripts with no to/from parameters, then it reports nothing.
Any ideas?
That's very strange... Have you tried the date in a different format? You can enter the dates in the format "22/02/2020", "22/02/2020 15:00", or in ISO 8601 format such as "2020-02-22T15:00:00", or even "2020-02-22T15:00:00-08:00" to specify an offset to UTC (time zone).
DeleteAlso, please try the newer version I have just uploaded.
Hey Nuno, We followed the directions to set the script up, but when we run it, it just returns 1 meeting. For conference rooms that i know have more than 1 meeting.
ReplyDeleteany ideas?
Robert
That's very strange, never had that happening to me... Are those other meetings within the timespan chosen?
DeleteAlso, please try the newer version I have just uploaded. Please note it requires a certificate for authentication, but you can change the function to use a Client Secret instead if you want.
Hi Nuno,
ReplyDeleteI have been able to successfully run the script however when I run using the -all switch it shows "retrieving 116 meeting rooms" however it is only exporting 87 room data results and I have gone through the log and cannot see any lines that state "0 meetings retrieved from"
That's strange... Probably those meeting rooms don't have any meetings, but it still should highlight that. Please try the newer version I have just uploaded as it now exports meeting rooms with 0 meetings.
DeleteHi I am having issues where the script just ENDs halfway through exporting data from 116 meetings rooms. Only does approx 60 meetings, have verified meeting rooms have bookings aswell.
ReplyDeleteHi. Please try the newer version I have just uploaded as it now uses MSAL to retrieve the token. Please note that it requires a certificate for authentication, but you can change the function to use a Client Secret instead if you want.
Deletethanks you,. Trying your script for the first time, and I am also seeing "Unable to get token: 'The remote server returned an error: (401) Unauthorized.'". Verified that the application has the following rights:
ReplyDeleteCalendars.Read,
Place.Read.All
User.Read
User.Read.All
and Admin consent is OK .
any thoughts?
Please try the newer version I have just uploaded as it now uses MSAL to retrieve the token. Please note that it requires a certificate for authentication, but you can change the function to use a Client Secret instead if you want.
DeleteI am also seeing "Unable to get token: 'The remote server returned an error: (401) Unauthorized.'". Verified that the application has the following rights:
ReplyDeleteCalendars.Read,
Place.Read.All
User.Read
User.Read.All
I have confirmed they have all been consented by the Admin?
Please try the newer version I have just uploaded as it now uses MSAL to retrieve the token. Please note that it requires a certificate for authentication, but you can change the function to use a Client Secret instead if you want.
DeleteHi there, the script and these comments now seem to only reference using a certificate. Are you able to share the code required to use clientsecret?
ReplyDeleteHi. You need to update all references of the variable "CertThumprint" to something like "Secret" and then update the Get-MsalToken cmdlet inside the "Get-OAuthToken" function to use a secret instead of a certificate.
DeleteHi, great script.. Now that you have updated to use certificate I got clientsecret working by referencing the old script via github. This is more a general question rather than a request. Do you think its possible to report on which days are more popular. Or to say another way what % of bookings fall on each workday, for a given room, for a given timeframe?
ReplyDeleteHi Jono. Thank you! :)
DeleteTo use a certificate, you need to update all references of the variable "CertThumprint" to something like "Secret" and then update the Get-MsalToken cmdlet inside the "Get-OAuthToken" function to use a secret instead of a certificate.
Yes, it is technically possible. You'd need to keep track of all days (days of the month, week days, whetever you prefer) and then use that for your stats (I suggest an array or hashtable). It might be tricky, but it's doable!
Regards, Nuno
How do you I use this script with client secret instead of certificate
ReplyDeleteYou need to update all references of the variable "CertThumprint" to something like "Secret" and then update the Get-MsalToken cmdlet inside the "Get-OAuthToken" function to use a secret instead of a certificate.
DeleteHello Nuno, Thank you for this script. I have replaced all "CertThumprint" with "Secret" and updated these; [Parameter(Mandatory = $False)]
Delete[String] $ClientID = "xxxxxxxxxxxxxxxxxxx",
[Parameter(Mandatory = $False)]
[String] $Secret = "xxxxxxxxxxx",
[Parameter(Mandatory = $False)]
[String] $TenantID = "xxxxxxxxxxxxxxxxx"
)
I guess I am not understanding how to update this section; Function Get-OAuthToken {
Param ($ClientID, $TenantID, $Secret)
Try {
Import-Module MSAL.PS -ErrorAction Stop
} Catch {
Write-Log -Type "ERR" -Message "Unable to import MSAL PowerShell module: '$($_.Exception.Message)'. Exiting script."
Exit
}
Try {
$ClientCertificate = Get-Item "Cert:\CurrentUser\My\$Secret"
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientCertificate $ClientCertificate -ErrorAction Stop
# Get token expiration date and time so we can renew it 2 minutes before it expires
$global:tokenExpireDateTime = (Get-Date $token.ExpiresOn.DateTime).AddSeconds(-120)
Return $token.AccessToken
} Catch {
Write-Log -Type "ERR" -Message "Unable to get OAuth token using MSAL: '$($_.Exception.Message)'. Exiting script."
Exit
}
}
I know I need to update the ClientCertificate with Secret in some way, but I am not sure exactly how to do that?
The following should do it :)
DeleteRemove the following line:
$ClientCertificate = Get-Item "Cert:\CurrentUser\My\$Secret"
And update this line:
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientCertificate $ClientCertificate -ErrorAction Stop
To this:
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientSecret $Secret -ErrorAction Stop
0 meetings retrieved from 'WE Conference Room 1'
ReplyDeleteUnable to query Graph API: 'The remote server returned an error: (400) Bad Request.'. The mailbox could be inactive, soft-deleted, or hosted on-premise
s.
This is what i am getting for all Conference Rooms any idea what the request is ??
Hi. Is that meeting room in Exchange Online? Does it work for other meeting rooms? Try printing the value of $uri at the start of the Query-GraphAPI function.
DeleteCan you help with this error I am getting what result is it looking for??
ReplyDeleteUnable to get OAuth token using MSAL: 'Exception calling "GetResult" with "0" argument(s): "Invalid provider type specified."'. Exiting script.
Which version of PowerShell are you using? Are you able to "manually" (outside of the script) use the MSAL module to retrieve a token?
DeleteI am getting this error see below I am using ,net 4.8 a self signed cert and have change the cert to a RSA cert instead of CNG still same error any help would be appreciated
ReplyDeleteUnable to get OAuth token using MSAL: 'Could not use the certificate for signing. See inner exception for details. Possible cause: this may be a known issue with apps build against .NET Desktop 4.6 or lower. Either target a higher version of .NET desktop - 4.6.1 and above, or use a different certificate type (non-CNG) or sign your own assertion as described at https://aka.ms/msal-net-signed-assertion. '. Exiting script.
Unable to get OAuth token using MSAL: 'Cannot process argument transformation on parameter 'ClientSecret'. Cannot convert the "#########" value of type "System.String" to type "System.Security.SecureString".'. Exiting script. After chaning the certthumprint to Secret. Can you please suggest.
ReplyDeleteCan you show me your code please?
DeleteI wanted to let you know that your script saved me a bunch of time. Thank you very much for taking the time to create such a useful script.
ReplyDeleteGlad to hear it helped! :) Thank you for the feedback!!
DeleteWhat do i need to modify to use a Client Secret instead of a certificate?
ReplyDeleteYou can use something like:
DeleteGet-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientSecret (ConvertTo-SecureString $Secret -AsPlainText -Force)
Unable to get OAuth token using MSAL: 'Cannot process argument transformation on parameter 'ClientSecret'. Cannot convert the xxxxxxxxxxxxxxxx value of type "System.String" to type "System.Security.SecureString".'. Exiting script. - Getting the same error as above - Happy to share code
ReplyDeletePlease try updating your code to: "-ClientSecret (ConvertTo-SecureString $Secret -AsPlainText -Force)"
DeleteUnable to get OAuth token using MSAL: 'Cannot process argument transformation on parameter 'ClientSecret'. Cannot convert the "clientsecret" value of type "System.String" to type "System.Security.SecureString".'. Exiting script. I am using following To this:
ReplyDelete$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientSecret $Secret -ErrorAction Stop
Please try updating your code to: "-ClientSecret (ConvertTo-SecureString $Secret -AsPlainText -Force)"
DeleteI cannot get Certificate to work (Or can you please provide exact steps ?).... In any case i have decided to use Client Secret you posted in one of the comments earlier and it gives me above errror (Unable to get OAuth token using MSAL: 'Cannot process argument transformation on parameter 'ClientSecret'. Cannot convert the "MyClientSecret" value of type "System.String" to type "System.Security.SecureString".'. Exiting script.)
ReplyDeletePlease try updating your code to: "-ClientSecret (ConvertTo-SecureString $Secret -AsPlainText -Force)"
DeleteHello Nuno - thanks so much for such an awesome script.
ReplyDeleteTrying to get it working with a Client Secret and here's what I've done so far.
1) Created an app registration, assigning it the appropriate permissions.
2) Downloaded the script and inputted the $ClientID and $TenantID.
3) Changed Certthumprint to $Secret everywhere.
4) Removed this line $ClientCertificate = Get-Item "Cert:\CurrentUser\My\$Secret"
5) Updated this line:
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientCertificate $ClientCertificate -ErrorAction Stop
To this:
$token = Get-MsalToken -ClientId $ClientID -TenantId $TenantID -ClientSecret $Secret -ErrorAction Stop
6. The error i get is :
Unable to get OAuth token using MSAL: 'Cannot process argument transformation on parameter 'ClientSecret'. Cannot convert the "--my--secret--value" value of type "System.String" to type "System.Security.SecureString".'. Exiting script.
Are you able to advise how this is possible to use a Secret instead of a Certificate please. Thanks a lot - you're a scripting hero.
Thank you! :)
DeleteTry updating your code to: "-ClientSecret (ConvertTo-SecureString $Secret -AsPlainText -Force)"
Great script! Just what i was looking for. I switched to use client secret, but nothing else changed.
ReplyDeleteThank you for the feedback! :)
DeleteGood one!
ReplyDeleteThank you! :)
Delete