Automation, automation, automation!
Why should you manually set up dozens of groups, policies and other settings when it could be automated?
To automate our Intune setup, Microsoft Graph API is the answer.
And since most of us aren’t developers, we stick to PowerShell as our script language of choice.
You find the reference for this API on
https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0 , but my experience is that it takes a lot of trial and error to figure out the correct syntax and at the moment the API reference are missing some real world examples.
In this post I will share my functions with you.
Some of them are based on the Microsoft Graph API and Intune Powershell samples found at https://github.com/microsoftgraph/powershell-intune-samples
You could also take a look at the PowerShell Module Microsoft.Graph.Intune for easier authentication and more functions added every month.
Authentication
We have to send an auth token with every REST request we send to MS Graph API
This is how you can authenticate to get this auth token:
function Get-AuthToken {
<#
Authentication against Intune tenant
#>
[cmdletbinding()]
param
(
[Parameter(Mandatory=$true)]
$User
)
$userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User
$tenant = $userUpn.Host
Write-Host "Looking for AzureAD module..."
$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if ($AadModule -eq $null) {
Write-Host "AzureAD PowerShell was not found - looking for AzureADPreview"
$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
}
if ($AadModule -eq $null) {
write-host
write-host "AzureAD Powershell module not installed..." -f Red
write-host "Install with 'Install-Module AzureAD' or 'Install-Module AzureADPreview' fra en elevert PowerShell-prompt" -f Yellow
write-host "Script cannot continue..." -f Red
write-host
exit
}
# Getting path to ActiveDirectory Assemblies
# If the module count is greater than 1 find the latest version
if($AadModule.count -gt 1){
$Latest_Version = ($AadModule | select version | Sort-Object)[-1]
$aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
# Checking if there are multiple versions of the same module found
if($AadModule.count -gt 1){
$aadModule = $AadModule | select -Unique
}
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
else {
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$Tenant"
try {
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx
# Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result
# If the accesstoken is valid then create the authentication header
if($authResult.AccessToken){
# Creating header for Authorization token
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $authResult.AccessToken
'ExpiresOn'=$authResult.ExpiresOn
}
return $authHeader
}
else {
Write-Host
Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red
Write-Host
break
}
}
catch {
write-host $_.Exception.Message -f Red
write-host $_.Exception.ItemName -f Red
write-host
break
}
}
write-host
# Checking if authToken exists before running authentication
if($global:authToken){
# Setting DateTime to Universal time to work in all timezones
$DateTime = (Get-Date).ToUniversalTime()
# If the authToken exists checking when it expires
$TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes
if($TokenExpires -le 0){
write-host "Authentication Token expired" $TokenExpires "minutes ago" -ForegroundColor Yellow
write-host
# Defining User Principal Name if not present
if($User -eq $null -or $User -eq ""){
$User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication"
Write-Host
}
$global:authToken = Get-AuthToken -User $User
}
}
# Authentication doesn't exist, calling Get-AuthToken function
else {
if($User -eq $null -or $User -eq ""){
$User = Read-Host -Prompt "Login name for Azure AD"
Write-Host
}
# Getting the authorization token
$global:authToken = Get-AuthToken -User $User
}
Test JSON
Because we are going to use a lot of JSON, let us make a function to check our JSON syntax
Function Test-JSON(){
<#
Testing if JSON syntax is correct
#>
param (
$JSON
)
try {
$TestJSON = ConvertFrom-Json $JSON -ErrorAction Stop
$validJson = $true
}
catch {
$validJson = $false
$_.Exception
}
if (!$validJson){
Write-Host "Wrong format in JSON" -f Red
break
}
}
Set Intune as MDM authority
We start our configuration by setting Intune as our MDM authority.
For this we create two functions that we use together, one to find our AzureAD Oranization ID and one to set Intune as MDM autohority
Usage: Update-MDMAuth -OrgID Get-OrgID
Function Get-OrgID(){
<#
Finds Organization ID
#>
[cmdletbinding()]
$graphApiVersion = "v1.0"
$emptybody = @"
{
}
"@
try {
$Resource = "organization"
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
$GroupsResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).value
$OrgID = $GroupsResponse.id
return $OrgID
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Function Update-MDMAuth(){
<#
Sets Mobile Device Device Management Authority to Intune
#>
[cmdletbinding()]
param
(
$OrgID
)
$graphApiVersion = "v1.0"
$Resource = "/organization/$OrgID/setMobileDeviceManagementAuthority"
$JSON = @"
{
}
"@
try {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
}
}
Creating groups
Let us create some groups to use with our Intune policies
We create variables with JSON and then use the command
Add-Group -JSON $JSONvariablehere
JSON variable:
$JSON_Group_Group1 = @"
{
"description": "Group for Intune",
"displayName": "Group1",
"mailEnabled": false,
"mailNickname": "Group1",
"securityEnabled": true
}
"@
Function to create groups:
Function Add-Group(){
<#
Adding group
#>
[cmdletbinding()]
param
(
$JSON
)
$graphApiVersion = "v1.0"
$Resource = "groups"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "No JSON specified..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Branding
Let us add some branding.
Like with the groups we add the information in JSON and then run our function to import the settings.
Set-IntuneBrand -JSON $JSON_Branding
JSON:
$JSON_Branding = @"
{
"intuneBrand":{
"displayName": "Contoso Inc",
"contactITName": "Contoso helpdesk",
"contactITPhoneNumber": "+1555555555",
"contactITEmailAddress": "helpdesk@contoso.com",
"contactITNotes": "",
"privacyUrl": "http://contoso.com/privacy",
"onlineSupportSiteUrl": "http://contoso.com/support/",
"onlineSupportSiteName": "Contoso Helpdesk",
"themeColor": {"r":0,"g":0,"b":255},
"showLogo": true,
"showNameNextToLogo": true,
"@odata.type":"#microsoft.management.services.api.intuneBrand"
}
}
"@
Function to add branding:
Function Set-IntuneBrand(){
[cmdletbinding()]
param
(
$JSON
)
$graphApiVersion = "v1.0"
$App_resource = "deviceManagement"
try {
if(!$JSON){
write-host "No JSON was passed to the function, provide a JSON variable" -f Red
break
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($App_resource)"
Invoke-RestMethod -Uri $uri -Method Patch -ContentType "application/json" -Body $JSON -Headers $authToken
}
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Windows Hello configuration
Let us do the configuration of Windows Hello from Enrollment Settings in Intune. By now, you now the drill. Create JSON, import via Microsoft Graph API
Usage: Update-deviceEnrollmentConfiguration -JSON $JSON_Enrollment_Hello -EnConfDesc “This is the default Windows Hello for Business configuration applied with the lowest priority to all users regardless of group membership.”
$JSON_Enrollment_Hello = @"
{
"@odata.type": "#microsoft.graph.deviceEnrollmentWindowsHelloForBusinessConfiguration",
"pinMinimumLength": 4,
"pinMaximumLength": 127,
"pinUppercaseCharactersUsage": "disallowed",
"pinLowercaseCharactersUsage": "disallowed",
"pinSpecialCharactersUsage": "disallowed",
"state": "enabled",
"securityDeviceRequired": false,
"unlockWithBiometricsEnabled": true,
"remotePassportEnabled": true,
"pinPreviousBlockCount": 0,
"pinExpirationInDays": 0,
"enhancedBiometricsState": "notConfigured"
}
"@
Function Update-deviceEnrollmentConfiguration(){
<#
Update an Enrollment Configuration
#>
[cmdletbinding()]
param
(
$JSON,
$EnConfDesc
)
$ConfID = Get-EnrollmentConfID -Desc "$EnConfDesc"
$Resource = "deviceManagement/deviceEnrollmentConfigurations/$ConfID"
$graphApiVersion = "v1.0"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "Ingen JSON spesifisert..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Patch -Body $JSON -ContentType "application/json"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Notifications for Compliance Policy
We create an email template to be added to our compliance policies later.
The template are created in, you guessed it, JSON! We add it with three functions.
Add-Notification -JSON $JSON_Notification_Compliance
$NotificationID = Get-NotificationID -NotificationName “Notification”
Add-NotificationMessage -JSON $JSON_Notification_Compliance_en -NotificationID $NotificationID
$JSON_Notification_Compliance = @"
{
"displayName": "Notification",
"brandingOptions": "includeCompanyLogo, includeCompanyName"
}
"@
$JSON_Notification_Compliance_no = @"
{
"locale": "en-us",
"subject": "Regarding your mobile device",
"messageTemplate": "One of your mobile devices are not in compliance and you will be blocked from accessing company reources in 24 hours.
"
}
"@
Function Add-Notification(){
<#
Adding template for notifications. Add multiple languages with Get-NotificationId og Add-NotificationMessage
#>
[cmdletbinding()]
param
(
$JSON
)
$graphApiVersion = "v1.0"
$Resource = "deviceManagement/notificationMessageTemplates"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "Ingen JSON spesifisert..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
$body = [System.Text.Encoding]::UTF8.GetBytes($JSON);
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $body -ContentType "application/json; charset=utf-8"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
####################################################
Function Get-NotificationID(){
<#
Finds Notification ID
#>
[cmdletbinding()]
param
(
$NotificationName
)
$graphApiVersion = "v1.0"
$emptybody = @"
{
}
"@
try {
$Resource = "deviceManagement/notificationMessageTemplates?`$filter=displayName+eq+'$NotificationName'"
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
$NotificationsResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).value
$NotificationID = $NotificationsResponse.id
return $NotificationID
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
####################################################
Function Add-NotificationMessage(){
<#
Adding template. Could be added in multiple languages
#>
[cmdletbinding()]
param
(
$JSON,
$NotificationID
)
$graphApiVersion = "v1.0"
$Resource = "deviceManagement/notificationMessageTemplates/$NotificationID/localizedNotificationMessages"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "No JSON specified..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Creting compliance policies
Next up, we have a tricky one, compliance policies.
To get the JSON (our now dear friend) correct for this one, I suggest setting the policies via GUI and then run GET https://graph.microsoft.com/v1.0/deviceManagement/deviceCompliancePolicies via Graph Explorer, your best friend while working with this API
For every platform you need JSON like this (if someone know how to add the notification email action together with the noncompliant action, please leave a comment):
$JSON_CompliancePolicy_Android = @"
{
"@odata.type": "microsoft.graph.androidCompliancePolicy",
"displayName": "Android",
"passwordRequired": true,
"passwordMinimumLength": 6,
"passwordRequiredType": "numericComplex",
"passwordMinutesOfInactivityBeforeLock": 10,
"storageRequireEncryption": true,
"scheduledActionsForRule":[{"ruleName":"Mark device noncompliaant","scheduledActionConfigurations":[{"actionType":"block","gracePeriodHours":72,"notificationTemplateId":""}]}]
}
"@
We then add the policies with the following function.
Usage: Add-DeviceCompliancePolicy -JSON $JSON_CompliancePolicy_Android -graphApiVersion “v1.0”
Function Add-DeviceCompliancePolicy(){
<#
Adding a Device Policy
#>
[cmdletbinding()]
param
(
$JSON,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceCompliancePolicies"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "No JSON specified..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Assign compliance policy to group
We then assign the policy to a group with this three functions.
Get-GroupID to find the ID of a group by its name, Get-DeviceCompliancePolicyID to find the ID of the policy by name and at last Add-DeviceCompliancePolicyAssignment to bring it together.
You use them like this:
$GroupID = Get-GroupID -GroupName “Group1”
$PolicyID = Get-DeviceCompliancePolicyID -Name “Android”
Add-DeviceCompliancePolicyAssignment -CompliancePolicyId $PolicyID -TargetGroupId $GroupID
Function Get-GroupID(){
<#
Finner Objekt-ID på gruppe
#>
[cmdletbinding()]
param
(
$GroupName
)
$graphApiVersion = "v1.0"
$emptybody = @"
{
}
"@
try {
if($GroupName -eq "" -or $GroupName -eq $null){
write-host "Ingen gruppenavn spesifisert..." -f Red
}
else {
$Resource = "groups?`$filter=displayName+eq+'$GroupName'"
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
$GroupsResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).value
$GroupID = $GroupsResponse.id
return $GroupID
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Function Get-DeviceCompliancePolicyID(){
<#
Finner ID på DeviceCompliancePolicy
#>
[cmdletbinding()]
param
(
$Name,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceCompliancePolicies"
try {
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)?`$filter=displayName+eq+'$Name'"
$CompliancePolicyResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).value
$CompliancePolicyID = $CompliancePolicyResponse.id
return $CompliancePolicyID
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Function Add-DeviceCompliancePolicyAssignment(){
[cmdletbinding()]
param
(
$CompliancePolicyId,
$TargetGroupId,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceCompliancePolicies/$CompliancePolicyId/assign"
try {
if(!$CompliancePolicyId){
write-host "Ingen Compliance Policy Id spesifisert" -f Red
break
}
if(!$TargetGroupId){
write-host "Ingen gruppe-Id spesifisert" -f Red
break
}
$JSON = @"
{
"assignments": [
{
"@odata.type": "#microsoft.graph.deviceCompliancePolicyAssignment",
"target": {
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
"groupId": "$groupid"
}}
]
}
"@
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Adding configuration policies
The same thing here as compliance policies. Use Graph Explorer to find the correct JSON like:
$JSON_DevConf_MacOS = @"
{
"@odata.type": "#microsoft.graph.macOSGeneralDeviceConfiguration",
"description": "",
"displayName": "Device restriction - macOS",
"passwordBlockSimple": true,
"passwordExpirationDays": 60,
"passwordMinimumCharacterSetCount": 1,
"passwordMinimumLength": 8,
"passwordMinutesOfInactivityBeforeLock": 15,
"passwordMinutesOfInactivityBeforeScreenTimeout": 10,
"passwordPreviousPasswordBlockCount": 5,
"passwordRequiredType": "alphanumeric",
"passwordRequired": true
}
"@
You can also use this for Windows Update policy:
$JSON_DevConf_UpdateForBusiness = @"
{
"@odata.type": "#microsoft.graph.windowsUpdateForBusinessConfiguration",
"description": "",
"displayName": "Windows 10 update rings",
"deliveryOptimizationMode": "httpWithPeeringNat",
"prereleaseFeatures": "userDefined",
"automaticUpdateMode": "autoInstallAtMaintenanceTime",
"microsoftUpdateServiceAllowed": true,
"driversExcluded": false,
"installationSchedule": {
"@odata.type": "#microsoft.graph.windowsUpdateActiveHoursInstall",
"activeHoursStart": "07:00:00.0000000",
"activeHoursEnd": "20:00:00.0000000"
},
"qualityUpdatesDeferralPeriodInDays": 5,
"featureUpdatesDeferralPeriodInDays": 30,
"qualityUpdatesPaused": false,
"featureUpdatesPaused": false,
"qualityUpdatesPauseExpiryDateTime": "0001-01-01T00:00:00Z",
"featureUpdatesPauseExpiryDateTime": "0001-01-01T00:00:00Z",
"businessReadyUpdatesOnly": "businessReadyOnly"
}
"@
We then add it to Intune with this function.
Add-DeviceConfiguration -JSON $JSON_DevConf_UpdateForBusiness
Function Add-DeviceConfiguration(){
<#
Adding a Device Configuration
#>
[cmdletbinding()]
param
(
$JSON,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceConfigurations"
try {
if($JSON -eq "" -or $JSON -eq $null){
write-host "Ingen JSON spesifisert..." -f Red
}
else {
Test-JSON -JSON $JSON
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
}
catch {
Write-Host
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Assign configuration policy to group
Again we run our Get-GroupID function to get the ID of a group by name.
We then run a function to get the configuration policy ID by name and use the two to assign the policy to a group in the last PowerShell function in this post.
$GroupID = Get-GroupID -GroupName “Group1”
$PolicyID = Get-DeviceConfigurationID -Name “Android”
Add-DeviceConfigurationPolicyAssignment -ConfigurationPolicyId $PolicyID -TargetGroupId $GroupID
Function Get-DeviceConfigurationID(){
<#
Finner ID på DeviceConfigurationPolicy
#>
[cmdletbinding()]
param
(
$Name,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceConfigurations"
try {
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)?`$filter=displayName+eq+'$Name'"
$ConfigurationPolicyResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).value
$ConfigurationPolicyID = $ConfigurationPolicyResponse.id
return $ConfigurationPolicyID
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
Function Add-DeviceConfigurationPolicyAssignment(){
<#
Assigner DeviceConfiguration til gruppe
#>
[cmdletbinding()]
param
(
$ConfigurationPolicyId,
$TargetGroupId,
$graphApiVersion = "v1.0"
)
$Resource = "deviceManagement/deviceConfigurations/$ConfigurationPolicyId/assignments"
try {
if(!$ConfigurationPolicyId){
write-host "Ingen Configuration Policy Id spesifiert" -f Red
break
}
if(!$TargetGroupId){
write-host "Ingen gruppe-Id spesifisert" -f Red
break
}
$JSON = @"
{
"@odata.type": "#microsoft.graph.deviceConfigurationAssignment",
"target": {
"@odata.type": "#microsoft.graph.groupAssignmentTarget",
"groupId": "$TargetGroupId"
}}
"@
$uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json"
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
This concludes this first step into the world of Graph API and Intune.
Leave A Comment