
The Device filter
We started by creating a device filter to filter on Windows 10 (all versions) and Windows 11 21H1 like below:
(device.osVersion -startsWith "10.0.1") or (device.osVersion -startsWith "10.0.22000")
The Application
Next we created an application using the PowerShell App Deployment Toolkit (PSADK). The code part itself is small as it doesn't have to do that much.
The application will only show a message when the device is being enrolled and will exit with code 1603 to let the enrollment fail. When the device is not in enrolment, it will set the neccasary registry key and exit.
In the Deploy-Application.ps1 the installation part looks like below:
##*===============================================
##* INSTALLATION
##*===============================================
[String]$installPhase = 'Installation'
$ifDefaultUser0 = $false
$LoggedOnUserSessions | ForEach-Object {
If ($_.UserName -eq 'defaultuser0') {
Write-Log -Message "$($_.UserName) user is signed in." -Source $appDeployToolkitName
$ifDefaultUser0 = $true
}
}
If ($ifDefaultUser0) {
If (-not($IsOOBEComplete)) {
Write-Log -Message "Requirement text: $RequirementText" -Severity 1 -Source $deployAppScriptFriendlyName
Copy-File -Path "$dirFiles\Logo.png" -Destination "$configToolkitCachePath\EnrollemntRequirements"
$RequirementText | Out-File -FilePath "$configToolkitCachePath\EnrollemntRequirements\RequirementText.txt"
Copy-File -Path "$dirFiles\cmtrace.exe" -Destination "$envWinDir\System32"
Start-Sleep -Seconds 3
Set-RegistryKey -Key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'ConsentPromptBehaviorAdmin' -Type 'DWord' -Value '0'
Start-Sleep -Milliseconds 500
[__ComObject]$WShell = New-Object -ComObject 'WScript.Shell' -ErrorAction 'SilentlyContinue'
$WShell.SendKeys('+{F10}')
$i = 0
Do {
$i++
Get-Process -Name cmd | Stop-Process -Force
Start-Sleep -Milliseconds 500
} Until ($i -ge 10)
Set-RegistryKey -Key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'ConsentPromptBehaviorAdmin' -Type 'DWord' -Value '1'
Execute-Process -Path "$dirFiles\ServiceUI.exe" -Parameters "$dirFiles\popup.exe" -NoWait
}
Exit-Script -ExitCode 1603
} Else {
Write-Log -Message "defaultuser0 user is not signed in. Skip." -Source $appDeployToolkitName
}
#endregion
##*===============================================
##* POST-INSTALLATION
##*===============================================
[String]$installPhase = 'Post-Installation'
#Remove unzipped folder
If ($ZIPName -and $ZIPRemove) {
Remove-Folder -Path $ZIPDestination
}
#Region POST-INSTALL
##
#endregion
#This should be the last task
If ($Set_INGAuditKey) {
Set-RegistryKey -Key $AuditKey -Name 'ApplicationName' -Value $PKGName
Set-RegistryKey -Key $AuditKey -Name 'InstallDate' -Value $currentDateTime
Set-RegistryKey -Key $AuditKey -Name 'Version' -Value $appVersion
Set-RegistryKey -Key $AuditKey -Name 'Language' -Value $appLang
Set-RegistryKey -Key $AuditKey -Name 'Revision' -Value $appRevision_version
}
#Reboot section
If ($IsRebootRequired -or $IsRebootRequired_Install) {
$mainExitCode = 3010 #By default, Intune sets 3010 as soft reboot
}
Next to the Deploy-Application.ps1 script the are 2 main files included: ServiceUI.exe and Popup.exe. This last one is created from the below popup.ps1 script.
$ErrorActionPreference = 'SilentlyContinue'
function Show-WPFWindow
{
param
(
[Parameter(Mandatory)]
[Windows.Window]
$Window
)
$result = $null
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
function Convert-XAMLtoWindow
{
param
(
[Parameter(Mandatory=$true)]
[string]
$XAML
)
Add-Type -AssemblyName PresentationFramework
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
$result = [Windows.Markup.XAMLReader]::Load($reader)
$reader.Close()
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
while ($reader.Read())
{
$name=$reader.GetAttribute('Name')
if (!$name) { $name=$reader.GetAttribute('x:Name') }
if($name)
{$result | Add-Member NoteProperty -Name $name -Value $result.FindName($name) -Force}
}
$reader.Close()
$result
}
function Show-PopupWindow {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[ValidateNotNullorEmpty()]
[String[]]$NotificationTitle,
[Parameter(Mandatory = $true)]
[ValidateNotNullorEmpty()]
[String[]]$NotificationContent,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[switch]$PassThru = $true
)
#region XAML
$xaml = @'
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Window" Width="1010" Height="355" Topmost="True" WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True" Background="Transparent" WindowStartupLocation="CenterScreen" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" ShowInTaskbar="False">
<Grid Margin="0,0,0,0">
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" Height="345" Width="1000" VerticalAlignment="Top" Margin="5,5,5,5" CornerRadius="5" Background="#f0f0f0">
<Border BorderThickness="0" HorizontalAlignment="Center" Height="50" VerticalAlignment="Top" Width="1600" Margin="0,0,0,0" CornerRadius="5" Background="#d3d3d3">
<TextBlock Name="TextTitle" FontSize="12" FontWeight="Bold" Foreground="Black" Margin="5,5,5,5" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Global Workplace Services inform you"/>
</Border>
</Border>
<Image Name="Logo" Height="200" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="30,80,0,0"/>
<Image Name="ICPLogo" Height="40" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="25,12,0,0"/>
<TextBlock Name="TextNotificationTitle" FontSize="17" FontWeight="Bold" Foreground="Black" Margin="5,27,5,5" HorizontalAlignment="Center" TextWrapping="Wrap"/>
<TextBlock Name="TextNotificationContent" FontSize="30" FontWeight="Bold" Foreground="Black" Margin="240,100,50,50" HorizontalAlignment="Center" TextWrapping="Wrap"/>
</Grid>
</Window>
'@
#endregion
$window = Convert-XAMLtoWindow -XAML $xaml
$window.TextNotificationTitle.Text = $NotificationTitle
$window.TextNotificationContent.Text = $NotificationContent
$window.Logo.Source = "$env:ProgramFiles\SRC\EnrollemntRequirements\Logo.png"
$window.ICPLogo.Source = "$env:WinDir\ImmersiveControlPanel\images\logo.png"
$null = Show-WPFWindow -Window $window
}
[string]$Text = ''
[string]$RequirementText = ''
$RequirementTextFile = "$env:ProgramFiles\SRC\EnrollemntRequirements\\RequirementText.txt"
If (Test-Path -Path $RequirementTextFile -PathType Leaf) {
$Text = Get-Content -Path $RequirementTextFile
}
$Text.Split(';') | ForEach-Object {
$RequirementText = $RequirementText + $_ + " `r`n"
}
[string]$NotificationContent = "This device cannot be enrolled because it does not meet the minimum requirements `n" + $RequirementText
Show-PopupWindow -NotificationTitle 'Enrollment restrictions' -NotificationContent $NotificationContent
We created a nice Intinewin package out of it, so so we could create the application in Intune. Below the most important part of the app configuraction:
As you can see the application is assigned to all Windows 10 and Windows 11 21H2 devices, but on the already enrolled devices it will only set the registry value and exit.
The Enrollment Status Page
The last piece of the puzzle is the ESP, which is targetted to the all Windows 10 and Windows 11 21H2 devices again and will only have the above application as blocking app assigned to it.
Conclussion
When you have other teams also manaing Windows devices in the same Intune tetant and you cannot what till every teams is ready to block versions from being block, the bove setup can be used.
Engineers running the pre-provisiong will get a nice message and also users will get a message they can understand.
Comments
Post a Comment