Quick test of WDS

Just a quick-test of a TFTP server – just to validate if it is responsive…

These commands be run from any client (screenshots are from Win7)

Step 1

Install the TFTP Client


Step 2

Run the command in a folder where you have permissions to write in

tftp -1 <servername> GET \boot\x86\wdsnbp.com

If the TFTP-client is not installed the below error message will be received


If it is successfull, you will have downloaded a small file


Parallels Software Update Point–selfsigned certificate

As a continuation of the previous post on howto setup the Parallels Software Update Point (introduced in Parallels Mac Management for SCCM 4.5) – here comes a minor hack howto enable WSUS for selfsigned certificates and leverage this within Parallels SUP

Step 1.

Enable Selfsigned certificates for WSUS

Set the following registry key

HKLM\Software\Microsoft\Update Services\Server\Setup
DWORD: EnableSelfSignedCertificates – 1

Step 2

Open certmgr.msc where WSUS is installed and export the WSUS selfsigned certificate

Export the WSUS Publishers Self-signed certificate from Trusted publishers to a file. Remember to choose to export the private key…


…and all the extended properties…


… and set a password…


Step 3

Run some code provided by Parallels to set the certificate you just exported as the signing certificate. Replace CERTFILE and CERTPW


$updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()

$config = $updateServer.GetConfiguration()

$config.SetSigningCertificate("CERTFILE", "CERTPW")

Step 4.

Complete the setup wizard. As you already followed all the previous steps.


Software Center can not be loaded

Regardless of what version of the ConfigMgr agent (2012 –> 1602) you get – there still seems to be a possibility to have left-overs from ConfigMgr 2007.

within the SCClient log-file the following error would be generated;

Exception Microsoft.SoftwareCenter.Client.Data.WmiException: Provider load failure       (Microsoft.SoftwareCenter.Client.SingleInstanceApplication at OnGetException)

The following is presented to the user when starting Software Center


Software Center can not be loaded. There is a problem loading the required components for Software Center.

It seems that this is due to a reference no longer in use – the dcmsdk.dll, located under SysWOW64 (on 32-bit systems). Sample output using reg query:

(Default)    REG_SZ    Configmgr Desired Configuration WMI Provider

(Default)    REG_SZ    C:\WINDOWS\SysWOW64\CCM\dcmsdk.dll

End of search: 2 match(es) found.

Fix? Delete the registry key – sample command line;

reg delete HKLM\Software\Wow6432node\classes\CLSID\{555B0C3E-41BB-4B8A-A8AE-8A9BEE761BDF} /f

App-V 5 and publishing error code: 040000002C.

A minor defect that causes a publishing failure for any packages (only tested for publishing towards a user though. The error code looks like this;

Publish-AppvClientPackage : Application Virtualization Service failed to
complete requested operation.
Operation attempted: Publish AppV Package.
AppV Error Code: 040000002C.
Error module: Virtualization Manager. Internal error detail: 4FC086040000002C.

There seems to already be a few discussions online that assists in resolving the with a few different methods – one seems to suggest to delete a registry key and there is a one that contains a more granular approach by resetting the registry values under LocalVFSSecuredFolders.

A correct view is that each SID under this registry key references the %USERPROFILE%.


and incorrect (and the cause of the error) references the Default-user profile


A quick script (which you can wrap in a Compliance Item or a script – or whatever the preference is..) to remediate this. The actual fix (Set-ItemProperty) is prefixed with # – please test it before you deploy it.

$return = 0
$users = ($k = gi HKLM:\SOFTWARE\Microsoft\AppV\client\Virtualization\LocalVFSSecuredUsers).GetValueNames() | % {

New-Object PSObject -Property @{

Name = $_

Type = $k.GetValueKind($_)

Value = $k.GetValue($_)

} | select Name, Type, Value


foreach ($u in $users) {
if ($u.value -eq 'c:\users\Default\AppData\Local\Microsoft\AppV\Client\VFS') {
$return = 1
#Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\AppV\client\Virtualization\LocalVFSSecuredUsers' -Name $($u.Name) -value '%USERPROFILE%\AppData\Local\Microsoft\AppV\Client\VFS'



Per the above forum post this should be resolved within App-V 5.0 SP3, however I have still seen minor occurances for later releases – so I wouldn’t call that a  confirmed fix.

Office 365 and its import service

Office 365 is the cloud service with a major adoption. One part of this is getting the on-premises Exchange-servers to be removed, and instead leveraging the Outlook Online provided service. The typically increase in allowed mailbox size is a big selling point, but additional benefits are added every day.

Migration of PST

The increased mailbox size does start the discussion of howto eliminate all PST-files spread among all the local client harddrives and the file-servers in an organization. Microsoft has offered the PST Capture tool (scan all devices, locate all PSTs and import them), and as of last year (2015) the Import PST Files to Office 365 was a way to allow sysadmins to perform a more controlled (batch) upload of files.   As always, the end-users can migrate the data via Outlook.

None of these ways are “great”. The PST Capture Tool has a great process of collecting files and dumping them, but its essentially a gather tool that will without any intelligence of what the user wants and then dump anything it can find into a mailbox.

The newly arrived Import PST file-service is a batch-management tool that seems to target the admins that has a bunch of files at a single time (or potentially a few times) to upload. Options are either to upload this into an Office 365 managed Azure Storage Space or simply ship a hard-drive with a collection of files.
There are a few people who have explained that the Office 365 Import service has a powershell interface, unfortunately its not documented and Microsoft support does not acknowledge that it exists.

In addition to the the above options provided by Microsoft there are a few third-party options – such as MessageOps.

End-user driven migration

To make something that is end-user friendly a bit of automation is required of the above tools. Currently a dropbox (a folder where users can dump the PST-files) has been designed, however inorder to get that working there quite a few hurdles that someone has to overcome inorder to produce any type of favourable result. The below notes are for my own memory…

Office 365 Import Service

As the Office 365 Import Service is a Microsoft supported tool it was it was considered the most reliable option of all of the above. Requiring Outlook for end-users to migrate the data seemed to be a high-cost and not very friendly solution. The PST Capture tool were most likely to migrate data which wasn’t relevant to the user, and the risk was of course that something was missed in the process. Third-party options inccured additional licensing cost (ontop of any Office 365 licensing) and was therefore discarded early in the process.

Account requirements

To initiate anything for the Office 365 PST Import service you are required to have certain permissions, aswell as only leveraging simple authentication if there is an intent to automate the process. If any type of multifactor authentication is enabled the ability to connect to the Office 365 via Powershell session is disabled.image


A service account has to be setup that has the role Mailbox Import Export assigned to it. This isn’t directly granted any set of permissions so its recommended to create a new group, assign the role to it and make the service-account a member of the group.

It also seems that to be able to access the Office 365 PST Import Service from the portal one has to be a Global Admin aswell. Powershell cmdlets are only available once the Role Mailbox Import Export has been assigned.

Storage (Azure)

Office 365 Import Service offers to setup a Azure Storage Space for the tenant, and will provide the Shared Access Signature required to upload files (if using the network upload) or a storage key if using the option to shipping a harddrive. To leverage any kind of automation the only accessible path for the Office 365 PST Import service is the blob located on an Azure Storage Space. It seems that sometime in March (2016) the previous method of using the storage key to generate a Shared Access Signature (SAS) to allow for read-operations for the Import Service (technically this is performed by the Mailbox Replication Service provided by Office 365) was discontinued. One can find a storage key for the option to send in a hard-drive, however that seems to not leverage the same upload space as the network upload and therefore the storage key can’t be used.

Fortunately enough the option is only requiring an Azure Storage Space which can be provided via a normal Azure-subscription. Setup a Blob in an Azure Storage Space, and immediately you have access to the storage space. Once the Storage Space is setup you can retrieve the storage key by locating the key-icon


There will be two keys which you can leverage.


To generate a Shared Access Signature (needed for the automation part) you can download the Azure Storage Explorer 6. The tool allows a quick and easy way to view whats in a Blob on the Storage Space, aswell as generating the SAS-key.

Once you start the tool choose to add your storage space with the storage key above. Remember to check HTTPS.


Once you have connected to your Storage Space, choose to create a new Blob (with no anonymous access). Once this is created you can press Security to start generating the SAS-key.


Generate the signature by selecting a start-date (keep track of what timezone you are in) and the end-date. These dates will set the validity for the period of your SAS-key. Remember to define the actions you want to allow. To upload files you need to allow write, and to use the SAS-key for importing the files you need to allow read. There is the possibility to generate multiple SAS-keys and use them for different parts of the process.


A SAS-key are built of multiple parts – here comes a brief explanation;

#sv = storage services version; 2014-02-14
#sr  = storage resource; b (blob), c (container)
#sig = signature
#st = start time; 2016-02-01T13%3A30%3A00Z
#se = expiration time; 2016-02-09T13%3A30%3A00Z
#sp = permissions; rw (read,write)





Copy files to Azure Storage Space

There are multiple ways to copy files to any Azure Storage Space. You can use the Azure Storage Explorer 6 that was used to generate the SAS-key. Someone has provided a GUI for AZCopy command-line tool, but for automation the command-line usage for AZCopy is the route to go. Microsoft has written an excellent guide for this which doesn’t need any additional information.

Connecting to Office 365

Managing Office 365 for any type of automated manage is performed via a PSSession (PowerShell Session). A PSSession will import all available cmdlets from Office 365. As you can imagine quite a few are similar to Exchange, and it may therefore provide some overlap. To avoid confusion the recommended approach is to append a prefix for all cmdlets from the session which can be defined when the session is imported. This is a sample script that will provide the username and password that is required to connect to, configure the proxy-options for the Powershell session and setup the session with O365.

$password = ConvertTo-SecureString "password" -AsPlainText -Force
$userid = "name-admin@company.onmicrosoft.com" 
$cred = New-Object System.Management.Automation.PSCredential $userid,$password 
$proxyOptions = New-PSSessionOption -ProxyAccessType IEConfig -ProxyAuthentication Negotiate -OperationTimeout 360000
$global:session365 = New-PSSession -configurationname Microsoft.Exchange -connectionuri https://ps.outlook.com/powershell/ -credential $cred -authentication Basic -AllowRedirection -SessionOption $proxyOptions
Import-PSSession $global:session365 -Prefix  O365


Once the session is started the modules are imported with the prefix O365, as an example commands go from:





Using the Import-service via Powershell

As noticed the Office 365 Import service is a GUI only approach that is not supported for automation. That beeing said there are options to start this via Powershell. Multiple blog-posts are documenting the New-MailboxImportRequest cmdlet (and with the prefix its now: New-O365MailboxImportRequest), however Microsoft support will barely acknowledge its existance.

As long as you have the previous stated account permissions assigned (Mailbox Import Export Role) the cmdlet will be available and can be used.

For Office 365 the only supported source is an Azure Storage Space. The import-service is creating one for you, however today (2016-05-12) we are unable to create the Shared Access Signature to allow the automation part use that Storage Space. January 2016 this doesn’t seem to be the case and therefore we can assume that potentially this will change in the future.

Below command-line will allow you to start an import. If you receive the error 404 most likely there is an bad path to the file, and a result of 403 most likely is a bad SAS-key.

Remember: The O365 is the prefix we choose to use when running Import-PSSession. The actual cmdlet is New-MailboxImportRequest

New-o365MailboxImportRequest -Mailbox user@mailbox.com -AzureBlobStorageAccountUri https://yourstorage.blob.core.windows.net/folder/User/test.pst -BadItemLimit unlimited -AcceptLargeDataLoss –AzureSharedAccessSignatureToken “?sv=2012-02-12&se=9999-12-31T23%3A59%3A59Z&sr=c&si=IngestionSasForAzCopy201601121920498117&sig=Vt5S4hVzlzMcBkuH8bH711atBffdrOS72TlV1mNdORg%3D" -TargetRootFolder Nameoffolderinmailbox


Retrieving statistics

Once the import is started it fires off and actually goes through pretty quickly. As you can imagine the results can be retrieved by using Get-O365MailboxImportRequest and Get-O365MailboxImportRequestStatistics. One oddity was that the pipe of passing on Get-O365MailboxImportRequest to the Get-O365MailboxImportRequestStatistics didn’t work as expected. Apparently the required identifier is named Identity and it actually requests the RequestGuid.

Sample loop;

$mbxreqs = Get-O365MailboxImportRequest
foreach ($mbx in $mbxreqs) {
$mbxstat = Get-O365MailboxImportRequestStatistics -Identity $mbx.RequestGuid
$mbxstat | Select-Object TargetAlias,Name,targetrootfolder, estimatedtransfersize,status, azureblobstorageaccounturi,StartTimeStamp,CompletionTimeStamp,FailureTimeStamp, identity

The above data are things which was useful for a brief overview. Sometimes you can manage with the Get-O365MailboxImportRequest.

Cleanup of Azure Storage Space

What does not happen automatically (well, nothing in this process happens automatically) is the removal of the PST-files uploaded to the Azure Storage Space. Having the users PST-files located in a Storage Space will consume resources (and money), aswell as the user might be a bit uncomfortable about it. As always the attempt is to automate this process. To retrieve the cmdlets for managing the Azure Storage Space (remember, multiple ways to handle this. AZCopy is a single-purpose tool) you need to download Azure Powershell. Microsoft again has an excellent guide howto get started. What would be even faster is if all these services could provide a common approach of management. For Office 365 you import a session, but for Azure you download and install cmdlets?

Once the Azure Powershell cmdlets are installed you can easily create a cleanup job that will delete any file older than 15 days. First a time is defined. Secondaly we setup a connection to the Azure Storage Space (New-AzureStorageContext), and then we retrieve all files in our specific blob, filter based on our time-limit and then start removing them.

Good to know: Remove-AzureStorageBlob does accept –Whatif. However, –Whatif will still execute the remove. Test your code carefully… Most likely this is true for many other cmdlets.

[datetime]$limit = (Get-Date).AddDays(-15)
$context = New-AzureStorageContext -StorageAccountName $straccountname -StorageAccountKey $straccountkey -ErrorAction Stop

Get-AzureStorageBlob -Container $strblob -blob *.pst -Context $context | Where-Object { $_.LastModified -lt $limit } | ForEach-Object {Remove-AzureStorageBlob -Blob $_.Name -Container $strblob -Context $context}



A long rant that haven’t given anything to you. To be honest – this is memory notes for myself. The parts that are involved in creating an automated workflow requires a lot of moving bits and pieces that utilizes what a common-man would define as the cloud. The cloud is several messy parts that aren’t polished, not well documented, always in preview (technical preview, beta, early release, not launched..) and constantly changing.

All of the above are things that provided a bit of struggle. Most likely the struggle is due to lack of insight into a few of the technologies, and as more insight was gained the right questions were asked. If you read all of the links above carefully you will most likely see a few comments from me.

Parallels Mac Management for SCCM–Software Update Point

As of Parallels Mac Management 4.5 there are great new features – such as the new role Software Update Point.

The addition of this role is to enable managed updates for the OSX-devices within your environment and it acts as a bridge between the Apple Software Update Server (or the able service) and the Configuration Manager environment which PMM integrates into. All of these products will now integrate in a (sort of) seamless way and PMM can now enable its new role (PMM SUP) to inject updates into Microsoft WSUS, which ConfigMgr then uses to publish content. The Apple SUS is optional and if one is setup you can leverage this to further control updates.

Most of this knowledge is based on the Parallels Mac Management for SCCM (bad acronym right there..) Admin guide


To start using the PMM for SCCM Software Update Point it is required to have a Microsoft WSUS server installed and leveraged for the ConfigMgr environment. Most likely this is already in place if you are already managing updates for Windows-devices.

Allow locally published content

It is required to configure clients to trust locally published content from WSUS. Complete instructions are available from Microsoft, however a quick way to verify if this is setup is to check the following registry key.

AcceptTrustedPublisherCerts – 1


In addition the signing certificate setup for WSUS needs to be trusted by the client.

WSUS server

The PMM for SCCM SUP should be installed on server that has WSUS installed (top server in a hierarchy). Before completing that installation a few things needs to be verified. A service account has to be used and configured for the SUP-role, and this has to be a member of the local administrator-group on the server. In addition the service account has to be a member of the local group WSUS Administrators.


Choose Update Server

There are three options when choosing what type of source the Apple Updates should be retrieved from. Basis are:

  • Apple Software Updates (public)
    Users can choose what updates to install, able to postpone installation and restarts.
    Updates will be downloaded from Apple
    • Local Update Server (intranet source)
      Users can choose what updates to install, able to postpone restarts
    • Local Update Server (intranet source) – filtered
      Administrators deploys updates

My personal preference is the Apple Software Updates, but incase you want to avoid WAN traffic and potentially more control of updates for your devices the option is a local Apple Software Update Server (or – Local Update Server as stated above). The Apple Software Update Server is part of OSX Server (which can be purchased from Apple Store). Like all other things – this role can be enabled and setup pretty easily. However, it does require an OSX-instance that is running as a server in your environment.

Apple Software Update Server

Once the Apple Software Update Server is setup the PMM for SCCM SUP needs to be configured to direct all requests to this server. A simply registry key edit will finalize the configuration.

These items are only requried to change if you want to use the Apple SUS.

Node: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\pmm_sup_service\Pa rameters

Server Address: SusCatalogBaseUrl
Port: HttpServerPort.
Server settings update interval: InfoUpdateIntervalSeconds
Catalog check: CatalogRefreshIntervalSeconds

The log-file for any activity is generated in the following log-file;


ConfigMgr configuration

ConfigMgr needs to be configured to synchronize the new Apple Updates. First, update Classifications on the synchronizations properties of the ConfigMgr Software Update Point.


In addition the Apple product needs to be selected.


Client settings

If one is using the public Apple Software Updates there isn’t a need to configure the PMM for SCCM agent as the agent is set to use this source by default. There are three options that can be configured in the following options file:


This matches the previous suggested routes;

0 — Apple Software Update server (default).
1 — Local update server.
2 — Local update server with selected updates.

Set the option :SuCatalogMode to the desired choice in case you need to update it. PMM has realized that their provided Configuration Items are sub-par so in the admin-guide there are script examples (page 134-135) that you can use to create your own Configuration Items.


Within an environment that already has ConfigMgr, WSUS and PMM setup – the addition of PMM for SCCM SUP isn’t a lot of extra work to enable management of OSX Updates.

VMware Horizon View Client–silent install

A few short notes on howto silently deploy the VMware Horizon View Client 4.0.1.

The latest release can be downloaded from VMware


File: ‘VMware-Horizon-Client-x86_64-4.0.1-3698521.exe’

Intent is to have no desktop-shortcut, enable all features, set a default server and have the user automatically login.


'/s /v"/qn 

Registry update:

'HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\VMware, Inc.\VMware VDM\Client\Security'
Name: 'LogInAsCurrentUser' Value: 1 Type: DWORD

ConfigMgr: Match client address to IP-Range Boundaries

Despite the Microsoft recommendation, primarily due to additional workload that it causes, to not leverage IP-Ranges we have noticed a far greater significant accuracy of where clients retrieve content from based on our IP-ranges. So yes, we have our boundaries, with few exceptions, setup using IP-ranges.

We also have clients spread around the globe, new networks beeing spun-up, networks that aren’t supposed to be used for servers and clients and much more to actually be used for these type of things. The issue at hand is to understand where clients are actually connecting from, and what locations we know about.

To get some type of insight of where ConfigMgr clients are actually connecting from we started polling our database. In the end – this turned into two SQL-queries that would get all the IP-range boundaries, and a summary of how many clients we support on each network. As lazy as one can be – this ended up gathering enough information to present to other teams to present where clients are connecting from, how many there are and that we don’t previously didn’t know about this location.

To list how many clients you have per a /24-subnet. This may of course not necessarily be the exact size of a subnet, but it allows for an easy count-up of clients.

select SUBSTRING(ip.IPAddress0, 1, 
LEN(ip.IPAddress0) - CHARINDEX('.',REVERSE(ip.IPAddress0))) + ".1" As IP,
 COUNT(*) as Devices
 from v_Network_DATA_Serialized as ip 
where ip.IPAddress0 IS NOT NULL and ip.IPSubnet0 != "64"
and ip.DNSDomain0 like "%yourdomain.com"
and ip.TimeStamp > DATEADD(day, -10, GETDATE())
GROUP BY  SUBSTRING(ip.IPAddress0, 1, LEN(ip.IPAddress0) - CHARINDEX('.',REVERSE(ip.IPAddress0)))

A list of all boundaries where we split the start and end IP-address of a specific range

select bound.DisplayName,
SUBSTRING(bound.value,1,CHARINDEX('-',bound.value) -1) AS LEFTHALF,
SUBSTRING(bound.value,CHARINDEX('-',bound.value) +1 ,100) AS RIGHTHALF
from vSMS_Boundary as bound
where bound.BoundaryType = "3"
and bound.DisplayName != "some boundary to exclude"

Information about the clients within a specific range that we do not know about

select DNSHostName0,
from v_Network_DATA_Serialized as ip
where ip.IPAddress0 IS NOT NULL
and ip.IPSubnet0 != '64'
and ip.DNSDomain0 like '%yourdomain.com'
and ip.TimeStamp > DATEADD(day, -10, GETDATE())
and ip.IPaddress0 like 'XXX.YYY.ZZZ.%'


To join all of this information together some basic, crude, logic was built in powershell to match up networks that clients are in and that we know about. The function to perform the actual IP-range lookup is from stackoverflow-reply. Sample output first:2015-11-22 16_07_41-Clipboard




function IsIpAddressInRange {
 [string] $ipAddress,
 [string] $fromAddress,
 [string] $toAddress

 $ip = [system.net.ipaddress]::Parse($ipAddress).GetAddressBytes()
 $ip = [system.BitConverter]::ToUInt32($ip, 0)

 $from = [system.net.ipaddress]::Parse($fromAddress).GetAddressBytes()
 $from = [system.BitConverter]::ToUInt32($from, 0)

 $to = [system.net.ipaddress]::Parse($toAddress).GetAddressBytes()
 $to = [system.BitConverter]::ToUInt32($to, 0)

 $from -le $ip -and $ip -le $to

$ErrorActionPreference = "silentlycontinue"
$database = "ConfigMgrServer"
$datasource = "ConfigMgrDB"

$netquery = "select SUBSTRING(ip.IPAddress0, 1, LEN(ip.IPAddress0) - CHARINDEX('.',REVERSE(ip.IPAddress0))) + '.1' As IP, COUNT(*) as Devices from v_Network_DATA_Serialized as ip where ip.IPAddress0 IS NOT NULL and ip.IPSubnet0 != '64' and ip.DNSDomain0 like '%yourdomain.com' and ip.TimeStamp > DATEADD(day, -10, GETDATE()) GROUP BY SUBSTRING(ip.IPAddress0, 1, LEN(ip.IPAddress0) - CHARINDEX('.',REVERSE(ip.IPAddress0))) ORDER BY Devices DESC"

$networks= Invoke-Sqlcmd -Query $netquery -server $datasource -Database $database

$query = "select bound.DisplayName, SUBSTRING(bound.value,1,CHARINDEX('-',bound.value) -1) AS LEFTHALF,SUBSTRING(bound.value,CHARINDEX('-',bound.value) +1 ,100) AS RIGHTHALF from vSMS_Boundary as bound where bound.BoundaryType = '3' and bound.DisplayName != 'exclusion boundary'"

$iprange = Invoke-Sqlcmd -Query $query -server $datasource -Database $database

foreach ($net in $networks) {
 if (!($net.ip -eq '')) {
 $i = 0
 $J = $iprange.count
 $boundaryfound = $false
 do {
 if (IsIpAddressInRange $net.ip $iprange[$i].LEFTHALF $iprange[$i].RIGHTHALF)

 $boundaryfound = $true
 } until ($i -gt $j)
 if ($boundaryfound -eq $false) 
 write-host "Network: $($net.ip) - Devices: $($net.Devices)"

 #$($($net.ip) -replace ".$")
 $devquery = "select DNSHostName0,DNSDomain0,IPAddress0,IPSubnet0,DefaultIPGateway0,DHCPServer0 from v_Network_DATA_Serialized as ip
 where ip.IPAddress0 IS NOT NULL
 and ip.IPSubnet0 != '64'
 and ip.DNSDomain0 like '%yourdomain.com'
 and ip.TimeStamp > DATEADD(day, -10, GETDATE())
 and ip.IPaddress0 like '$($($net.ip) -replace ".$")%'"
 $devices= Invoke-Sqlcmd -Query $devquery -server $datasource -Database $database


ConfigMgr, apps and OSX

ConfigMgr offers limited support to manage an OSX-device, however you can extend the capabilities using third-party tooling such as Parallels Mac Management for SCCM.

Parallels Mac Management for SCCM primarily offers something similar to Software Center – namely an interface called Parallels Application Portal that will allow available applications (not the classic package) to be installed or removed through a user interface. Unlike the Windows-applications and their respective deployment types for an application the ability to configure the deployment is rather peculiar.

Some basics

You will need access to an instance of OSX where you can generate the package. As previously described on howto deploy Symantec Endpoint Protection there is a small tool to generate a ConfigMgr compatible package from various different formats available for OSX to install applications.

Once the package is generated it will contain the binary pieces of the application, aswell as a basic command-line to install the application and (optional, but enabled by default) a detection method to verify that the application is installed.


Most likely the command-line will look something like this

/usr/sbin/installer -pkg "Parallels Desktop.pkg"  -target "/" –verboseR

As Parallels Mac Management for SCCM has the ability to also uninstall applications there is a need to specify the command-line for actually removing the application. Using the “:” you can provide the two commands on the same command-line.

Uninstall command-line (more about rm on Mac Developer Library)

rm -rf "/Applications/Parallels Desktop.app"

Combined command-line (notice the : at the start, the middle and the end of the command-line):

:/usr/sbin/installer -pkg "Parallels Desktop.pkg"  -target "/" -verboseR:rm -rf "/Applications/Parallels Desktop.app":

Detection Method

Detection Method will be determined by default (you will need to specify the –c option to avoid having it generated within the ConfigMgr package) when a package is created.


The Package ID can be reviewed within OSX using the pkgutil.

Sample command-line to review if a package is installed or not within OSX

$ pkgutil --pkg-info com.parallels.package

Sample output

$ pkgutil --pkg-info com.apple.pkg.BaseSystem
package-id: com.apple.pkg.BaseSystem
volume: /
location: /
install-time: 1306707387
groups: com.apple.snowleopard-repair-permissions.pkg-group com.apple.FindSystemFiles.pkg-group
$ date -r 1306707387
Sun May 29 15:16:27 PDT 2011

As you can see we request information if a specific package is installed. To list all packages on a volume you can use the following command

$ pkgutil --packages –volume /

Additional command-line

During the uninstall command we technically only remove the application, however the information which we base the detection on is left behind. To remove the package information the following command-line can be used

$ pkgutil --forget com.parallels.package

Using && (and) we can combine our multiple commands for uninstall – both removing the Parallels Desktop.app and the package information.

:/usr/sbin/installer -pkg "Parallels Desktop.pkg"  -target "/" -verboseR:rm -rf "/Applications/Parallels Desktop.app" && pkgutil --forget com.parallels.package:


Unlike the Windows-applications where the install / uninstall scenario are split into two separate command-lines there is a single-command line to handle for OSX. One needs to be familiar with OSX tools to manage applications and the terminal capabilities to successfully manage a successful installation and uninstall of an application.

ConfigMgr client–install and maintenance

After going down a rabbit hole attempting to understand the process of why ConfigMgr clients fail. Fail to install, fail to keep themselves running, failure to repair themselves – there has been a realization that a lot of people have spent an insane amount of time doing the same thing. Oddly enough, very few people seem to understand the implications of doing things one way or another.

Hopefully this can be a summary post that will detail the implications of choosing different paths when installing the ConfigMgr client.


There is an extensive documentation of what the technical requirements are of the platform you intend to install the ConfigMgr client on. Most likely this will not be any major issue as the majority of these will be fulfilled on any supported platform and if they are not available prerequisite will be installed as part of the very stable CCMSetup.exe.

ConfigMgr setup (called ccmsetup.exe) is a wrapper executable that will leverage the contents of ccmsetup.cab. The .CAB-file contains a XML file that will detail all prerequisite checks that should be performed on a client and attempt to verify that they are installed, and if not download them (from a source-repository defined in many ways – if none is specified the folder which ccmsetup is started from will be the source)  and install them.

Can this cause issues? Yes. If the folder where ccmsetup.exe is called from does not contain the prerequisites specified in ccmsetup.cab so they actually can’t be downloaded or the alternative source-folders specified doesn’t contain them the installation will fail. Or worse, if the requirements are invalid this will also cause issues. An invalid hash for SCEPInstall.exe was the culprit of an update released by Microsoft or the publically acknowledged MicrosoftPolicyPlatformSetup.msi invalid signature has also been the cause of headaches.

So lets clarify;

Don’t remove things from the ConfigMgr client source-folder.




When ccmsetup.exe is started it is a non-interactive process which only allows anyone to review the progress by reading log-files. For the impatient that hopes to have a progress-bar running – there is none. (log files located in c:\windows\ccmsetup\logs)

CCMSetup.exe has some intelligence to avoid have someone firing of the non-interactive process and fail to properly install the ConfigMgr client. It uses the Active Directory (in multiple ways) to identify most of the settings that are required, however of course there are many optional and beneficial options.

Install Properties

There is a small rule when it comes to passing parameters to ccmsetup.exe
Parameters that start with a / is dedicated for the ccmsetup.exe-wrapper itself, whereas the parameters without (and usually written in capital letters) are dedicated for the MSI and used by the installation process. Parameters meant for the ccmsetup.exe (with /) should be written first and before all parameters meant for the client MSI.

So, the client will do the following to identify how it should be installed:

Parse commandline

Ccmsetup command line: "C:\WINDOWS\ccmsetup\ccmsetup.exe" /runservice "SMSCONFIGSOURCE=P" "smssitecode=P01"

Read from registry

Command line parameters for ccmsetup have been specified.  No registry lookup for command line parameters is required.

Query Active Directory

Performing AD query: '(&(ObjectCategory=mSSMSManagementPoint)(mSSMSDefaultMP=TRUE)(mSSMSSiteCode=P01))'

Parameters published within Active Directory is defined from the ConfigMgr environment when modifying the Site-settings



So, as long as you have a fairly uncomplex environment of ConfigMgr the installation of the ConfigMgr client will be simple and you can pass the installation files to anyone without a lot of instructions. Just double-click this file (ccmsetup.exe) and the settings will be retrieved from Active Directory, at minimum.

Download of installation-files

If there are multiple offices and perhaps even some limited bandwidth scenarios with high-latency a quick question comes to mind – how can we optimize this?

As previously noted the most common scenario is that the client itself and the prerequisites will download themselves from the folder they were started into a local-cache folder named ccmsetup. Technically, the ccmsetup will just perform enough actions to get this download started and then handover to the local process that will continue to download the of remaining prerequisites and client-files as illustrated by the log-file.


Once the local file exists (along with ccmsetup.cab) the real (now local) installation-process will continue the installation. This will continue to download the remaining bits and pieces from either the source-folder or an alternative source-folder:


There can be multiple source-folders specified and before it attempts to use one the ccmsetup.exe will verify that the source-folder can be reached – if not it will invalidate it.

Technically, the commandline can look like this

ccmsetup.exe /source:\\validfileshare\client<em> </em>/source:<em>\\invalidfileshare\client </em>/source:<em>\\validfileshare2\client


The folder used will be based on availability (must be reachable) and the order in which they were listed. There is no intelligence that calculates latency or bandwidth, the only check performed is if the files are reachable. However, if you want that to be used you can leverage the ConfigMgr infrastructure using the property /mp.


MP stands for Management Point and this specific property will only define what Management Point CCMSETUP will contact to retrieve the client source-files. The property will not be used by the ConfigMgr client itself (you can use a different property for this). The Management Point will leverage the ConfigMgr package created during its setup (called Configuration Manager Client Package) and all of the ConfigMgr infrastructure. Based on the boundaries defined and what Distribution Point will serve those boundaries it will download the package from the best local (read Fast boundary) Distribution Point, and if none are available it will fallback to a remote one (read slow).

Sample review of the earlier stages of an CCMSetup running where it is contacting the Management Point for content download.


The download from a Distribution Point will leverage BITS and the priority of that download can be specified using the BITS priority property.




ConfigMgr is a living product and therefore there are lots of released updates for it. ConfigMgr 2007 had a set of specific solutions (hotfixes) released that included updates to the client and every once in a while these were gathered up in a Service Pack or Release Pack (SP or R) which provided a brand new MSI-file.ConfigMgr 2012 still has the concept of Service Pack and Release Pack, however very few hotfixes have been released in between these releases and instead they are release in cumulative packs that will provide a new MSP-file with all the fixes from backwards.

Great improvement that ConfigMgr 2012 has a single Microsoft Patch to be installed. Of course there is a desire to ensure that the clients receives these fixes as soon as possible and if possible to ensure that at installation-time the patch is applied. This is especially important during Operating System Deployment as the fixes may resolve issues during the Operating System Deployment process.

Patches introduces the first challenge when it comes to ensuring that a client will install properly.

Supported method

Microsoft has recommended the approach of using the generic Windows Installer-property PATCH. This has been around as a recommended method since SMS 2003, and continue to be the official recommended way forward.

There are a few caveats to using the PATCH property and that is namely the limitation of referencing any type of file there.

File path has to be an absolute path and no variables can be used when the command-line is parsed by Windows Installer. If the file referenced does not have the extension MSP it will be ignored. In essence: You have to write the specific path where the file is located in plain old english (or.. well..)

Microsoft has therefore provided great blog-articles (no technet-article as the property is a generic Windows Installer property) on howto leverage this for the published Client Installer Properties and multiple ways of using this property during the Operating System Deployment process.

Applying a ConfigMgr Hotfix During the Client Installation of an OS Deployment

Patch ConfigMgr 2012 x86 and x64 clients during a task sequence using the PATCH property

Deploying ConfigMgr Hotfixes

There is one key take away that is worth noting and that is the fact that using the PATCH property will install all the bits of the new patch during the initial installation of the client and once the installation is completed the client will be at the latest build of the client. If applying the patch post-installation it is required to restart the ConfigMgr client (we want to release any locks to a file) before we have actually applied the update.

Primary concept here are based into a few parts that will provide us with a few different ways of populating the PATCH property depending on when and how we install the MSP.

Install on existing Windows machines

When using the published installer properties (used for client push scenarios, manually triggered installs without any overriding options) we will reference the patch using a UNC-path. The UNC-path can reference any file-share that the computer account has access to. Sample PATCH-property


Using a UNC-path of course is a hard-coded reference to a specific file-share (and using DFS you can of course offer some abstraction here), however there is a concern to be raised with this method.

Referencing a UNC-path would of course require that the client has access to the MSP-file on the occasion that a future repair would happen or during the installation. If the file would not be reachable (move, network disconnect, permissions improperly configured) the installer with exit with the generic exit code of 1635. Even worse though is the complete failure of the installation due to a high-latency / low bandwidth scenario where the file-copy operation just fails. Sample error code in such a scenario:

MSI: Action 1:44:18: InstallFiles. Copying new files    ccmsetup    2015-08-02 01:44:18    8560 (0x2170)
MSI: Internal Error 2902. ixfAssemblyCopy    ccmsetup    2015-08-02 01:44:20    8560 (0x2170)
MSI: Action 1:44:21: Rollback. Rolling back action:    ccmsetup    2015-08-02 01:44:21    8560 (0x2170)

Install during Operating System Deployment

During OSD there seems to be two ways to reference the patches. The previous (circa 2007 and a bit of the life-span of 2012 in) way was to reference the patches in their respective packages when downloaded by ConfigMgr during the OSD-process. A sample path has been expressed in the first article. The PATCH would reference a folder, temporarily, created by a specific package and could install the patch with local access.


During later articles there is a new recommended method of running a pre-step to copy the file into a local-folder (c:\windows\temp anyone?) and then referencing this folder instead


Briefly looking over these methods we have a few things worth noting;

1. We do not have the ability to leverage a single way of referencing these patches if we were to follow Microsoft practices. UNC-paths for one method and a local-copy for a different method?

2. We can not leverage the ConfigMgr infrastructure when downloading patches since we are forced to reference them using a hardcoded path during a manual install / push-scenario

3. Patch installation from a UNC-path may be high-risk as any loss of network connectivity or if the connection is less than perfect may result in a complete failure of the client install. Preferred method (which is most likely this is the new recommended approach for OSD) would be to download a copy to the local harddrive on the client.

4. There is no dynamic way of placing the patches in a single location and have the ConfigMgr client automatically apply them. We have a hardcoded reference to the patch location, and in addition we also have a hardcoded reference to what patch we are deploying.

Now, remember all these cons as more will be remarked later.

Unsupported method

Since SMS 2003 there has been some legacy code that will allow the CCMSetup to detect a specific folder, download any patches located in this folder and then post installation also install the patches.

The folder is called ClientPatch (surprise!) and should be created in each architecture directory.


Once the installation is started and detects that this folder is located in the source-folder it is currently using it will download the file



After the installation of client.msi is completed it will continue to install any downloaded MSP-files.



This method is unsupported and there is no testing performed by the ConfigMgr team if any changes they make will potentially cause any future issues. There is a lot of public ‘it works without issues’ and some people saying ‘we have identified issues’.

People outside of Microsoft claims that it´operates without issues.

SCCM 2012 Client Push – Including hotfixes / CU patches in Client Push

System Center 2012 Configuration Manager R2 Automating Client Patch installation during Client Push Install with CU2

ClientPatch folder method for including client updates – supported?

Change in how to apply Patch with SCCM Client push



Issues that have been identified relate to specific properties not beeing parsed properly is using this approach as the installation order is to setup the client, and then after the client is installed it will automatically install the patch. As the patch installation must stop all services (think ConfigMgr agent, but also the Task Sequence service) to release any locks to files that it wants to update the loss of properties seems harmless (and yet also a logical side-effect) in comparison.

As you might guess; Stopping the Task Sequence service during Operating System Deployment is a high-risk undertaking.



Configuration Manager has introduced several mechanisms to ensure a ConfigMgr client stays healthy. One part of this, which has been remarked early on, is the CCMEval scheduled task.


The CCMEval performs two tasks namely to identify (task one) and remediate (task two) unhealthy clients. The name is a give-away. There is an option to configure it to only perform the first (either through a property at install-time or as a post-configuration task) which of course will only notify you as an administrator through the ConfigMgr console. And by notify we mean that you have to actively dig out the information under Monitoring –> Client Status.


CCMEval’s doings (or undoings) can be identified through the log-file named ccmsetup-ccmeval.log located in C:\Windows\ccmsetup\Logs.

Identify task

Lets run through its doings when performing a health check to identify a unhealthy client

First we can see that it triggers the ccmsetup with the parameter /evaluate and focusing only on prerequisites. Most likely this will identify that all necessary prerequisites are installed, available for installation if they are missing and if not it should trigger an installation of the missing prerequisites.

As you can see it remembers the command-line we used for installing the client. A validation will also happen (just like it does during install-time) that source-folders are validated.


The previously used command-line for installation is saved away in the registry. As far as the investigation goes this little vital component is saved in the below registry-key.


Once it has validated the source the client knows about (remember; working folder, /source and /mp are valid options to specify this during the initial installation) it will start to digest the information that it knowns about the prerequisites. Just as the initial installation it will extract the XML-file (now using the local-copy) from ccmsetup.cab and then proceed to ensure what prerequisites are applicable, available and installed.


Once the prerequisites had their run there is an secondary run that will validate the client itself


The result of this (and what checks are performed to ensure that a healthy ConfigMgr client is on the machine) is logged in a secondary file located in C:\Windows\CCM\Logs and its named (surprise!) ccmeval.log



Remediate Task

The above portion will only identify the current state of a client and if configured as such – the CCMeval will stop at the above part and inform (notify) the ConfigMgr hierarchy that this is the case. By default it is also enabled to remediate a client which is considered unhealthy.

One of the more harmless remediation is to just start the CCMExec-service. Fairly easy right? Serivce not running? Start it.

One of the more challenging remediation is to reinstall either the prerequisites or even the client in itself.

Wait. What? why would this be a challenge? Lets play out two potential scenarios that are very likely to happen if following some articles that have been posted above.

Scenario #1

You followed the suggestion to ensure that the ConfigMgr 2012 hotfixes are installed during the Task Sequence that deploy the operating system using the package that contains the ConfigMgr Client. A sample PATCH-property would be seen like this:


As this is a temporary location for storing packages only during the Task Sequence execution once a Task Sequence has completed the folder is removed.
If the client were to become faulty due to <insert any reason> a repair would be attempted using the initial command-line as found in the registry (HKLM\Software\Microsoft\CCMSetup) such as this

"/runservice" "/source:\\fileshare\validsource" "SMSCONFIGSOURCE=P" "smssitecode=P01" "FSP=fsp.domain.com" "PATCH="C:\_SMSTaskSequence\OSD\XXX00002\x64\hotfix\KB2905002\Configmgr2012ac-r2-kb2905002-x64.msp"  "

However, this installation will fail with a generic error code of 1635 due to the installer being unable to locate the previously temporary folder. The patch is no longer in the above location.

Scenario #2

During a client push scenario we have published the UNC-path where our patch-files are located on a file-share within our environment. This could be on the site-server, a DFS-root or somewhere else.

Sample property


There are two potential concerns that may cause harm here if a repair ever were to be triggered. If an admin was haggled to cleanup, save disk space or perform any similar action a year later a scenario will arise where the patch is not available. Perhaps some a new way of distributing the hotfix was discovered and it was decided to cleanup old file-shares. Well, if the above patch was no longer available at the above location all future repairs would halt with a generic 1635 error.

The other concern raised is if the file is still available however the client is constrained by high latency. Perhaps some packet drops. Well, perhaps the connection might be congested with Channel9 video streams. During the patch file-copy part the following error is very likely to happen

MSI: Action 1:44:18: InstallFiles. Copying new files    ccmsetup    2015-08-02 01:44:18    8560 (0x2170)
MSI: Internal Error 2902. ixfAssemblyCopy    ccmsetup    2015-08-02 01:44:20    8560 (0x2170)
MSI: Action 1:44:21: Rollback. Rolling back action:    ccmsetup    2015-08-02 01:44:21    8560 (0x2170)


In the two above scenarios we will end-up with a completely unhealthy ConfigMgr client.

This is why a suggestion has been created to combine the PATCH property method of installing patches and the ClientPatch-concept into a single new way forward of deploying patches.

Go vote!