Script to configure Azure AD Cloud Kerberos Trust

As businesses increasingly operate in hybrid environments spanning both on-premises and cloud infrastructure, the need for seamless authentication across multiple environments becomes paramount. To address this challenge, organizations are turning to automated processes for implementing and managing Cloud Kerberos Trust. This automated approach streamlines the integration of Kerberos-based authentication in diverse environments, ensuring efficient and secure access to cloud resources.

The PowerShell script Enable-CloudKerberosTrust.ps1 simplifies and automates the process of Configuring Azure AD Cloud Kerberos Trust.

To get a deeper understanding and a great story, You should also read to following article series by Ben Whitemore and Michael Mardahl who inspired the script.

1. Install Azure AD Kerberos PowerShell module
2. Prompt the user for domain admin credentials (if it detects it is not running as domain admin)
3. Create a Kerberos Server object
4. Verify a Kerberos Server object has been created successfully
5. Create "CKT-Policy" Intune configuration profile 
6. Create OMA-URI for Cloud Kerberos Trust enablement
7. Assign the configuration profile
1. Azure Active Directory global administrator.

2. Active Directory domain administrator.

3. Approve admin consent for the following permissions in Microsoft Graph application in Azure AD apps:
CloudPC.ReadWrite.All, DeviceManagementConfiguration.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, Directory.Read.All
.PARAMETER Domain
Specifies the on-premises Active Directory domain. A new Azure AD Kerberos Server object will be created in this Active Directory domain.
.PARAMETER UserName
Specifies the UPN of an Azure Active Directory global administrator.
.PARAMETER TenantID
Specifies the Azure AD tenant ID for the new Intune configuration policy.
.PARAMETER Group
Specifies the device group to assign the new Intune configuration policy.
.PARAMETER LogPath
Specifies path to save script output to.
.EXAMPLE
.\Enable-CloudKerberosTrust.ps1 -Domain xyz.com -UserName [email protected] -TenantID 0570e92c-8fb4-4775-9eb8-61f20dd2ce72 -Group Group1 -LogPath .\

Download the script: Enable-CloudKerberosTrust.ps1

NOTE: THIS SCRIPT IS CONTINUALLY BEING IMPROVED – If you would like to suggest additional checks or improvements, feel free to reach out with your input.

Check Autopilot Prerequisites – first update

Autopilot is an indispensable tool for managing and deploying Windows devices in the enterprise. Before deploying Autopilot, it is crucial to ensure that your environment meets the necessary prerequisites. This process can be time-consuming and prone to errors, which is why the Autopilot Prerequisite Checker has been introduced to automate the prerequisite checking process.

The Autopilot Prerequisite Checker is a PowerShell script that validates whether your environment meets the requirements for deploying Autopilot. The updated script now checks for the following prerequisites:

Tenant checks:

Check license requirements
Automatic Windows enrollment (MDM authority is set)
DNS records
Check user can join device to Azure AD
Check Enrollment Status Page
Check Windows Autopilot Deployment Profile
Check company branding

Device checks:

Windows OS version
Hardware hash uploaded to Intune
Check Windows Autopilot Deployment Profile assignment status
Updated with more devices check in version 1.0.1:
 - Windows InstallDate
 - Bios Version
 - Bios Status
 - Bios Serialnumber
 - OS Serialnumber
 - Hostname
 - Keyboardlayout
 - Timezone
 - TPM present
 - TPM Enabled
 - TPM ready

User checks:

User is licensed correctly

Network checks:

Required communication for Intune Autopilot is allowed
Updated with multiple in version 1.0.1 with more URLs

Using the script is a breeze. It can be run on any machine with PowerShell installed. Simply download the script, execute it, and wait for the results. The output will indicate whether your environment meets the necessary prerequisites for Autopilot.

Download the updated script 1.0.1

The advantages of using the updated script are numerous. It saves time by automating the prerequisite checking process, allowing you to concentrate on more crucial tasks. Additionally, it minimizes the risk of errors, ensuring that your Autopilot deployment is successful on the first attempt. Ultimately, it provides peace of mind by confirming that your environment meets the requirements for deploying Autopilot.

In summary, the Autopilot Prerequisite Checker is a robust script that simplifies the process of verifying the prerequisites for deploying Autopilot. Whether you are an IT administrator or a consultant, the Autopilot Prerequisite Checker is an essential tool for ensuring the success of your Autopilot deployment.

NOTE: THIS SCRIPT IS CONTINUALLY BEING IMPROVED – If you would like to suggest additional checks or improvements, feel free to reach out with your input.

Download all OneDrive files for a user using PowerShell

Powershell script to download a users OneDrive content.

New and improved: Download-OD4BAccount.ps1

.Example 
.\Download-OD4BAccount.ps1 -Username [email protected] -Destination "D:\OD4B" -ThreadCount 3 -Verbose

Script prerequisites:

1. Microsoft Graph PowerShell Module installed on local machine. The script automatically checks for and installs module if needed.

2. An Azure AD user that has an admin consent to approve the following permissions in Microsoft Graph application in Azure AD apps:
   Organization.Read.All, User.Read.All, Directory.Read.All

This was inspired by Adnan's script, which i have used on multiple occasions.
But when downloading very large OneDrive data structures, Multi-Threads seems to work faster and smoother.
 

List Packages that run in user context (Run with user’s rights)

Introduction

After last weeks post with the script sample to list Packages that run in user context, there where some good feedback from people still using packages, and requiring a list of packages that install within the user context (Run with user’s rights / Execution mode as user)

It seemed that many was still using Packages, either as a result of legacy migration or to avoid some application re-packaging.

So here is the followup post, with a new script to list all packages and package with programs that run in user context.

From my point of view, its still the same; Using PSADT pretty much any package can be converted to be installed as system, and the needed stuff (registry keys, files etc) in the user context can be added in a structured and controlled way.

I do still come across some applications that i would prefer to have in MSI with all settings etc added, at least for simplicity, for those packages I still prefer to use Advanced Installer.
When talking Advanced Installer, they also have a great support for MSIX, that makes to process so much easier and cost efficient.

This script will list all packages with programs, that is configured to install as user (within the user context)

All you need to do is configure the path to your import module and set the site code.

A file will be created in “C:\TEMP\Packages_and_Programs_Run_Mode_List.csv” with the following format:

“Package Name”,”Package ID”,”Program Name”,”Run with USER’s right”
“My Application”,”BB10001D”,”execute”,”TRUE

With the example above we have a package ‘My Application’ that has a run mode configured: Run with user’s rights

Properties on the program, where the program run enviroment is configured to Run with Users’s rights


Download the script from TechNet Galleryhttps://gallery.technet.microsoft.com/Generate-a-list-of-d8778d4c?redir=0



List Applications that run in user context (Install for User)

Introduction

When deploying applications sometimes they are created to install within the active users context.
This means that the actual installation requires the users to have the needed permissions to the filesystem, registry and etc.
In some cases local administrative rights are needed to perform the application installation, this is not a good practice.

As applications mature for the modern design of the Windows Operating System or we choose to remove the users administrative rights due to security reasons, we may need to list and change the behavior of existing Applications.

This script was created to list applications that is configured to run with Installation behavior: Install for User

The actual output will end up in the export csv file

Script Download [download id=”893″]



Today with the modern management tools and applications, the users should not have local administrative rights on a permanent basis.
Most, if not all applications can be repackaged to deploy without the need for administrative rights.



Useful links:

PowerShell Application Deployment Toolkit: https://psappdeploytoolkit.com
Advanced Installer: https://www.advancedinstaller.com/
Access Director Enterprise: https://ctglobalservices.com/access-director-enterprise/



Cleaning up shortcuts

So the issue at hand;
I was replacing a Office application on Windows systems, where i noticed that shortcuts created by the users, was not upgraded/removed when the new office version was installed.

The issue seems to be related to users creating custom shortcuts, directly to exe files.
I some cases the shortcut name was clear, but in other cases the users had chosen something they found fit.

The following PowerShell script was created to remove shortcuts (lnk files) based on the executable. This means you can specific the exe or use a wildcard if there is multiple executable files releated to an application.

$ShortcutLocations = Get-ChildItem -Recurse (“C:\Users”,”C:\ProgramData\Microsoft\Windows\Start Menu”) -Include *.lnk -Force -ErrorAction SilentlyContinue

########
# This script searches for all *.lnk files to "C:\Program files (x86)\App\My Application.exe" or "C:\Program Files\App\My Application.exe"
# It searches in C:\users\* profiles paths, including Users Desktops, %AppData%\Microsoft\Internet Explorer\Quick Launch and in ProgramData...StartMenu
# The name of the link file can have many different names, therefore we must find each shortcut based on path to target exectuable and not on lnk name.
# Then the lnk file must be deleted.
#
# The script should be run with admin rights, otherwise shortcuts will only be deleted for the user running the script.
########

### Specify shortcut's target executable here.
$AppExecutable = "C:\Program files*\Microsoft Office\Office15\*.exe"
# * Due to mask it contains "Program files" and "Program files (x86)" paths both.
###

### Paths to browse and search for shortcuts.
$ShortcutLocations = Get-ChildItem -Recurse ("C:\Users","C:\ProgramData\Microsoft\Windows\Start Menu") -Include *.lnk -Force -ErrorAction SilentlyContinue
# * -Recurse = Includes all subdirectories.
###


### Get properties for shortcuts in the locations

Function Get-ShortcutsProperties {
$Shell = New-Object -ComObject WScript.Shell 
Foreach ($Shortcut in $ShortcutLocations)
{
$Properties = @{
ShortcutName = $Shortcut.Name;
ShortcutFullName = $Shortcut.FullName;
ShortcutLocation = $shortcut.DirectoryName
ShortcutTarget = $Shell.CreateShortcut($Shortcut).targetpath
}
New-Object PSObject -Property $Properties
}
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}
###

$ShortcutsList = Get-ShortcutsProperties

### Compare shortcut's target path with $AppExecutable and delete it in case of corresponding one
Foreach ($item in $ShortcutsList) {

if ($item.ShortcutTarget -like $AppExecutable) {

Remove-Item -Path $item.ShortcutFullName -Force -ErrorAction SilentlyContinue
 }
}
######## End of the script

Download the PowersShell Script here: [download id=”877″]

MSiX – Remote machine conversions

The MSiX Packaging Tool (1.2019.226.0) Preview now has the ability to connect to a remote machine, where you can run the conversion.
This is great news, and solves the normal issue with contamination on “non-sanitised” machines.

I have always preferred to do my packaging and re-packaging on Hyper-V Virtual Machines
This gives a total control and clean enviroment, with easy ability to get back to a controlled point of reference, using checkpoints.

Getting started with remote machine conversions? Fear not! It is quite simple to get started.

– PowerShell remoting must be enabled for secure access to the remote machine.
– You must be logged on with administrative privileges on the machine.

To enable PowersShell remoting on the machine, run the following command in an elevated PowerShell prompt: Enable-PSRemoting -Force -SkipNetworkProfileCheck

If network/firewall restrictions are in place, remember to allow inbound traffic on port 1599 (MSiX Packaging Tool default port, it can be changed with the settings tab)

If you are connecting using a non-domain joined machine, you must use a certificate to connect over https.
To enable PowerShell remoting and allowing WinRM over https run the following commands in an elevated PowerShell prompt

Enable-PSRemoting -Force -SkipNetworkProfileCheck

New-NetFirewallRule -Name "Allow WinRM HTTPS" -DisplayName "WinRM HTTPS" -Enabled True -Profile Any -Action Allow -Direction Inbound -LocalPort 5986 -Protocol TCP

To generate a self-signed certificate, configure WinRM secure configuration and export the certificate, you can run this script: (or download: [download id=”863″])

$thumbprint = (New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\LocalMachine\My -KeyExportPolicy NonExportable).Thumbprint
$command = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname=""$env:computername"";CertificateThumbprint=""$thumbprint""}"
cmd.exe /C $command
Export-Certificate -Cert Cert:\LocalMachine\My\$thumbprint -FilePath <path_to_cer_file>

On your locale Machine, copy the exported certificate and install it into the Trusted Root Store.
It can be imported with the following command: Import-Certificate -FilePath <path> -CertStoreLocation Cert:\LocalMachine\Root





Poweshell under the security context of another user (RunAs)

Recently i needed to run some powershell scripts under multiple security context’s – the main reason for this was my client’s strict delegation model.

We ended up with multiple service account with rights only to the needed systems (Its not such a bad thing!)

The result was this powershell script to change security context

$SPAccountName = “<username>”;
$AccountPassword = “<password>”;
$AccountPasswordAsSecureString = $AccountPassword | ConvertTo-SecureString -Force -AsPlainText
$credential = New-Object System.Management.Automation.PsCredential(“$env:userdomain\$SPAccountName”,$AccountPasswordAsSecureString)
$SvcAccSession = New-PSSession -Credential $credential;
Invoke-Command -Session $SvcAccSession -Script { Import-Module ActiveDirectory }
Invoke-Command -Session $SvcAccSession -Script { Get-AdGroupMember “Some-group”}

In the above example we just get the member of some application group – but really, you can do whatever you like.

If you need it to query a specific server you can use -Computername <servername> right after New-PSSession.

This method also came in rather handy when running service-side powershell execution invoked by a webservice.. but more on that later

 

Unable to use Power Shell AD cmdlets on Remote Server

I came across this error when building a web service executing powershell cmdlets

When executing the commands directly on the server worked without problems

but when using New-PSSession to invoke the scripts I ended up with the following error:

WARNING: Error initializing default drive: ‘Unable to contact the server. This
may be because this server does not exist, it is currently down, or it does not
have the Active Directory Web Services running.’.
Unable to contact the server. This may be because this server does not exist,
it is currently down, or it does not have the Active Directory Web Services
running.
+ CategoryInfo : ResourceUnavailable: (:) [Get-ADObject], ADServe
rDownException
+ FullyQualifiedErrorId : ActiveDirectoryServer:0,Microsoft.ActiveDirector
y.Management.Commands.GetADObject
+ PSComputerName : localhost

Note that PSComputerName was not defined in my script – default is localhost.

To resolve the problem i did the following:

  1. Added “-Computername <Server1>” to my script file (Server1 is a domain controller, that had Active Directory Web Services running (default on Domain controllers running Windows Server 2012 R2) (Check Link for running on Windows Server 2003 and Windows Server 2008)
  2. Executed “Winrm QuickConfig” on Server1

I was searching for groups with a specific like description with the following command: get-adobject -Filter {description -like “ps1*”}

and the result with the problem solved:

PSComputerName : Server1
RunspaceId : b83f4390-36b7-4cfa-8539-279b12fce09f
DistinguishedName : CN=Application Group
1,OU=Applications,DC=ThomasMarcussen,DC=com
Name : Application Group 1
ObjectClass : group
ObjectGUID : 4c57f3b5-726b-4de7-882b-2c80b3f0fdb8

PSComputerName : Server1
RunspaceId : b83f4390-36b7-4cfa-8539-279b12fce09f
DistinguishedName : CN=Application Group
2,OU=Applications,DC=ThomasMarcussen,DC=com
Name : Application Group 2
ObjectClass : group
ObjectGUID : 70289cdd-0277-457e-bc2d-162703342f74

 

 

Change the size of a virtual machine by using a Azure PowerShell script

Finally i got around to moving my demo environment to Azure

I don’t need my environment to perform 100% while not using it, so came a cross this nice way to scale my environment on-demand.

This is possbile with a simple powershell script:

Function HowTo-SetAzureVMSize{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$ServiceName,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$Name=$ServiceName,
[parameter(Mandatory=$true)]
[string]$VMSize
)
PROCESS{
Get-AzureVM –ServiceName $ServiceName –Name $Name |
Set-AzureVMSize $VMSize |
Update-AzureVM
}
}
HowTo-SetAzureVMSize -ServiceName {your-cloud-service-name} -Name {your-vm} –VMSize “{your-desired-vm-size}”

Example:

Function HowTo-SetAzureVMSize{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$ServiceName,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$Name=$ServiceName,
[parameter(Mandatory=$true)]
[string]$VMSize
)
PROCESS{
Get-AzureVM –ServiceName $ServiceName –Name $Name |
Set-AzureVMSize $VMSize |
Update-AzureVM
}
}
HowTo-SetAzureVMSize -ServiceName ThomasMarcussen -Name TMSRV001 –VMSize “Standard_D2”

Currently not all hardware configurations are available in all locations – I tested in Western Europe.

Virtual Machine Sizes:

A0 (Shared core, 768 MB Memory)
A1 (1 core, 1.75 GB Memory)
A2 (2 cores, 3.5 GB Memory)
A3 (4 cores, 7 GB Memory)
A4 (8 cores, 14 GB Memory)
A5 (2 cores, 14 GB Memory
A6 (4 cores, 28 GB Memory)
A7 (8 cores, 56 GB Memory)

D1 (1 core, 1.75 GB Memory)
D2 (2 cores, 7 GB Memory)
D3 (4 cores, 14 GB Memory)
D4 (8 cores, 28 GB Memory)
D11 (2 cores, 14 GB Memory)
D12 (4 cores, 28 GB Memory)
D13 (8 cores, 56 GB Memory)
D13 (16 cores, 112 GB Memory)

Allowed values are:

ExtraSmall
Small
Medium
Large
ExtraLarge
A5
A6
A7
A8
A9

Basic_A0
Basic_A1
Basic_A2
Basic_A3
Basic_A4

Standard_D1
Standard_D2
Standard_D3
Standard_D4
Standard_D11
Standard_D12
Standard_D13
Standard_D14