mirror of
https://github.com/Gerenios/AADInternals
synced 2026-06-08 11:09:38 +00:00
496 lines
16 KiB
PowerShell
496 lines
16 KiB
PowerShell
# This script contains utility functions for provisioning API at https://provisioning.microsoftonline.com
|
|
# Office 365 / Azure AD v1, a.k.a. MSOnline module uses this API
|
|
|
|
# Azure AD Roles
|
|
$AADRoles=@{
|
|
"Helpdesk Administrator"= "729827e3-9c14-49f7-bb1b-9608f156bbb8"
|
|
"Service Support Administrator"= "f023fd81-a637-4b56-95fd-791ac0226033"
|
|
"Billing Administrator"= "b0f54661-2d74-4c50-afa3-1ec803f12efe"
|
|
"Partner Tier1 Support"= "4ba39ca4-527c-499a-b93d-d9b492c50246"
|
|
"Partner Tier2 Support"= "e00e864a-17c5-4a4b-9c06-f5b95a8d5bd8"
|
|
"Directory Readers"= "88d8e3e3-8f55-4a1e-953a-9b9898b8876b"
|
|
"Exchange Service Administrator"= "29232cdf-9323-42fd-ade2-1d097af3e4de"
|
|
"Lync Service Administrator"= "75941009-915a-4869-abe7-691bff18279e"
|
|
"User Account Administrator"= "fe930be7-5e62-47db-91af-98c3a49a38b1"
|
|
"Directory Writers"= "9360feb5-f418-4baa-8175-e2a00bac4301"
|
|
"Company Administrator"= "62e90394-69f5-4237-9190-012177145e10"
|
|
"SharePoint Service Administrator"= "f28a1f50-f6e7-4571-818b-6a12f2af6b6c"
|
|
"Device Users"= "d405c6df-0af8-4e3b-95e4-4d06e542189e"
|
|
"Device Administrators"= "9f06204d-73c1-4d4c-880a-6edb90606fd8"
|
|
"Device Join"= "9c094953-4995-41c8-84c8-3ebb9b32c93f"
|
|
"Workplace Device Join"= "c34f683f-4d5a-4403-affd-6615e00e3a7f"
|
|
"Compliance Administrator"= "17315797-102d-40b4-93e0-432062caca18"
|
|
"Directory Synchronization Accounts"= "d29b2b05-8046-44ba-8758-1e26182fcf32"
|
|
"Device Managers"= "2b499bcd-da44-4968-8aec-78e1674fa64d"
|
|
"Application Administrator"= "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3"
|
|
"Application Developer"= "cf1c38e5-3621-4004-a7cb-879624dced7c"
|
|
"Security Reader"= "5d6b6bb7-de71-4623-b4af-96380a352509"
|
|
"Security Administrator"= "194ae4cb-b126-40b2-bd5b-6091b380977d"
|
|
"Privileged Role Administrator"= "e8611ab8-c189-46e8-94e1-60213ab1f814"
|
|
"Intune Service Administrator"= "3a2c62db-5318-420d-8d74-23affee5d9d5"
|
|
"Cloud Application Administrator"= "158c047a-c907-4556-b7ef-446551a6b5f7"
|
|
"Customer LockBox Access Approver"= "5c4f9dcd-47dc-4cf7-8c9a-9e4207cbfc91"
|
|
"CRM Service Administrator"= "44367163-eba1-44c3-98af-f5787879f96a"
|
|
"Power BI Service Administrator"= "a9ea8996-122f-4c74-9520-8edcd192826c"
|
|
"Guest Inviter"= "95e79109-95c0-4d8e-aee3-d01accf2d47b"
|
|
"Conditional Access Administrator"= "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9"
|
|
"Reports Reader"= "4a5d8f65-41da-4de4-8968-e035b65339cf"
|
|
"Message Center Reader"= "790c1fb9-7f7d-4f88-86a1-ef1f95c05c1b"
|
|
"Information Protection Administrator"= "7495fdc4-34c4-4d15-a289-98788ce399fd"
|
|
"License Administrator"= "4d6ac14f-3453-41d0-bef9-a3e0c569773a"
|
|
"Cloud Device Administrator"= "7698a772-787b-4ac8-901f-60d6b08affd2"
|
|
"Teams Communications Administrator"= "baf37b3a-610e-45da-9e62-d9d1e5e8914b"
|
|
"Teams Communications Support Engineer"= "f70938a0-fc10-4177-9e90-2178f8765737"
|
|
"Teams Communications Support Specialist"= "fcf91098-03e3-41a9-b5ba-6f0ec8188a12"
|
|
"Teams Service Administrator"= "69091246-20e8-4a56-aa4d-066075b2a7a8"
|
|
"Guest User"= "10dae51f-b6af-4016-8d66-8c2a99b929b3"
|
|
}
|
|
|
|
# Boolean to string
|
|
function b2s
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[bool]$Bool
|
|
)
|
|
Process
|
|
{
|
|
$Bool.ToString().ToLower()
|
|
}
|
|
}
|
|
|
|
# Create SOAP envelope
|
|
function Create-Envelope
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$AccessToken,
|
|
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Command,
|
|
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$RequestElements,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[String]$TenantId
|
|
)
|
|
Process
|
|
{
|
|
# Create the envelope
|
|
$message_id=(New-Guid).ToString()
|
|
$envelope=@"
|
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
|
|
<s:Header>
|
|
<a:Action s:mustUnderstand="1">http://provisioning.microsoftonline.com/IProvisioningWebService/$Command</a:Action>
|
|
<a:MessageID>urn:uuid:$message_id</a:MessageID>
|
|
<a:ReplyTo>
|
|
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
|
</a:ReplyTo>
|
|
<UserIdentityHeader xmlns="http://provisioning.microsoftonline.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
|
<BearerToken xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService">Bearer $AccessToken</BearerToken>
|
|
<LiveToken i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService"/>
|
|
</UserIdentityHeader>
|
|
<ClientVersionHeader xmlns="http://provisioning.microsoftonline.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
|
<ClientId xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService">50afce61-c917-435b-8c6d-60aa5a8b8aa7</ClientId>
|
|
<Version xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService">1.2.183.81</Version>
|
|
</ClientVersionHeader>
|
|
<ContractVersionHeader xmlns="http://becwebservice.microsoftonline.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
|
<BecVersion xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService">Version47</BecVersion>
|
|
</ContractVersionHeader>
|
|
<a:To s:mustUnderstand="1">https://provisioningapi.microsoftonline.com/provisioningwebservice.svc</a:To>
|
|
</s:Header>
|
|
<s:Body>
|
|
<$Command xmlns="http://provisioning.microsoftonline.com/">
|
|
<request xmlns:b="http://schemas.datacontract.org/2004/07/Microsoft.Online.Administration.WebService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
|
<b:BecVersion>Version16</b:BecVersion>
|
|
$(Add-BElement -Parameter "TenantId" -Value $TenantId)
|
|
<b:VerifiedDomain i:nil="true"/>
|
|
$RequestElements
|
|
</request>
|
|
</$Command>
|
|
</s:Body>
|
|
</s:Envelope>
|
|
"@
|
|
# Debug
|
|
Write-Debug "ENVELOPE ($Command): $envelope"
|
|
|
|
# Return
|
|
return $envelope
|
|
|
|
}
|
|
}
|
|
|
|
# Calls the provisioning SOAP API
|
|
function Call-ProvisioningAPI
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Envelope
|
|
)
|
|
Process
|
|
{
|
|
$Headers=@{
|
|
"User-Agent" = Get-UserAgent
|
|
}
|
|
|
|
# Call the API
|
|
Invoke-RestMethod -UseBasicParsing -Uri "https://provisioningapi.microsoftonline.com/provisioningwebservice.svc" -ContentType "application/soap+xml" -Method POST -Body $envelope -Headers $Headers
|
|
}
|
|
}
|
|
|
|
|
|
# Parses the response object(s) from SOAP message
|
|
function Parse-SOAPResponse
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
$Response
|
|
)
|
|
Process
|
|
{
|
|
# Check if empty
|
|
if(![string]::IsNullOrEmpty($Response))
|
|
{
|
|
# All good, try to parse the response object
|
|
$results=(Select-Xml -Xml $response -XPath "//*[local-name()='$($Command+"Result")']").Node
|
|
|
|
# Check if we got response
|
|
if([string]::IsNullOrEmpty($results))
|
|
{
|
|
# Got error
|
|
throw $Response.Envelope.Body.Fault.Reason.Text.'#text'
|
|
}
|
|
|
|
# Sometimes response message is empty
|
|
if($results.ReturnValue -ne $null)
|
|
{
|
|
(Remove-XMLNameSpace $results.ReturnValue).ReturnValue
|
|
}
|
|
else
|
|
{
|
|
return ""
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Empty, so throw an exception
|
|
throw "Null or empty Response"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Remove namespace from xml doc
|
|
function Remove-XMLNameSpace
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
$xmlDoc
|
|
)
|
|
Process
|
|
{
|
|
$xml=[System.Xml.Linq.XDocument]::Parse($xmlDoc.OuterXml)
|
|
|
|
$remove=@()
|
|
foreach ($XE in $xml.Descendants())
|
|
{
|
|
if($XE.Name.LocalName.Length -eq 1)
|
|
{
|
|
# Remove "c" etc. tags
|
|
$remove+=$XE
|
|
}
|
|
else
|
|
{
|
|
# Strip the namespace and attributes
|
|
$XE.Name = $XE.Name.LocalName
|
|
$XE.RemoveAttributes()
|
|
}
|
|
|
|
}
|
|
|
|
foreach($XE in $remove)
|
|
{
|
|
$XE.Remove()
|
|
}
|
|
|
|
return [xml]$xml.ToString()
|
|
}
|
|
}
|
|
|
|
# Parses the given ServiceInformation object from Get-CompanyInformation and returns as hashtable
|
|
# Aug 11th 2018
|
|
function Parse-ServiceInformation
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[System.Xml.XmlElement]$ServiceInformation
|
|
)
|
|
Process
|
|
{
|
|
# Set the return hastable
|
|
$retVal=@{}
|
|
|
|
# Loop through service information elements. There might be even more than these here.
|
|
|
|
foreach($service in $ServiceInformation.ServiceInformation)
|
|
{
|
|
$settings=$null
|
|
$instance = $service.ServiceInstance
|
|
$instance_name=$instance.Split("/")[0]
|
|
|
|
if($instance_name -ceq "sharepoint")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
}
|
|
elseif($instance_name -ceq "SharePoint")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
#$service.ServiceElements.XElement.ServiceExtension.DNSRecords.DNSRecord
|
|
}
|
|
elseif($instance_name -eq "RMSOnline")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.RmsCompanyServiceInfo.ServiceLocations.ServiceLocation
|
|
}
|
|
elseif($instance_name -eq "SCO")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.WindowsIntuneServiceInfo.ServiceParameters.ServiceParameter
|
|
$name = $service.ServiceElements.XElement.WindowsIntuneServiceInfo.ServiceParameters.ServiceParameter.Name
|
|
$value = $service.ServiceElements.XElement.WindowsIntuneServiceInfo.ServiceParameters.ServiceParameter.Value
|
|
if($name -ne $null)
|
|
{
|
|
$settings=@{$name = $value}
|
|
}
|
|
}
|
|
elseif($instance_name -ieq "YammerEnterprise")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
}
|
|
elseif($instance_name -ieq "ProjectWorkManagement")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.Topology
|
|
}
|
|
elseif($instance_name -ieq "Netbreeze")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
}
|
|
elseif($instance_name -ieq "DynamicsMarketing")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
}
|
|
elseif($instance_name -ieq "CRM")
|
|
{
|
|
$settings=$service.ServiceElements.XElement.ServiceExtension.ServiceParameters.ServiceParameter
|
|
}
|
|
$retVal[$instance]=$settings
|
|
|
|
|
|
}
|
|
|
|
$retval
|
|
}
|
|
}
|
|
|
|
|
|
# Get Sku and service name from SKU array
|
|
# Aug 12th 2018
|
|
function Get-SkuAndServiceName
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[psobject[]]$SKUs,
|
|
[Parameter(Mandatory=$True)]
|
|
[string]$ServicePlanId
|
|
)
|
|
Process
|
|
{
|
|
$attributes=@{}
|
|
foreach($sku in $SKUs)
|
|
{
|
|
$attributes["SkuName"]=$sku.SkuPartNumber
|
|
foreach($service in $sku.ServiceStatus)
|
|
{
|
|
if($service.ServicePlanId -eq $ServicePlanId)
|
|
{
|
|
$attributes["ServiceName"]=$service.ServiceName
|
|
$attributes["ServiceType"]=$service.ServiceType
|
|
$attributes["ProvisioningStatus"]=$service.ProvisioningStatus
|
|
|
|
return New-Object psobject -Property $attributes
|
|
}
|
|
}
|
|
}
|
|
# No matching SKU found so return $null
|
|
$null
|
|
}
|
|
}
|
|
|
|
|
|
# Creates a <namespace:parameter> -element
|
|
function Add-Element
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$False)]
|
|
[String]$NameSpace,
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Parameter,
|
|
[Parameter(Mandatory=$False)]
|
|
$Value
|
|
)
|
|
Process
|
|
{
|
|
|
|
if(![string]::IsNullOrEmpty($NameSpace))
|
|
{
|
|
$Parameter="$NameSpace`:$Parameter"
|
|
}
|
|
if([string]::IsNullOrEmpty($Value))
|
|
{
|
|
$element="<$Parameter i:nil=`"true`"/>"
|
|
|
|
}
|
|
else
|
|
{
|
|
if($Value -is [Boolean])
|
|
{
|
|
$Value=b2s -Bool $Value
|
|
}
|
|
$element="<$Parameter>$Value</$Parameter>"
|
|
}
|
|
|
|
$element
|
|
}
|
|
}
|
|
|
|
# Creates a <b:parameter> -element
|
|
function Add-BElement
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Parameter,
|
|
[Parameter(Mandatory=$False)]
|
|
$Value
|
|
)
|
|
Process
|
|
{
|
|
Add-Element -NameSpace "b" -Parameter $Parameter -Value $Value
|
|
}
|
|
}
|
|
|
|
# Creates a <c:parameter> -element
|
|
function Add-CElement
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Parameter,
|
|
[Parameter(Mandatory=$False)]
|
|
$Value
|
|
)
|
|
Process
|
|
{
|
|
Add-Element -NameSpace "c" -Parameter $Parameter -Value $Value
|
|
}
|
|
}
|
|
|
|
# Creates a <d:parameter> -element
|
|
function Add-DElement
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Parameter,
|
|
[Parameter(Mandatory=$False)]
|
|
$Value
|
|
)
|
|
Process
|
|
{
|
|
Add-Element -NameSpace "d" -Parameter $Parameter -Value $Value
|
|
}
|
|
}
|
|
|
|
# Converts xml to PSObject
|
|
function ConvertXmlTo-PSObject
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[System.Xml.XmlLinkedNode]$xml
|
|
)
|
|
Begin
|
|
{
|
|
$XMLProperties=@(
|
|
"InnerText"
|
|
"InnerXml"
|
|
"OuterXml"
|
|
"BaseURI"
|
|
"Prefix"
|
|
"NamespaceURI"
|
|
"Name"
|
|
"LocalName"
|
|
"Value"
|
|
"IsEmpty"
|
|
"HasAttributes"
|
|
"HasChildNodes"
|
|
"IsReadOnly"
|
|
"ChildNodes"
|
|
)
|
|
}
|
|
Process
|
|
{
|
|
$attributes=[ordered]@{}
|
|
|
|
foreach($property in $xml.PSObject.Properties)
|
|
{
|
|
if(!$XMLProperties.Contains($property.Name))
|
|
{
|
|
switch($property.TypeNameOfValue)
|
|
{
|
|
"System.String"
|
|
{
|
|
$attributes[$property.Name] = $property.Value
|
|
break
|
|
}
|
|
"System.Boolean"
|
|
{
|
|
$attributes[$property.Name] = $property.Value
|
|
break
|
|
}
|
|
"System.Object[]"
|
|
{
|
|
$values=@()
|
|
foreach($value in $property.Value)
|
|
{
|
|
$values += $value
|
|
}
|
|
$attributes[$property.Name] = $values
|
|
break
|
|
}
|
|
"System.Xml.XmlElement"
|
|
{
|
|
$values = ConvertXmlTo-PSObject -xml $property.Value
|
|
$attributes[$property.Name] = $values.PSObject.Properties.Value
|
|
break
|
|
}
|
|
"System.Xml.XmlNodeList"
|
|
{
|
|
$attributes[$property.Name] = $property.Value
|
|
break
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return New-Object psobject -Property $attributes
|
|
}
|
|
}
|