Delving into the “Last PXE Advertisement” flag

This post has actually come from having a look at the search queries coming up in my blog visit stats – “all active pxe flag deployements” – which seems like a good thing to look into.

If you’re trying to make a device collection you’ll find the LastPXEAdvertisement doesn’t appear to be available through the query builder UI. Here I’ll look into getting the data through PowerShell and then also putting it into a Device Collection within MEMCM.

So first of all in PowerShell, I’ve written up a script which will get the list of devices with active PXE Deployments running (i.e. where if you click them and go “Clear Required PXE Deployments” it’ll pop up a box saying when it last ran). This flag often needs clearing if you want to re-deploy the existing device.

The function queries WMI for all the LastPXEAdvertisement objects, then for each one looks up the deployment details (so you can see the display name rather than just the ID e.g. SITE2000B). I’ve cached the deployment details in a hashtable to prevent unnecessary WMI querying where there are hundreds of devices sat on the same deployment.

I then return an array of results which can be iterated over with a “foreach” loop, as shown at the bottom of the script.

# Get-DevicesWithActivePXEFlag Script
# Katy Nicholson, 17 Aug 2020
#
# https://katynicholson.uk/

Function Get-DevicesWithActivePXEFlag {
    param (
        [String][Parameter(Mandatory=$true, Position=1)] $SiteServer,
        [String][Parameter(Mandatory=$true, Position=2)] $SiteCode
    )
    try {
        $return = @()
        $DeploymentCache = @{}
        $Devices = Get-WmiObject -Namespace "ROOT\SMS\site_$SiteCode" -ComputerName $SiteServer -Query "SELECT * FROM SMS_LastPXEAdvertisement"
        foreach ($Device in $Devices) {
            if ($DeploymentCache.ContainsKey($Device.AdvertisementID)) {
                $deployment = $DeploymentCache[$Device.AdvertisementID]
            } else {
                $deployment = Get-WmiObject -Namespace "ROOT\SMS\site_$SiteCode" -ComputerName $SiteServer -Query ("SELECT * FROM SMS_DeploymentInfo WHERE DeploymentID = '" + $Device.AdvertisementID + "'")
                $DeploymentCache.Add($deployment.DeploymentID, $deployment)
            }
            $return += [PSCustomObject]@{
                "ComputerName"=$Device.NetbiosName
                "LastPXEAdvertisement"=$Device.LastPXEAdvertisementTime
                "GUID"=$Device.SMBIOSGUID
                "DeploymentID"=$deployment.DeploymentID
                "Collection"=$deployment.CollectionName
                "Target"=$deployment.TargetName
            }
        }
        return $return

    } catch {
 
    }
}

$Devices = Get-DevicesWithActivePXEFlag -SiteServer "memcm.server.fqdn" -SiteCode "SITE"

        Foreach ($Device in $Devices) {
            Write-Host $Device.ComputerName " " $Device.LastPXEAdvertisement " " $Device.Target " " $Device.Collection " " $Device.GUID
        }
Some results from my server showing the computer name, time, deployment (task sequence), device collection name and the device’s SMBIOSGUID

Well now that I’ve worked out the WMI query, surely we should be able to manually enter this into the MEMCM wizard? Yes we can.

Create a new Device Collection, and for the membership rules add a Query rule. Give it a name and click on “Edit Query Statement”, then “Show Query Language”. Paste in the below query, then OK a couple of times.

select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_SYSTEM inner join SMS_LastPXEAdvertisement on SMS_LastPXEAdvertisement.NetbiosName = SMS_R_System.NetbiosName

You’ll be warned you’re about to select every computer in the world, ignore this – I just think it’s showing this because it doesn’t support querying LastPXEAdvertisement through the UI. Give it a few minutes and you should see your device collection populate with only computers with the Last PXE Advertisement data present.

I started a second function in the PowerShell script to clear the flag for either a named device, or a named device collection, but it seems you can’t run Remove-WmiObject on the SMS_LastPXEAdvertisement (at least when I tried it said “not supported”).

Quick addendum: if you want to cycle through and remove all devices with the LastPXEAdvertisement flag from the device collection to which the advertised deployment relates to, you can so as follows (substitude E:\Program Files…. for the path you installed MEMCM):

$Devices = Get-DevicesWithActivePXEFlag -SiteServer "memcm.server.fqdn" -SiteCode "SITECODE"
Import-Module "E:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1"

cd "SITECODE:"

Foreach ($Device in $Devices) {
    Write-Host $Device.ComputerName 
    Remove-CMDeviceCollectionDirectMembershipRule -CollectionName $Device.Collection -ResourceName $Device.ComputerName -Force            
}

and to clear the PXE flag:

$Devices = Get-DevicesWithActivePXEFlag -SiteServer "memcm.server.fqdn" -SiteCode "SITECODE"
Import-Module "E:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1"

cd "SITECODE:"

Foreach ($Device in $Devices) {
    Write-Host $Device.ComputerName 
    Clear-CMPXEDeployment -DeviceName $Device.ComputerName            
}

 

Another update – now I’ve slept on this, I thought it would be useful to see which devices have required deployments advertised to them over “Media and PXE” but haven’t got a Last PXE flag, i.e. those who haven’t started the deployment yet:

Function Get-DevicesWithRequiredDeploymentWithoutPXEFlag {
    param (
        [String][Parameter(Mandatory=$true, Position=1)] $SiteServer,
        [String][Parameter(Mandatory=$true, Position=2)] $SiteCode
    )
    $return = @()
    $DevicesWithRequiredDeployments = Get-WmiObject -Namespace "ROOT\SMS\site_$SiteCode" -ComputerName $SiteServer -Query "
        SELECT SMS_FullCollectionMembership.Name, SMS_AdvertisementInfo.CollectionName,
        SMS_AdvertisementInfo.PackageName
        FROM
        SMS_FullCollectionMembership
        INNER JOIN SMS_Collection ON SMS_Collection.CollectionID = SMS_FullCollectionMembership.CollectionID
        INNER JOIN SMS_AdvertisementInfo ON SMS_AdvertisementInfo.CollectionID = SMS_Collection.CollectionID
        INNER JOIN SMS_Advertisement ON SMS_Advertisement.AdvertisementID = SMS_AdvertisementInfo.AdvertisementID
        WHERE SMS_Advertisement.OfferType = 0 AND SMS_Advertisement.RemoteClientFlags = 35104"
    $DevicesWithActivePXEFlag = Get-DevicesWithActivePXEFlag -SiteServer $SiteServer -SiteCode $SiteCode
    foreach ($Device in $DevicesWithRequiredDeployments) {
        if (-not ($DevicesWithActivePXEFlag.Where{$_.ComputerName -eq $Device.SMS_FullCollectionMembership.Name})) {
            $return += [PSCustomObject]@{
                "ComputerName"=$Device.SMS_FullCollectionMembership.Name
                "Target"=$Device.SMS_AdvertisementInfo.PackageName
                "Collection"=$Device.SMS_AdvertisementInfo.CollectionName
            }
        }
    }
    return $return

}

This needs the previous function to work, and returns data in a similar form. Unfortunately as it involves looping through comparing the devices with deployments to those who have the PXE flag I can’t see a way to convert this into a MEMCM device collection. I’m going off the data I can see in WMI Explorer on my server to pull out OfferType=0 to mean Required, and RemoteClientFlags=35104 to mean “Media and PXE”.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.