The easiest method to re-run an advertisement on Advanced Clients is to use
the context menu on the advertisement in the SMS Admin Console. When you use it,
an additional mandatory assignment is created with the current date and time as schedule.
An advertisement with an additional assignment is run on all clients that receive it,
whether they ran it before or not. Only if the advertisement expired it will not run.
If you want only the clients that never executed the program before to run it, create
a new advertisement with a mandatory assignment in the future. The clients will
check against their execution history and if they find they ran the program successfully
before, they will ignore the advertisement.
The reason is that a special property of the advertisement - ADV_RepeatRunBehavior -
is set to RerunIfFail if there is only one mandatory assignment and to RerunAlways
if there are more.
Quite simple, isn't it?
But what if we want to re-run the advertisement on one single client?
Well, why should we want to do this? For testing reasons. Because just this client
failed. Etc. There are several reasons.
In SMS 2.0 we just deleted the job file from the complete folder and cycled the APM,
do you remember?
There is no complete folder on Advanced Clients, but there is an execution history
in the registry. HKLM\Software\Microsoft\SMS\Mobile Client\Software Distribution\Execution History
Note that not the advertisement-IDs are used, but the combination of package-ID and program name.
So basically all we would have to do is delete the package's execution history key and run it again.
But how do we run an advertisement again without creating a new one or adding
a new assignment? Just deleting the execution history doesn't help. Why?
The reason lies in the way the Advanced Client handles mandatory assignments. The
advertisement is passed to the client via a policy. So let's have a look at the
policy (btw.: Get accustomed to the PolicySpy, you will need it!)
Policy
In the PolicySpy window we find what we are looking for on the Requested-tab under
the Machine node. This is a representation of the namespace \\.\root\ccm\policy\machine\requestedconfig
The policy looks like this:instance of CCM_Policy_Policy3
{
DownloadSource = "http://<mp>/SMS_MP/.sms_pol?T9920005-T9900006-6CC4AEB6.2_00";
PolicyCookie = "2004-01-30 10:21:42.217";
PolicyHash = "1F9002FB2402B4BB1F3603E38670CEBF";
PolicyID = "T9920005-T9900006-6CC4AEB6";
PolicySource = "SMS:T99";
PolicyState = "Active";
PolicyType = "Machine";
PolicyVersion = "2.00";
};
instance of CCM_Scheduler_ScheduledMessage
{
PolicyID = "T9920005-T9900006-6CC4AEB6";
PolicyVersion = "2.00";
PolicySource = "SMS:T99";
PolicyRuleID = "{00fdc1a9-9a39-41fa-b832-ea324c83bfe7}";
PolicyInstanceID = "{b77352f2-d0b8-4d29-b53d-fb79b3edc187}";
ScheduledMessageID = "T9920005-T9900006-6CC4AEB6";
TargetEndpoint = "direct:execmgr";
ReplyToEndpoint = "";
Triggers =
{
"SMSSchedule;ScheduleString=99ED188000080000"
};
TriggerMessage = ""
"<?xml version='1.0' ?>"
"<SoftwareDeploymentMessage MessageType='Execution'>"
" <AdvertisementID>T9920005</AdvertisementID>"
" <PackageID>T9900006</PackageID>"
" <ProgramID>Per-system unattended</ProgramID>"
" <HistoryLocation>Machine</HistoryLocation>"
"</SoftwareDeploymentMessage>";
ActiveTime = "20040113153800.000000+***";
ActiveTimeIsGMT = FALSE;
ActiveMessage = ""
"<?xml version='1.0' ?>"
"<SoftwareDeploymentMessage MessageType='Activation'>"
" <AdvertisementID>T9920005</AdvertisementID>"
" <PackageID>T9900006</PackageID>"
" <ProgramID>Per-system unattended</ProgramID>"
"</SoftwareDeploymentMessage>";
};
instance of CCM_SoftwareDistribution
{
PolicyID = "T9920005-T9900006-6CC4AEB6";
PolicyVersion = "2.00";
PolicySource = "SMS:T99";
PolicyRuleID = "{00fdc1a9-9a39-41fa-b832-ea324c83bfe7}";
PolicyInstanceID = "{949da526-6377-4d87-8385-c55d37f5340e}";
ADV_AdvertisementID = "T9920005";
PKG_PackageID = "T9900006";
PRG_ProgramID = "Per-system unattended";
ADV_ADF_Published = FALSE;
ADV_ActiveTime = "20040113153800.000000+***";
ADV_ActiveTimeIsGMT = FALSE;
ADV_MandatoryAssignments = TRUE;
ADV_RCF_InstallFromLocalDPOptions = "RunFromCache";
ADV_RCF_InstallFromRemoteDPOptions = "No";
ADV_RCF_PostponeToAC = FALSE;
ADV_FirstRunBehavior = "Run";
ADV_RepeatRunBehavior = "RerunIfFail";
PKG_Name = "Microsoft Office Professional Edition 2003";
PKG_Version = "11.0.5614.0";
PKG_Manufacturer = "Microsoft Corporation";
PKG_Language = "German (Germany)";
PKG_PSF_ContainsSourceFiles = TRUE;
PKG_SourceVersion = 1;
PKG_SourceHash = "";
PKG_ContentSize = 605681;
PKG_MIFChecking = TRUE;
PKG_MIFFilename = "MSIUNL8G";
PKG_MIFName = "{829998FB-F3D7-42F1-97AC-FAC3CE5528A4}";
PKG_MIFVersion = "Microsoft Office Professional Edition 2003";
PKG_MIFPublisher = "Microsoft Corporation";
PRG_ProgramName = "Per-system unattended";
PRG_Comment = "";
PRG_Category = {""};
PRG_PRF_Disabled = FALSE;
PRG_PRF_InstallsApplication = TRUE;
PRG_HistoryLocation = "Machine";
PRG_CommandLine = "msiexec.exe /q ALLUSERS=2 /m MSIUNL8G /i \"PRO11.MSI\" /l* c:\\logs\\O2K3de.log";
PRG_WorkingDirectory = "";
PRG_DependentPolicy = FALSE;
PRG_PRF_ShowWindow = "Normal";
PRG_PRF_AfterRunning = "NoAction";
PRG_DiskSpaceReq = "598016";
PRG_MaxDuration = 43200;
PRG_Requirements = ""
"<?xml version='1.0' ?>"
"<SWDReserved>"
" <PackageHash.1>DB88A69AAF75C1B71F0C9D4F83401AB2</PackageHash>"
" <ProductCode></ProductCode>"
" <Requirements></Requirements>"
"</SWDReserved>";
PRG_PRF_UserLogonRequirement = "None";
PRG_PRF_UserInputRequired = FALSE;
PRG_PRF_RunWithAdminRights = TRUE;
PRG_PRF_MappedDriveRequired = FALSE;
PRG_PRF_PersistMappedDrive = FALSE;
PRG_ForceDependencyRun = FALSE;
};
Awful lot of code, I know. But let us have a look at some details. How do we know
this is the policy we are looking for?PolicyID = "T9920005-T9900006-6CC4AEB6";
The PolicyID is built from the advertisement ID, the package ID and some additional
(probably arbitrary but unique) characters.
The policy contains several parts, instances of Advanced Client Classes that configure the client.
The instance of CCM_Scheduler_ScheduledMessage tells the Scheduler on the client when to run the program.
There is a trigger with a ScheduleString that contains the date and time.
The instance of CCM_SoftwareDistribution tells the execution manager what to do.
It contains the information we specified for the advertisement and the program
such as RunFromCache or UserInputRequired for example.
Scheduling
If the client has not seen the policy before, it takes the information and creates
a schedule for the program. If the mandatory assignment lies in the past, the advertisement
is executed immediately. If it lies in the future, it is schedued for that future
time and the execution is triggered by the scheduler.
After the advertisement ran, the schedule is not deleted. But as the time is
now in the past and the policy is not new for the client, it will not be re-run
automatically when we delete the status from the execution history.
You can see the advertisement with the ClientSpy,
tab Software Distribution Pending Executions, node Past Mandatory Advertisements
With No Future Scheduled Executions.
The conclusion is: we need to trigger the execution!
As we meanwhile know the ScheduledMessageID, this is fairly simple. We
could use sendsched.vbs from the SMS Toolkit 1 to do it. I will show you a different way later.
Client config
First let us take an excursion to the actual config.
Where does the information
from the policy go?
We use the PolicySpy again to find out.
The oinformation can be found in the namespace\\.\root\ccm\policy\machine\actualconfig
that is presented on the Actual tab in the Machine tree.
Navigate to CCM_Scheduler_ScheduledMessage. There you will find a ScheduledMessageID=<Policy ID>.
It will look like this:instance of CCM_Scheduler_ScheduledMessage
{
ActiveMessage = "<?xml version='1.0' ?><SoftwareDeploymentMessage MessageType='Activation'> <AdvertisementID>T9920005</AdvertisementID> <PackageID>T9900006</PackageID> <ProgramID>Per-system unattended</ProgramID></SoftwareDeploymentMessage>";
ActiveTime = "20040113153800.000000+***";
ActiveTimeIsGMT = FALSE;
ReplyToEndpoint = "";
ScheduledMessageID = "T9920005-T9900006-6CC4AEB6";
TargetEndpoint = "direct:execmgr";
TriggerMessage = "<?xml version='1.0' ?><SoftwareDeploymentMessage MessageType='Execution'> <AdvertisementID>T9920005</AdvertisementID> <PackageID>T9900006</PackageID> <ProgramID>Per-system unattended</ProgramID> <HistoryLocation>Machine</HistoryLocation></SoftwareDeploymentMessage>";
Triggers = {"SMSSchedule;ScheduleString=4D46288000080000A582288007C80000"};
};
The Triggers part contains the schedule(s). In this case there are two, 4D46288000080000
and A582288007C80000. The schedule strings can be translated to human readable
format by READSCHED.EXE from the SMS 2.0 Support Tools.
Also in the Machine tree you can find CCM_SoftwareDistribution. Find the instance where
ADV_AdvertisementID=<Advertisement ID>.
You will find something like this:
instance of CCM_SoftwareDistribution
{
ADV_ActiveTime = "20040113153800.000000+***";
ADV_ActiveTimeIsGMT = FALSE;
ADV_ADF_Published = TRUE;
ADV_AdvertisementID = "T9920005";
ADV_FirstRunBehavior = "Run";
ADV_MandatoryAssignments = TRUE;
ADV_RCF_InstallFromLocalDPOptions = "RunFromCache";
ADV_RCF_InstallFromRemoteDPOptions = "No";
ADV_RCF_PostponeToAC = FALSE;
ADV_RepeatRunBehavior = "RerunAlways";
PKG_ContentSize = 605681;
PKG_Language = "German (Germany)";
PKG_Manufacturer = "Microsoft Corporation";
PKG_MIFChecking = TRUE;
PKG_MifFileName = "MSIUNL8G";
PKG_MIFName = "{829998FB-F3D7-42F1-97AC-FAC3CE5528A4}";
PKG_MIFPublisher = "Microsoft Corporation";
PKG_MIFVersion = "Microsoft Office Professional Edition 2003";
PKG_Name = "Microsoft Office Professional Edition 2003";
PKG_PackageID = "T9900006";
PKG_PSF_ContainsSourceFiles = TRUE;
PKG_SourceHash = "";
PKG_SourceVersion = "1";
PKG_version = "11.0.5614.0";
PRG_Category = {""};
PRG_CommandLine = "msiexec.exe /q ALLUSERS=2 /m MSIUNL8G /i \"PRO11.MSI\" SOURCELIST=\"\\\\t2003.lab\\instsoft$\\O2K3de\" /l* c:\\logs\\O2K3de.log";
PRG_Comment = "";
PRG_DependentPolicy = FALSE;
PRG_DiskSpaceReq = "598016";
PRG_ForceDependencyRun = FALSE;
PRG_HistoryLocation = "Machine";
PRG_MaxDuration = 43200;
PRG_PRF_AfterRunning = "NoAction";
PRG_PRF_Disabled = FALSE;
PRG_PRF_InstallsApplication = TRUE;
PRG_PRF_MappedDriveRequired = FALSE;
PRG_PRF_PersistMappedDrive = FALSE;
PRG_PRF_RunWithAdminRights = TRUE;
PRG_PRF_ShowWindow = "Normal";
PRG_PRF_UserInputRequired = FALSE;
PRG_PRF_UserLogonRequirement = "None";
PRG_ProgramID = "Per-system unattended";
PRG_ProgramName = "Per-system unattended";
PRG_Requirements = "<?xml version='1.0' ?><SWDReserved> <PackageHash.1>DB88A69AAF75C1B71F0C9D4F83401AB2</PackageHash> <ProductCode></ProductCode> <Requirements></Requirements></SWDReserved>";
PRG_WorkingDirectory = "";
};
Looks familiar? Yes, that is created form part of the policy we looked at before.
Scripting it
Now we have all the information we need for our script. I will explain the important
parts of the code only and attach the script that brings it all together.
First connect to the actual configuration on the client:set objNMS = GetObject("winmgmts://" & strMachine & "/root/ccm/policy/machine/actualconfig")Get all the ScheduledMessageIDs there are:Set objScheds = objNMS.ExecQuery("select * from CCM_Scheduler_ScheduledMessage")
We only need the one that corresponds to our advertisement. It would be nice to use
a WQL-query like select * from CCM_Scheduler_ScheduledMessage where ADV_AdvertisementID like "<AdvID>"
But unfortunately that works only on XP and W2K3, so we have to do it like this:strAdvID = <AdvID>
For each objSched in objScheds
If Instr(objSched.ScheduledMessageID, strAdvID) > 0 then
GetAdvSchMsgID = objSched.ScheduledMessageID
exit for
End If
Next
Now, we know the ScheduledMessageID, the next step would be deleting the execution
history, but I found a different way I like better.
The CCM_SoftwareDistribution class has a property ADV_RepeatRunBehavior which is by
default set to RerunIfFail.
We can set ist to RerunAlways remotely:Set objScheds = objNMS.ExecQuery("select * from CCM_SoftwareDistribution where ADV_AdvertisementID = '" & strAdvID & "'" )
for each objSched in objScheds
objSched.ADV_RepeatRunBehavior = strRerunBehavior
objSched.Put_ 0
NextNow we can trigger the schedule and the advertisement will re-run regardless of any history.set objNMS = GetObject("winmgmts://" & strMachine & "/root/ccm")
Set objSMSClient = objNMS.Get("SMS_Client")
objSMSClient.TriggerSchedule strSchMsgIDAfter we triggered re-running, we can set ADV_RepeatRunBehavior to the old value.
But we have to wait a few seconds that it takes till the execution manager on the
client actually starts the program.
At that moment it checks the value, and if we reset it too early, we will not get
what we want.
Well, that's all. If you find any mistakes or can't make it work in your environment,
drop me an e-mail.
9063ReRunAdv.zip