Recently, I found an excellent blogpost on how to back up AzureAD Conditional Access policies (link) using the new AzureAD PowerShell module and decided to create my own when I encountered a little bug…
TL;DR Instead of using ToJson() method use ConvertTo-Json cmdlet on the objects returned by Get-AzureMSConditionalAccessPolicy.
Explained I was trying to create my own version of a restore script when I encountered the following error:
Cannot convert value "@{operator=OR; builtInControls=System.Object[]; customAuthenticationFactors=System.Object[]; termsOfUse=System.Object[]}" to type "Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls". Error: "Cannot convert the "@{operator=OR; builtInControls=System.Object[]; customAuthenticationFactors=System.Object[]; termsOfUse
=System.Object[]}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls"."
At line:2 char:1
+ [Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls]$GrantCo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
The main difference between my script and Barbara’s is that I used the ToJson() method on the returned Microsoft.Open.MSGraph.Model.ConditionalAccessPolicy type objects:
$CAs = Get-AzureADMSConditionalAccessPolicy foreach ($CA in $CAs){$CA.ToJson()}
This way, the JSON output has no underscore prefix in “operator” compared to the output generated by ConvertTo-Json (“_Operator”):
Bitlocker keys can be stored in Active Directory and in Azure Active Directory too – but querying the latter is a bit trickier than usual. The following script will export all Bitlocker recovery keys (from your Azure Active Directory tenant) to an HTML table.
TL;DR 1. Ensure that you meet the following prerequisites: – you have adequate rights in AzureAD (Global Admin for example 🙂 ) – the following PowerShell modules are installed: AzureRM, AzureAD 2. Run the script below (make sure that the path is valid). – the script will prompt for AzureAD credentials twice, it is normal (scipt explained later)
In the first line, $exportFile defines the output filename as a variable (it will be used at the end of the script). $exportFile = "C:\TEMP\BitLockerReport.html"
Next, we will connect to the Azure Resource Manager (AzureRM) – to install the module, PowerShell should be running in elevated mode Install-Module AzureRM Import-Module AzureRM.Profile Login-AzureRmAccount
Next, we are going to prepare the Rest API headers used to gather information. It basically consists of retrieving a RefreshToken, which is then used to create an Access Token. This token will grant access to resources (Authorization header). $context = Get-AzureRmContext $tenantId = $context.Tenant.Id $refreshToken = @($context.TokenCache.ReadItems() | Where-Object {$_.tenantId -eq $tenantId -and $_.ExpiresOn -gt (Get-Date)})[0].RefreshToken $body = "grant_type=refresh_token&refresh_token=$($refreshToken)&resource=74658136-14ec-4630-ad9b-26e160ff0fc6" $apiToken = Invoke-RestMethod "https://login.windows.net/$tenantId/oauth2/token" -Method POST -Body $body -ContentType 'application/x-www-form-urlencoded' $header = @{ 'Authorization' = 'Bearer ' + $apiToken.access_token 'X-Requested-With' = 'XMLHttpRequest' 'x-ms-client-request-id' = [guid]::NewGuid() 'x-ms-correlation-id' = [guid]::NewGuid() }
Next, we connect to AzureAD and query all AzureAD device with Windows operating system (Bitlocker applies only on Windows, so other devices are irrelevant): Connect-AzureAD $AzureADDevices = Get-AzureADDevice -all $true | ? {$_.deviceostype -eq "Windows"}
The following lines are basically the essence of the script: for each device it queries the old Azure endpoint for information (I’m sure that GraphAPI can be used as well) $deviceRecords = @() $deviceRecords = foreach ($device in $AzureADDevices) { $url = "https://main.iam.ad.ext.azure.com/api/Device/$($device.objectId)" $deviceRecord = Invoke-RestMethod -Uri $url -Headers $header -Method Get $deviceRecord }
And that was the only part which required the Access Token. NOTE: if you’re testing some parts of the script, make sure to run the previous block (starting with Get-AzureRMContext) as access tokens expire after 1 hour and you may experience errors. Now, we filter out the devices that have Bitlocker information: $Devices_BitlockerKey = $deviceRecords.Where({$_.BitlockerKey.count -ge 1})
The next block is basically creating a custom object to store the neccessary information as of my needs. The report should contain the following information on each line: – Device DisplayName – Drive Type – Recovery Key ID – Recovery Key Because a device can have multiple key ids (OS disk, data disk, etc.), I need to loop through each device’s each BitlockerKey property, so that information can be printed to a simple table (no multivalued cells): $obj_report_Bitlocker = foreach ($device in $Devices_BitlockerKey){ foreach ($BLKey in $device.BitlockerKey){ [pscustomobject]@{ DisplayName = $device.DisplayName driveType = $BLKey.drivetype keyID = $BLKey.keyIdentifier recoveryKey = $BLKey.recoveryKey } } }
Now that information is ready to be exported, we add the HTML tags to the information and export it:
This blogpost is about deploying Teams with custom settings, like automatic startup, automatic login, open in background and so on. To make auto-logon work, AzureAD join is a prerequisite.
TL;DR – Make sure AzureAD seamless SSO is set up (link) – Download Teams installers from here (link) – Create a folder in NETLOGON (or other share that can be accessed by users) and place the installers there – Deploy the script below as user logon script, correct paths in the first two lines +1: Use Microsoft’s script (link) as startup script to create firewall exceptions
$Teams_x64_installer = "\\domain.com\Netlogon\Teams\x64\Teams_windows_x64.exe"
$Teams_x86_installer = "\\domain.com\Netlogon\Teams\x86\Teams_windows.exe"
#OSCheck
if ((gwmi -query "select Caption from Win32_OperatingSystem").Caption -notmatch "Windows 10"){exit}
#Check office version
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
#if no Office found, set bitness to match OS architecture
if ($bitness -eq $null) {
$bitness = "x"+(gwmi -query "select osarchitecture from win32_operatingsystem").osarchitecture.substring(0,2)
}
#select installer
switch ($bitness){
"x64"{$EXE_teamsInstall = $Teams_x64_installer}
"x86"{$EXE_teamsInstall = $Teams_x86_installer}
}
#Check if Teams is already present, install if needed
If (Test-Path "$env:USERPROFILE\Appdata\Local\Microsoft\Teams\Update.exe"){}else{
#Install Teams
$Command_teamsInstall = "$EXE_teamsInstall -s"
Invoke-Expression $Command_teamsInstall
#Wait for install process to finish
while (Get-Process | ? {$_.Path -eq "$EXE_teamsInstall"}){
Start-Sleep 1}
}
$desktopConfig = "$env:appdata\Microsoft\Teams\desktop-config.json"
##If it was not previously backed up, then back it up and modify configuration
if (Test-Path "$desktopConfig.original"){}else{
#Create backup
Copy-Item $desktopConfig -Destination "$desktopConfig.original"
#Import JSON config
$JSON_desktopConfig = Get-Content $desktopConfig -Raw | ConvertFrom-Json
#Set JSON config
$JSON_desktopConfig.isAppFirstRun = $false
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isForeground" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isMaximized" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "teamsUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "lyncUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "appPreferenceSettings" -Value "" -Force
$JSON_desktopConfig.appPreferenceSettings = [pscustomobject]@{
openAsHidden = $true
openAtLogin = $true
runningOnClose = $true
}
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isLoggedOut" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "pastModernAuthSucceeded" -Value $true -Force
#Export JSON config
$JSON_desktopConfig | ConvertTo-Json -Depth 20 | Set-Content $desktopConfig
}
#If it is not set to run automatically, then change this behavior
if (Get-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\ -Name com.squirrel.Teams.Teams -ErrorAction SilentlyContinue){}else{
#Create startup registry setting
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\" -name "com.squirrel.Teams.Teams" -PropertyType String -Value ("$env:USERPROFILE" + '\Appdata\Local\Microsoft\Teams\Update.exe --processStart "Teams.exe" --process-start-args "--system-initiated"')
}
Explained
To enable automatic login, AzureAD seamless SSO is needed. It’s very easy to set up, just follow Microsoft’s guide (link)
Downloading Teams EXE installers is also very straightforward:
Next step is to place these installers to a shared folder where users have at least READ permission. I prefer to use the domains NETLOGON folder for this:
Next, prepare the deployment script. This one consists of the following:
First, the paths of the exe files are defined in separate variables: $Teams_x64_installer = "\domain.com\Netlogon\Teams\x64\Teams_windows_x64.exe" $Teams_x86_installer = "\domain.com\Netlogon\Teams\x86\Teams_windows.exe"
Then, there is an OS check (it will install only on Windows 10): if ((gwmi -query "select Caption from Win32_OperatingSystem").Caption -notmatch "Windows 10"){exit}
The following lines are looking for Office (Outlook exactly) to determine the bitness – so that the script will install the same version of Teams: $bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness if($bitness -eq $null) { $bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness} if($bitness -eq $null) { $bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness} if($bitness -eq $null) { $bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness} if($bitness -eq $null) { $bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness} if($bitness -eq $null) { $bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
If Office is not found, the matching OS architecture will be used: if ($bitness -eq $null) {$bitness = "x"+(gwmi -query "select osarchitecture from win32_operatingsystem").osarchitecture.substring(0,2)}
Based on the determined architecture, $EXE_teamsInstall variable is defined: switch ($bitness){ "x64"{$EXE_teamsInstall = $Teams_x64_installer} "x86"{$EXE_teamsInstall = $Teams_x86_installer} }
Then the script is checking if Teams is already installed. If not, the installer invokes the installation command and waits for the process to finish: If (Test-Path "$env:USERPROFILE\Appdata\Local\Microsoft\Teams\Update.exe"){}else{ #Install Teams $Command_teamsInstall = "$EXE_teamsInstall -s" Invoke-Expression $Command_teamsInstall #Wait for install process to finish while (Get-Process | ? {$_.Path -eq "$EXE_teamsInstall"}){ Start-Sleep 1} }
The following step is to configure the Teams client. Teams stores its configuration data in a JSON file, this is what we have to manipulate. You can find an awesome walkthrough by Dr Scripto (link). My version works as follows:
First, the configuration JSON file is defined in $desktopConfig variable: $desktopConfig = "$env:appdata\Microsoft\Teams\desktop-config.json"
Then the script checks if there is a backup file (desktop-config.json.original). if (Test-Path "$desktopConfig.original"){}else{
If it finds one, it assumes that the script already ran. If there is no backup file, it creates a backup: Copy-Item $desktopConfig -Destination "$desktopConfig.original"
Then comes the JSON manipulation: – import the config to a variable: $JSON_desktopConfig = Get-Content $desktopConfig -Raw | ConvertFrom-Json – make the following changes: disable first run wizard, open in backup, keep the app running on close, omit first time login screen: $JSON_desktopConfig.isAppFirstRun = $false $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isForeground" -Value $false -Force $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isMaximized" -Value $false -Force $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "teamsUrlProtocolsRegistered" -Value $true -Force $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "lyncUrlProtocolsRegistered" -Value $true -Force $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "appPreferenceSettings" -Value "" -Force $JSON_desktopConfig.appPreferenceSettings = [pscustomobject]@{ openAsHidden = $true openAtLogin = $true runningOnClose = $true } $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isLoggedOut" -Value $false -Force $JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "pastModernAuthSucceeded" -Value $true -Force -the changes then get exported to the configuration file: $JSON_desktopConfig | ConvertTo-Json -Depth 20 | Set-Content $desktopConfig
The last step is to make the app run automatically by creating a registry key (if it does not exist): if (Get-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\ -Name com.squirrel.Teams.Teams -ErrorAction SilentlyContinue){}else{ #Create startup registry setting New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\" -name "com.squirrel.Teams.Teams" -PropertyType String -Value ("$env:USERPROFILE" + '\Appdata\Local\Microsoft\Teams\Update.exe --processStart "Teams.exe" --process-start-args "--system-initiated"') }
Now that the script is ready, it is time to deploy the script as a user logon script:
Tracking changes made by administrators in Azure and/or Office365 can be difficult and I’m sure that there are a lot of alternatives to query this information – but I wanted to share this basic script, even though several parts of it may need improvement.
TL;DR: 1. Make sure you have ExchangeOnlineManagement PS module installed 2. Check the values of the variables, make changes if needed 3. Run the script, use an AAD admin account when connecting to ExchangeOnline 4. Results will be exported to $outputDirectory in HTML format (C:\Office365_AuditExport by default)
The first four lines contains the values of the variables used later. The time range queried is the last 30 days ($startDate, $endDate) and the report will be exported to C:\Office365_AuditExport folder ($outputDirectory). The last variable will be used as a suffix for the filename: $startDate = (get-date).AddDays(-30) $endDate = (Get-date) $outputDirectory = "C:\Office365_AuditExport\" $str_date = Get-Date -Format yyyyMMdd_HHmm
Then we connect to Exchange Online: Connect-ExchangeOnline
The next step is to query the roles in Exchange and store the members of these roles in a variable – if the member is not a group: $administrators = Get-RoleGroup | % {Get-RoleGroupMember $_.Name | ? {$_.RecipientType -ne "group"} } | % {$_.windowsLiveId} | select -Unique
These userIDs can be joined to a string, separated with a comma, because the Search-UnifiedAuditLog cmdlet accepts it in this form: $userIds = $administrators -join ","
Next, we set the record types we want to query. Possible values can be found here (link): $recordtypes = "ExchangeAdmin","MicrosoftTeams","MicrosoftTeamsAdmin","SecurityComplianceCenterEOPCmdlet","SharePoint","SharePointSharingOperation","SkypeForBusinessCmdlets"
Now we are ready to load the audit logs. The maximum result size is limited to 5000 records for a search session by default, you can overcome this issue with several methods (example): $auditevents = foreach ($recordtype in $recordtypes){ Search-UnifiedAuditLog -StartDate $startDate -EndDate $enddate -UserIds $userIds -ResultSize 5000 -RecordType $recordtype Clear-Variable recordtype }
Azure Active Directory events use a different schema so they are loaded in a separate variable: $azureAD_adminAuditEvents = Search-UnifiedAuditLog -StartDate $startDate -EndDate $enddate -UserIds $userIds -ResultSize 5000 -RecordType 8
Now that the informations are loaded, it’s time to convert it and filter out unnecessary events (like commands with Get verb): $obj_report = $auditevents.auditdata | ConvertFrom-Json | ? {($_.usertype -eq 2) -and ($_.operation -notmatch "Get-")} | select workload,userid,@{Label='TimeStamp';Expression={[datetime]$_.creationtime}},operation,@{Label='parameters';Expression={($_.parameters | % {" -" + $_.Name + " " + $_.value}) -join ""} }
The same applies to the AzureAD events: $obj_AzureADreport = $azureAD_adminAuditEvents.auditdata | ConvertFrom-Json | select workload,userid,@{Label='TimeStamp';Expression={[datetime]$_.creationtime}},operation,id
The event data loaded in $obj_report and $obj_AzureADreport is then inserted to HTML code:
The last step is to export the HTML report to the previously defined directory: if (!(Test-Path $outputDirectory)){mkdir $outputDirectory} $body > $outputDirectory\O365Audit_$str_date.html
The result should look like this:
The script can be improved in several ways, but it can be a good start or at least serve as inspiration. Probably I will share an improved version later…
The official Microsoft documentation (link) recommends deploying the connection scripts as packages, but I thought that it would be fancy to deploy them as applications – because the application model is more powerful and offers several features that can’t be achieved with packages.
TL;DR: Device Tunnel (details) 1. Create the application which runs the configuration script: powershell.exe -ExecutionPolicy Bypass -File ".\DeviceTunnel_installer.ps1" 2. Detection method: PowerShell script, Get-VPNConnection -AllUserConnection "DEVICE TUNNEL" -ErrorAction SilentlyContinue 3. User Experience: Install for system; Whether or not a user is logged on; Minimized 4. Requirement: Only Windows 10 Deploy the application to a device collection.
User Tunnel (details) 1. Create the application which runs the configuration script: powershell.exe -ExecutionPolicy Bypass -File ".\UserTunnel_installer.ps1" 2. Detection method: PowerShell script, Get-VPNConnection "USER TUNNEL" -ErrorAction SilentlyContinue 3. User Experience: Install for system; Only when a user is logged on; Minimized 4. Requirement: Only Windows 10 Deploy the application to a user collection. Notice that the user experience is set to “Install for system”, but the application is deployed to a User collection. Based on my testing, it causes the program to run in SYSTEM context (admin rights!), but the detection method runs in the current user context (which is good in our case – and bad if you were trying to write a detection script which requires admin rights…).
Cheat: Scoped User Tunnel deployment (eg. notebooks only) (details) If you want to limit the deployment of the User Tunnel to only selected devices, here is a workaround: 1. Create another application which creates a registry key, eg.: HKEY_LOCAL_MACHINE\Software\AOVPN\UserTunnelDeploymentEnabled (DWORD) = 1 2. Configure this application as a dependency for the User Tunnel application with automatic install disabled 3. Deploy this application to those devices on which you want to enable the User Tunnel deployment
Extended edition
Device Tunnel In the following steps I’m creating an application which configures an AlwaysOn VPN device tunnel, named F12_AOVPNDevice.
For scripts, information should be manually specifiedJust the usual general informationsThe deployment type is Script InstallerGive a name to the deployment type too
On the Content page, browse for the folder where the script can be found. The following installation program is specified in my case:
The application detection method will be a PowerShell script, with the following content: Get-VPNConnection -AllUserConnection "F12_AOVPNDevice" -ErrorAction SilentlyContinue
On the User Experience tab, configure the settings as follows:
On the Requirements page, one requirement will be specified: only Windows 10 (32/64 bits) operating systems are required:
The process is straightforward from this point. After creating the application, deploy it to the device collection. For testing purposes, I deployed it as Available:
After successful installation, the VPN connection can be verified several ways – I chose PowerShell:
User Tunnel
Deploying the user tunnel is almost the same, although there are some aspects to consider: – If the application was successfully installed for a user on the computer, it may take some time for another user on the same machine (The next Application Deployment Evaluation cycle + User Policy Evaluation Cycle). Microsoft’s approach (deploy the package once for every user who logs on) is better in other ways: the profile will be installed immediately for users logging on for the first time; there is no need to evaluate user policies; etc. – Deploying the application to a User Collection means that users will receive the VPN profile anywhere they log on – even on their PCs that doesn’t need it (cheat below). – The detection method is only looking for a VPN connection with a particular name – make sure that this name is unique, or fine tune the detection method to check the server address too…
So let’s start:
Everything almost the same so far. I forgot to take screenshot of the Content page, but you can see my settings on the Summary screenshot below. On the Detection Method page, the PowerShell script is a bit different: Get-VPNConnection "F12_AOVPN_User" -ErrorAction SilentlyContinue There is no -AllUserConnection parameter, because user tunnels are user specific.
On User Experience page, choose “Install for system” as installation behavior, so the script will run in SYSTEM context. The logon requirement should be set to “Only when a user is logged on”. I’m not sure if RDP sessions (or Hyper-V enhanced sessions) satisfy this criteria, but keep in mind that console sessions are required.
Now everything is ready, the application can be deployed to a user collection.
Cheat: Scoped User Tunnel deployment If you want to restrict the user tunnel deployment to certain computers, there can be some standard ways (SCCM Global Conditions?) or uncommon solutions like this.
Before moving to this solution, consider the official Microsoft recommended deployment method (package for every user who logs on) as this can be deployed to device collections too. The only disadvantage is that anybody logging on the computer will receive this setting – but keep in mind that User Tunnel connection request are handled by NPS – so even if a not intended user receives the VPN settings, the connection won’t establish.
So the idea behind this workaround is to create a registry key on the target system to determine if User Tunnels can be deployed. The registry configuration is a separate SCCM application which can be used as a dependency for the User Tunnel application… not too elegant, but it works.
Create a separate application (Enable User Tunnel) with the following deployment type:
On Content page speficy the source directory and the installation program powershell.exe -executionpolicy bypass -File ".\Enable_UserTunnel_Deployment.ps1"
The Detection method will consist of checking the registry setting:
After creating the application, modify the User Tunnel application so it will have this deployment type as a dependency. Navigate to the Dependencies tab of the deployment type and click on “Add..” and select this new application as dependency:
Make sure you unchecked the Auto Install box.
The next step is to deploy “Enable User Tunnel Deployment” application to those devices on which you want to enable user tunnel deployment. On those devices where this application is not installed, Software Center will not install the user tunnel with the following status: “This software is not applicable to your device”
Now I install the application on the computer:
After some time you can retry the installation of the user tunnel:
This blogpost will describe the steps to restore a deleted Android private application in Intune.
TL;DR: 1. Login to https://play.google.com/work 2. In Admin Settings, find your Organization ID and search by this ID on top of the page 3. Click on the desired application and Approve it 4. Intune – Apps – All apps – Add – Managed Google Play app – Select (Alternatively: Tenant administration – Connectors and tokens – Managed Google Play) 5. Click Sync, wait a minute then refresh the Apps page
Extended edition:
For demo purposes I “accidentally” delete my private Android app “F12HU Hello”
As you can see, Intune will tell you that it will programatically un-approve the application from managed Google Play
Don’t try to upload the APK again, because you can’t upload an application with the same package name (unique identifier of the application)
You have to Approve your application again from the Google play console. Go to https://play.google.com/work and log in with your Play account, then navigate to Admin Settings where you can find your Organization ID
Copy this ID in the search bar on top of the page and search for applications, you will see your private apps
Click on the app and select Approve, select your settings and you are done
Now, if you go back to Intune navigate to Tenant administration – Connectors and tokens – Managed Google Play and click on Sync
The information on this website is provided for informational purposes only and I make no warranties, either express or implied. Information in these documents, including URL and other Internet Web site references, is subject to change without notice. The entire risk of the use or the results from the use of this document remains with the user.
The postings on this site are my own and do not necessarily represent the postings, strategies or opinions of my employer.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.