Skip to main content

Powershell

Calling the Microsoft Graph API via PowerShell without a user

A colleague recently asked me how to access the Microsoft Graph API using PowerShell without specifying his user account or credentials. So here’s a little post about the required configuration to authenticate against the OAuth 2.0 endpoint of Azure AD with an app registration. This is especially useful for automation services like Azure automation. At the end of this post you’ll find a PowerShell template. Gather application information # Create a new client secret for your app and note down the following values: Client Secret Application ID (client ID) Directory ID (tenant ID) Azure AD App registration ## PowerShell code Request authentication token # In order to use the Graph API we need an authentication token. The information we gathered before is now sent to the Azure AD OAuth 2.0 endpoint. https://login.microsoftonline.com/{TenantID}/oauth2/v2.0/token In the request supply a body with the following content: $body=@{ client_id="8f9f420d-606c-4e13-889e-837072dbfb42" client_secret="BlaBlaExampleSecret" #Generated secret scope="https://graph.microsoft.com/.default" grant_type="client_credentials" } The scope and grant_type are required attributes. A full example looks like: $body=@{ client_id="8f9f420d-606c-4e13-889e-837072dbfb42" client_secret="BlaBlaExampleSecret" scope="https://graph.microsoft.com/.default" grant_type="client_credentials" } $tenantId="7955e1b3-cbad-49eb-9a84-e14aed7f3400" Invoke-WebRequest -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body $body -Method Post If everything works we receive an access token object as HTML 200/ok response:

Introducing the OneDrive AutoMountTeamSites setting

Reviewing the latest OneDrive features I wanted to try the new AutoMountTeamSites setting which lets you preconfigure SharePoint online sites to sync automatically for defined users and devices. Updated on 12.07.2019: Included the Intune administrative template configuration The setting is officially described as follow: This setting lets you specify SharePoint team site libraries to sync automatically the next time users sign in to the OneDrive sync client. (Microsoft) If you enable this setting, the OneDrive sync client will automatically download the contents of the libraries you specified as online-only files the next time the user signs in. The user won’t be able to stop syncing the libraries. (Microsoft) Prerequisites # In order to get things up an running we need at least: OneDrive sync client version 19.012.0121.0011 or newer Windows 10 Version 1709 or newer OneDrive Files On-Demand enabled (described below) Be aware that this feature is not supported with on-premises SharePoint sites and not recommended to enable this setting for more than 1'000 devices. The device limit is related to the Windows Push Notification Service which tells the OneDrive clients when a file change occurs on a server side. When you exceed that limit clients will find themselves in a polling mode. Hans Brender explains this behavior well on his blog.

Intune map network drives and execute PowerShell script on each user logon

Recently a customer needed a drive mapping solution to access his on premise file shares during his transition phase to a cloud-only workplace. I wanted to share the solution with you because it’s a frequently asked question around a modern workplace migration. The following solution can also be extended or modified for a printer mapping or other PowerShell scripts which need to run on each user logon. Updated 04.08.2019: I’ve developed an automated solution to generate network drive mapping configurations with an online tool which also migrates group policy network drive mappings. See: next-level-network-drive-mapping-with-intune. Direct link to the final scripts Lets assume we have the following scenario: - Customer with hybrid user-identities (Azure AD Connect) - On premise ressources with legacy file shares - Devices are Azure AD joined  ( **not** hybrid joined) - MDM managed with Intune - [Optional] Always on VPN for external on-premise resource access - [Optional] Windows Hello for Business deployment as described [here](https://docs.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-hybrid-aadj-sso) Architecture # With my colleague Alain Schneiter I designed the following solution: Main PowerShell script stored on Azure blob storage which handles the drive mapping - driveletters, UNC paths and descriptions can be configured within the script Client side script deployed with Intune which triggers the main script during logon. The main script is not stored locally which makes it easy to customize (no updates oder changes needed on client side) Deployment is user targeted via Azure AD group and Intune Azure blob storage configuration # We wanted to store the script within Azure because the customer was already using Azure blob storage. It’s also possible to store the PowerShell script on GitHub if you don’t want to use Azure.

Clean up stale Azure AD devices

If you are using Azure AD and the time passes you’ll have a lot of old device entries. If you enable the automatic device cleanup rule in Microsoft Intune the device is only removed within MDM and the Azure AD entry still exists. Intune device cleanup rule For this reason I created a tiny PowerShell snippet to create a report with all devices which didn’t contact your Azure AD tenant since the treshold date specified. If you confirm the operation you can also delete all affected devices. Please be careful when running the script because when removing a device from Azure AD the stored Bitlocker recovery keys are also removed. I can recommend Roger Zander’s Azure table-based Bitlocker recovery key solution.

Set Office 365 UsageLocation property with Azure automation

If you want to assign Microsoft licenses to your Azure AD users e.g. Microsoft 365 E3 licenses you can do this with group based licensing as described here. The problem is that even with group based licensing the UsageLocation property for each user must be set individually. Update: 13.01.2019: Since group based licensing is GA the tenant location is used if no UsageLocation is set on a user object. Use this guide if you want to manually assign licenses or override the tenant settings if you need to configure different UsageLocations. Possible bulk and automation solutions # You can achieve this with the following options: “Manual” trough Azure or Office 365 portal PowerShell (must be triggered manually or through scheduled task) Azure AD Connect synchronisation (UsageLocation populated in on prem AD) Azure automation with PowerShell runbook as in this post 🙂 Azure automation sounds expensive? # Fortunately Azure automation offers 500 minutes of script runtime for free. Find more details under Automation pricing. Just to give you an idea: If the executed script has an average runtime of 1 minute you could run it (500 minutes / (30 calendear days / 1 minute script runtime)) = 16x per day. Each month. For free.

PowerShell Script Test Open TCP Ports

Recently I was troubleshooting ADFS connection issues when I discovered a nice little Cmdlet called “Test-NetConnection”. With this Cmdelet you can verify TCP connectivity, in my case from a client to the ADFS server. The Test-NetConnection cmdlet displays diagnostic information for a connection. It supports ping test, TCP test, route tracing, and route selection diagnostics. Depending on the input parameters, the output can include the DNS lookup results, a list of IP interfaces, IPsec rules, route/source address selection results, and/or confirmation of connection establishment. Find a full documentation on the Microsoft Docs Page. About the script # With this Script you are able to specify server names and port numbers to check in a CSV File. The Script generates an CSV output file as a report. You can use this script for troubleshooting or engineering purposes to verify if TCP ports are opened. Simply add the hostname and TCP port to the “CheckList.csv” and the script checks the specified servers and ports. The script will generate an output file for the same path containing the suffix “Report_” with the test results. CheckList.csv: Report_CheckList.csv generated after script execution:

PowerShell Function Validate Object Properties Using ValidateScript

 Recently I was working on a PowerShell script with many custom functions. When I started to use PowerShell custom objects I wanted to be able to pass them to a function. So I faced the challenge of validating my object for all required properties and came up with this solution, using the ValidateScript block to test the object: Customizing the ValidateScript # As you can see I use a ValidateScript for the parameter validation to test the object for the required properties. The properties can be specified in an array: $requiredProperties=@("Property1","Property2","Property3", "Property4") When we call the Function with an appropriate object: $config= [PSCUSTOMOBJECT]@{ property1= "Value"; property2= "Value"; property3= "Value"; property4= "Value"; } We receive the following output: PS H:\> New-Example -InputObject $config Succesfully passed ValidateScript Result # If we remove one or more properties from our custom object, an error is thrown: PS H:\> $config= [PSCUSTOMOBJECT]@{ property1= "Value"; property2= "Value"; property3= "Value"; } New-Example -InputObject $config New-Example : Cannot validate argument on parameter 'InputObject'. Property: 'Property4' missing At line:10 char:26 + New-Example -InputObject $config + ~~~~~~~ + CategoryInfo : InvalidData: (:) [New-Example], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,New-Example If you want to go a step further you could extend the ValidateScript to… Prevent passing properties with a NULL or empty value # $_.PSObject.Properties | ForEach-Object { if (([string]::IsNullOrEmpty($_.Value))){ Throw [System.Management.Automation.ValidationMetadataException] "Property '$($_.Name)' has either a NULL or empty value" } } If we call our function again with the added IsNullOrEmpty validation NULL or emtpy values throw an exception:

Managing printers with PowerShell

Managing printers with PowerShell instead of VBScript? Sometimes it’s necessary to add and remove specific printers to a computer. For example during a client deployment or when a user logs on. This post covers how to manage printers with PowerShell. The following PowerShell commands are supported with PowerShell version 4 and newer. Installing a local network printer # Installing a local printer (without a printserver) consists of the following steps: Add the printer driver to your system’s driverstore Install the printer driver from the driverstore Add a printer port to communicate with the printer Last but not least add the printer Add the printer driver to the driverstore # Before you can install the printer driver you need to import the printer driver to your system’s driverstore. This can be achieved with the built in Windows “pnputil” utility. The following code adds all drivers from the specified path to the driverstore: Get-ChildItem %PathToYourDriverFolder% -Filter *.inf -Recurse | % {pnputil.exe /a $_.FullName} Install the printer driver from the driverstore # This step is quite simple, you just need to know the name of the printer driver you want to install. For example “HP Universal Printing PCL 6”.