Bookings, GraphAPI, Powershell

Microsoft Bookings API how to

When it comes to Microsoft Bookings and automation the documentation about API can be found here, there is also a PowerShell module, at first I didn’t know how to connect to Bookings API and I’ve created a booking mailbox with Exchange Online PowerShell with New-SchedulingMailbox BUT! do not do it.

This New-SchedulingMailbox is not a good way to create it – later I had some issues when I was trying to do changes on the booking resource using API, see here and here.

Ther code to connect to the API is:

$TenantID       = "<tenant>"
$AccountName    = ""
$Password       = '<bookingautomationpassword>'
$ClientId       = "XXXXXXX-XXX-XXX-XXX-XXXXXXXXXXXXX" # "Booking-GraphAPI" application ID</bookingautomationpassword></tenant>

# Constants - Endpoints
$AzureResourceURI = "$($tenantID)/oauth2/token"
$ResourceID  = ""

# Construct the Body for the POST
$Body = "grant_type=password"`
         +"&amp;username=" +$Accountname `
         +"&amp;client_id=" +$clientId `
         +"&amp;password=" +$Password `
         +"&amp;resource=" +[system.uri]::EscapeDataString($ResourceID)

Write-Host "Getting the authorization token"

# The result should contain a token for use with Graph
$Response = Invoke-WebRequest -Uri $AzureResourceURI -Method POST -Body $Body
$ResponseJSON = $Response|ConvertFrom-Json

After connectig you can use this to create a Booking with PowerShell module:

$NewBookingParams = @{
    DisplayName = "FirstBooking"
    BusinessType = "IT Services"
    WebSiteUrl = ""
    SchedulingPolicy = @{
        AllowStaffSelection = $false
        MaximumAdvance = "P30D"
        MinimumLeadTime = "P1D"
$NewBooking = New-MgBookingBusiness @NewBookingParams

Adding users is easy, so I will just share a way I am creating a service:

$NewServiceParams = @{
    BookingBusinessId = $PrimarySmtpAddress
    DefaultDuration = "00:15:00" # 15 minutes duration
    IsLocationOnline = $true
    MaximumAttendeesCount = 10
    StaffMemberIds = $StaffMemberId #A staff member ID to be assigned to the service
    DisplayName = "15 min call"
    DefaultReminders = @{
        Message = "Just a quick reminder that your service is comming up soon."
        Offset = "P1D"
        #0 - All recipients, 2 - Customer, 1 - Staff
        Recipients = "2"

New-MgBookingBusinessService @NewServiceParams

API, Powershell

Managing Kiuwan users through API with PowerShell

If you have Kiuwan with enabled SAML, and you manage access to the enterprise app using groups – this script is for you.

With this script running from time to time (in my case it is every 15 minutes) after a user manager in Kiuwan adds a user – user is added to the relevant group in Active Directory. If user is removed – then certain user is removed from the Active Directory group.

The script can be found here, the key part is this:

$USER = "Kiuwan_API_User"

# PUT USER PASSWORD HERE &amp;lt;&amp;lt;
$password = 'PutPasswordHere'

$HeaderAuth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $USER, $password)))
$SessionHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$SessionHeader.Add('Authorization',('Basic {0}' -f $HeaderAuth))

# PUT KIUWAN ID HERE &amp;lt;&amp;lt;

$URL = ""
$APIResponse = Invoke-RestMethod -Method Get -Uri $URL -Headers  $Sessionheader -Verbose -TimeoutSec 33

More about Kiuwan’s API can be found here

And here is a good video showing it’s capabilities can be found here:


Monitor hosts ip address change in ZABBIX.

Do not know why decided to implement that so late. Anyway this is how i’ve done it.

Created ZBX external item:

The itself script looks like this:

pawelski@ZbxServer:/usr/lib/zabbix/externalscripts$ tail
ping $1 -c 1 | sed -nE ‘s/^PING[^(]+\(([^)]+)\).*/\1/p’

Also, please note that the script – in case the host is not responding will reply with something like:

ping: host blabla unavailable

I do not want that garage in ZABBIX, plus it can really mess up the triggers.

Let’s imagine host replies on IP, later item has value “ping: blabla is not supported”. – what will happen if we apply trigger on this and set it to alert us when the value will change? – many unnecessary alerts, as the IP might not change, but the value of the trigger for sure will, first from “” to “ping: blabla” and later back to “”.

I want this sort of values to convert the item in the unsupported state, hence I add pre-processing:

The Parameters value is: \D*\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D*\s*

And that is it. We will get IPs of our hosts, and when thehost is unavailable it return unsupported item – no garbage in the latest data. Now we can create a trigger on the item to monitor change of the latest value.

Have you already done it in a different way, or maybe you see some potential issues in this solution? If yes please give me a shout, I’m more than happy to discuss it.

Exchange Online, Powershell

New-ComplianceSearch BUG – ExchangeLocation gets cleared.

Just creating some script for GDPR email removal mechanism, and noticed one interesting thing – already reported this bug to MS.

Last time when I got issue about Compliance Searches it was that when telling it to “purge” the messages it was not really purging the messages – I flagged that you need to use Search-Maibox to actually do it – case was submitted to MS and they changed the documentation.

There is something more – when creating a compliance search and assigning it to the case I noticed that when triggering a command the ExchangeLocation was…empty. It wouldn’t be weird but I explicitly told  I want to have “all” there.

Continue reading

Exchange Online

Get-InboxRule and “You may need elevated permissions. isn’t within your current write scopes. Can’t perform save operation.”

Reminder – for myself as well.

When granting permissions for the role group to get the inbox rules (Get-InboxRule), do not copy role from “View-Only Recipients” or anything else that has:

Get-ManagementRole “” | fl

ImplicitRecipientWriteScope : None

Otherwise, even you if you’ve left the Role Group in the default scope you will get an error.

Exchange 2016, Exchange Online, Powershell

“Mailbox size exceeds target quota 2.3 GB” when moving the mailbox between databases / servers.

When receiving such error please check you quota on mailboxdatabase:

[PS] D:\Exchange Server\V15\Bin&gt;Get-MailboxDatabase | fl

RunspaceId : 5aa6941c-eadf-4c8e-b9fb-8163b7426622
JournalRecipient :
MailboxRetention : 30.00:00:00
OfflineAddressBook :
OriginalDatabase :
PublicFolderDatabase :
ProhibitSendReceiveQuota : <strong>2.3 GB</strong> (2,469,396,480 bytes)
ProhibitSendQuota : 2 GB (2,147,483,648 bytes)
RecoverableItemsQuota : 30 GB (32,212,254,720 bytes)
RecoverableItemsWarningQuota : 20 GB (21,474,836,480 bytes)

Set it up ou to your needs, in my case this database will be hosted only to export mailboxes to PST files:

 Get-MailboxDatabase WROMR0-DB001 | Set-MailboxDatabase -ProhibitSendReceiveQuota 120GB -ProhibitSendQuota 120GB 
Exchange 2016, Powershell

Exchange 2016, owa/auth.owa and error 500 on ECP.

I was receiving error 500 and website was landing on owa/auth.owa on my Exchange 2016 server.

Interesting thing was – that happened to all admins but me  – who installed the server.

I found this blog post:

I’ve done all the steps, I ran UpdateCas.ps1 – that didn’t help, so I ran multiple commands that Alexander proposed – unfortunately that didn’t help out as well, additionally now I was getting popup asking me for to log in instead of nice Exchange website.

So I thought at least I will get back to the settings I had – removed Windows authentication and enabled form based authentication on ECP and OWA virtual directories, so basically I went back to previous settings:

Get-owaVirtualDirectory "\owa (Default Web Site)" | Set-owaVirtualDirectory -FormsAuthentication $true -BasicAuthentication $true -WindowsAuthentication $false

Get-ecpVirtualDirectory "\owa (Default Web Site)" | Set-ecpVirtualDirectory -FormsAuthentication $true -BasicAuthentication $true -WindowsAuthentication $false

Done iisreset, and once again wanted to see my error, I refreshed the page on the test user I made aaaaaaannndd… it was all working well.

A mystery…


Powershell, ZABBIX

Get pending windows updates status on ZABBIX using custom LLD (Low Level Discovery) and PowerShell

Just recently I got some time, and was rethinking the solution of reading windows updates.

At the beginning I thought I will use PowerShell to get update list and later use dependent items to parse the script output, but this wouldn’t be so nice, as I would need to manually work on parsing the file on the zabbix side, create items etc. + so far zabbix does not offer (I work on 3.4, at the time being 4.0 available) LLD on dependent items.

Well, why not use current LLD to read them?


You can do it – I will show you how.

Continue reading


Low Level Discovery (LLD) for PostgreSQL on ZABBIX using ODBC.

How about ZABBIX PostgreSQL monitoring with LLD without custom addons installed on the server or milions of very heavy userparameter? 🙂

I’ve been searching for some way to monitor PostgreSQL database, all the solution I’ve found were based either on some custom addon:

Or had tooooonnns of userparameters that were just killing the server:


Well I though there is a better way, and you know what? I think there is.

Continue reading