Category Archives: Intune

Deploying an embedded file (FONT) in a Powershell script through Intune MDM

Most solutions that describe how to deploy a font through Intune use an external source to host fonts such as Azure Blob storage.

If you want to KISS (keep it simple, stupid), you don’t want to maintain two different things (your script and externally accessible storage).

The following example shows how to embed a file in a PowerShell script, and then install it into the Fonts folder. This could, of course, be used for other purposes, but don’t forget that the script size limit in Intune is only 200kb.

First, execute the following in a PS window:

$inputFontPath = "C:\fonts\YourFont.ttf"
Compress-Archive $inputFontPath -CompressionLevel Optimal -DestinationPath (Join-Path $Env:TEMP -ChildPath "tempzipfontzipfile.zip") -Force
[Array]$bytes = [io.file]::ReadAllBytes((Join-Path $Env:TEMP -ChildPath "tempzipfontzipfile.zip"))
$b64 = [System.Convert]::ToBase64String($bytes)
$b64 | Set-Clipboard

You have now compressed and base64 encoded YourFont.ttf, and this is loaded in memory (clipboard).

Create a new file, e.g. YourFont.ps1 and add the following:

$b64 = "<SELECT EVERYTHING BETWEEN THESE QUOTES, THEN PRESS CTRL+V>"
$byteContent = [System.Convert]::FromBase64String($b64)
$byteContent | Set-Content (Join-Path $Env:TEMP -ChildPath "tempzipfontzipfile.zip") -Encoding Byte -Force
Expand-Archive -Path (Join-Path $Env:TEMP -ChildPath "tempzipfontzipfile.zip") -DestinationPath (Join-Path $Env:TEMP -ChildPath "tempfontsfolder") -Force

$sa =  new-object -comobject shell.application
$Fonts =  $sa.NameSpace(20)
gci (Join-Path $Env:TEMP -ChildPath "tempfontsfolder") | % {$Fonts.MoveHere($_.FullName)}

Remove-Item (Join-Path $Env:TEMP -ChildPath "tempzipfontzipfile.zip") -Force -ErrorAction SilentlyContinue
Remove-Item (Join-Path $Env:TEMP -ChildPath "tempfontsfolder") -Force -Recurse -ErrorAction SilentlyContinue

On the first line, follow the instructions (e.g. paste your b64-encoded font on that line). Now save and check if the size is below 200kb, then distribute the script to your users. For Fonts, don’t forget to let the script run in system context as administrative permissions are required when installing Fonts.

This method can be used to deploy other payloads as well, happy scripting!

IssuePfx – The submission failed error Intune to PKI connector

As I couldn’t google an answer to this one and the error was misleading, if you are using the Intune Service Connector to distribute PCKS certificates from your onprem PKI to your Intune clients and see the following error in the Connector eventlogs:

{

“Metric”:{

“Dimensions”:{

“UserId”:”c659cd5a-86e5-4733-ae58-55a896f63d53″,

“DeviceId”:”4cec597c-cd90-4077-b6c0-612a213353ef”,

“CaName”:”PATH TO CA\\CAFriendlyName”,

“TemplateName”:”Intune”,

“ElapsedMilliseconds”:”786″,

“AgentId”:”1af3469a-ef31-cfd2-3bfc-cba69a6d215d”,

“DiagnosticCode”:”0x0FFFFFFF”,

“DiagnosticText”:”We are unable to complete your request because a server-side error occurred. Please try again. [Exception Message: \”DiagnosticException\”] [Exception Message: \”IssuePfx – The submission failed\”]”

},

“Name”:”PkcsCertIssue_Failure”,

“Value”:0

}

}

And this error on your CA:

EventId 22:

Active Directory Certificate Services could not process request 136204 due to an error: Error 0xc8000211 (ESE: -529).  The request was for COMPUTERNAME.  Additional information: Error Parsing Request

Ensure you restart the Active Directory Certificate Services service on your CA. This is not required as per the documentation, but was surely required in my environment.

Mapping legacy server shares in your Windows 10 MDM Intune pilot

In a Windows 10 full MDM (AzureAD+Intune) scenario, you’ll move your email, app and file workloads to Office 365 (or alternatives).

In your pilot or hybrid phase, you may still need access to certain file shares on your servers, so here’s a simple PowerShell script you can deploy using Intune Device Configuration that maps your desired share. Deploy multiple times for multiple shares (or groups of users).

It will create a shortcut in a location you define, so the mapping is always user-driven, it will automatically suggest your user’s AzureAD login as username. You can of course customize the script to your liking if you did not change your local AD upn yet.

Gitlab homehttps://gitlab.com/Lieben/assortedFunctions/blob/master/intuneServerShareMapper.ps1

Requirements:

  • Windows 10 (MDM)
  • Intune
  • Direct SMB lan connection to share

Remove-StaleIntuneDevices using a scheduled Azure Runbook

I recently came upon a really cool post by Josh and Sarah that explains how to clean up stale devices in Intune using the Graph API.

As I want to run this from an Azure runbook, silently, I had to modify it a little so it automatically consents to azure app permissions and logs in silently. If you’d like to use it, feel free to add it from the Azure gallery (search for Lieben) or download it yourself.

Make sure you’ve also imported the AzureAD and AzureRM modules into your automation account, and configured a credential object for the script to use.

GitLab: Remove-StaleIntuneDevicesForAzureAutomation.ps1

Technet: Remove-Stale-Intune-4b07488a

set Intune MDM user scope to ALL using Powershell and hidden API

If you want to change the settings on this page (or most Azure Portal pages) programmatically:

Microsoft’ll tell you to use your browser, there is no API/PS for this yet. As I really hate the answer “no”, I used Fiddler and baked some Powershell:


login-azurermaccount
$context = Get-AzureRmContext
$tenantId = $context.Tenant.Id
$refreshToken = $context.TokenCache.ReadItems().RefreshToken
$body = &quot;grant_type=refresh_token&amp;amp;amp;refresh_token=$($refreshToken)&amp;amp;amp;resource=74658136-14ec-4630-ad9b-26e160ff0fc6&quot;
$apiToken = Invoke-RestMethod &quot;https://login.windows.net/$tenantId/oauth2/token&quot; -Method POST -Body $body -ContentType 'application/x-www-form-urlencoded'

$header = @{
'Authorization' = 'Bearer ' + $apiToken.access_token
'Content-Type' = 'application/json'
    'X-Requested-With'= 'XMLHttpRequest'
    'x-ms-client-request-id'= [guid]::NewGuid()
    'x-ms-correlation-id' = [guid]::NewGuid()
}
$url = &quot;https://main.iam.ad.ext.azure.com/api/MdmApplications/eab0bcaf-9b2e-4e62-b9be-2eea708422f8?mdmAppliesToChanged=true&amp;amp;amp;mamAppliesToChanged=true&quot;

$content = '{&quot;objectId&quot;:&quot;eab0bcaf-9b2e-4e62-b9be-2eea708422f8&quot;,&quot;appId&quot;:&quot;0000000a-0000-0000-c000-000000000000&quot;,&quot;appDisplayName&quot;:&quot;Microsoft Intune&quot;,&quot;appCategory&quot;:null,&quot;logoUrl&quot;:null,&quot;isOnPrem&quot;:false,&quot;appData&quot;:{&quot;mamEnrollmentUrl&quot;:null,&quot;mamComplianceUrl&quot;:null,&quot;mamTermsOfUseUrl&quot;:null,&quot;enrollmentUrl&quot;:&quot;https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc&quot;,&quot;complianceUrl&quot;:&quot;https://portal.manage.microsoft.com/?portalAction=Compliance&quot;,&quot;termsOfUseUrl&quot;:&quot;https://portal.manage.microsoft.com/TermsofUse.aspx&quot;},&quot;originalAppData&quot;:{&quot;mamEnrollmentUrl&quot;:&quot;https://wip.mam.manage.microsoft.com/Enroll&quot;,&quot;mamComplianceUrl&quot;:&quot;&quot;,&quot;mamTermsOfUseUrl&quot;:&quot;&quot;,&quot;enrollmentUrl&quot;:&quot;https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc&quot;,&quot;complianceUrl&quot;:&quot;https://portal.manage.microsoft.com/?portalAction=Compliance&quot;,&quot;termsOfUseUrl&quot;:&quot;https://portal.manage.microsoft.com/TermsofUse.aspx&quot;},&quot;mdmAppliesTo&quot;:2,&quot;mamAppliesTo&quot;:2,&quot;mdmAppliesToGroups&quot;:[],&quot;mamAppliesToGroups&quot;:[]}'
Invoke-RestMethod –Uri $url –Headers $header –Method PUT -Body $content -ErrorAction Stop

You can do almost anything using the above snippet and changing the endpoint URL and POST contents. Use Fiddler to capture, then replicate in code 🙂

Be warned and use at your own risk, obviously this method is unsupported.