PowerShell
Adding users in bulk to Microsoft DLP and retention policies for Microsoft Teams
It is possible to perform a bulk addition of users to Microsoft DLP and retention policies for Microsoft Teams with PowerShell cmdlets. It’s actually pretty simple and straight forward, as you will see below.
A few tips:
- This uses the Exchange Online Management V2 module – install the module before importing it. Install the EXO V2 module | Microsoft Docs.
- To install and connect to EXO, follow the top 2 commands outlined at Connect to Security & Compliance Center PowerShell using the EXO V2 module | Microsoft Docs.
- My observation is that the cmdlets will insert new records, not overwrite them. Test this on a sample retention policy first! I recommend adding a second test user account immediately after, so that you can experience that the users are truly added to the existing list (i.e. the list is not overwritten with just that single user).
- Remember to first connect using the Connect-IPPSSession cmdlet.
Two example commands to get you started:
- Teams chats: Set-RetentionCompliancePolicy -Identity “ThePolicyName” -AddTeamsChatLocation “UPN@domain.com”
- Team DLP policy: Set-DlpCompliancePolicy -Identity “ThePolicyName” -AddTeamsLocation “UPN@domain.com”

Scoping Office 365 ATP Policies
Policies within Office 365 ATP can be applied to (or scoped) in several ways, as in the screenshot below. By far the simplest method, and most secure, is to protect the entire domain. But what if your organization doesn’t own the licensing to cover everyone in the domain? This post will walk through an example of how to setup and configure the policies to be scoped to a specific group along with a couple of the configuration best practices.

Aside from applying O365 ATP policies to all users of a domain, applying to groups requires using an Exchange Online (EXO) distribution list (DL) or Microsoft 365 group. The challenge with using either of these, as you might suspect, is that users can send/receive messages and/or collaborate in that shared DL/group. So we need to further limit and restrict the actions that users can take. My examples/process below will focus on using an M365 Group.
- In Azure AD > Groups, create a new Microsoft 365 group. Create this group without any members since we’ll need to make other changes and test before adding production users.

Second, we need to configure this group to limit interactions/notifications with users . Before running these commands, there are a couple notes that are of great importance.
- The latest preview version of the EXO module needs to be used.
- To get these commands to function, it may be necessary to update [Windows 10] with the latest package management and PowerShellGet modules in order to have the latest Install-Module cmdlets that support newer parameters such as “AllowPrerelease”.
- After updating PowerShellGet, restart the PowerShell/ISE app.
Install-Module -Name PackageManagement -Repository PSGallery -Force
Install-Module -Name PowerShellGet -Repository PSGallery -Force
- Install and import the Exchange Online PowerShell v2 module (if not already done). The abbreviated version of these instructions are as follows.
Install-Module -Name ExchangeOnlineManagement -RequiredVersion 2.0.3-Preview -AllowPrerelease
Import-Module -Name ExchangeOnlineManagement
- Connect to Exchange Online instance (with admin user).
Connect-ExchangeOnline
- Configure the group to be hidden in Office clients and in the GAL.
Set-UnifiedGroup -Identity "Group Name" -HiddenFromExchangeClientsEnabled:$true
- Disable notifications to users about being added to the group.
Set-UnifiedGroup -Identity "Group Name" -UnifiedGroupWelcomeMessageEnable:$false

Next, the group needs to be updated to restricted to accept only messages from a specific list of users.
- Update group settings in Exchange Online Admin Center > Recipients > Groups.

Finally, update the M365 group to:
- Update group to use a dynamic membership – single user to test and confirm settings as desired.
- Update group to use a dynamic membership – users assigned O365 ATP licenses.
- Scope O365 ATP policies (Safe Links, Safe Attachments, etc.) to the new M365 group.

Auto MDM Enroll: Failed (The system tried to delete the JOIN of a drive that is not joined.)
When setting up hybrid Azure AD join with on-premises Windows 10 environments, if you encounter the an error that “The system tried to delete the JOIN of a drive that is not joined.“, then there is a good chance that the device has not yet synchronized into Azure AD.
A few tips to help you isolate the cause and get past this issue:
- First, confirm the device exists in Azure Active Directory (or not). In the Azure portal, navigate to Azure Active Directory > Devices > All devices.
- Review the steps in Troubleshooting hybrid Azure Active Directory joined Windows 10 and Windows Server 2016 devices. Note that this article points back to another article on How to configure hybrid Azure Active Directory joined devices, which presently contains way more helpful information to help you troubleshoot.
- In the most current Azure AD Connect releases, use the built-in Troubleshooter. Then in the PowerShell windows which launches, use both options to troubleshooting options for Object Sync and Password Hash Sync.
In my case, the troubleshooting guides were useful to confirm that I had configured everything correctly. Then the Azure AD Connect troubleshooter reported an error that “Password Hash Synchronization cloud configuration is disabled”. Searching that issue on the Internet led me to discover that the cause was likely due to mismatched passwords between the Azure AD account “On-Premises Directory Synchronization Service Account” with the password currently set in the local synchronization service.
To fix that, first set a new password for the “On-Premises Directory Synchronization Service Account”. To do that, try setting it in Azure directly. However, given that it’s a special account, it may be necessary to reset the password through PowerShell with the MSOL cmdlets. While I’m not getting into the full end-to-end setup and use of those add-on Azure PowerShell cmdlets, the command could be as simple as:
Connect-AzureAD Set-AzureADUserPassword -ObjectId abc123def456xyz980 -Password MyP@ssw0rd! -ForceChangePasswordNextLogin $false
Next, start program Synchronization Service Manager, then click on Connectors. Locate the Windows Azure Active Directory Account and click Properties.
Finally, set the password. Voila, devices will now sync to Azure AD on the next synchronization!
Automating Web URLs as Start Menu Links
In my previous post on Creating Web URLs as Start Menu Links, I outlined details how to manually create links to URLs (as seen in the images below). While this does work, most folks in the systems management community would prefer to automate this link creations. The following PowerShell script can be used to create a custom start menu link for all users.
Note that a problem that you may encounter is the link not being displayed in the grouping. This could be caused by having two .lnk files with the same target path pointing to the same URL.
# Create a Shortcut with Windows PowerShell $oWScriptShell = New-Object -ComObject WScript.Shell $sTargetFile = "C:\Windows\explorer.exe" $sShortcutFile = $oWScriptShell.SpecialFolders("AllUsersPrograms") + "\Links\t3chn1ck.lnk" # Note: to open URL in a specific browser like Edge, add in front of the URL Microsoft-edge: $sURL = "http://t3chn1ck.com" #Delete existing shortcut if exists If (Test-Path $sShortcutFile){ Remove-Item $sShortcutFile } $oShortcut = $oWScriptShell.CreateShortcut($sShortcutFile) $oShortcut.IconLocation = "explorer.exe,20" $oShortcut.TargetPath = $sTargetFile $oShortcut.Arguments = $sURL $oShortcut.Save()
Windows 10 Full Device Wipe via PowerShell
One of the new capabilities of Windows 10 is the ability to manage it like a mobile device using Configuration Service Providers. One of those functions is the ability to perform a full wipe (restore to factory default) of the device using the RemoteWipe CSP. While this capability can be accomplished using a MDM provider such as Microsoft Intune, you may at some point have the need to demonstrate it without a device being managed.
!!! WARNING !!! CAUTION !!! DISCLAIMER !!!
Using the script below will cause the Windows 10 system to immediately perform a reset of Windows to factory default. No data and no applications are saved. Use extreme caution when testing this script. Setting it up for deployment with a tool (such as ConfigMgr) could come with extreme consequences if incidentally deployed.
!!! WARNING !!! CAUTION !!! DISCLAIMER !!!
Now that you’ve been fully warned, to demonstrate how to use the RemoteWipe and invoke the doWipeMethod, please reference the example script at https://msdn.microsoft.com/en-us/library/windows/desktop/dn948434.aspx. Also, it could be good to add a user input for a “password” to continue and it can easily be added to front of the script. For example:
$pass = Read-Host 'Enter the password to perform a full wipe of Windows 10 to factory defaults.' if ($pass -eq '1-2-3-4-5') { write-host -ForegroundColor Green 'Password accepted ... That''s amazing. I''ve got the same combination on my luggage!!' } else { write-host -ForegroundColor Red 'Wrong password, terminating script' exit }
Testing Windows 10 Assigned Access
Based upon the information in article Set up a kiosk on Windows 10, it is possible to quickly setup a Windows 10 UWP app to run with Assigned Access. From that article, I’ve outlined (below) the quick-start steps for testing purposes.
- Login to Windows with an account that has local admin rights.
- Create a local user account (such as “kiosk”) with a password and do not grant the account local admin privileges.
- Sign out of Windows.
- Login to Windows with the kiosk user account so that it builds the profile.
- If the tablet has physical keyboard capabilities, then change that user to use Tablet Mode and log out. Otherwise, skip this step.
- Login to Windows with the local admin account.
- Edit the registry to enable auto login of the kiosk account.
- Use the PowerShell script in this article to get the AUMID for the UWP app.
- If you’re just looking for a quick example, use the MSN News app with ID – Microsoft.BingNews_8wekyb3d8bbwe!AppexNews
- Based upon the information in the previous step, run a PowerShell command in this article to set the kiosk user to have assigned access to your UWP app.
- Verify that the user was properly assigned to launch the application by:
- Start > Settings > User accounts > Family and other users
- Under the “Other Users” section, select “Set up assigned access”
- Ensure the user shows the application
Also, to sideload a UWP application, see this information: https://msdn.microsoft.com/en-us/windows/uwp/packaging/packaging-uwp-apps#sideload-your-app-package.
More information on best practices for developing UWP apps for Assigned Access: https://msdn.microsoft.com/en-us/library/windows/hardware/mt633799.aspx
Remove Universal Apps During ConfigMgr OSD
As part of a systems management strategy for Windows 10, many organization may choose to uninstall Universal Apps. During OSD for ConfigMgr, this uninstall process use a simple PowerShell script (as shown below) to execute the commands for removing the targeted Universal Apps. While this does command does “remove” the Apps as seen in the event logs (Apps and Services > Microsoft > Windows > AppXDeployment-Server) the Apps are regenerated upon the first logon of a user.
Get-AppXPackage -Name *bing* -AllUsers | Remove-AppXPackage
Furthermore, there is an option (UniversalAppUninstall) within a WICD Provisioning Package. There are times when this option would be a better approach, but I have not been successful in having it function to uninstall Apps. Unfortunately, information is scant on this topic.
A Solution
Stumbling around for other who may have found other means to address this situation, Jörgen Nilsson (Microsoft MVP) has a PowerShell script which does completely remove those undesired Universal Apps. The key difference is that his script uses the Remove-AppxProvisionedPackage cmdlet against the full package name.
The variable for AppList that I use this:
$AppsList = "Microsoft.BingFinance","Microsoft.BingNews","Microsoft.BingWeather","Microsoft.XboxApp","Microsoft.SkypeApp","Microsoft.MicrosoftSolitaireCollection","Microsoft.BingSports","Microsoft.ZuneMusic","Microsoft.ZuneVideo","Microsoft.Windows.Photos","Microsoft.People","Microsoft.MicrosoftOfficeHub","Microsoft.WindowsMaps","microsoft.windowscommunicationsapps","Microsoft.Getstarted","Microsoft.3DBuilder"
To execute the script as part of a Task Sequence in ConfigMgr, it’s as easy as having placing the script file in a classic Package, and having the step “Execute PowerShell Script” with the Bypass option set.
ConfigMgr 2012 R2 PowerShell to Install SMP Role
In a recent customer engagement, we needed to mass deploy the State Migration Point (SMP) role to nearly 70 servers. After completing about a dozen of these one by one, I thought PowerShell would be a much faster way to accomplish the end goal. The below script can be used as an example for finding existing site systems that do not have the SMP role installed, while allowing it to skip servers with certain names (in this example, it skips servers that begin with TEST in the name).
import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1') # Site Code + : $SiteCode = "GAL:" Set-Location $SiteCode #Properties for Setting the SMP Role $UsmtDrivePath = "F:\USMT" $MaxNumClients = 100 $MinFreeSpace = 3 $TimeDeleteAfterDays = 5 $SiteSystemServers = Get-CMSiteSystemServer write-host $SiteSystemServers.Count ForEach ($Server in $SiteSystemServers) { $ServerName = $Server.NetworkOSPath.Replace("\\", " ") $CheckSMP = Get-CMSiteRole -RoleName "SMS State Migration Point" -SiteSystemServerName $ServerName #write-host $CheckSMP.Count # If SMP Count is zero, SMP not installed If ($CheckSMP.Count -eq 0) { If ($ServerName.ToUpper().StartsWith("TEST")) { # Do Nothing, skip this type of server } Else { Write-host "No SMP Role, installing on" $ServerName $Folder = New-CMStorageFolder -StorageFolderName $UsmtDrivePath -MaximumClientNumber _ $MaxNumClients -MinimumFreeSpace $MinFreeSpace -SpaceUnit Gigabyte Add-CMStateMigrationPoint -SiteSystemServerName $ServerName -StorageFolder $Folder _ -AllowFallbackSourceLocationForContent $False -EnableRestoreOnlyMode $False -SiteCode $SiteCode _ -TimeDeleteAfter $TimeDeleteAfterDays -TimeUnit Days } } Else { Write-host "SMP Role installed, skipping server" $ServerName } }
Finding ConfigMgr Collections with Queries
Using ConfigMgr 2012 R2 (and newer), the following PowerShell script can be used to identify which device collections have a query in them, and those that do not.
Example output:
import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1') # Site Code + : Set-Location "GAL:" $CollectionList = Get-CMDeviceCollection ForEach ($Collection in $CollectionList) { $RuleName = (Get-CMDeviceCollectionQueryMembershipRule -CollectionId $Collection.CollectionID).RuleName If ([string]::IsNullOrEmpty($RuleName)) { write-host "NO Query: " $Collection.CollectionID "," $Collection.Name -foregroundcolor Red } Else { write-host "YES Query:" $Collection.CollectionID "," $Collection.Name ", Query name:" $RuleName } }
Azure AD – PowerShell Script to Change UPN of All Users in a Group
Imagine that if users in a domain have a UPN suffix which is not a public domain, such as @company.local instead of @company.com. When those users synchronize into Azure AD for EMS, Intune, O365, etc., then the users’ UPNs will be @company.onmicrosoft.com instead of a friendly @company.com UPN for logging into portals or for enrolling devices.
This is an instance that recently occurred for a customer. There are plenty of PowerShell examples around for how to change the UPN of users in Azure AD. However, this customer wanted the ability to only change the users that were part of a specific AD group, rather than the entire organization.
The following PowerShell script can do exactly just that. But please use extreme caution and thoroughly test the script first as well as the impact to those users and the Microsoft cloud technologies which they use. There are high risks and many possible negative side effects. Use this script at your own risk.
# This script will change the UPN for the user members of an AD group $AdGrp = "EMS_Users" $oldSuffix = "@company.onmicrosoft.com" $newSuffix = "@company.com" # Get the AD Group in Azure $AzAdGrp = Get-MsolGroup -All | Where-Object { $_.DisplayName -eq $AdGrp } $AzAdGrp_members = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId write-host "Total members of group: " $AzAdGrp_members.Count # Create array of users to change # Example command to test only a portion of the users in the group: $users = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId | Get-MsolUser | Where-Object { $_.UserPrincipalName -like "*john.doe*"} # Command to run for all users in the group: # $users = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId | Get-MsolUser # Change UPN of users $users | ForEach-Object { $newUpn = $_.UserPrincipalName.Replace($oldSuffix,$newSuffix) Set-MsolUserPrincipalName -NewUserPrincipalName $newUpn -UserPrincipalName $_.UserPrincipalName Write-host "New UPN assigned: " $newUpn }