function Invoke-DattoProvision { param ( [Parameter(Mandatory)] [string]$CompanyName, [Parameter(Mandatory)] [hashtable]$Credentials ) if (-not $Credentials["DattoURL"] -or -not $Credentials["DattoKey"] -or -not $Credentials["DattoSecret"]) { throw "Missing Datto RMM credentials in hashtable." } $TokenUrl = "$($Credentials["DattoURL"].TrimEnd('/'))/auth/oauth/token" $SiteUrl = "$($Credentials["DattoURL"].TrimEnd('/'))/api/v2/site" $TokenBody = @{ grant_type = "password" username = $Credentials["DattoKey"] password = $Credentials["DattoSecret"] } $TokenHeaders = @{ "Content-Type" = "application/x-www-form-urlencoded" "Accept" = "application/json" } try { # Construct Basic Auth manually $pair = "public-client:public" $bytes = [System.Text.Encoding]::UTF8.GetBytes($pair) $base64 = [System.Convert]::ToBase64String($bytes) $TokenHeaders["Authorization"] = "Basic $base64" $TokenResponse = Invoke-RestMethod -Uri $TokenUrl -Method Post -Headers $TokenHeaders -Body $TokenBody $AccessToken = $TokenResponse.access_token } catch { throw "[Datto] Token request failed: $($_.Exception.Message)" } $SiteHeaders = @{ "Authorization" = "Bearer $AccessToken" "Content-Type" = "application/json" "Accept" = "application/json" } $SiteBody = @{ name = $CompanyName } | ConvertTo-Json -Depth 3 try { $SiteResponse = Invoke-RestMethod -Uri $SiteUrl -Method Put -Headers $SiteHeaders -Body $SiteBody [System.Windows.MessageBox]::Show("Datto RMM site created: $CompanyName", "Datto RMM") } catch { throw "[Datto] Site creation failed: $($_.Exception.Message)" } }