Install computer-targeted application during OS deployment via PowerShell and ConfigMgr 2012

A few months ago I did a blog post about installing user-targeted applications during operating system deployments via PowerShell and ConfigMgr. This time I will do a similar post, on request, about installing computer-targeted applications during operating system deployments. Yes, I know it might be worth a discussing about why someone is still using computer-targeted deployments, but that will not be a part of this blog post.

Script

A big part of this script, and by that also this post, might look familiar, as it’s based on the previous script for user-targeted applications. Just like with that previous script I will go through all the key steps of the script. The following five steps make sure that I only get the applications that are required for the computer. Also, in case there is nothing targeted a new variable will be created to prevent the Install Application step from starting.

Step 1 – Get the container node

The first step is to get the container node of the application deployment collections. This will be used to make sure that only (device-)collections used for application deployments will be queried. This information can be retrieved in WMI in the class SMS_ObjectContainerNode. This class shows the different folders in the console and its location. The property ObjectTypeName can be used to see the type of objects in the folder. In my case, I occasionally use identical folder names. So to get the container node information that I need, I use the following code snippet:

$ContainerNodeId = (Get-WmiObject -ComputerName $SiteServer ` -Class SMS_ObjectContainerNode ` -Namespace root/SMS/site_$SiteCode ` -Filter "Name='$Container' and ` ObjectTypeName='SMS_Collection_Device'").ContainerNodeId

Step 2 – Get the collections

The second step is to get the collections within the container with a specific collection member. This information can be retrieved in WMI via the classes SMS_ObjectContainerItem and SMS_FullCollectionMembership. This first class shows the relation between an container and the objects within an container and the second class shows the different collection members and their memberships. So to get the collections within the container and with a specific collection member, I need to join these two classes. To do this, I use the following code snippet:

$CollectionIds = (Get-WmiObject -ComputerName $SiteServer ` -Namespace root/SMS/site_$SiteCode -Query "SELECT fcm.* ` FROM SMS_FullCollectionMembership fcm, ` SMS_ObjectContainerItem oci ` WHERE oci.ContainerNodeID='$ContainerNodeId' ` AND fcm.Name='$ResourceName' ` AND fcm.CollectionID=oci.InstanceKey").CollectionId

Step 3 – Get the targeted applications

The third step is to get the applications that are targeted to the filtered collections. This makes sure that only applications deployed to collections, of which the device is a member, will be filtered. This information can be found in WMI in the class SMS_ApplicationAssignment. The property OfferTypeID can be used to see if the deployment is required or available and I only want to have the required applications. So this makes that I use the following code snippet:

$ApplicationNames = (Get-WmiObject -ComputerName $SiteServer ` -Class SMS_ApplicationAssignment ` -Namespace root/SMS/site_$SiteCode ` -Filter "TargetCollectionID='$CollectionId' and ` OfferTypeID='0'").ApplicationName

Step 4 – Create the task sequence variables

The fourth step is to create task sequence variables for the applications that have to be installed during the OS deployment. For every application I create a task sequence variable named APPIdXX with the value of the application. To achieve this I use the following code snippet:

foreach ($ApplicationName in $ApplicationNames) { $Id = "{0:D2}" -f $Count $AppId = "APPId$Id" $TSEnv.Value($AppId) = $ApplicationName $Count = $Count + 1 }

Step 5 – Create an extra task sequence variable

The fifth, and last, step is to create a task sequence variable in case there are no applications targeted to the computer. This variable can be used to skip the Install application step, to prevent it from failing. As a Install application step will fail when there is a base variable configured, but there are none supplied during the task sequence. To achieve this I use the following code snippet:

else { $TSEnv.Value("SkipApplications") = "True" break }

>> The complete script is available via download here on the TechNet Galleries! <<

Usage

Now download the PowerShell script via the link above and add the PowerShell script to an old-school Package, so it will be available for a task sequence. Then create a standard Install an existing image package task sequence. Now edit the task sequence and make sure the following steps are included:

  • InstCompTargAdd a step Run PowerShell Script with the following settings:
    • Package: <NameOfPackageThatContainsTheScript>
    • Script name: <NameOfTheScript>
    • Parameters: %_SMSTSMachineName%
      • Note: The script needs more input parameters, but I usually add those parameters directly in the script as they are “static” per environment.
    • PowerShell execution policy: Bypass
  • Add a step Install Application with the following settings:
    • Select Install applications according to dynamic variable list
    • Base variable name: APPId
    • Add Condition Task Sequence Variable SkipApplications not exists

Note: The computer account running the script needs read access to ConfigMgr. So in most cases this would mean that the Domain Computers need read access to ConfigMgr. This can be achieved via the build-in role of Read-only Analyst

64 thoughts on “Install computer-targeted application during OS deployment via PowerShell and ConfigMgr 2012”

  1. I was wondering about this. I created a small application requirement for all users to circumvent this problem once I figured out that if nothing was advertised, the script would error out.

    Reply
    • Yeah, if the there is nothing deployed the script won’t fail, but the Install applications step will fail. That step requires the base variable to be set when it is configured. To cover that scenario I created an extra variable that will be set when there are no membership. The only scenario that is covered, is when there is a membership but nothing is targeted (I considered that would be a configuration mistake anyway).

      Reply
  2. hey peter,
    first thanks for your great piece of work!

    i am getting an error when running your script in my tasksequence.
    do i have to edit your script? what about this:
    ResourceName
    SiteCode
    SiteServer
    Container

    if yes, can i use a variable for the resourcename? like %_SMSTSMachineName%?

    with best regards
    Tommy

    Reply
    • Hi Tommy,
      Yes, as mentioned in the post, you would also need to supply those other variables. You need to supply the resource name as an input variable during the task sequence, as that’s the only moment that %_SMSTSMachineName% exists.
      Peter

      Reply
  3. hi peter,
    thanks for your quick reply. as you described it, I have edited the script. unfortunately the tasksequence runs into an error. the smsts.log says:

    „Failed to run the action: Get computer-targeted applications.
    Unknown error (Error: 00000001; Source: Unknown)“

    so I tested the script manually in PowerShell ISE:

    Get-TargetedApplications_Computer.ps1 “Test-Machine” “P01” “Test-Server.de” “Software Deployments”

    With the following result:

    New-Object : Die COM-Klassenfactory für die Komponente mit CLSID {00000000-0000-0000-0000-000000000000} konnte aufgrund des folgenden Fehlers nicht abgerufen werden:
    80040154 Klasse nicht registriert (Ausnahme von HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
    In C:\_Install\Get-TargetedApplications_Computer.ps1:12 Zeichen:14
    + $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ResourceUnavailable: (:) [New-Object], COMException
    + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand
    Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
    In C:\_Install\Get-TargetedApplications_Computer.ps1:22 Zeichen:21
    + $TSEnv.Value($AppId) = $ApplicationName
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    APPId01 Software1
    Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
    In C:\_Install\Get-TargetedApplications_Computer.ps1:22 Zeichen:21
    + $TSEnv.Value($AppId) = $ApplicationName
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    APPId02 Software 2
    Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
    In C:\_Install\Get-TargetedApplications_Computer.ps1:22 Zeichen:21
    + $TSEnv.Value($AppId) = $ApplicationName
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    APPId03 Adobe Reader 11

    with best regards
    Tommy

    Reply
    • Hi Tommy,

      Looking at your output I can see that the script is working, as I’m seeing the APPIdxx in the output. The errors are because it tries to create task sequence variables and that’s not possible out-side a task sequence.

      The error code you’re getting in the task sequence is usually related to the task sequence not able to find the script. Make sure it’s all set-up properly and check your smsts.log for more information.

      Peter

      Reply
  4. hi peter,
    my tasksequence is still not runnnig. unfortunately, the smsts.log does not really help. is there a way to enable logging for your script (put the results and errors in a special logfile). that would make the troubleshooting easier, because when the powershell script is running (after “Setup Windows and ConfigMgr”), there is no support for F8, so i cannot check the script manually to see the error.

    with best regards
    tommy

    Reply
    • Hi Tommy,

      The script doesn’t do a lot of logging, besides writing the variables and their values. What I usually do in cases like this, is creating a next step that will always fail. By doing that the information about the script will always be in the smsts log file.

      Peter

      Reply
  5. Hi Peter,

    I’ve hit a snag while using this script. It’s been slightly modified to work with our setup however it has been tested and does not produce any errors, retrieves the list of software that needs to be deployed and the task sequence successfully completes the step “get computer-targeted applications”. However, when it runs the “install computer-targeted applications”, the TS error 0x80070002 is thrown. I’ve checked the logs but can’t find any reference to the error and there is nothing to suggest why it would be generating it. Once the error message is closed the PC boots to windows and functions normally, however none of the applications are installed. Do you know why this would be happening? Could it be to do with what order in the TS the install is happening at? Or could it be something else?

    Thanks in advance,
    Chris.

    Reply
    • Hi Chris,

      It’s hard to say anything useful based on this information. The only thing I can say is that the script has to run before the Install Applications step and that you have to use the same base variable. The rest of the information has to come from the log files.

      Also, you could try to run the script out side of a task sequence to see if it’s at least trying to create the correct variables.

      Peter

      Reply
  6. Thanks for the reply Peter,

    I had another look through the logs and there is a reference to where I think the problem lies. Seems like despite the script finding the applications that need to be installed (have tested it outside of TS environment multiple times, definitely produces a list of apps), and the TS base variable APPId being created, there are no items being saved to the variable list. From the log (only including the important info, not all the time/date stamps, etc):

    Here’s an example of the output from the script:
    APPId01 BlockMaster Device Lockout 1.0
    APPId02 Adobe Reader 11.0.7
    APPId03 Microsoft Office Lync 2013 Basic 15.0.4420.1017
    APPId04 Microsoft Office 2007 Standard 12.0.6535.5002
    APPId05 Adobe Flash Player Active X 14.0.0.145
    APPId06 Microsoft Internet Explorer 10.0

    Any ideas as to why nothing can be found in the list despite the script finding the apps and the TS base variable being created?

    Cheers,
    Chris.

    Reply
    • Hi Chris,

      At least the output looks good. Are there also no errors during the creation of the task sequence variables? If not then you have to look further in the log file to see why it’s failing during the installation of the applications.

      Peter

      Reply
  7. Sorry about my last post, it appears as though the output from the logs wasn’t displayed (probably due to the format I had them in). Here’s the output again, without any symbols that could prevent them showing up:

    DefaultVarlist found
    No variables found in the default variable list
    Action command line: smsappinstall.exe /app: /basevar:APPId /continueOnError:True

    Reply
  8. Hi Peter,

    Thanks for this great work! This is exactly what I need! But now i have one problem. I have a secondary site. And for Clients isn’t allowed to connect directly to the Primary Site (only with port 80). How must the secondary site to be configured, that is possible for Clients to connect to the secondary site? Or isn’t this possible?

    Stefan

    Reply
  9. Thanks for your reply. You mentioned the domain computer account needs read access on ConfigMgr using security roles. Can you point me in the right direction how how to achieve this? I’m getting a access denied error. Thanks again.

    Reply
  10. Finally got it going. Thankyou a million.
    Another question, I understand you cannot run a TS within a TS. What wmi class should I use to pull down the policy just before the TS completes? I’ve looked at sms_tasksequencepackage, and it seems I may need to join some tables from another class? A bit of info – this 2nd TS installs apps using the dynamic variable list but I’ve used the collection variables so I can control the order of the applications install. Or is this not possible?
    Thanks in advance.

    Reply
  11. Hi there
    The SMS Provider can not be installed on a Secondary Site Server. In addition, the clients are in a different domain, and the SMS Provider can not be installed on a server in a different domain than the Prirmary server.
    To solve this, we have now created on the Primary Site Server a REST API (IIS), which executes the script (part 1) and a string of IDs and packages returns. In the second script (Part 2) this string is then split into arrays and constructed so that the result is consistent with the origin scripts match.
    In addition, several containers can be specified in the script, and a user is stored for reading. The script will now only be started, no parameters need to be passed, because it makes no more sense in our scenario.
    Here is the script. The REST API I can not publish unfortunately.

    Part 1:

    Function Get-UDSCCMApplications {
    param (
    [string]$Firma
    )

    $User = “DOMAIN\ServiceAccount”
    $pass = “Crypted Password” | ConvertTo-SecureString -key (Key that used to create Crypted Password)
    $cred = New-Object System.Management.Automation.PsCredential($User,$pass)

    $SiteServer = ‘FQDN of Server’
    $SiteCode = ‘P01’
    $arrContainers = @(‘Application’,’Testing’)
    $ResourceName = $Firma

    $Count = 1
    [array]$arrApplications = @()
    ForEach ($Container in $arrContainers){
    #$ContainerNodeId = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ObjectContainerNode -Namespace root/SMS/site_$SiteCode -Filter “Name=’$Container’ and ObjectTypeName=’SMS_Collection_Device'”).ContainerNodeId
    #$CollectionIds = (Get-WmiObject -ComputerName $SiteServer -Namespace root/SMS/site_$SiteCode -Query “SELECT fcm.* FROM SMS_FullCollectionMembership fcm, SMS_ObjectContainerItem oci WHERE oci.ContainerNodeID=’$ContainerNodeId’ AND fcm.Name=’$ResourceName’ AND fcm.CollectionID=oci.InstanceKey” -Credential $cred).CollectionId
    $Session = New-PSSession -ComputerName $SiteServer -Credential $cred
    $ContainerNodeId = Invoke-Command -Session $Session -ScriptBlock {param ($SiteServer, $SiteCode, $Container);$ContainerNodeId = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ObjectContainerNode -Namespace root/SMS/site_$SiteCode -Filter “Name=’$Container’ and ObjectTypeName=’SMS_Collection_Device'”).ContainerNodeId; Return $ContainerNodeId} -ArgumentList $SiteServer, $SiteCode, $Container
    $CollectionIds = Invoke-Command -Session $Session -ScriptBlock {param ($SiteServer, $SiteCode, $ResourceName, $ContainerNodeId);$CollectionIds = (Get-WmiObject -ComputerName $SiteServer -Namespace root/SMS/site_$SiteCode -Query “SELECT fcm.* FROM SMS_FullCollectionMembership fcm, SMS_ObjectContainerItem oci WHERE oci.ContainerNodeID=’$ContainerNodeId’ AND fcm.Name=’$ResourceName’ AND fcm.CollectionID=oci.InstanceKey”).CollectionId; Return $CollectionIds} -ArgumentList $SiteServer, $SiteCode, $ResourceName, $ContainerNodeId
    if ($CollectionIds -ne $null) {
    foreach ($CollectionId in $CollectionIds) {
    #$ApplicationNames = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ApplicationAssignment -Namespace root/SMS/site_$SiteCode -Filter “TargetCollectionID=’$CollectionId’ and OfferTypeID=’0′”).ApplicationName
    $ApplicationNames = Invoke-Command -Session $Session -ScriptBlock {param ($SiteServer, $SiteCode, $CollectionId);$ApplicationNames = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ApplicationAssignment -Namespace root/SMS/site_$SiteCode -Filter “TargetCollectionID=’$CollectionId’ and OfferTypeID=’0′”).ApplicationName; Return $ApplicationNames} -ArgumentList $SiteServer, $SiteCode, $CollectionId
    if ($ApplicationNames -ne $null) {
    foreach ($ApplicationName in $ApplicationNames) {
    $Id = “{0:D2}” -f $Count
    $AppId = “APPId$Id”
    $Count = $Count + 1
    $TempObj = new-object PSObject
    $TempObj | add-member -membertype NoteProperty -name “ID” -Value $AppId
    $TempObj | add-member -membertype NoteProperty -name “Name” -Value $ApplicationName.ToString()
    $arrApplications += $TempObj
    }
    }
    }
    }
    Remove-PSSession -Session $Session

    }
    If ($Count -eq 1) {
    $TempObj = new-object PSObject
    $TempObj | add-member -membertype NoteProperty -name “ID” -Value “APPId00”
    $TempObj | add-member -membertype NoteProperty -name “Name” -Value “Skip applications”
    $arrApplications += $TempObj
    }

    $strApplication = “”
    ForEach ($Application in $arrApplications){
    If ($strApplication -eq “”) {
    $strApplication = “{0},{1}” -f $Application.ID,$Application.Name
    } Else {
    $strApplication = $strApplication + “;{0},{1}” -f $Application.ID,$Application.Name
    }

    }
    $Return = $strApplication
    return $Return
    }

    Part 2:
    $URI = ‘http://FQDN of Server:8081/UDSCCM/api/UD_SCCM/get_UDSCCMApplications/’ + $Env:COMPUTERNAME

    $Applications = Invoke-RestMethod -URI $URI
    $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

    $Entrys = $Applications.Split(“;”)
    ForEach ($Entry in $Entrys){
    $arrApplication = $Entry.Split(“,”)
    [string]$AppId = $arrApplication[0].Trim()
    [string]$ApplicationName = $arrApplication[1].Trim()

    If ($ApplicationName -eq “Skip applications”){
    $TSEnv.Value(“SkipApplications”) = “True”
    Write-Host “Skip applications”
    exit
    } Else {
    $TSEnv.Value($AppId) = $ApplicationName
    Write-Host $AppId $ApplicationName
    }
    }

    Stefan

    Reply
  12. Hi Peter,

    Thank you for this great Script!

    I managed to get your script working for packages aswell (yay, my first powershell-wmiquery for SCCM 😉 ).
    But im quite sure my approach for getting the PackageID and ProgramName is circumstantial, perhaps you know a better way?

    Here is the Script:
    ====================================

    [CmdletBinding()]

    param (
    [string]$ResourceName,
    [string]$SiteCode,
    [string]$SiteServer,
    [string]$Container
    )

    function Get-TargetedApplications {
    $Count = 1
    $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

    $ContainerNodeId = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ObjectContainerNode -Namespace root/SMS/site_$SiteCode -Filter “Name=’$Container’ and ObjectTypeName=’SMS_Collection_Device'”).ContainerNodeId
    $CollectionIds = (Get-WmiObject -ComputerName $SiteServer -Namespace root/SMS/site_$SiteCode -Query “SELECT fcm.* FROM SMS_FullCollectionMembership fcm, SMS_ObjectContainerItem oci WHERE oci.ContainerNodeID=’$ContainerNodeId’ AND fcm.Name=’$ResourceName’ AND fcm.CollectionID=oci.InstanceKey”).CollectionId
    if ($CollectionIds -ne $null) {
    foreach ($CollectionId in $CollectionIds) {
    $AdvertisementIDs = (Get-WmiObject -ComputerName $SiteServer -Class SMS_Advertisement -Namespace root/SMS/site_$SiteCode -Filter “CollectionID=’$CollectionId’ and OfferType=’0′”).AdvertisementID
    if ($AdvertisementIDs -ne $null) {
    Foreach ($AdvertisementID in $AdvertisementIDs) {
    $Id = “{0:D3}” -f $Count
    $PackageID = (Get-WmiObject -ComputerName $SiteServer -Class SMS_Advertisement -Namespace root/SMS/site_$SiteCode -Filter “AdvertisementID=’$AdvertisementID'”).PackageID
    $ProgramName = (Get-WmiObject -ComputerName $SiteServer -Class SMS_Advertisement -Namespace root/SMS/site_$SiteCode -Filter “AdvertisementID=’$AdvertisementID'”).ProgramName
    $PkgID = “PkgID$Id”
    $TSEnv.Value($PkgID) = “$PackageID`:$ProgramName”
    Write-Host “$PkgID $PackageID`:$ProgramName”
    $Count = $Count + 1
    }
    }
    }
    }
    else {
    $TSEnv.Value(“SkipPackages”) = “True”
    Write-Host “Skip packages”
    break
    }
    }

    Get-TargetedApplications

    ====================================

    Reply
    • Hi Malte,

      I would get the package details once and then first check if it’s not empty. After doing that user .ProgramName and .PackageId to get the required information. That would save you time, as you’re doing a query less.

      Peter

      Reply
  13. Oh right, now it looks much better :).

    Thanks!

    Here is the changed code:

    =============================
    Foreach ($AdvertisementID in $AdvertisementIDs) {
    $Id = “{0:D3}” -f $Count
    $Pkg = (Get-WmiObject -ComputerName $SiteServer -Class SMS_Advertisement -Namespace root/SMS/site_$SiteCode -Filter “AdvertisementID=’$AdvertisementID'”)
    $PkgID = “PkgID$Id”
    $TSEnv.Value($PkgID) = “$($Pkg.PackageID)`:$($Pkg.ProgramName)”
    Write-Host “$PkgID $($Pkg.PackageID)`:$($Pkg.ProgramName)”
    $Count = $Count + 1
    }
    ========================

    Reply
  14. Quick question. I was able to get the script to work in the machine is part of a collection with a required application but if the machine is not part of any collections with a required application I get a TS error 0000001 incorrect function. Any help would greatly appreciated.

    Thank you,

    Reply
  15. If the machine is in a collection or collections that have required applications the variable it set correctly and it installs the applications accordingly. It is when the machine is not part of any collections with a required application that I get the error. It is the Script step in the task sequence not the install step. If I run the script manually in the task sequence he reports skip applications and the skipapplications variable is being set.

    Reply
  16. The only error in the smsts.log is error 000001 Incorrect Function. I am # out the Param for $SiteCode, $SiteServer, and $Container. I have created new variables in the script for those variables with our SCCM information. I still have the param for $ResourceName and left the cmdletBinding at the top. In the Task Sequence I am calling the script.ps1 %_SMSTSMachineName. If I remove the CMDLETBinding and variablize all the parameters the script doesn’t error out in the task sequence but it writes the skipapplications variable.

    Reply
  17. Here is a copy of the script that errors out when the machine is not a member of any collections with a required application

    [CmdletBinding()]

    param (
    [string]$ResourceName
    # [string]$SiteCode,
    # [string]$SiteServer,
    # [string]$Container
    )

    $SiteCode = “SMSSITECODE”
    $SiteServer = “ServerName”
    $Container = “SCCM FOLDER”

    function Get-TargetedApplications {

    $Count = 1
    $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
    $ContainerNodeId = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ObjectContainerNode -Namespace root/SMS/site_$SiteCode -Filter “Name=’$Container’ and ObjectTypeName=’SMS_Collection_Device'”).ContainerNodeId
    $CollectionIds = (Get-WmiObject -ComputerName $SiteServer -Namespace root/SMS/site_$SiteCode -Query “SELECT fcm.* FROM SMS_FullCollectionMembership fcm, SMS_ObjectContainerItem oci WHERE oci.ContainerNodeID=’$ContainerNodeId’ AND fcm.Name=’$ResourceName’ AND fcm.CollectionID=oci.InstanceKey”).CollectionId
    if ($CollectionIds -ne $null) {
    foreach ($CollectionId in $CollectionIds) {
    $ApplicationNames = (Get-WmiObject -ComputerName $SiteServer -Class SMS_ApplicationAssignment -Namespace root/SMS/site_$SiteCode -Filter “TargetCollectionID=’$CollectionId’ and OfferTypeID=’0′”).ApplicationName
    if ($ApplicationNames -ne $null) {
    foreach ($ApplicationName in $ApplicationNames) {
    $Id = “{0:D2}” -f $Count
    $AppId = “Bnote$Id”
    $TSEnv.Value($AppId) = $ApplicationName
    $Count = $Count + 1
    Write-Host $AppId $ApplicationName
    }
    }
    }
    }
    else {
    $TSEnv.Value(“SkipBnoteApplications”) = “True”
    Write-Host “Skip applications”
    break
    }
    }

    Get-TargetedApplications

    Reply
  18. Peter,

    You can disregard the issue. I got the script working. It seems the task sequence and had a typo, in the variable %_SMSTSMachineName% some how the last percent sign was missing. Not sure how it would still install applications but it is working now.

    Thank you very much for pointing me in the right direction and writing this script.

    Dennis

    Reply
  19. Hi Peter

    I’ve managed to make your script work fine after having initially forgotten to set the PS script policy to Bypass. I now get a list of applications provided to the TS. Applications are installed until it comes across an application that installs another application as a dependency which in turn returns the 1641 error code (reboot required). The reboot is then carried out by the TS. After booting into the system, the task sequence initializes the SCCM client but instead of installing the rest of the applications, it goes into the next step. In the log, I can see that that this step is completed and the Install Application step is completed. But in reality, it seems to forget to go back and carry on the installation. What is interesting, is that, when I manually assign the application to be installed without using the Dynamic Variable, after the reboot, the TS returns to processing further installations. I was thinking the variable list was forgotten after a reboot but from the log, I can see it’s all there. So I believe this is another bug of SCCM.
    The smsts.log says:
    …. for each app it says the line below with a different step number. There are 32 apps in the deployment list.

    Could you perhaps try to reproduce the issue? Just put an application that requires a reboot in the middle of the variable list (for me it’s 3/32) so nothing after gets installed.
    I’m running SCCM 2012 R2 SP1 CU1, as latest as I can get. 🙁

    Thanks
    Matt

    Reply
    • Hi Matt,

      I haven’t been able to reproduce this behavior, yet, but I do have a question. Does this behavior only happen when you’re using my script, or also when you’re assigning the applications to the dynamic variable via something like a collection variable?

      Thanks!
      Peter

      Reply
  20. Hello Peter,

    I think after line 30, should also add this, because if there is no application deploy to Primary user, appID is null, SkipAppklication isn’t set in the script, then Install User Targeted Applications will fail.

    31. else {
    32. $TSEnv.Value(“SkipApplications”) = “True”
    33. }

    Reply
  21. Hello Peter, my comment was supposed to post to the “install user targeted applications”. Sorry I wrote it in the wrong post. Please correct this so that not confuse other readers.

    Regards, Sandy

    Reply
  22. Hi Peter

    I’ve been really struggling with this in an unknown computer PXE scenario. Whilst I have been able to get a command prompt up mid-build and run the script manually OK, I am unable to get it to run as advertised as part of the TS itself. I have tried adding domain computers to read-only analyst, even gave them full administrator at one point. I have also tried under various user accounts too. I have also tried running it as a command line and although this doesn’t actually error as it does if I run it as a powershell script, it also doesn’t create the variables.
    What I think might be happening is that it doesn’t understand that it is in a specific collection. To that end this is what I currently do:
    1. I have created a collection and targeted several applications to it
    2. I run the script found here to add the computer to the relevant collection: https://blogs.msdn.microsoft.com/vinpa/2010/09/01/how-to-add-a-knownunknown-computer-to-a-specified-collection-during-os-deployment/
    3. I have also tried adding unknown computers to the collection in question.

    None of the above seems to work. I appreciate that it will probably work fine if I were to deploy zero touch but I need both methods to work.
    Any ideas?
    Thanks

    Reply
  23. Hi Peter,

    Thanks for the script, we’re using it and it works well. However I have come across a scenario where I believe it is failing. Can you please advise what happens when a machine is a member of a collection where the App has dependencies?

    Reply
  24. Hi Peter,

    I tried running your script and I get the following error within task sequence. Its giving me access denied errors but I am using domain admin account (Administrator) to run SCCM, TS etc. Just to be sure, I went ahead and added the administrator account to Wmi containers and provided full access.

    For the parameters, I am using the following

    $SiteCode = “P01”
    $SiteServer = “SCCM-1602.mydomainname.com”
    $Container = “Profiles”

    My collection where all the software deployments are targeted to is placed under following folder structure in SCCM

    Device Collections > OSD > Profiles so that is why $container is set to Profiles.

    Any idea what am I doing wrong here?

    C/P from my smsts.log file…

    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    (E_ACCESSDENIED)) RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    At RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    C:\_SMSTaskSequence\Packages\P0100026\Get-TargetedApplications_Computer.ps1:17 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    char:25 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + … erNodeId = (Get-WmiObject -ComputerName $SiteServer -Class SMS_Object … RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedA RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    ccessException RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.Pow RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    erShell.Commands.GetWmiObjectCommand RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    (E_ACCESSDENIED)) RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    At RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    C:\_SMSTaskSequence\Packages\P0100026\Get-TargetedApplications_Computer.ps1:18 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    char:23 RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + … ctionIds = (Get-WmiObject -ComputerName $SiteServer -Namespace root/S … RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedA RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    ccessException RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.Pow RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    erShell.Commands.GetWmiObjectCommand RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)
    RunPowerShellScript 3/29/2017 4:45:14 PM 3188 (0x0C74)

    Reply
  25. Hi Peter,

    I have one question lets say I want to do a new OS installation on computer2 and my current computer is computer1. Can I change the computer lookup for the script to look at computer2? This way all software from his legacy system is installed on the new computer.

    Regards,

    Jeroen Budding

    Reply
  26. Hi and thanks for the writeup(s). I’ll probably be using this… but I have to ask:

    It’s now Sept. 2018, and we’re running SCCM Current Branch v1802. Is this script still the only way to achieve this? Seems like such an obvious want/need that I’m surprised there’s no built in mechanism.

    I’ll probably answer my own question. There’s a uservoice suggestion for this that’s been “Noted” for over 3 years: https://configurationmanager.uservoice.com/forums/300492-ideas/suggestions/8486518-apply-all-deployed-applications-step-in-osd

    Still, as much as I want this, I can’t gauge whether the set up and troubleshooting are worth the man hours, just to avoid duplicating the list of apps in my OSD TS. Without having grok’d the entire process yet, I’m not even sure this will be possible in our “multi-tenant” environment… as a tenant.

    Reply
    • Hi Matt,
      This script is a method to achieve your goal, as it’s not within the product itself yet.
      As it’s a script running in a task sequence, it might be more challenging with troubleshooting. However, you do get a lot in return. A fully installed device before the user logs in.
      Regards, Peter

      Reply
  27. Hello. The script errors every time. It simply returns error code 1. nothing further is in the logs to determine the issue. any thoughts/

    Reply
  28. Hi Peter,
    I downloaded your script and executed it directly on the primary to test it. I commented out all the ts variables. I noticed that the variable $ CollectionIds always remains empty and therefore I only get scip apps.
    Is the query perhaps no longer correct for sccm cb?

    Reply
  29. I can’t find these scripts on Technet anymore, are they still available to download somewhere? Specifically, this one and the user-targeted script. Thank you!

    Reply

Leave a Reply to Chris Cancel reply

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