Installing the Microsoft Intune client directly after a task sequence

This blog post will be about a bit strange scenario, it will be about deploying a device via a task sequence of ConfigMgr and ending up with the Microsoft Intune client. There are some cases in which the customer elects to manage some devices through Microsoft Intune, instead of ConfigMgr, but still wants to deploy the operating system via ConfigMgr. In those cases creativity is required to get the Microsoft Intune client installed.

The ConfigMgr client and the Microsoft Intune client can’t coexist on one device and it’s not possible to remove the ConfigMgr client during the task sequence (without breaking the task sequence).  That’s were the SMSTSPostAction task sequence variable comes in place. This variable can be used to trigger an (unmonitored) action after the task sequence is completed. In this blog post I’ll provide a simple PowerShell script to remove the ConfigMgr client and to install the Microsoft Intune client. Also, I’ll show how to use this PowerShell script in a task sequence.

Script

Now let’s start with the PowerShell script, by going through it step-by-step. The first step is the declaration of the required variables. Most of these variables are set to the default values. The $NewPath variable will be used as a temporary folder.

$NewPath = "C:\Temp" $CertificateName = "MicrosoftIntune.accountcert" $UninstallPath = "C:\Windows\ccmsetup" $UninstallerName = "ccmsetup.exe" $UninstallerArguments = "/Uninstall" $InstallerName = "Microsoft_Intune_Setup.exe" $InstallerArguments = "/Quiet"

The next step is to copy the Microsoft Intune client installation files to the temporary folder. This is done to overcome installation problems from the initial location after copying the installation files during the task sequence. This can be done by creating the temporary folder via the New-Item cmdlet and by copying the installation files via the Copy-Item cmdlet.

New-Item $NewPath -Type Directory Copy-Item "$PSScriptRoot\$InstallerName" -Destination $NewPath Copy-Item "$PSScriptRoot\$CertificateName" -Destination $NewPath

After everything is in place the removal can be started of the ConfigMgr client. This can be done by triggering the Start-Process cmdlet and waiting for that action to finish.

Start-Process -FilePath "$UninstallPath\$UninstallerName" ` -ArgumentList $UninstallerArguments -Wait -PassThru

After the removal of the ConfigMgr client it’s possible to start the installation of the Microsoft Intune client. This can be done by triggering the Start-Process cmdlet again and letting it wait for the action to finish. Keep in mind that when that process finishes the Microsoft Intune client is not fully installed yet. The processes are started to trigger all the different agent installations.

Start-Process -FilePath "$NewPath\$InstallerName" ` -ArgumentList $InstallerArguments -Wait -PassThru

At the end when the removals and installations are done, it’s time to clean up the installation files that were copied. This can be done by using a simple Remove-Item action on the temporary folder.

Remove-Item $NewPath -Force -Recurse

Save the script as Install-IntuneClient.ps1 and add the script together with the Microsoft Intune client installation files into one old-school Package. This Package does not require a Program and will only be used to provide the content during the task sequence. That means that this Package will contain the following three files, Microsoft_Intune_Setup.exe, MicrosoftIntune.accountcert and Install-IntuneClient.ps1.

Task Sequence

Now let’s have a look at how to use this PowerShell script in a task sequence. Well, the actual PowerShell script will not be started during the task sequence, but it will be added as an action directly after the task sequence is finished.

1 CopyClientFilesThe first action is to copy the content of the old-school Package, used to hold the previously mentioned files, to a local location on the device. This can be achieved by a simple Run Command Line step with a similar command to XCOPY.EXE “.\*.*” “%TEMP%” /HERCIY.
2 PostActionThe second action is to trigger an (unmonitored) action after the task sequence is completed. This can be achieved by a Set Task Sequence Variable step that will set the variable SMSTSPostAction to a similar command as PowerShell.exe -ExecutionPolicy ByPass -File “%TEMP%\Install-IntuneClient.ps1”.

All together this will make sure that after a successful task sequence the created PowerShell script will be started. I’ve tested this now a numerous times and it works like a charm, just keep in mind that it’s triggered after the task sequence is started. That means that this action is not part of the task sequence progress and by that not monitored. To achieve something like that, the PowerShell script can be adjusted to log and sent more information.

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

Install User-targeted Applications during OS Deployment via PowerShell and ConfigMgr 2012

Let’s start my first post of this great new year with another nice PowerShell script. This post will be about deploying required user targeted applications, to the device of the primary user, during OS deployment. Yes, I know the setting of Pre-deploy software to the user’s primary device, but that doesn’t give enough control. After deployment, the device has to be completely ready for use.

A bit more than a year ago I already did a post about pre-provisioning user applications during OS deployment via Orchestrator and ConfigMgr 2012. This time I wanted to make less assumptions. I also wanted to be sure that a user is a member of a collection and what the application is that is deployed to the collection. I first tried to achieve this goal by adjusting my runbook in Orchestrator and I made it work (and it still works), but to make it work I had to use all custom PowerShell activities. This made me think why I still wanted this and I couldn’t come up with something better than “because I can”. So I decided to make one PowerShell script to find the applications and to create the task sequence variables.

Script

The main part of this script is gathering data and filtering it. In short I could say this script consists of five queries and an action. The following six steps make sure that I only get the applications, that are required for the primary user of the device, to be installed during the OS deployment.

Step 1 – Get the Primary User

The first step is to get the primary user of the device that’s being deployed. That information can be retrieved in WMI in the class SMS_UserMachineRelationship. This class shows the relationship of a user with a device, even when it’s only a suggestion yet. The properties of Sources and Types can be used to see how the primary user is defined and to see if it’s a suggestion or a “real” affinity. I know that, in my case, all the device affinities are administrator defined. So to get the user name of the primary user of a device I use the following code snippet (format is <Domain>\<User>:

$PrimaryUser = (Get-WmiObject -ComputerName $SiteServer ` -Class SMS_UserMachineRelationship ` -Namespace root\SMS\Site_$SiteCode ` -Filter "ResourceName='$ResourceName'").UniqueUserName

Step 2 – Get the Container Node

The second step is to get the container node of the application deployment collections. This will be used to make sure that only 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_User'").ContainerNodeId

Step 3 – Get the Collections

The third step is to get the collections within the container. This information can be retrieved in WMI in the class SMS_ObjectContainerItem. This class shows the relation between an container and the objects within an container. So to get the collections within the container I use the following code snippet:

$InstanceKeys = (Get-WmiObject -ComputerName $SiteServer ` -Class SMS_ObjectContainerItem ` -Namespace root/SMS/site_$SiteCode ` -Filter "ContainerNodeID='$ContainerNodeId'").InstanceKey

Step 4 – Filter the Collections

The fourth step is to filter the collections on a specific collection member. This will make sure that only collections used for application deployments AND with the specific collection member will be queried later on.  This information can be found in WMI in the class SMS_FullCollectionMembership. This class shows the different collection members and their memberships. The best thing, the property SMSID shows the collection member in exactly exactly the same format as I have the primary user of the device. So to filter the collections I use the following code snippet:

$CollectionId = (Get-WmiObject -ComputerName $SiteServer ` -Class SMS_FullCollectionMembership ` -Namespace root/SMS/site_$SiteCode ` | Where-Object {$_.CollectionID -eq $InstanceKey -and ` $_.SMSID -eq $PrimaryUser}).CollectionId

Note: For an unknown reason, to me, a normal filter did not work together with the property SMSID. That’s why I had to use an where-object statement.

Step 5 – Get the targeted Applications

The fifth step is to get the applications that are targeted to the filtered collection. This makes sure that only applications deployed to collections, of which the primary user of 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. 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 6 – Create the Task Sequence Variables

The sixth, and last 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 }

Note: In the complete script I already created a variable $Count with the value 0 and an object named $TSEnv of Microsoft.SMS.TSEnvironment.

>> 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:

  • imageAdd 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

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.

How to perform an action directly after the task sequence is finished with ConfigMgr 2012

Last week I already did a post about a new task sequence variable and this week my post will be about another new task sequence variable. This one will probably be used a little less, but can be very useful in some specific situations. Think about situations where an action needs to be performed directly after the task sequence is finished, without impacting the status of the task sequence. In this post I will use a situation where I want the machine to shutdown at the end of the task sequence, as an example.

Configuration

TSEdiSMSTSPosActJust like last week, the configuration is actually very easy and it’s just more about knowing that the task sequence variable exists. This is another new task sequence variable in ConfigMgr 2012 SP1, which is currently still in BETA, named SMSTSPostAction. This task sequence variable can be used to configure a post action for a task sequence. To configure this, follow the next steps:

  • Open a task sequence in the Task Sequence Editor.
  • Add a Set Task Sequence Variable –step to the task sequence.
  • Fill in as Task Sequence Variable SMSTSPostAction and, in this example, as Value cmd /c shutdown /s /t 0 /f.
  • Close the Task Sequence Editor.

Result

Normally adding a shutdown action to a task sequence would cause the task sequence to fail, but now the task sequence will first end successfully and then it will perform the shutdown. A look at the deployment status will show this result. And of course I can show a screenshot of that or of a turned off machine, but I think the SMSTS.log will show some more useful information. As the SMSTS.log will also log the post action.SMSTSLogAct_1SMSTSLogAct_2

Note

Keep in mind that the SMSTS.log will register the action, but does not register a success or failure of the action.

How to apply the default install.wim of Windows 7 to C:\ with ConfigMgr 2012

It’s already known that the default install.wim of Windows 8, by default, applies to C:\, but wouldn’t it be great if there was this same functionality for Windows 7? That way there is no need for a Build and Capture task sequence anymore to maintain a thin image. Applying the default image to C:\ in combination with offline servicing of updates will do the trick. Well… I’ve got good news! In this post I will show how to apply the default install.wim of Windows 7 to C:\!

Configuration

TSEdiOSDPreDriLetThe configuration is actually very easy, it’s more about knowing that it exists. ConfigMgr 2012 SP1, which is currently still in BETA, brings a set of new task sequence variables. One of these variables can be used to apply the install.wim to any drive of choice. To configure this, follow the next steps:

  • Open a task sequence, to deploy Windows 7, in the Task Sequence Editor.
  • Add a Set Task Sequence Variable –step anywhere before the Apply Operating System –step.
  • Fill in as Task Sequence Variable OSDPreserveDriveLetter and as Value False.
  • Close the Task Sequence Editor.

Result

By default the install.wim of Windows 7 would have applied to D:\, but by setting OSDPreserveDriveLetter to False it will apply to any drive of choice. Of course I can show this result with a screenshot of an Windows Explorer, but I think, in this case, a look at the SMSTS.log file will show more information of this success.OSDPreDriLet