Category Archives: EMS

Local client SPO migration script

For a customer case/project, we wanted to move only recently synced/modified Sharepoint Online data from Tenant A to the user’s Desktop on the device itself.

The Desktop was synced to Onedrive for Business in Tenant B.

After copying, files from Tenant A should become read-only on the local device, and the link in Explorer to Tenant A’s sharepoint should be removed, including the actual onedrive sync relationship to prevent further ul/dl’s.

Resulting in https://gitlab.com/Lieben/assortedFunctions/-/blob/master/migrate-modifiedSpOSyncedFilesToUserDesktop.ps1

Deallocate Azure AD Joined Azure Virtual Desktop VMs when a user logs off

When you shut down a VM or log off, the VM isn’t actually deallocated and still costs money.

Bernd wrote a nice guide on how to deallocate a VM when a user logs off, using GPO’s, since combined with Start On Connect the user experience is still pretty decent.

For Intune / Microsoft Endpoint Manager, no solution was known yet. So I base64 encoded Bernd’s solution and wrapped it into a SYSTEM wide scheduled task that is triggered by a security eventlog logoff entry.

Deploy this to your VM’s in Intune (either through a user or a machine group) and it’ll ensure users’ VM’s get deallocated when they log off.

This also works on shared VM’s, as it will only deallocate if it is the last user logging off.

You can download/view set-AVDDeallocateOnLogoff.ps1 here.

(re) configuring hidden VPN Profile properties

Using MEM (Intune) we can automatically deploy VPN profiles to our users’ managed devices directly.

The set of parameters that can be configured in MEM is extremely limited compared to what actually ends up on the rasphone.pbk file (VPN Profile) on a Windows client.

Example of a .pbk file for an Azure P2S VPN connection with Conditional Access/cert based SSO:

[AzureVirtualNetwork]
Encoding=1
PBVersion=6
Type=4
AutoLogon=0
UseRasCredentials=1
LowDateTime=-1117351264
HighDateTime=30942358
DialParamsUID=927022140
Guid=AABC7C8342FD91458105A961BE471F8E
VpnStrategy=7
ExcludedProtocols=8
LcpExtensions=1
DataEncryption=256
SwCompression=1
NegotiateMultilinkAlways=1
SkipDoubleDialDialog=0
DialMode=0
OverridePref=15
RedialAttempts=0
RedialSeconds=0
IdleDisconnectSeconds=0
RedialOnLinkFailure=0
CallbackMode=0
CustomDialDll=
CustomDialFunc=
CustomRasDialDll=%windir%\system32\cmdial32.dll
ForceSecureCompartment=0
DisableIKENameEkuCheck=0
AuthenticateServer=0
ShareMsFilePrint=1
BindMsNetClient=1
SharedPhoneNumbers=0
GlobalDeviceSettings=0
PrerequisiteEntry=
PrerequisitePbk=
PreferredPort=VPN2-0
PreferredDevice=WAN Miniport (IKEv2)
PreferredBps=0
PreferredHwFlow=0
PreferredProtocol=0
PreferredCompression=0
PreferredSpeaker=0
PreferredMdmProtocol=0
PreviewUserPw=0
PreviewDomain=0
PreviewPhoneNumber=0
ShowDialingProgress=0
ShowMonitorIconInTaskBar=1
CustomAuthKey=13
CustomAuthData=314442430D000405C000000020005005C0000001500000014000000A8985D3A65E5E5C4B2D7D66D40C6DD2FB19C5436020001001230FE0006000100FCD02C00
CustomAuthData=3BCB684FDAE6ED1B763A3EDEB989B12C95EFFAFFD330281E75F1C671B03CDD800FF0844797977764005000500
AuthRestrictions=128
IpPrioritizeRemote=0
IpInterfaceMetric=1
IpHeaderCompression=1
IpAddress=0.0.0.0
IpDnsAddress=172.1.230.4
IpDns2Address=172.1.230.5
IpWinsAddress=0.0.0.0
IpWins2Address=0.0.0.0
IpAssign=1
IpNameAssign=2
IpDnsFlags=0
IpNBTFlags=1
TcpWindowSize=0
UseFlags=2
IpSecFlags=0
IpDnsSuffix=
Ipv6Assign=1
Ipv6Address=::
Ipv6PrefixLength=0
Ipv6PrioritizeRemote=1
Ipv6InterfaceMetric=0
Ipv6NameAssign=1
Ipv6DnsAddress=::
Ipv6Dns2Address=::
Ipv6Prefix=0000000000000000
Ipv6InterfaceId=0000000000000000
DisableClassBasedDefaultRoute=1
DisableMobility=0
NetworkOutageTime=0
IDI=
IDR=
ImsConfig=0
IdiType=0
IdrType=0
ProvisionType=0
PreSharedKey=
CacheCredentials=0
NumCustomPolicy=0
NumEku=0
UseMachineRootCert=0
Disable_IKEv2_Fragmentation=0
PlumbIKEv2TSAsRoutes=0
NumServers=0
RouteVersion=1
NumRoutes=0
NumNrptRules=0
AutoTiggerCapable=0
NumAppIds=0
NumClassicAppIds=0
SecurityDescriptor=
ApnInfoProviderId=
ApnInfoUsername=
ApnInfoPassword=
ApnInfoAccessPoint=
ApnInfoAuthentication=1
ApnInfoCompression=0
DeviceComplianceEnabled=0
DeviceComplianceSsoEnabled=0
DeviceComplianceSsoEku=
DeviceComplianceSsoIssuer=
WebAuthEnabled=0
WebAuthClientId=
FlagsSet=0
Options=0
DisableDefaultDnsSuffixes=0
NumTrustedNetworks=0
NumDnsSearchSuffixes=0
PowershellCreatedProfile=0
ProxyFlags=0
ProxySettingsModified=0
ProvisioningAuthority=
AuthTypeOTP=0
GREKeyDefined=0
NumPerAppTrafficFilters=0
AlwaysOnCapable=0
DeviceTunnel=0
PrivateNetwork=0

NETCOMPONENTS=
ms_msclient=1
ms_server=1

MEDIA=rastapi
Port=VPN2-0
Device=WAN Miniport (IKEv2)

DEVICE=vpn
PhoneNumber=azuregateway-12341ef-4922-4edc-a492-589b3e547c58-1ba19cb9ae52.vpn.azure.com
AreaCode=
CountryCode=0
CountryID=0
UseDialingRules=0
Comment=
FriendlyName=
LastSelectedPhone=0
PromoteAlternates=0
TryNextAlternateOnFail=1

Modifying VPN Profile settings

To allow admins further customization of these settings, I’ve written a Proactive Remediation script that can customize any VPN profile property to any value you specify.

In our case, we used it to set IpInterfaceMetric, which defaults to 0, causing ambiguously routed traffic to never prefer the VPN connection (since this is a split tunnel connection). Setting it to 1 resolved our DNS/routing issues to certain private endpoints in our Azure environment.

Code / git link: https://gitlab.com/Lieben/assortedFunctions/-/blob/master/set-vpnConnectionInterfaceMetric.ps1

Automated Stale Device Cleanup in Azure Active Directory using a runbook

As with cleaning up inactive guest users, inactive devices also pose several issues for organizations.

Microsoft recommends cleaning up stale devices after 90 days, but does not provide a service option or automation to do so.

Therefore, here’s another runbook you may run to just report on your inactive devices, or to automatically (and optionally periodically) clean up inactive devices in your environment when the removeInactiveDevices switch is supplied.

Managed identity

When run locally, interactive sign in is required. When running as a runbook in Azure automation, the Managed Identity of the automation account is leveraged. This requires you to set Device.ReadWrite.All or Device.Read.All permissions depending on if you want to script to do the cleanup as well. If doing cleanup, also add the managed identity to the cloud device administrator (Azure AD) role.

Autopilot / on premises devices

Note that the script will log an error (and not attempt to delete the device) when a device is an autopilot record (not a real device) or when the device is synced from an on-premises active directory.

Disable vs Delete

The runbook also has a disable option, in which it will first disable a device and wait a configurable ($disableDurationInDays) period of time before actually deleting a device.

Reports

If you wish, you can also let the script mail you a report in CSV format. Add the Mail.Send graph permissions like you did with device permissions and give the MailFrom and MailTo parameters a value.

Download

Download get-AzureADInactiveDevices.ps1 from Gitlab

Disclaimer

As always, the script is provided as-is and should be reviewed and then used at your own risk.

Redirecting anything to Onedrive for Business

A while ago I wrote a script that can mount Teams Libraries and then redirect any local folder to them.

In many situations, this solution is a little overkill though, so I’ve also created a second version which simply allows you to redirect any local folder (including variable paths!) to any location in a user’s Onedrive folder.

The configuration is set through the registry, an example file is included.

It can be used as a onetimer or as logonscript, and it can also be used to migrate existing content or create hard links for specific local appdata folders.