Skip to main content

2 posts tagged with "Software"

View All Tags

· One min read

This post will show you how to use registry keys to test, set and remove target versions for Windows Feature Updates. This allows you to prevent Windows 10 or 11 from updating past your configured limit.

The Script

<#
.DESCRIPTION:
Script to disable the Windows 11 upgrade
.SYNOPSIS:
This script can check the Windows 11 upgrade settings or be used to set/unset those settings using. `-Test` for test-only mode, `-Unset` to remove the block on Windows 11 upgrades and no parameters to set the block.
.AUTHOR:
Mikey O'Toole
www.homotechsual.dev
.REVISION HISTORY:
2023-02-16: Parameterise the script to allow more control over the target versions
2022-01-25: Initial version
#>
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'RMM script - not useful to implement ShouldProcess')]
param (
[Switch]$Test,
[Switch]$Unset,
[String]$TargetProductVersion = '22H2',
[String]$TargetProduct = 'Windows 11'
)
function Test-UpdateSettings {
$UpdateSettings = Get-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\'
$Message = [System.Collections.Generic.List[String]]::New()
if ($UpdateSettings.TargetReleaseVersion -and $UpdateSettings.TargetReleaseVersion -ne 0) {
$Message.Add('Windows Update is currently set to target a specific release version.')
if ($UpdateSettings.TargetReleaseVersionInfo) {
$Message.Add("Target release version: $($UpdateSettings.TargetReleaseVersionInfo.ToString())")
} else {
$Message.Add('Target release version is not set.')
}
if ($UpdateSettings.ProductVersion) {
$Message.Add("Product version: $($UpdateSettings.ProductVersion.ToString())")
} else {
$Message.Add('Product version is not set.')
}
} else {
$Message.Add('Windows Update is currently set to target all versions.')
}
if ($String -is [array] -or $String.Count -gt 0) {
return $Message.Join(' ')
} else {
return $Message
}

}

function Set-UpdateSettings ([switch]$Unset) {
if ($Unset) {
try {
Set-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'TargetReleaseVersion' -Value 0 -Type DWord
if (Test-Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\TargetReleaseVersionInfo') {
Remove-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'TargetReleaseVersionInfo'
}
if (Test-Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\ProductVersion') {
Remove-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'ProductVersion'
}
} catch {
Throw $_
}
$Message = 'Windows Update is now set to target all versions.'
} else {
try {
Set-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'TargetReleaseVersion' -Value 1 -Type DWord
Set-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'TargetReleaseVersionInfo' -Value $TargetProductVersion
Set-ItemProperty -Path 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\' -Name 'ProductVersion' -Value $TargetProduct
$Message = 'Windows Update is now set to target Windows 10, 21H2.'
} catch {
Throw $_
}
}
return $Message
}

if ($Test) {
$Message = Test-UpdateSettings
Write-Output $Message
} elseif ($Unset) {
$Message = Set-UpdateSettings -Unset
Write-Output $Message
} else {
$Message = Set-UpdateSettings
Write-Output $Message
}
Parameters

When you run this script you might want to pass some parameters - here's what they do:

  • -Test - This will test the current target version settings and show you the results.
  • -Unset - This will remove the target version settings.
  • -TargetProductVersion - Specify the target version to aim for, examples would be 21H2 or 22H2.
  • -TargetProduct - Specify the target product to aim for, examples would be Windows 10 or Windows 11.

· 2 min read

This post will show you how to deploy the Printix client using NinjaOne Documentation fields and a PowerShell script.

Creating Fields

Creating custom fields in NinjaOne

To create a custom field at the device level in NinjaOne go to Administration > Devices and select either Role Custom Fields or Global Custom Fields then select Add.

  • Role Custom Fields are custom fields that are specific to a device role.
  • Global Custom Fields are custom fields that are applicable to all devices.

Make sure you add the fields to the roles you want to use them in at Administration > Devices > Roles.

To create a custom field at the organisation level in NinjaOne go to Administration > Apps > Documentation, enable the Documentation feature if you haven't already. If you have then select Add.

When you create your custom field you need to make sure that you set the "Scripts" permission to ensure that you can read or write to the field from your scripts - as appropriate for the script you're using.

We're adding two documentation fields to facilitate this script. You'll need to note your document template id, in the screenshots / our internal use we have a template called "Integration Identifiers" which we use to store any integration identifiers we need to reference in our scripts.

Field LabelField NameField TypeDescription
Printix Tenant IdprintixTenantIdTextHolds the customer's Printix tenant id.
Printix Tenant DomainprintixTenantDomainTextHolds the customer's Printix domain.

The Script

[Cmdletbinding()]
param (
[Parameter(Mandatory = $true)]
[String]$DocumentTemplate
)
try {
$PrintixTenantId = Ninja-Property-Docs-Get-Single $DocumentTemplate printixTenantId
$PrintixTenantDomain = Ninja-Property-Docs-Get-Single $DocumentTemplate printixTenantDomain
Write-Verbose ('Found Printix Tenant: {0} ({1})' -f $PrintixTenantId, $PrintixTenantDomain)
if (-not ([String]::IsNullOrEmpty($PrintixTenantId) -and ([String]::IsNullOrEmpty($PrintixTenantDomain)))) {
$PrintixInstallerURL = ('https://api.printix.net/v1/software/tenants/{0}/appl/CLIENT/os/WIN/type/MSI' -f $PrintixTenantId)
Write-Verbose ('Built Printix Installer URL: {0}' -f $PrintixInstallerURL)
$PrintixFileName = "CLIENT_{$PrintixTenantDomain}_{$PrintixTenantId}.msi"
$PrintixSavePath = 'C:\RMM\Installers'
if (-not (Test-Path $PrintixSavePath)) {
New-Item -Path $PrintixSavePath -ItemType Directory | Out-Null
}
$PrintixInstallerPath = ('{0}\{1}' -f $PrintixSavePath, $PrintixFileName)
Invoke-WebRequest -Uri $PrintixInstallerURL -OutFile $PrintixInstallerPath -Headers @{ 'Accept' = 'application/octet-stream' }
if (Test-Path $PrintixInstallerPath) {
Start-Process -FilePath 'msiexec.exe' -ArgumentList @(
'/i',
('"{0}"' -f $PrintixInstallerPath),
'/quiet',
('WRAPPED_ARGUMENTS=/id:{0}' -f $PrintixTenantId)
) -Wait
} else {
Write-Error ('Printix installer not found in {0}' -f $PrintixInstallerPath)
}
}
} catch {
Write-Error ('Failed to install Printix Client: `r`n {0}' -f $_)
}
Parameters

When you run this script you need to pass your document template id. For example, sticking with our example above, you'd run the script with the parameter: -DocumentTemplate Integration Identifiers

The Results

Printix Documentation Fields

Printix Installation Activity

We run this script on a group of devices which don't have the Printix client installed.