The members of the ControlUp community discussed creating an alert for when users upgrade to Windows 11, and potential methods to determine this information. There was talk of using SCCM for confirmation, querying event logs, and even using a custom script that was shared in the text. The script was described as an experiment that the user can share if others are interested.
Read the entire ‘Creating an Alert for Windows 11 Upgrades Using SCCM and Event Logs’ thread below:
Happy Friday All
is is possible to create a trigger based on when you upgrade to Windows 11
So eg , today 9am you are still on Windows 10 , you then get a popup from our IT team to upgrade to Windows 11
(you see this as a opportunity to miss a few meetings and you update 😄 ) i want to create a alert to show that you just upgraded to Windows 11 once your device comes online again
The message part is easy
The "send it only once after upgrade" might require some additional thought.
How are you performing the actual upgrade?
its done , via the SCCM team and thats the hard part , some users will start the update once they get the popup , others will dismiss and only do it later when they are ready
so for me the important past is , you were on Win 10 and you are now on 11 so send the alert
Hello Joe , Happy Friday
Thinking this through. Ideally you would have some actual confirmation that the upgrade is completed. That information most reliably lives in SCCM. A query to that and then writing it in a custom index would be the nicest approach.
If that’s not feasible, we need to look for something local. Maybe windows event log based
Once its in an index it’s easy. You could even tie a survey into it asking for feedback how to upgrade process went (maybe NPS with an open text question)
We obviously would see a change in OS version in _devices, but I think there is no trigger on differential (e.g. if before it was windows 10 but now windows 11 -> do something)
we have os_install_date in the device_install_date index
But that probably would also include new machines, not just once that are upgraded
i dont see these
we have os_install_date in the device_install_date index
Hm. maybe a custom script we have in our lab. Let me check
Thank you 🙂
It’s in the library
I love this community
although this is a different index, but should contain the same information
I suspect the script I have in my lab was some experience to determine device age. Maybe it’s a @member project lol
“`#requires -runasadministrator
requires -Version 3.0
.SYNOPSIS
Retrieve timestamps that could be candidates for the best OS installation date
.DESCRIPTION
The script retrieves the installation date of the operating system by querying the registry key path "HKLM:\SYSTEM\Setup\Status\SysprepStatus". It also retrieves the last write time of the "C:\Windows\Setup\State\State.ini" file. Additionally, it retrieves the creation date of the computer object in a domain environment or null if not in a domain. It then retrieves the details of the operating system and hardware using CIM instances. Finally, it finds the oldest user profile directory in "C:\Users" excluding the "Public" folder.
.PARAMETER None
.EXAMPLE
.\GetInstalldate.ps1
Runs the script and displays the system information.
.OUTPUTS
The script outputs a custom object containing the following properties:
- tags: Edge device tags
- device_group: Edge device group
- first_user_creation_date: The creation date of the oldest user profile directory.
- sysprep_date: The installation date of the operating system.
- os_install_date: The installation date of the operating system.
- state_ini_last_write_time: The last write time of the "C:\Windows\Setup\State\State.ini" file.
- computer_id_when_created: The creation date of this devices domain ID if domain joined
- first_user: The name of the oldest user profile directory.
- os_name: The name of the operating system.
- os_version: The version of the operating system.
- hw_manufacturer: The manufacturer of the hardware.
- hw_model: The model of the hardware.
- hw_serial_number: The serial number of the hardware.
>
Define the registry key path
$RegistryPath = "HKLM:\SYSTEM\Setup\Status\SysprepStatus"
$NativeRegQuery = ‘[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern Int32 RegQueryInfoKey(
Microsoft.Win32.SafeHandles.SafeRegistryHandle hKey,
StringBuilder lpClass,
Int32 lpCls, Int32 spare, Int32 subkeys,
Int32 skLen, Int32 mcLen, Int32 values,
Int32 vNLen, Int32 mvLen, Int32 secDesc,
out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);’
$regData = Add-Type $NativeRegQuery -Name GetRegData -Namespace RegQueryInfoKey -Using System.Text -PassThru
function getRegTime($regPath) {
$reg = get-item $regPath -force
if ($reg.handle) {
$time = New-Object System.Runtime.InteropServices.ComTypes.FILETIME
$result = $regData::RegQueryInfoKey($reg.Handle, $null, 0,0,0,0,0,0,0,0,0, [ref]$time)
if ($result -eq 0) {
$low = [uint32]0 -bor $time.dwLowDateTime
$high = [uint32]0 -bor $time.dwHighDateTime
$timeValue = ([int64]$high -shl 32) -bor $low
return [datetime]::FromFileTime($timeValue)
}
}
}
Clear-Host
$sysPrepDate = (getRegTime $RegistryPath)
$ErrorActionPreference = "silentlyContinue"
$stateIniLastWriteTime = (Get-Item "C:\Windows\Setup\State\State.ini").LastWriteTime
$setupActLogLastWriteTime = (Get-Item "C:\Windows\Panther\setupact.log").LastWriteTime
if (Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty PartOfDomain) {
$searcher = New-Object system.directoryservices.directorysearcher
$searcher.PropertiesToLoad.AddRange(@(‘whencreated’))
$null = $searcher.Filter = "(name=$env:ComputerName)"
$computerWhenCreated = $searcher.FindOne().Properties.whencreated
} else {
$computerWhenCreated = $null
}
$OperatingSystem = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
$Hardware = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
$Bios = Get-CimInstance -ClassName Win32_BIOS -ErrorAction Stop
$OSDisplayVersion = $null
$WindowsCurrentVersion = Get-Item ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion’
‘DisplayVersion,ReleaseId’ -split ‘,’ | ForEach-Object {
$KeyName = $_
if ([string]::IsNullOrWhiteSpace($OSDisplayVersion)) {
$OSDisplayVersion = $WindowsCurrentVersion.GetValue($KeyName)
}
}
Define the path to the users’ profiles
Define the path to the users’ profiles
$usersPath = (Get-ItemProperty -path ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList’ -Name ‘ProfilesDirectory’).ProfilesDirectory
Get the list of user profile directories, excluding the Public folder
$oldestProfile = $null
$ignoreProfiles = @(‘Default’,’Default User’,’Public’,’All Users’,’desktop.ini’, ‘Administrator’)
Get-ChildItem $usersPath | Where-Object { $.PSIsContainer -and $.Name -notin $ignoreProfiles } | Sort-Object CreationTime | Select-Object -First 1 | ForEach-Object {$oldestProfile = $_}
$EdgeDXRegistrationDate = [datetime]::MaxValue
Get-ChildItem -Path ‘C:\ProgramData\Avacee\sip_agent\cachefiles’ | Where-Object {$_.Name -in @(‘DeviceAccessToken.txt’,’uid.txt’)} | ForEach-Object {
$fileObj = $_
if ($fileObj.LastWriteTime -lt $EdgeDXRegistrationDate) {
$EdgeDXRegistrationDate = $fileObj.LastWriteTime
}
}
$dateList = @()
function ConvertToDateString($date) {
if ($date.Year -eq 9999) {
return $null
}
if ($date.Year -lt 2000) {
return $null
}
if ($date) {
return $date.Date.ToUniversalTime().ToString("yyyy-MM-dd")
}
return $null
}
$customObject = $null
Create a custom object
$customObject = [PSCustomObject]@{
tags = "$env:EDXDEVICETAGS"
device_group = "$env:EDXDEVICEGROUP"
sysprep_date = ConvertToDateString($sysPrepDate)
state_ini_last_write_time = ConvertToDateString($stateIniLastWriteTime)
setup_act_log_last_write_time = ConvertToDateString($setupActLogLastWriteTime)
computer_id_when_created = ConvertToDateString($computerWhenCreated)
os_name = $OperatingSystem.Caption
os_patch = $OSDisplayVersion
os_version = $OperatingSystem.Version
os_install_date = ConvertToDateString($OperatingSystem.InstallDate)
hw_manufacturer = $Hardware.Manufacturer
hw_model = $Hardware.Model
bios_install_date = ConvertToDateString($Bios.InstallDate)
bios_release_date = ConvertToDateString($Bios.ReleaseDate)
first_user = $oldestProfile.Name
first_user_creation_date = ConvertToDateString($oldestProfile.CreationTime)
edge_registration_date = ConvertToDateString($EdgeDXRegistrationDate)
}
$ignoreDates = @(‘edge_registration_date’,’bios_release_date’)
$dateList = $customObject.psobject.properties.name | Where-Object {$ -match "(date|time|when_created)$" -and $ -notin $ignoreDates} | ForEach-Object {
$FieldName = $_
$StrValue = $customObject.$FieldName
if ($StrValue){
$Value = ([datetime]::ParseExact($StrValue, "yyyy-MM-dd", $null))
} else {
$Value = $null
}
[pscustomobject]@{
Key = $FieldName
Value = $Value
}
} | Where-Object {$null -ne $_.Value} | Sort-Object -Property Value
$maxDate = $dateList | Measure-Object -Property Value -Maximum | Select-Object -ExpandProperty Maximum
$minDate = $dateList | Measure-Object -Property Value -Minimum | Select-Object -ExpandProperty Minimum
$maxDateFields = $dateList | Where-Object {$_.Value -eq $maxDate} | Select-Object -ExpandProperty Key
$minDateFields = $dateList | Where-Object {$_.Value -eq $minDate} | Select-Object -ExpandProperty Key
$customObject | Add-Member -MemberType NoteProperty -Name "max_date" -Value (ConvertToDateString($maxDate))
$customObject | Add-Member -MemberType NoteProperty -Name "min_date" -Value (ConvertToDateString($minDate))
$customObject | Add-Member -MemberType NoteProperty -Name "max_date_fields" -Value ($maxDateFields -join ",")
$customObject | Add-Member -MemberType NoteProperty -Name "min_date_fields" -Value ($minDateFields -join ",")
Write-Output("### SIP DATA BEGINS ###")
Write-Output(ConvertTo-Json $customObject -Compress)
Write-Output("### SIP DATA ENDS ###")
Write-Output("### SIP EVENT BEGINS ###")
Write-Output("OS installdate has run")
Write-Output("### SIP EVENT ENDS ###") “`
Yes, it’s one of my experiments. Don’t think its the last one. I you’re interested, I can send you the last one Monday.
Continue reading and comment on the thread ‘Creating an Alert for Windows 11 Upgrades Using SCCM and Event Logs’. Not a member? Join Here!
Categories: All Archives, ControlUp Edge DX, ControlUp Scripts & Triggers