<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Some Assembly Required</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jeffbutte/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jeffbutte/feed.xml</link>
    <description>A few hints on how to make things work...</description>
    <lastBuildDate>Sun, 08 Apr 2018 15:58:04 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>LINUX Certificate Enrollment and Automated Renewal Using NDES !v2</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/linux-certificate-enrollment-and-automated-renewal-using-ndes-v2</link>
      <pubDate>Thu, 05 Apr 2018 23:08:24 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=565</guid>
      <description><![CDATA[I am periodically asked about a “version 2.0” of my post on “LINUX Certificate Enrollment and...]]></description>
      <content:encoded><![CDATA[I am periodically asked about a “version 2.0” of my post on “<a href="https://blogs.technet.microsoft.com/jeffbutte/2016/12/16/236/">LINUX Certificate Enrollment and Automated Renewal Using NDES</a>”. I continue to watch the development of CERTMONGER.  While promising, the project development hasn’t gotten to a point exactly meets needs outlined in my example scenario.

Rather than do a 2.0 post for now, I have updated the original post with details that have changed.  Let’s cover a few things that have changed and more detail into the lack of a 2.0 post.
<h3>SCEP RFC</h3>
The SCEP RFC continues to evolve.  It had gone years without an update but now receives regular updates.  Security is the primary driver as the industry adjusts to the deprecation of SHA1.

To support the changes, the Open Source community has continued to update the SSCEP client.

Since my original post, the client now supports requesting SHA2 based certificates.
<h3><span>CERTMONGER READY?</span></h3>
<blockquote>"The certmonger daemon monitors certificates for impending expiration, and can optionally refresh soon-to-be-expired certificates with the help of a CA. If told to, it can drive the entire enrollment process from key generation through enrollment and refresh." (FreeIPA, <a href="https://www.freeipa.org/page/Certmonger">https://www.freeipa.org/page/Certmonger</a>)</blockquote>
From a features set perspective, certmonger has many capabilities beyond SSCEP making it more flexible.  However, there continue to be two key limitations:
<ul>
 	<li>Certmonger does not appear to have a provision for downloading a CA chain. That task is left up to the system administrator.  A SSCEP / Certmonger solution would fill that gap as the getca command does that for you.  Neither solution actually adds the import the CA chain to the system CA trust chain.  This must be done separately  (See my other post for automating this).</li>
 	<li>Certmonger has issues with multi-tiered Windows based CA hierarchies.    For many orgs, this can be a deal breaker.  Having a single tier online CA works fine.  Per many threads and my testing, having a two tier hierarchy (offline root / online Windows based NDES issuing CA) will result in a failed request in the monitored queue :
<pre>status: CA_UNREACHABLE
ca-error: Error: failed to verify signature on server response.
stuck: no</pre>
</li>
</ul>
The leading indicator is that the client is unable to validate the CA chain for the server response.

&nbsp;
<h3><span>PATH FORWARD</span></h3>
As the products evolve, I periodically look for ways to improve the process.  In the mean time I will continue to update the original post / example solution until the need for a 2.0 post.]]></content:encoded>
    </item>
    <item>
      <title>Upgrading System Center Configuration Manager (SCCM) LINUX Clients</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/upgrading-system-center-configuration-manager-sccm-linux-clients</link>
      <pubDate>Fri, 09 Mar 2018 21:22:52 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=405</guid>
      <description><![CDATA[OVERVIEW
Microsoft periodically releases updated Microsoft System Center Configuration Manager -...]]></description>
      <content:encoded><![CDATA[<h4><strong>OVERVIEW</strong></h4>
Microsoft periodically releases updated Microsoft System Center Configuration Manager - Clients for Additional Operating Systems.  The update releases often do not align with the Configuration Manager server or Windows client releases.  You should periodically check the download site for the most current release.

Microsoft System Center Configuration Manager - Clients for Additional Operating Systems  <a href="https://www.microsoft.com/en-us/download/details.aspx?id=47719">https://www.microsoft.com/en-us/download/details.aspx?id=47719</a>

Now would be a great time to upgrade your older deployed System Center Configuration Manager (SCCM) Clients for Linux.
<blockquote><u>Disclaimer:</u> The information provided below is an EXAMPLE using a single method for a single operating system with the expectation that you have a healthy SCCM environment in a supported configuration. It is highly recommended that you test your configurations in a non-production environment, tailoring the configuration to your environment.  A good overview of this process can be found at <a href="https://technet.microsoft.com/en-us/library/jj573939.aspx#BKMK_UpgradeLinuxClient">https://technet.microsoft.com/en-us/library/jj573939.aspx#BKMK_UpgradeLinuxClient</a></blockquote>
The TechNet example is great in that it reminds administrators of the importance of keeping things simple.  While the simple solution may be fine for a small deployment, it may be too simple for an enterprise.  Today we will expand on the upgrade process by demonstrating a real-world example for an enterprise.  Remember, there are a number of ways to approach this.  This EXAMPLE is just one way.

The SCCM Linux client upgrade process leverages “AT” which is a Linux job execution scheduling tool.  If the SCCM client executes the upgrade directly, it would fail.  During the upgrade process, the SCCM Linux client process (ccmexecd) will be terminated, the binaries removed and then replaced by the newer version.  To get around the process termination, AT functions as an out-of-band execution mechanism.

The overall upgrade process is:
<ul>
 	<li>CREATE DEPLOYMENT COLLECTION(S)</li>
 	<li>CREATE A DEPLOYMENT PACKAGE (WITH LOGIC)</li>
 	<li>MONITOR DEPLOYMENT</li>
</ul>
During a first time SCCM Linux client install, a few values are required.  At a minimum, the install requires that you specify a site code, its associated management point and an OS specific tar file containing the installation binaries.   To perform the upgrade, those same values are required.
<h4><strong>CREATE DEPLOYMENT COLLECTIONS</strong></h4>
We start with creating deployment collections for a few reasons.  First, there isn’t a consistent way to query from the client side to get the previously used, required install values.  To ensure success in our example we will create query based collections that identifies systems that:
<ul>
 	<li>Are UNIX and Linux agented systems</li>
 	<li>Are running an agent less than the version we are deploying</li>
 	<li>Are of a specific distribution</li>
 	<li>Belong to a specified Site Code</li>
 	<li>Connect to a specific Management Point.</li>
</ul>
The results will tell you everything required to perform the upgrade.  Another critical reason to create collections is that it will determine the number of upgrade packages you require.  Based on this example, you will need a package for every site code.

For production environments, it is recommended that you build a hierarchy of limiting collections.  A site code hierarchy may look like:
<pre>_Global LINUX Clients  
|_Global LINUX Clients Centos 6  
| |_ Global LINUX Clients CentOS 6 SC1  
|    |_ Global LINUX Clients CentOS 6 SC1 Not Current  
| |_ Global LINUX Clients CentOS 6 SC2  
|    |_ Global LINUX Clients CentOS 6 SC2 Not Current  
|_ Global LINUX Clients Centos 7  
| |_ Global LINUX Clients Centos 7 SC1  
|    |_ Global LINUX Clients Centos 7 SC1 Not Current  
| |_ Global LINUX Clients Centos 7 SC2  
|    |_ Global LINUX Clients Centos 7 SC2 Not Current  
|_ Global LINUX Clients RedHat 6  
| |_ Global LINUX Clients RedHat 6 SC1  
|    |_ Global LINUX Clients RedHat 6 SC1 Not Current  
| |_ Global LINUX Clients RedHat 6 SC2  
|    |_ Global LINUX Clients RedHat 6 SC2 Not Current  
|_ Global LINUX Clients RedHat….  
|_ ….and so on
</pre>
The above hierarchy example is for illustration purposes.  Your will need to build a hierarchy that suits your organization’s needs.

WQL query statements for those collections may look like:

&nbsp;

UNIX AND LINUX AGENT
<pre>select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.ClientEdition = 13</pre>
&nbsp;

CENTOS LINUX 7
<pre>select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like "CentOS Linux 7%"</pre>
&nbsp;

CLIENT ASSOCIATED TO SITECODE SC1
<pre>select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SMSInstalledSites = "SC1"</pre>
&nbsp;

CLIENT NOT CURRENT
<pre>select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where LOWER(SMS_R_System.ClientVersion) &lt; "5.00.7958.2437"</pre>
&nbsp;

In the above “CLIENTS NOT CURRENT” query, you would edit the query every time you import a new client package and set the “less than client version” number to be the version number of the client you are going to install.

The following example is a PowerShell method for building out a similar hierarchy. The script requires that you pass the parameters selected from your environment for the following:
<ul>
 	<li><span><span>Site Code</span></span></li>
 	<li>T<span><span>he Client OS</span></span></li>
 	<li><span><span>The Client Version (as seen from the SCCM client)</span></span></li>
 	<li><span><span>The Limiting Collection (normally the all systems collection)</span></span></li>
</ul>
&nbsp;
<pre><span style="color: #000080">Param</span>(
    <span style="color: #ff0000">$SiteCode</span> = <span style="color: #800000">'SC1'</span>,
    <span style="color: #ff0000">$ClientOS </span>= <span style="color: #800000">'CentOS Linux 7'</span>,
    <span style="color: #ff0000">$ClientVersion</span> = <span style="color: #800000">'5.00.7958.2437'</span>,<span style="color: #800000">
    <span style="color: #ff0000">$LimitingCollectionID</span> = <span>'SMS00001'</span></span>
) 
<span style="color: #008000">#Date Time</span>
<span style="color: #ff0000">$TodaysDate</span> = <span style="color: #0000ff">Get-Date</span> <span style="color: #000080">-Format</span> <span style="color: #800000">"yyyy-MM-dd"</span>
<span style="color: #008000">#Collection  Comment</span>
<span style="color: #ff0000">$CollectionComment</span> = <span style="color: #800000">"Created by: Collection Creation Script; "</span> +
                     <span style="color: #800000">"Created on: </span>$(<span style="color: #ff0000">$TodaysDate</span>);" +
                     <span style="color: #800000">"Executed by: </span>$(<span style="color: #ff0000">$env:USERNAME</span>)"
<span style="color: #ff0000">$CMRefreshSchedule</span> = @{DurationInterval = <span style="color: #800000">'Days'</span>
                       DurationCount = <span style="color: #800000">7</span>
                       DayOfWeek = <span style="color: #800000">'Saturday'  </span>                
}
<span style="color: #ff0000">$LinuxClientMaintenanceCollections</span> = @(
    @{
        Name = <span style="color: #800000">'_Global LINUX Clients'</span>
        LimitingCollectionID = <span style="color: #ff0000">$LimitingCollectionID </span>
        RefreshSchedule = (<span style="color: #0000ff">New-CMSchedule</span> <span style="color: #ff0000">@CMRefreshSchedule</span> <span style="color: #000080">-Start</span> (<span style="color: #0000ff">Get-Date</span> <span style="color: #000080">-Hour </span><span style="color: #800080">01 </span><span style="color: #000080">-Minute</span> <span style="color: #800080">00 </span><span style="color: #000080">-Second</span> <span style="color: #800080">00</span>))
        RefreshType = <span style="color: #800000">'Periodic'</span>
        MembershipRules = @(
            @{  RuleType = <span style="color: #800000">'Query'</span>
                Params = @{ RuleName = <span style="color: #800000">'_Global LINUX Clients'</span>
                            QueryExpression = <span style="color: #800000">'select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.ClientEdition = 13'</span>
                }
            }
        )
    }
    @{
        Name = <span style="color: #800000">"_Global LINUX Clients</span> $(<span style="color: #ff0000">$ClientOS</span>)<span style="color: #800000">"</span>
        LimitingCollectionName = <span style="color: #800000">'_Global LINUX Clients'</span>
        RefreshSchedule = (<span style="color: #0000ff">New-CMSchedule</span> <span style="color: #ff0000">@CMRefreshSchedule </span>-Start (<span style="color: #0000ff">Get-Date</span> <span style="color: #000080">-Hour</span> <span style="color: #800080">01 </span><span style="color: #000080">-Minute</span> <span style="color: #800080">10 </span><span style="color: #000080">-Second</span> <span style="color: #800080">00</span>))
        RefreshType = <span style="color: #800000">'Periodic'</span>
        MembershipRules = @(
            @{  RuleType =<span style="color: #800000"> 'Query'</span>
                Params = @{ RuleName =<span style="color: #800000"> '_Global LINUX Clients'
</span>                            QueryExpression = <span style="color: #800000">"select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like `"</span>$(<span style="color: #ff0000">$ClientOS</span>)<span style="color: #800000">%`""</span>
                }
            }
        )
    }
    @{
        Name = <span style="color: #800000">"_Global LINUX Clients</span> $(<span style="color: #ff0000">$ClientOS</span>) $(<span style="color: #ff0000">$SiteCode</span>)<span style="color: #800000">"</span>
        LimitingCollectionName = <span style="color: #800000">"_Global LINUX Clients</span> $(<span style="color: #ff0000">$ClientOS</span>)<span style="color: #800000">"</span>
        RefreshSchedule = (<span style="color: #0000ff">New-CMSchedule</span> <span style="color: #ff0000">@CMRefreshSchedule </span><span style="color: #000080">-Start</span> (<span style="color: #0000ff">Get-Date <span style="color: #000080">-Hour </span></span><span style="color: #800080">01 </span><span style="color: #000080">-Minute</span> <span style="color: #800080">20 </span><span style="color: #000080">-Second</span> <span style="color: #800080">00</span>))
        RefreshType = <span style="color: #800000">'Periodic'</span>
        MembershipRules = @(
            @{  RuleType = <span style="color: #800000">'Query'</span>
                Params = @{ RuleName = <span style="color: #800000">'_Global LINUX Clients'</span>
                            QueryExpression = <span style="color: #800000">"select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SMSInstalledSites = `"</span>$(<span style="color: #ff0000">$SiteCode</span>)`<span style="color: #800000">""</span>
                }
            }
        )
    }
    @{
        Name = <span style="color: #800000">"_Global LINUX Clients</span> $(<span style="color: #ff0000">$ClientOS</span>) $(<span style="color: #ff0000">$SiteCode</span>) <span style="color: #800000">Not Current"</span>
        LimitingCollectionName = <span style="color: #800000">"_Global LINUX Clients</span> $(<span style="color: #ff0000">$ClientOS</span>) $(<span style="color: #ff0000">$SiteCode</span>)<span style="color: #800000">"</span>
        RefreshSchedule = (<span style="color: #0000ff">New-CMSchedule <span style="color: #ff0000">@CMRefreshSchedule</span></span> <span style="color: #000080">-Start</span> (<span style="color: #0000ff">Get-Date</span> <span style="color: #000080">-Hour</span> <span style="color: #800080">01 </span><span style="color: #000080">-Minute</span> <span style="color: #800080">30 </span><span style="color: #000080">-Second</span> <span style="color: #800080">00</span>))
        RefreshType = <span style="color: #800000">'Periodic'</span>
        MembershipRules = @(
            @{  RuleType = <span style="color: #800000">'Query'
</span>                Params = @{ RuleName = <span style="color: #800000">'_Global LINUX Clients'</span>
                            QueryExpression = <span style="color: #800000">"select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where LOWER(SMS_R_System.ClientVersion) &lt; `"</span>$(<span style="color: #ff0000">$ClientVersion</span>)`<span style="color: #800000">""</span>
                }
            }
        )
    }
)
<span style="color: #008000">#Check for the folder</span>
<span style="color: #000080">If</span> (<span style="color: #0000ff">Get-Item </span>(<span style="color: #800000">'DeviceCollection\_Global LINUX Clients'</span>)) {<span style="color: #ff0000">$true</span>}
<span style="color: #000080">else </span>{
    <span style="color: #0000ff">mkdir </span>(<span style="color: #800000">'DeviceCollection\_Global LINUX Clients'</span>)
    <span style="color: #0000ff">Start-Sleep</span> <span style="color: #000080">-Seconds</span> <span style="color: #800080">5</span>
}
<span style="color: #000080">Foreach </span>(<span style="color: #ff0000">$Collection</span> in <span style="color: #ff0000">$LinuxClientMaintenanceCollections</span>){
    <span style="color: #ff0000">$ColParams</span> =<span style="color: #ff0000"> $Collection</span>.Clone()
    <span style="color: #ff0000">$ColParams</span>.Remove(<span style="color: #800000">'MembershipRules'</span>)
    <span style="color: #ff0000">$ColParams</span>.Add(<span style="color: #800000">'Comment'</span>,<span style="color: #ff0000">$CollectionComment</span>)
    <span style="color: #0000ff">New-CMDeviceCollection</span> <span style="color: #ff0000">@ColParams</span>
    <span style="color: #000080">Foreach </span>(<span style="color: #ff0000">$rule</span> in <span style="color: #ff0000">$Collection</span>.MembershipRules){
        <span style="color: #ff0000">$RuleParams</span> = <span style="color: #ff0000">$Rule</span>.Params
         <span style="color: #000080">switch</span>(<span style="color: #ff0000">$rule</span>.RuleType) {
            <span style="color: #800000">'None'</span> {}
            <span style="color: #800000">'Query'</span> {<span style="color: #0000ff">Add-CMDeviceCollectionQueryMembershipRule</span> <span style="color: #000080">-CollectionName</span> <span style="color: #ff0000">$Collection</span>.Name <span style="color: #ff0000"> @RuleParams</span> }
            <span style="color: #800000">'Include'</span> {<span style="color: #0000ff">Add-CMDeviceCollectionIncludeMembershipRule</span> <span style="color: #000080">-CollectionName</span> <span style="color: #ff0000">$Collection</span>.Name <span style="color: #ff0000">@RuleParams </span>}
            <span style="color: #800000">'Exclude' </span>{<span style="color: #0000ff">Add-CMDeviceCollectionExcludeMembershipRule</span> <span style="color: #000080">-CollectionName</span> <span style="color: #ff0000">$Collection</span>.Name <span style="color: #ff0000">@RuleParams</span>}
        }
    }
   <span style="color: #008000"> #Move Collection to Folder</span>
   <span style="color: #0000ff"> Get-CMDeviceCollection</span> <span style="color: #000080">-Name</span> <span style="color: #ff0000">$Collection</span>.Name | <span style="color: #0000ff">Move-CMObject</span> <span style="color: #000080">-FolderPath</span> (<span style="color: #800000">'DeviceCollection\_Global LINUX Clients'</span>)
}</pre>
Now that you have a picture of the landscape that requires upgrading, you can create pilot groups.  Create collections that have direct membership of clients chosen from your “Not Current” collections that match the criteria that you have chosen to pilot.  For example, you may choose to pilot:
<ul>
 	<li>An array of OS release versions</li>
 	<li>System that have different security hardening configurations</li>
 	<li>Systems with different application loads</li>
 	<li>Development machines versus production machines</li>
</ul>
Whatever your criteria, you can now choose a smaller sampling of systems to verify the success of the SCCM Client Upgrade package.
<h4><strong>CREATE A DEPLOYMENT PACKAGE (WITH LOGIC)</strong></h4>
To begin, you need to create a deployment package for the new client.  For a larger deployment, the logic would ideally include:
<ul>
 	<li> Simple dynamic setup</li>
 	<li> Logging to a syslog server</li>
 	<li> Performing post deployment cleanup</li>
</ul>
<strong><u>Preparing the Installation Files</u></strong>
<ol>
 	<li>On a Windows system, download the installation bits from <a href="https://www.microsoft.com/en-us/download/details.aspx?id=47719"></a><a href="https://www.microsoft.com/en-us/download/details.aspx?id=47719">https://www.microsoft.com/en-us/download/details.aspx?id=47719</a></li>
 	<li>Execute the downloaded <strong>Config Mgr Clients for Linux.EXE</strong> file to unpack the installation media. Store the extracted files in a folder.  Example: Client-5.00.7958.2437</li>
 	<li>Create a script file called schedule_upgrade.sh It is highly recommended that you created this script on a LINUX system to avoid file encoding issues and Unicode characters.  This script will be executed by the older SCCM client.  It will perform an in-place upgrade of the client.  Utilize the following script as an example for your pilot.  Customize it as need.  The logic in the script is:
* Accept the paramaters of a site code and management point.
* Create a log function that will be used for troubleshooting and execution history.
* Define the installation source path.
* Update the install script with the correct execution path.
* Schedule the upgrade (in the example for 64-bit systems).
* Schedule the post upgrade cleanup.</li>
</ol>
<pre><span style="color: #008000">#!/bin/sh</span>
SITECODE=<span style="color: #ff6600">$1</span>
MPSERVER=<span style="color: #ff6600">$2</span>
TARGETVERSION=<span style="color: #ff0000">5.00.7958.2437</span>
<span style="color: #008000">###############################################################################
# EDIT ONLY THE VALUES ABOVE. THE TARGET VERSION VALUE MUST EXACTLY MATCH
# THE VERSION NUMBER OF THE CLIENT UPGRADE
###############################################################################</span>
LOGDIR=/opt/microsoft/cm/packagelog/
LOGFILE=<span style="color: #ff6600">$LOGDIR</span>/sccm_client_upgrade_<span style="color: #ff6600">$TARGETVERSION</span>.log
INSTALLPATH=/tmp/upgrade
TARGETPATH=/opt/microsoft/cm/bin
SOURCEPATH=<span style="color: #800000">$(printf `pwd`)
</span><span style="color: #008000">###############################################################################
# LOG FUNCTION TO WRITE LOCAL LOG FILE AND TO /VAR/LOG/MESSAGES
###############################################################################</span>
writelog<span style="color: #800000">() {</span>
    <span style="color: #0000ff">echo</span> <span style="color: #3366ff">${*}</span> <span style="color: #ff0000">2</span><span style="color: #800000">&gt;&amp;</span><span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
    <span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #0000ff">-f</span> /bin/logger <span style="color: #800000">]</span> 
    <span style="color: #0000ff">then</span> 
        logger <span style="color: #3366ff">${*}</span>
    <span style="color: #0000ff">fi</span> 
<span style="color: #800000">}</span>
<span style="color: #008000">###############################################################################
# Create an upgrade log file to track activity
###############################################################################</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #800000">!</span> <span style="color: #0000ff">-d</span> <span style="color: #ff6600">$LOGDIR</span> <span style="color: #800000">]</span>
<span style="color: #0000ff">then</span>
    <span style="color: #0000ff">mkdir</span> -p <span style="color: #ff6600">$LOGDIR</span>
<span style="color: #0000ff">fi</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #0000ff">-f</span> <span style="color: #ff6600">$LOGFILE</span> <span style="color: #800000">]</span>
<span style="color: #0000ff">then
   </span> <span style="color: #0000ff">rm</span> -f <span style="color: #ff6600">$LOGFILE</span>
<span style="color: #0000ff">fi
touch</span> <span style="color: #ff6600">$LOGFILE</span>
writelog <span style="color: #800000">$(date)</span>
writelog <span style="color: #808080">"CCMEXECD - Log file created for the SCCM client upgrade to $TARGETVERSION from path $INSTALLPATH"</span>
<span style="color: #008000">###############################################################################
<span style="color: #000000">writelog</span> <span style="color: #808080">"CCMEXECD - Defining the install path directory. Removing installation bits from any previous upgrade."
</span>###############################################################################</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[ !</span> <span style="color: #0000ff">-d</span> <span style="color: #ff6600">$INSTALLPATH</span> <span style="color: #800000">]
</span><span style="color: #0000ff">then</span>
    <span style="color: #0000ff">mkdir</span> -p <span style="color: #ff6600">$INSTALLPATH</span>
<span style="color: #0000ff">else
   </span> <span style="color: #0000ff">rm</span> -Rf <span style="color: #ff6600">$INSTALLPATH</span>
    <span style="color: #0000ff">mkdir</span> -p <span style="color: #ff6600">$INSTALLPATH</span>
<span style="color: #0000ff">fi
</span><span style="color: #008000">###############################################################################
<span style="color: #000000">writelog</span> <span style="color: #808080">"CCMEXECD - Copy the installation media from the package download cache folder to the installation directory"</span>
###############################################################################</span>
<span style="color: #0000ff">cp</span> <span style="color: #ff6600">$SOURCEPATH</span><span style="color: #800000">/*</span> <span style="color: #ff6600">$INSTALLPATH
</span>writelog <span style="color: #808080">"CCMEXECD - Editing the $INSTALLPATH/execute_upgrade.sh file with the correct variables for installation."</span>
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>INSTALLPATH<span style="color: #800000">@</span><span style="color: #ff6600">$INSTALLPATH</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/execute_upgrade.sh
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>MPSERVER<span style="color: #800000">@</span><span style="color: #ff6600">$MPSERVER</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/execute_upgrade.sh
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>SITECODE<span style="color: #800000">@</span><span style="color: #ff6600">$SITECODE</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/execute_upgrade.sh
writelog <span style="color: #808080">"CCMEXECD - Editing the $INSTALLPATH/post_install_check.sh file with the correct variables for installation."</span>
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>TARGETPATH<span style="color: #800000">@</span><span style="color: #ff6600"><span style="color: #800000">$</span>TARGETPATH</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/post_install_check.sh
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>TARGETVERSION<span style="color: #800000">@</span><span style="color: #ff6600">$TARGETVERSION</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/post_install_check.sh
<span style="color: #0000ff">sed</span> -i s<span style="color: #800000">@</span>LOGFILE<span style="color: #800000">@</span><span style="color: #ff6600">$LOGFILE</span><span style="color: #800000">@</span>g <span style="color: #ff6600">$INSTALLPATH</span>/post_install_check.sh
<span style="color: #008000">###############################################################################
# Create a one time AT job to execute the upgrade. If the upgrade were
# executed by SCCM it would fail because the runtime would be killed
# during client uninstall. To resolve this, it is executed out of band
# using AT. 
# Note: Execution cannot be run from within the /opt/microsoft/configmgr/.cache/ directory. 
# The upgrade to the modern clients changes the directory structure and performs clean-up 
# during client upgrade. The modern client installation is moved to /opt/microsoft/cm/
###############################################################################</span>
writelog <span style="color: #808080">"CCMEXECD - Initiating SCCM Client Upgrade AT job."</span>
<span style="color: #008000">###############################################################################
# Change Directory to the upgrade directory before initiating the AT job 
# otherwise AT job PWD becomes the SCCM .cache/package directory (which will 
# not exist at the time of the execution.
###############################################################################</span>
cd <span style="color: #ff6600">$INSTALLPATH
</span><span style="color: #008000">###############################################################################
# Checking the version of the SCCM client in the event you are redeploying the
# package and the collections have not re-evaluated (collection membership).
###############################################################################</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #0000ff">-f</span> <span style="color: #ff6600">$TARGETPATH</span>/ccmexec <span style="color: #800000">]</span>
<span style="color: #0000ff">then</span>
    INSTALLEDVERSION=<span style="color: #800000">$(echo $(/opt/microsoft/cm/bin/ccmexec -v) | cut -d " " -f 3)
</span>    writelog <span style="color: #808080">"CCMEXECD - Checking the current installed version."
</span>    writelog <span style="color: #808080">"CCMEXECD - Installed SCCM version is $INSTALLEDVERSION"</span>
   <span style="color: #0000ff"> if</span> <span style="color: #800000">[</span> <span style="color: #ff6600">$INSTALLEDVERSION</span> = <span style="color: #808080">"TARGETVERSION"</span> <span style="color: #800000">]</span>
    <span style="color: #0000ff">then</span>
        writelog <span style="color: #808080">"CCMEXECD - Client is already at the version for this package."
</span>        writelog <span style="color: #808080">"CCMEXECD - Removing installation directory."
</span>       <span style="color: #0000ff"> rm</span> -Rf INSTALLPATH
    <span style="color: #0000ff">else</span>
        at -f $INSTALLPATH/post_install_check.sh -m now + <span style="color: #ff6600">15</span> min
        at -f $INSTALLPATH/execute_upgrade.sh -m now
   <span style="color: #0000ff"> fi</span>
<span style="color: #0000ff">else</span>
    at -f <span style="color: #ff6600">$INSTALLPATH</span>/post_install_check.sh -m now + <span style="color: #ff6600">15</span> min
    at -f <span style="color: #ff6600">$INSTALLPATH</span>/execute_upgrade.sh -m now
<span style="color: #0000ff">fi
</span></pre>
&nbsp;

<span style="color: #ff0000"><strong> </strong><strong>**WARNING**</strong></span> It is recommended that you create, edit and save this script on a LINUX machine.  If you do use a Windows based editor, ensure that you utilize one that saves the file in UNIX format with an encoding of UTF-8 without Byte Order Marks. By default, most Windows file editors add carriage returns AND line feeds to scripts (CRLF) as well as encodes the files in Unicode. If you choose to edit the files in Windows, see another post ( <a href="https://blogs.technet.microsoft.com/jeffbutte/2016/01/31/editing-converting-linux-scripts-from-a-windows-system/"><strong>Editing / Converting LINUX scripts from a Windows System </strong></a>) to ensure they are formatted correctly for LINUX.
<ol start="4">
 	<li>Create a script file called execute_upgrade.sh  This script will be executed by an AT job.  Because the script sources another script (the Linux SCCM client install script).
<pre><span style="color: #008000">#!/bin/sh
# DO NOT ALLOW ANY TRAILING SPACES OR RETURN CARRAIGES BEYOND THE TAR FILE</span>
INSTALLPATH/install -sitecode SITECODE -mp MPSERVER -keepdb INSTALLPATH/ccm-Universalx64.tar</pre>
</li>
 	<li><span><span>Create a script file called post_install_check.sh  This script will also be executed by an AT job at a later time to check the status of the install and perform clean up.</span></span><span></span>
<pre><span style="color: #008000">#!/bin/sh
###############################################################################
# LOG FUNCTION TO WRITE LOCAL LOG FILE AND TO /VAR/LOG/MESSAGES
###############################################################################</span>
writelog<span style="color: #800000">() {
</span>    <span style="color: #0000ff">echo</span> <span style="color: #3366ff">${*}</span> <span style="color: #800000">&gt;&gt;</span> LOGFILE
    <span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #0000ff">-f</span> /bin/logger <span style="color: #800000">]</span>
   <span style="color: #0000ff"> then</span>
        logger -s <span style="color: #3366ff">${*}</span>
    <span style="color: #0000ff">fi</span>
<span style="color: #800000">}</span>
<span style="color: #008000">###############################################################################</span>
writelog <span style="color: #808080">"CCMEXECD - Performing clean-up tasks. If there are any issues, check /var/spool/mail/root"</span>
<span style="color: #008000">###############################################################################</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #0000ff">-f</span> TARGETPATH/ccmexec <span style="color: #800000">]</span>
<span style="color: #0000ff">then</span>
    INSTALLEDVERSION=<span style="color: #800000">$(echo $(/opt/microsoft/cm/bin/ccmexec -v) | cut -d " " -f 3)
</span>    writelog <span style="color: #808080">"CCMEXECD - Installed SCCM version is $INSTALLEDVERSION"</span>
    <span style="color: #0000ff">if</span> [ <span style="color: #ff6600">$INSTALLEDVERSION</span> = <span style="color: #808080">"TARGETVERSION"</span> ]
    <span style="color: #0000ff">then</span>
        writelog <span style="color: #808080">"CCMEXECD - Removing installation directory."
</span>        <span style="color: #0000ff">rm</span> -Rf INSTALLPATH
    <span style="color: #0000ff">fi
else</span>
    <span style="color: #0000ff">if</span> [ -f /opt/microsoft/configmgr/bin/ccmexec ]
    <span style="color: #0000ff">then</span>
       INSTALLEDVERSION=<span style="color: #800000">$(echo $(/opt/microsoft/configmgr/bin/ccmexec -v) | cut -d " " -f 3)
</span>       writelog <span style="color: #808080">"CCMEXECD - Installed SCCM version is $INSTALLEDVERSION"
</span><span style="color: #0000ff">    fi</span>
    writelog <span style="color: #808080">"CCMEXECD - ## The expected version of TARGETVERSION was not found. Leaving the installation directory.  ##"
</span><span style="color: #0000ff">fi</span></pre>
</li>
 	<li><span>Manually test your scripts.  Copy / SCP the scripts and installation files to a Linux test machine and verify they execute as desired.  If there are issues, review the created log file as well as your local mail spool file to check the status of the executed upgrade job.  </span><span></span></li>
</ol>
<h4><strong>DEPLOYMENT PACKAGE</strong></h4>
Once your scripts are tested, create a SCCM package (see <a href="https://technet.microsoft.com/en-us/library/gg682112.aspx">https://technet.microsoft.com/en-us/library/gg682112.aspx</a> ).  SCCM supports only package deployment to UNIX / LINUX systems.  Applications are a Windows specific concept and are not support on non-windows platforms.  (see Deploying Software to Linux and UNIX Servers in Configuration Manager <a href="https://technet.microsoft.com/en-us/library/jj573943.aspx">https://technet.microsoft.com/en-us/library/jj573943.aspx</a> )  <span>Next, you will create a deployment package.  You will follow his process to create and deploy a separate package for each site code in your SCCM hierarchy.  In the hierarchy example above, you would create packages for SC1 and SC2</span>
<h4><span style="text-decoration: underline">Create the Deployment Package</span></h4>
<ol>
 	<li>Place your scripts in your SCCM package source share folder. (\\servername\sharename\path)  Example \\fileserver\packagesource$\Microsoft\SystemCenter\ConfigManager\Linux\Client-5.0.7958.2437</li>
 	<li>Start the Create Package Wizard.  Fill out the fields with the appropriate values and select the package source folder where you stored your shell scripts.

[caption id="attachment_425" align="alignnone" width="812"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/CreatePackage.png"><img width="812" height="685" class="size-full wp-image-425" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/03/CreatePackage.png" /></a> Specify information about this package[/caption]</li>
 	<li>On the Program Type page, select “Standard program”.</li>
 	<li>In the program command line, define the shell you intend to use, the script specified in your package followed by the two parameters of the site code and the management point.  Example:
<pre> /bin/sh ./execute_upgrade.sh SC1 sccmmp1.contoso.corp</pre>
Set the program to run “normal”. The “Program can r<u>u</u>n” value must be set to “Whether or not a user is logged on”.  SCCM client execution does not support the user context on non-Windows platforms.

[caption id="attachment_535" align="alignnone" width="719"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/StandardProgram1.png"><img width="719" height="610" class="size-full wp-image-535" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/03/StandardProgram1.png" /></a> Specify information about this standard program[/caption]

<a href="https://msdnshared.blob.core.windows.net/media/2018/03/StandardProgram1.png"></a></li>
 	<li>On the Requirements page, select the appropriate values for your environment. The Platform requirements can be set to either “This program can be run on any platform” or a platform specific setting.  It is recommended that you either filter at the collection level and or by the package requirements.   In this example, the program is set to run on any platform and will be filtered at the collection level.</li>
 	<li>Set the Estimated disk space to be 300MB. This will account for:
* the package content size
* the copy of the package it makes during deployment in the .cache/&lt;packageID&gt;/tmp directory
* the copy of the installation bits copied to /tmp/upgrade NOTE: After package deployment, the .cache/&lt;PackageID&gt; folder and subdirectories are deleted unless you checked the box to “Persist content in the client cache”</li>
 	<li>Complete the wizard screens (next… next… close).</li>
</ol>
<h4><strong><u>Distribute the Package</u></strong></h4>
Ensure that you distribute the package to all the required DPs. (<a href="https://technet.microsoft.com/en-us/library/gg682083.aspx">https://technet.microsoft.com/en-us/library/gg682083.aspx</a>)
<h4><strong><u>Deploy the Package</u></strong></h4>
<ol>
 	<li>Utilize the existing collection created previously that contains the target LINUX machines that are now <strong>Not Current</strong>. ENSURE that you are targeting the collection with a package that is SPECIFIC to the site code and management point specified in the script.

[caption id="attachment_525" align="alignnone" width="796"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/DeploySoftware1.png"><img width="796" height="665" class="size-full wp-image-525" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/03/DeploySoftware1.png" /></a> Specify general information for this deployment[/caption]</li>
 	<li>Select Next, on the “Specify the content destination” page.</li>
 	<li>On the “Specify settings to control how this software is deployed”, ensure that the “Purpose:” is set to “Required”.

[caption id="attachment_435" align="alignnone" width="790"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/DeploymentSettings.png"><img width="790" height="659" class="size-full wp-image-435" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/03/DeploymentSettings.png" /></a> Deployment Settings[/caption]</li>
 	<li>On the Scheduling page, select “Schedule when this deployment will become available:” and choose the default date. For the “Assignment schedule”, select “New…”, utilizing the default date or choose “Assign immediately after this event” --&gt; “Assign to the following Schedule” and click OK (which chooses the current date / time as the default).   The values “log on and “log off” are not supported in LINUX deployments.

[caption id="attachment_465" align="alignnone" width="791"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/Scheduling.png"><img width="791" height="660" class="size-full wp-image-465" alt=" Specify the schedule for this deployment" src="https://msdnshared.blob.core.windows.net/media/2018/03/Scheduling.png" /></a> Specify the schedule for this deployment[/caption]</li>
 	<li>Click “Next &gt;” on the User Experience page.</li>
 	<li>On the “Distribution Points” page, ensure the “Deployment options” are set to “Download content from distribution point and run locally”. Deselect the option to “Allow clients to share content”.  Linux clients do not support branch cache.  Click Next &gt;

[caption id="attachment_455" align="alignnone" width="791"]<a href="https://msdnshared.blob.core.windows.net/media/2018/03/DistributionPoint.png"><img width="791" height="659" class="size-full wp-image-455" alt="Distribution Points" src="https://msdnshared.blob.core.windows.net/media/2018/03/DistributionPoint.png" /></a> Distribution Points[/caption]</li>
 	<li>On the Summary page, click Next&gt;</li>
 	<li>Click Close.</li>
 	<li>Open the properties page of the package that was just deployed.</li>
</ol>
<h4><strong>MONITOR DEPLOYMENT</strong></h4>
<span>There are multiple ways to monitor the deployment.  There are  some challenges in monitoring the upgrade.  Monitoring the deployment does not tell you whether the upgrade is going well.  Monitoring the deployment indicates how well the package has been delivered to the client and the AT job has been setup.  Once those actions are completed, depending upon your enterprise configurations, you may loose a little visibility into what is occurring at a large scale.  Here are a few ways to approach monitoring your successful deployment.</span>
<h4><span style="text-decoration: underline">Monitor the Collections</span></h4>
Within the Configuration Manager Console, navigate to the device collections created above.  For example select your Global LINUX Clients collection.  Within the console, add the columns for:
<ul>
 	<li>Agent Edition</li>
 	<li>Client Version</li>
 	<li>Management Point</li>
 	<li>Operating System</li>
 	<li>Site Code</li>
</ul>
<a href="https://blogs.technet.microsoft.com/neilp/2012/03/18/long-live-right-click-tools-system-center-2012-configuration-manager-console-extensions/"></a>

Periodically you can refresh your collections to view the progress of the deployment across your sites
<h4><span style="text-decoration: underline">Monitor Deployment Reports</span></h4>
The deployment reports will provide good view of how successful the older Linux clients have downloaded the package and have executed the shell script setting up the AT job.

<a href="https://msdnshared.blob.core.windows.net/media/2018/03/MonitoringUpgradeDeploymentReport.png"><img width="1647" height="436" class="alignnone size-full wp-image-505" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/03/MonitoringUpgradeDeploymentReport.png" /></a>
<h4><span style="text-decoration: underline">Monitor Syslog</span></h4>
Many enterprises have centralized logging for Linux.  A common method used is syslog.  In this example, centralized syslog is configured using rsyslog.  The syslog server that aggregates all logs can be either monitored with tail or queried using grep.  In the example below, the query is based on the log entry created by the installation script using the logger command.  CCMEXECD was part of the text in the log entry.
<pre>[logadmin@sylogserver ~]$ cat /var/log/messages | grep -e CCMEXECD
Mar 18 22:56:41 centos7test logger: CCMEXECD - Log file created for the SCCM client upgrade to 5.00.7958.2437 from path /tmp/upgrade
Mar 18 22:56:41 centos7test logger: CCMEXECD - Defining the install path directory. Removing installation bits from any previous upgrade.
Mar 18 22:56:41 centos7test logger: CCMEXECD - Copy the installation media from the package download cache folder to the installation directory
Mar 18 22:56:42 centos7test logger: CCMEXECD - Editing the /tmp/upgrade/execute_upgrade.sh file with the correct variables for installation.
Mar 18 22:56:42 centos7test logger: CCMEXECD - Editing the /tmp/upgrade/post_install_check.sh file with the correct variables for installation.
Mar 18 22:56:42 centos7test logger: CCMEXECD - Initiating SCCM Client Upgrade AT job.
Mar 18 23:01:00 centos7test root: CCMEXECD - Performing clean-up tasks. If there are any issues, check /var/spool/mail/root
Mar 18 23:01:00 centos7test root: CCMEXECD - Installed SCCM version is 5.00.7958.2437
Mar 18 23:01:00 centos7test root: CCMEXECD - Removing installation directory.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Log file created for the SCCM client upgrade to 5.00.7958.2437 from path /tmp/upgrade
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Defining the install path directory. Removing installation bits from any previous upgrade.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Copy the installation media from the package download cache folder to the installation directory
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Editing the /tmp/upgrade/execute_upgrade.sh file with the correct variables for installation.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Editing the /tmp/upgrade/post_install_check.sh file with the correct variables for installation.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Initiating SCCM Client Upgrade AT job.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Checking the current installed version.
Mar 19 00:53:09 centos6dev logger: CCMEXECD - Installed SCCM version is 5.00.7958.2437
Mar 19 01:08:00 centos6dev root: CCMEXECD - Performing clean-up tasks. If there are any issues, check /var/spool/mail/root
Mar 19 01:08:00 centos6dev root: CCMEXECD - Installed SCCM version is 5.00.7958.2437
Mar 19 01:08:00 centos6dev root: CCMEXECD - Removing installation directory.</pre>
<h4><span style="text-decoration: underline">Monitor an Individual Client</span></h4>
For your pilot group, you will want to analyze a few clients closely to ensure that the upgrade goes exactly as you would like it.  It is recommended that you edit the existing client configuration and enable TRACE mode.

The configuration file in the older clients for the logs is /opt/microsoft/configmgr/etc/scxcm.conf it supports the log settings of: ERROR,WARNING INFO and TRACE.

To change the log level, edit the scxcm.conf and change each instance of the tag MODULE to the desired log level.

Ensure that you ONLY use TRACE during troubleshooting. The trace log is very verbose and can fill up a small disk quickly if you are not paying attention.

To speed up testing, you can execute a policy pull:
<pre>/opt/microsoft/configmgr/bin/ccmexec -rs policy</pre>
In real time you can watch the logs:
<pre>tail -f /var/opt/microsoft/scxcm.log</pre>
To get the most detail for testing configure the existing SCCM client for LINUX in trace mode.  Once you have restarted the client, initiate a policy pull and GREP on the package ID.  A simple one-line command example would be:
<pre>/opt/microsoft/configmgr/bin/ccmexec -rs policy ;  tail -f /var/opt/microsoft/scxcm.log | grep --color -e SC100091</pre>
<h4></h4>
<h4><strong>TROUBLESHOOTING DEPLOYMENTS</strong></h4>
For deployment troubleshooting deployment infrastructure issues, see the Troubleshooting Deployment section of <a href="https://blogs.technet.microsoft.com/jeffbutte/2016/02/01/deploying-a-script-or-package-to-a-linux-host-with-system-center-configuration-manager-2012-r2/">https://blogs.technet.microsoft.com/jeffbutte/2016/02/01/deploying-a-script-or-package-to-a-linux-host-with-system-center-configuration-manager-2012-r2/</a>
<h4><span style="text-decoration: underline">Analyze the Package Log</span></h4>
As long as the deployment infrastructure is functional the next step would be to evaluate the log file generated by the execute_install.sh script. Based on the example script, the log file will be found in /opt/microsoft/cm/packagelog
<pre>[root@centos6dev ~]# cat /opt/microsoft/cm/packagelog/sccm_client_upgrade_5.00.7958.2437.log
Mon Mar 19 00:53:08 EDT 2018
CCMEXECD - Log file created for the SCCM client upgrade to 5.00.7958.2437 from path /tmp/upgrade
CCMEXECD - Defining the install path directory. Removing installation bits from any previous upgrade.
CCMEXECD - Copy the installation media from the package download cache folder to the installation directory
CCMEXECD - Editing the /tmp/upgrade/execute_upgrade.sh file with the correct variables for installation.
CCMEXECD - Editing the /tmp/upgrade/post_install_check.sh file with the correct variables for installation.
CCMEXECD - Initiating SCCM Client Upgrade AT job.
CCMEXECD - Checking the current installed version.
CCMEXECD - Installed SCCM version is 5.00.7958.2437
CCMEXECD - Performing clean-up tasks. If there are any issues, check /var/spool/mail/root
CCMEXECD - Installed SCCM version is 5.00.7958.2437
CCMEXECD - Removing installation directory.</pre>
&nbsp;
<h4><span style="text-decoration: underline">Analyze the Mail Log</span></h4>
In the above example, the -m switch is used with the AT job.  This will send mail to the user when the job has completed even if there was no output.  CentOS uses POSTFIX so mail messages can be found in /var/spool/mail/  Since the SCCM client executes jobs as root, the mail file will be /var/spool/mail/root
<pre>[root@centos6dev ~]# cat /var/spool/mail/root
From root@centos6dev.contoso.corp Mon Mar 19 00:53:28 2018
Return-Path: &lt;root@centos6dev.contoso.corp&gt;
X-Original-To: root
Delivered-To: root@centos6dev.contoso.corp
Received: by centos6dev.contoso.corp (Postfix, from userid 0)
id B662940BDBD6; Mon, 19 Mar 2018 00:53:28 -0400 (EDT)
Subject: Output from your job 13
To: root@centos6dev.contoso.corp
Message-Id: &lt;20180319045328.B662940BDBD6@centos6dev.contoso.corp&gt;
Date: Mon, 19 Mar 2018 00:53:28 -0400 (EDT)
From: root@centos6dev.contoso.corp (root)
Beginning installation of Configuration Manager
Checking Prerequisites...
Removed symlink /etc/systemd/system/multi-user.target.wants/ccmexecd.service.
Generating a 2048 bit RSA private key
*************************+++++
***************************+++++
unable to write 'random state'
writing new private key to '/etc/opt/microsoft/cm/omi/ssl/omikey.pem'
-----
Start to kill old ccmexec process
Done
Datastore found in /var/opt/microsoft/cm.
Configuring CCMExec service(ccmexecd.service) ...
Created symlink from /etc/systemd/system/multi-user.target.wants/ccmexecd.service to /usr/lib/systemd/system/ccmexecd.service.
Starting Configuration Manager...
From root@centos6dev.contoso.corp Mon Mar 19 00:58:01 2018
Return-Path: &lt;root@centos6dev.contoso.corp&gt;
X-Original-To: root
Delivered-To: root@centos6dev.contoso.corp
Received: by centos6dev.contoso.corp (Postfix, from userid 0)
id 5639540BDBD6; Mon, 19 Mar 2018 01:08:01 -0400 (EDT)
Subject: Output from your job 12
To: root@centos6dev.contoso.corp
Message-Id: &lt;20180319045801.5639540BDBD6@centos6dev.contoso.corp&gt;
Date: Mon, 19 Mar 2018 01:08:01 -0400 (EDT)
From: root@centos6dev.contoso.corp (root)
root: CCMEXECD - Performing clean-up tasks. If there are any issues, check /var/spool/mail/root
root: CCMEXECD - Installed SCCM version is 5.00.7958.2437
root: CCMEXECD - Removing installation directory.</pre>
<h4></h4>
<h4><strong>COMMON ISSUES</strong></h4>
<strong>Issue:</strong>  The upgrade runs as an AT job but only generates an error:
Archive file not found or no read permissions
<strong>Cause 1 :</strong> The install shell script in the execute_upgrade.sh has either space, a return carriage or additional data following the specified TAR file.  The install script must be the last line in the execute_upgrade.sh script and must not have trailing data after the TAR file.
<strong>Cause 2:</strong> The install shell script parameters in the execute_upgrade.sh are in incorrect.  All specified parameters must be specified before the platform specific TAR file.  The TAR file must be the last parameter.
<b>Cause 3:</b><span style="float: none;background-color: transparent;color: #333333;cursor: text;font-family: Georgia,'Times New Roman','Bitstream Charter',Times,serif;font-size: 16px;font-style: normal;font-variant: normal;font-weight: 400;letter-spacing: normal;line-height: 24px;text-align: left;text-decoration: none;text-indent: 0px"> T</span>he execute_upgrade.sh script is not in the proper format.  To check the scripts, run the Linux “file” command against the scripts
<pre>[root@centos70]# file *.sh
 execute_upgrade.sh:    POSIX shell script, ASCII text executable
 post_install_check.sh: POSIX shell script, ASCII text executable
 schedule_upgrade.sh:   POSIX shell script, ASCII text executable, with CRLF line terminators</pre>
If you end up with file properties of: POSIX shell script, ASCII text executable, with CRLF line terminators then your file has been likely created with a Windows based editor that inserted Byte Order Marks (BOM). Update the file to the correct format.

<strong>Issue:</strong>  The upgrade runs as an AT job but only generates an error:
<pre>install: missing file operand
 Try 'install --help' for more information.</pre>
<strong>Cause:</strong> The schedule_upgrade.sh script is missing the change directory (cd) to the correct directory that the upgrade files are copied to.  When the AT job is scheduled, it inherits the present working directory (pwd) during the execution of the script.

&nbsp;

Hopefully this use case example has been helpful towards planning your upgrade!

Special thanks to <strong>Kevin Kasalonis</strong> for his contributions to this post.]]></content:encoded>
    </item>
    <item>
      <title>NDES EncryptedPassword</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/ndes-encryptedpassword</link>
      <pubDate>Mon, 18 Sep 2017 11:17:21 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=366</guid>
      <description><![CDATA[While doing some NDES work in my lab I found that my SCEP Administrative site...]]></description>
      <content:encoded><![CDATA[While doing some NDES work in my lab I found that my SCEP Administrative site  <a href="https://subca.contoso.corp/certsrv/mscep_admin/">https://subca.contoso.corp/certsrv/mscep_admin/</a>  was generating a HTTP 500 error.

The application event log contained the following two entries following any unsuccessful attempt to reach the SCEP admin site:
<pre>Log Name:  Application
Source:  Microsoft-Windows-NetworkDeviceEnrollmentService
Event ID:  2
Level:  Error
Description:
The Network Device Enrollment Service cannot be started (0x8009000b). Key not valid for use in specified state.</pre>
&nbsp;
<pre>Log Name:  Application
Source:  Microsoft-Windows-NetworkDeviceEnrollmentService
Event ID:  49
Level: Error
Description:
The Network Device Enrollment Service has failed to decrypt the encrypted password or the decrypted password's length doesn't match the one configured in the registry. To fix this, delete the EncryptedPassword entry in the registry.</pre>
&nbsp;

I looked at a few resources like <a href="https://social.technet.microsoft.com/wiki/contents/articles/9063.network-device-enrollment-service-ndes-in-active-directory-certificate-services-ad-cs.aspx">Network Device Enrollment Service (NDES) in Active Directory Certificate Services (AD CS)</a> But did not find an exact set of instructions to resolve the issue.  While the Event ID 49 is pretty explanitory, it does not explain exactly what to do and where to go.

The SCEP encrypted password is located at:
<pre>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MSCEP\EncryptedPassword</pre>
To resolve the issue:
<ol>
 	<li>Delete the EncryptedPassword REG_BINARY subkey stored in the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MSCEP\EncryptedPassword.</li>
 	<li>Restart Active Directory Certificate Services.</li>
 	<li>The next connection to the <a href="https://subca.contoso.corp/certsrv/mscep_admin/">https://subca.contoso.corp/certsrv/mscep_admin/</a>  site will generate a new value with the updated EncryptedPassword.</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>The Risk of Security Only Updates</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/the-risk-of-security-only-updates</link>
      <pubDate>Mon, 18 Sep 2017 09:18:00 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=365</guid>
      <description><![CDATA[This week I worked with a customer to resolve an issue where there was concern that users were...]]></description>
      <content:encoded><![CDATA[This week I worked with a customer to resolve an issue where there was concern that users were having an Active Directory Kerberos authentication issue.  Users were unable to log into LINUX systems using their Active Directory credentials.  The prevailing thought was that an update had broken the system and needed to be rolled back.  Updates had been applied to both their Active Directory servers and their Red Hat 7 systems.

The systems were domain joined using the System Security Services Daemon (SSSD).   To begin identifying the cause of the issue the team logged in locally at the console (root login via SSH was disabled).  The SSSD service was not running.  Attempts to start the service were unsuccessful.   The debug level in the /etc/sssd/sssd.conf file was updated to provide more meaningful and detailed error messages.  The SSSD.CONF file contains multiple sections; each with its own log file and debug level.  To begin, two sections were modified.

The SSSD section contains key components about the service (daemon) the monitors and the domain. Even at the highest debug level, this section / log does not provide a lot of detail.  We set it to the highest debug level just to ensure we did not miss any key details to the service failure.
<pre>[sssd]
debug_level = 9</pre>
The domain section contains the most detail and provide tremendous value in the logs when set at the highest debug level.
<pre>[domain/&lt;domainfqdn&gt;] 
debug_level = 9</pre>
At this point, we attempted to start the service:
<pre>systemctl start sssd.service</pre>
While the service failed to start, the logs filled with valuable troubleshooting data.  As suspected, the /var/log/sssd/sssd.log file did not provide anything meaning full.  The domain log, on the other hand (in this case /var/log/sssd/sssd_contoso.corp.log) provided all the detail we needed.
<pre>(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_load_module) (Ox0400): About to load module [ad].
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_module_open_lib (0x1000) : Loading module [ad] with path [/usr/lib64/sssd/libsss_ad.so]
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_module_open_lib (0x0010) : Unable to load module [ad] with path [/usr/lib64/sssd/libsss_ad.so] : /usr/lib64/samba/libgse-samba4.so: symbol krb5_get_init_creds_opt_set_pac_request, version krb5_3_MIT not defined in file libkrb5.so.3 with link time reference
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_load_module (Ox0020) : Unable to create DP module.
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_target_init] (0x0010) : Unable to load module ad
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_load_targets] (0x0020) : Unable to load target [id] [80] : Accessing a corrupted shared library.
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_init] (0x0020) Unable to initialize DP targets [1432158209] : Internal Error
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [dp_terminate_active_requests] (Ox0400) : Terminating active data provider requests
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [smbus_remove_watch] (Ox2000) : 0x55a0b53aa080/0x55a0b53a8f50
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [remove_socket_symlink] (0x4000) : The path points to [/var/1ib/sss/pipes/private/sbus-dp_CONTOSO.CORP.3977]
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [remove_socket_symlink] (0x4000) : The path including our pid is [/var/1ib/sss/pipes/private/sbus-dp_CONTOSO.CORP.39477]
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [remove_socket_symlink] (0x4000) : Removed the symlink
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [be_process_init] (0x0010) : Unable to setup data provider [1432158209] : Internal Error
(Thu Aug 17 09:48:36 2017) [sssd[be[CONTOSO.CORP]]] [main] (0x0010) : Could not initialize backend [1432158209]</pre>
The logs contained a couple of key items to search on.  The section that caught my attention was "version krb5_3_MIT not defined in file libkrb5.so.3".  Prior to updates, the version specified in the calling library must have matched the Kerberos libraries as the error did not exist.

Those details led me to the bug <a href="https://bugzilla.redhat.com/show_bug.cgi?id=1480310">https://bugzilla.redhat.com/show_bug.cgi?id=1480310</a>  The error or issue was caused by applying security only updates.
<pre>yum update-minimal --security</pre>
The result was that an update affected the linkage between the SSSD AD component and a Kerberos shared object (.so) library.

The solution was to update the krb5-libs or to execute an update of the entire system (recommended).  In this case, the customer applied the Kerberos library update only.
<pre>yum update krb5-libs</pre>
After the update was installed, SSSD could then be started.  A quick logon test confirmed that user authentication to Active Directory was restored.

Remember to set the debug_level values back to reasonable value of 5 or less.  A debug level of 9 could put even a moderately used system out of disk space by filling it with logs.

As always, the minimum recommended practice for all systems is to keep current on security and critical hotfixes.  Begin applying them to non-critical or non-production systems first and then perform any necessary functional tests.  Keep in mind, this is the <em><span style="text-decoration: underline">minimum</span></em>.  Microsoft has taken an approach recently with how to handle patching.  The product groups preform testing on fully patched systems.  Not all scenarios can be tested against when a customer selectively chooses which updates they apply across the lifecycle of an operating system.  To ensure a consistent and secure customer experience, Microsoft has transitioned to a new servicing model for Windows 7 and newer operating systems (see <a href="https://blogs.technet.microsoft.com/windowsitpro/2016/08/15/further-simplifying-servicing-model-for-windows-7-and-windows-8-1/">https://blogs.technet.microsoft.com/windowsitpro/2016/08/15/further-simplifying-servicing-model-for-windows-7-and-windows-8-1/</a> ) .  Your mileage may vary on <span style="text-decoration: underline"><strong>any</strong></span> operating system when you pick and choose your way through updates.]]></content:encoded>
    </item>
    <item>
      <title>SCCM Client for LINUX on FIPS Enabled Systems</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/sccm-client-for-linux-on-fips-enabled-systems</link>
      <pubDate>Wed, 06 Sep 2017 23:11:40 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=357</guid>
      <description><![CDATA[Many organizations in the Public Sector as well as businesses that interact with Public Sector...]]></description>
      <content:encoded><![CDATA[Many organizations in the Public Sector as well as businesses that interact with Public Sector entities are required to adhere to the U.S. Government Federal Information Processing Standard (FIPS) Publication 140 for cryptographic systems and modules.  See <a href="https://www.microsoft.com/en-us/TrustCenter/Compliance/FIPS">https://www.microsoft.com/en-us/TrustCenter/Compliance/FIPS</a>

The compliance applies to hardware, firmware and software that use cryptographic-based security systems.  Operating systems protect and store cryptographic data as well as execute software modules that enable the cryptographic algorithms.

Operating systems can be FIPS capable or can be in FIPS enforcement mode.  During FIPS enforcement mode, the operating systems will only allow the validated algorithms to operate.

While most operating systems have achieved FIPS compliance capability, it has seen limited deployment, often due to the limits of the applications installed on the operating systems.  As the threat landscape continues to evolve, organizations are now increasing their security posture, upgrading applications and enabling features like strict FIPS compliance.

For System Center Configuration Manager client for LINUX, FIPS posed some complex issues.  The client was not initially designed to support the specifically enforced algorithms FIPS requires.  To successfully install the client and make it run, the process involved pre-creating or changing the symbolic links to the required openssl supported modules.

On Friday (Aug 29, 2017), Microsoft released version 5.0.7958.2432 of the Config Mgr Clients for Linux.  The download can be found at the Microsoft System Center Configuration Manager - Clients for Additional Operating Systems  <a href="https://www.microsoft.com/en-us/download/details.aspx?id=47719">https://www.microsoft.com/en-us/download/details.aspx?id=47719</a>

The ".2432" release implements the appropriate symbolic links and configuration to support a FIPS enabled system.

<strong>OLDER CLIENTS</strong>

Here is an example of an install on a FIPS compliant CentOS 7.4 system (in strict enforcement mode).  In this example, to confirm that FIPS is enabled, run the command:
<pre>cat /proc/sys/crypto/fips_enabled</pre>
The returned output for a system in FIPS enforcement mode would be "1"

Attempting to install an OLDER SCCM client to the system would look similar to this:
<pre>Checking Prerequisites...
Checking existence of /lib64/libssl.so.1.0.1e-fips and /lib64/libcrypto.so.1.0.1e-fips ...
Checking existence of /lib64/libssl.so.1.0.1- and /lib64/libcrypto.so.1.0.1- ...
Checking existence of /lib64/libssl.so.1.0.1e and /lib64/libcrypto.so.1.0.1e ...
  Found /lib64/libssl.so.1.0.1e and /lib64/libcrypto.so.1.0.1e ...
Running preinstall validator
fips.c(143): OpenSSL internal error, assertion failed: FATAL FIPS SELFTEST FAILURE
./install: line 422:  3071 Aborted                 (core dumped) $TMPWRKDIR/$TMPBINDIR/preinstallvalidator
Pre-Install validator failed. Please check the version of OpenSSL with CM installation requirements.</pre>
&nbsp;

<strong>NEWER 5.0.7958.2432  CLIENT</strong>

Executing an installation of the newest client on the same system will be successful with an example output below:
<pre>Checking Prerequisites...
ccmexecd.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig ccmexecd off
Generating a 2048 bit RSA private key
..........+++
...........+++
writing new private key to '/etc/opt/microsoft/cm/omi/ssl/omikey.pem'
-----
Initializing data store.  This may take a few minutes...
Configuring CCMExec service(ccmexecd.service) ...
Created symlink from /etc/systemd/system/multi-user.target.wants/ccmexecd.service to /usr/lib/systemd/system/ccmexecd.service.
Starting Configuration Manager...</pre>
&nbsp;

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Linux Secure Dynamic DNS Update with Windows DNS</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/265</link>
      <pubDate>Sun, 18 Dec 2016 12:21:40 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=265</guid>
      <description><![CDATA[Earlier this week I was asked for recommendations on how to register Linux systems in DNS. While the...]]></description>
      <content:encoded><![CDATA[<p align="LEFT" dir="LTR">Earlier this week I was asked for recommendations on how to register Linux systems in DNS. While the records could be manually entered (or scripted) as static DNS records, it would be ideal if the process were more "dynamic". Windows clients register dynamically why not Linux. There were ideas about DHCP performing DNS registration on behalf of the client, etc.</p>
<p align="LEFT" dir="LTR">I responded with "Linux clients can dynamically register in DNS". That statement resulted in a funny look. The person responded with "... no… maybe I didn’t explain… it would be nice if they registered in DNS directly, using secure dynamic updates."</p>
<p align="LEFT" dir="LTR">Again… I responded with "…like I said, Linux clients can dynamically register in DNS… Microsoft DNS… configured for secure dynamic updates. Let me explain…"</p>
<span>The </span><a href="https://fedorahosted.org/sssd"><span><span lang="EN">System Security Services Daemon (SSSD)</span></span></a><span><span lang="EN"> for Linux is quickly becomes the foremost method for domain joining Linux systems to Microsoft Active Directory. SSSD has been around since 2008. It is a Fedora hosted project that has recently moved into the mainstream channels / repos. Formerly it could be found in EPEL. It is available for the majority of the mainstream Linux distros (RedHat, CentOS, Fedora, SUSE, Ubuntu, Debian, Gentoo, FreeBSD, etc).</span></span>
<p align="LEFT" dir="LTR">SSSD allows the domain joined Linux clients to perform secure dynamic updates in DNS.</p>
<p align="LEFT" dir="LTR">I recommended that the person domain join their systems with SSSD and they would have their dynamic DNS solution.</p>
<p align="LEFT" dir="LTR">A day later, they came back with the same problem. "… OK… I followed your instructions and domain joined the first Linux system. It authenticates to AD just fine, but it does not dynamically register in DNS. What did I do wrong?"</p>
<p align="LEFT" dir="LTR">So we began to see if ALL the instructions were followed. <span style="font-family: Wingdings">J</span></p>

<h3 align="LEFT">SECURE DYNAMIC UPDATE ZONES</h3>
<p align="LEFT" dir="LTR">Linux secure dynamic DNS updates using SSSD are based on the understanding that the clients are securely authenticating as themselves (not a user). Since they are securely communicating to Active Directory, SSSD expects to be performing an update to a DNS zone that is configure for Secure only updates.</p>


[caption id="attachment_295" align="alignnone" width="399"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/dns_zone.png"><img width="399" height="480" class="wp-image-295 size-full" alt="Active Direcctory DNS Zone Properties" src="https://msdnshared.blob.core.windows.net/media/2016/12/dns_zone.png" /></a> Active Direcctory DNS Zone Properties for a zone configured for Secure Dynamic Updates[/caption]
<p align="LEFT" dir="LTR">Later on, I’ll cover what happens if your zones are NOT secure or are supporting secure and non-secure updates.</p>
<p align="LEFT" dir="LTR">To diagnose the issue, we updated the /etc/sssd/sssd.conf file. We set the [domain/&lt;domainfqdn&gt;] debug level to 9. For the most part, any level from 5 and up would be sufficient.</p>

<pre>debug_level = 9</pre>
<p align="LEFT" dir="LTR">Then we restarted SSSD. The next step was to tail the log and look for the dns communications.</p>

[caption id="attachment_315" align="alignnone" width="1186"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_1.png"><img width="1186" height="257" class="wp-image-315 size-full" alt="SSSD Domain Log" src="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_1.png" /></a> The log can be found at /var/log/sssd/sssd_[domainname].log where [domainname] is the logging facility entry name in the /etc/sssd/sssd.conf file.[/caption]
<p align="LEFT" dir="LTR">There were two primary error entries.</p>

<ol type="a">
 	<li>
<pre>[ad_dyndns_sdap_update_done] (0x0040): Dynamic DNS update failed [5]: Input/output error</pre>
</li>
 	<li>
<pre>[ad_dyndns_nsupdate_done] (0x0040): Updating DNS entry failed [5]: Input/output error</pre>
</li>
</ol>
<p align="LEFT" dir="LTR">However… those entries were the effect; not a symptom. The entries that should catch your eye are:</p>

<ol type="a">
 	<li>
<pre>[resolv_gethostbyname_dns_query] (0x0100): Trying to resolve A record of 'usmdua8006' in DNS</pre>
</li>
 	<li>
<pre>[sdap_dyndns_dns_addrs_done] (0x0040): Could not receive list of current addresses [5]: Input/output error</pre>
</li>
</ol>
<p align="LEFT" dir="LTR">The very KEY item to focus on is the data that is being registered in DNS. The data should be a fully qualified name. In this example, the value 'usmdua8006' is NOT a fully qualified name. 'usmdua8006' is the single label name for the system. That leads us to the hostname. A hostname can be a single label name of a node on a network or it can be a fully qualified name (example: 'usmdua8006.contoso.corp')</p>
<p align="LEFT" dir="LTR">If you look in the screenshot above, you will see that the LINUX hostname is a single label name.</p>
<p align="LEFT" dir="LTR">Viewing this from the DNS server displays the same issue. The DNS server will fail to register a single label record.</p>


[caption id="attachment_305" align="alignnone" width="744"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/netmon_packet_capture.png"><img width="744" height="213" class="wp-image-305 size-full" alt="Frame captured with Network Monitor 3.4" src="https://msdnshared.blob.core.windows.net/media/2016/12/netmon_packet_capture.png" /></a> Frame captured with Network Monitor 3.4[/caption]
<p align="LEFT" dir="LTR">The solution is that the LINUX hostname must be the fully qualified name.  For example in CentOS 7, use hostnamectl to set the hostname to the FQND.</p>

<pre>hostnamectl set-hostname usmdua8006.contoso.corp</pre>
<p align="LEFT" dir="LTR">See your distribution specific documentation for setting the hostname properly.</p>
<p align="LEFT" dir="LTR">For this example the hostname is updated to the FQDN. The SSSD service is restarted.</p>

[caption id="attachment_325" align="alignnone" width="1181"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_2.png"><img width="1181" height="224" class="wp-image-325 size-full" alt="SSSD Domain Log" src="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_2.png" /></a> The log can be found at /var/log/sssd/sssd_[domainname].log where [domainname] is the logging facility entry name in the /etc/sssd/sssd.conf file.[/caption]
<p align="LEFT" dir="LTR">You can see by the log tail that the update is successful.</p>
<p align="LEFT" dir="LTR">If you look in Microsoft DNS, you will see that the record is created. Upon close inspection of the security (Advanced view), you will see that the Linux host itself (as seen by its Kerberos principle name / computer object name), registered the record.</p>


[caption id="attachment_275" align="alignnone" width="399"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_security_properties_1.png"><img width="399" height="444" class="wp-image-275 size-full" alt="DNS Record Security Properties" src="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_security_properties_1.png" /></a> The DNS record security tab reflects the record owner being the Active Directory computer account (Kerberos principal).[/caption]

[caption id="attachment_345" align="alignnone" width="400"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_host_properties.png"><img width="400" height="444" class="wp-image-345 size-full" alt="DNS Host Record Properties" src="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_host_properties.png" /></a> The record time stamp indicates that it is a dynamic record versus a static record.[/caption]
<p align="LEFT" dir="LTR">Now the problem is resolved.</p>
<p align="LEFT" dir="LTR">NON-SECURE DYNAMIC UPDATE ZONES</p>
<p align="LEFT" dir="LTR">As discussed earlier, what happens if the DNS zones are configured for "None" or "Nonsecure and Secure"?  This causes an interesting problem.</p>
<p align="LEFT" dir="LTR">In both scenarios, where we set the DNS zone to either None" or "Nonsecure and Secure", we will see a correctly formatted fully qualified name but then see a failure.</p>

[caption id="attachment_335" align="alignnone" width="1184"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_3.png"><img width="1184" height="223" class="wp-image-335 size-full" alt="SSSD Domain Log" src="https://msdnshared.blob.core.windows.net/media/2016/12/sssd_domain_log_3.png" /></a> The log can be found at /var/log/sssd/sssd_[domainname].log where [domainname] is the logging facility entry name in the /etc/sssd/sssd.conf file.[/caption]
<p align="LEFT" dir="LTR">The logs will show a failure to update the record with three key entries.</p>

<ol type="a">
 	<li>
<pre>[sdap_dyndns_update_done] (0x0080): nsupdate failed, retrying with server name</pre>
</li>
 	<li>
<pre>[ad_dyndns_sdap_update_done] (0x0040): Dynamic DNS update failed [1432158232]: Dynamic DNS update failed</pre>
</li>
 	<li>
<pre>[ad_dyndns_nsupdate_done] (0x0040): Updating DNS entry failed [1432158232]: Dynamic DNS update failed</pre>
</li>
</ol>
<p align="LEFT" dir="LTR">While the update failed, you will notice something odd. A DNS record was created. Upon close examination of the record’s security, you will not see the host’s authentication.</p>


[caption id="attachment_285" align="alignnone" width="400"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_security_properties_2.png"><img width="400" height="445" class="wp-image-285 size-full" alt="DNS Host Record Security" src="https://msdnshared.blob.core.windows.net/media/2016/12/dns_record_security_properties_2.png" /></a> Note that the DNS record security tab is missing the Active Directory computer account (Kerberos principal).[/caption]
<p align="LEFT" dir="LTR">What is even more confusing is the effect you see if the zone is set to "Nonsecure and Secure".  If the zone is set to "None", no update of any kind is done.  If the zone is set to "Nonsecure and Secure" (allowing anonymous updates), every 15 minutes, the DNS record disappears. 15 minutes later it will be back. What is going on?</p>
<p align="LEFT" dir="LTR">To understand what happens here, you must look at the design of the DNS update process. As seen in the verbose logs, every 15 minutes (the default),</p>

<ol>
 	<li>SSSD will perform a lookup on the host’s record.</li>
 	<li>If the record exists, SSSD will attempt to delete it</li>
 	<li>SSSD will send along Kerberos authentication token to use during the registration process (using the rights of the computer account).**</li>
 	<li>SSSD will issue a new record update registration.</li>
 	<li>SSSD will send along Kerberos authentication token to use during the registration process (using the rights of the computer account).**</li>
</ol>
<p align="LEFT" dir="LTR">If the zone is nonsecure or set to "none " and the record does NOT exist, at step 3, DNS will create the DNS record (A(host) and PTR). The DNS server will then discard the authentication token as it is not needed (the record was registered… end of process).</p>
<p align="LEFT" dir="LTR">SSSD will <span style="color: #ff0000"><strong>not</strong> </span>get the expected returned response of a successful authenticated update. SSSD will throw and error.</p>
<p align="LEFT" dir="LTR">Now, 15 minutes later, the process restarts. However, a record DOES already exist. SSSD will send a delete notification. SSSD will send along the authentication token. DNS will delete the DNS record and discard the authentication token. This unexpected response to SSSD will generate an error. Dynamic DNS processing will stop for that cycle. Because of this, no DNS record is recreated. This means until the NEXT cycle runs in 15 minutes, the client will be unresolvable (and cause great confusion every 15 minutes).</p>
<p align="LEFT" dir="LTR">Hopefully this explains a number of scenarios and how to set to proper configuration.  Enjoy your more modern Linux dynamic DNS experience!</p>
<p align="LEFT" dir="LTR">**Note – Due to modern DNS client cache, the momentary delete / recreate of the DNS record is not noticed by clients. They will continue to resolve the LINUX host throughout the process.</p>]]></content:encoded>
    </item>
    <item>
      <title>LINUX Certificate Enrollment and Automated Renewal Using NDES (Updated)</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/236</link>
      <pubDate>Fri, 16 Dec 2016 23:00:35 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=236</guid>
      <description><![CDATA[(APR 2018)  NDES continues to evolve (slowly) as everyone embraces the deprecation of SHA-1.  This...]]></description>
      <content:encoded><![CDATA[<span style="color: #ff0000">(APR 2018) </span> NDES continues to evolve (slowly) as everyone embraces the deprecation of SHA-1.  This post has been updated to reflect those changes and the impact on NDES.  Note the difference between the cryptography used in NDES / SCEP communications versus the cryptography in the certificates provided through NDES / SCEP.  For more detail on the reason for an update, <a href="https://blogs.technet.microsoft.com/jeffbutte/2018/04/05/linux-certificate-enrollment-and-automated-renewal-using-ndes-v2/">check here</a>.

We continue the customer conversation of managing heterogeneous environments... The conversations often revolve around “I know how to do this in (Windows / Linux)… how do I do this for both”.  In most cases, it is a matter of understanding risks, benefits and capabilities of the available technology.  Today we cover issuing and renewal of certificates for Linux systems issued from a Windows based Certificate Authority.

Certificates are needed for many reasons.  The example use case presented here would be to provide secure communications for an infrastructure agent like System Center Configuration Manager or to secure a web site running on Apache.  In those scenarios the certificate expiring will cause a service outage.  The solution would be to have the deployed certificates renewed (replaced) prior to expiration automatically.

Many Windows administrators are familiar with the native capability to auto-enroll domain joined systems with an enterprise Certificate Authority (CA). In simple terms, the process involves implementing an Active Directory integrated CA, configuring templates and enabling group policy to automatically enroll clients. (See: <a href="https://technet.microsoft.com/en-us/library/cc731522.aspx">https://technet.microsoft.com/en-us/library/cc731522.aspx</a> )

The reality is that implementing a proper CA hierarchy can be a lengthy task depending upon your organization’s size, security needs, requirements and policies.  (See: <a href="https://technet.microsoft.com/en-us/library/cc754057.aspx">https://technet.microsoft.com/en-us/library/cc754057.aspx</a> )  On a complexity scale (easy to difficult), it would be a moderate task to implement primarily because of the planning and design that should go into it.

This article is based on the existence of an already implemented Enterprise CA with Windows clients already auto-enrolled.

With your Windows clients taken care of the next question would be, “how do I do this with my Linux clients?” Auto-enrollment of domain joined Windows clients is made easier because the clients can already securely authenticate and be authorized by the enterprise CA. Non-domain joined systems like Linux clients and network devices require intervention to tell the enterprise CA, “I trust this device and authorize it to be enrolled”. To solve this, we will discuss two methods to obtain certificates; manual enrollment and automated using solutions like NDES.
<h3></h3>
<h3>MANUAL ENROLLMENT</h3>
Certificates can be obtained manually from a CA; often through web enrollment. The administrator authenticates to the CA on behalf of the device or system and generates (or submits) a certificate request.  While manual enrollment works perfectly, it does not allow to scale to large numbers of systems or address management of the certificates when they near expiration.
<h3></h3>
<h3>AUTOMATED ENROLLMENT USING NETWORK DEVICE ENROLLMENT SERVICE</h3>
The Network Device Enrollment Service (NDES) allows software on routers and other network devices running without domain credentials to obtain certificates based on the Simple Certificate Enrollment Protocol (SCEP) (See <a href="https://technet.microsoft.com/en-us/library/hh831498(v=ws.11).aspx">https://technet.microsoft.com/en-us/library/hh831498(v=ws.11).aspx</a> )

The Network Device Enrollment Service performs the following functions:
<ul>
 	<li>Generates and provides one-time enrollment passwords to administrators.</li>
 	<li>Submits SCEP enrollment requests to the CA.</li>
 	<li>Retrieves enrolled certificates from the CA and forwards them to the network device.</li>
</ul>
<h3></h3>
<h3>SIMPLE CERTIFICATE ENROLLMENT PROTOCOL</h3>
<span><span style="color: #ff0000">(APR 2018)</span> </span><span>SCEP, as a protocol, remains in draft with the IETF.  For a number of years it garnered little attention.  The industry continues to heavily embrace its use though. The SCEP draft has been updated more frequently over the past few years with the most recent update as of MAR 2018 (see </span><a href="https://tools.ietf.org/html/draft-gutmann-scep-10"><span>https://tools.ietf.org/html/draft-gutmann-scep-10</span></a><span> )  This of course makes SCEP security a moving target for all vendors and the open source community.  Hardware vendors for network devices will need to update firmware and software vendors as well as the open source community will need to update code to accommodate the changes.</span>
<h4><span style="color: #ff0000">SECURITY ADVISIORY</span></h4>
<h5 style="padding-left: 30px">In 2012 a security advisory was posted regarding the vulnerability of SCEP. (See <a href="https://www.kb.cert.org/vuls/id/971035">https://www.kb.cert.org/vuls/id/971035</a> ) The advisory states that Simple Certificate Enrollment Protocol (SCEP) does not strongly authenticate certificate requests made by users or devices. SCEP was designed for use in closed environments and not for the purpose of mobile device management. This solution may not meet your security requirements and warrant a thorough review. The use case example is for protected Linux systems, not fully untrusted mobile devices. There are a number of mitigations may allow this solution to meet your security requirements.</h5>
The above advisory is also subject to change as the spec is updated and the changes begin to be implemented.
<h3>IMPLEMENTATION OVERVIEW</h3>
The scenario outlined here should be executed in a lab allowing you to build a functional solution that you can then tune to meet your organization requirements.  The solution has been tested with number of Linux distributions.

The lab scenario setup for this article utilizes the following platforms:
<ul>
 	<li><span>Windows Server 2012 R2 Enterprise Certificate Authority in  a two tier hierarchy (offline root, online enterprise issuing subordinate) (APR 18) Tested with Windows Server 2016 in a two tier hierarchy.  The CA hierarchy should be configured to issue SHA2 certificates (SHA256 or higher). For this lab, the subordinate issuing authority is configured to issue SHA384 certificates.</span></li>
 	<li>CentOS 6.8 - 7.4</li>
</ul>
Within the LINUX environment, execute the actions with elevated privileges (via sudo or su). Ensure the hostname of your Linux system is the fully qualified domain name of the host. Example: linux1.contoso.corp The FQDN will be used in the certificate submission as the DNS name field for the certificate.
<h3></h3>
<h3>IMPLEMENTATION STEPS</h3>
<ol>
 	<li><strong>SETUP NDES FOR ACTIVE DIRECTORY CERTIFICATE SERVICES</strong></li>
</ol>
The first step in the process is to enable your environment to support NDES. Follow the implementation guidance in the NDES WIKI <a href="https://social.technet.microsoft.com/wiki/contents/articles/9063.network-device-enrollment-service-ndes-in-active-directory-certificate-services-ad-cs.aspx">https://social.technet.microsoft.com/wiki/contents/articles/9063.network-device-enrollment-service-ndes-in-active-directory-certificate-services-ad-cs.aspx</a>

&nbsp;
<ol start="2">
 	<li><strong>CONFIRM THE DEFAULT TEMPLATES EXIST</strong></li>
</ol>
Once NDES is deployed, confirm that the IPSEC Intermediate (Offline) template is deployed. The out-of-box template cryptography settings will likely be 1024 bit SHA 1.<span style="color: #ff0000"> (APR 2018)</span> The minimum key size should be updated to 2048.  The request hash can remain at SHA1 for testing or be moved to a higher value if all clients and network devices serviced by this NDES server support it.  For the purpose of the example it should be moved to SHA256

Note: Once your test environment is functional, you can go back and create new templates that meet the organizational needs.  Review the NDES wiki for the section on updating the registry to point to the new template name.

&nbsp;
<ol start="3">
 	<li><strong>INSTALL THE SSCEP CLIENT</strong></li>
</ol>
The Fedora hosted DogTag project is a collection of Open Source Certificate Authority technologies. One of the components is Simple SCEP (SSCEP). SSCEP can be found in the Extra Packages for Linux (EPEL) or can be pulled from GIT (see <a href="https://github.com/certnanny/sscep">https://github.com/certnanny/sscep</a> ).  To install SSCEP from EPEL, first add the epel repository and then install the client.  On the Linux system, execute the following:
<pre>yum install epel-release
yum install sscep</pre>
&nbsp;
<ol start="4">
 	<li><strong>INSTALL THE CA CHAIN ON THE LINUX CLIENT</strong></li>
</ol>
The Linux endpoint requires the CA hierarchy chain to being SCEP enrollment. In the following syntax example:
<ul>
 	<li>Replace “ContosoCA” with a simple name that reflects your CA (to indicate where the file came from).</li>
 	<li>Replace “NDES.CONTOSO.CORP” with the FQDN that reflects the CA running NDES’s fully qualified domain name.</li>
</ul>
Execute the following command:
<pre>sscep getca -F sha1 -c /etc/pki/ca-trust/source/anchors/contosoCA.crt -u <a href="https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe">https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe</a>?</pre>
Note the use of SHA 1.   This is specifying use for the fingerprint algorithm.  For more detail on why the SHA1 can be used with NDES / SCEP, see section 8.8 of the current draft (See <a href="https://tools.ietf.org/html/draft-gutmann-scep-10">https://tools.ietf.org/html/draft-gutmann-scep-10</a>).

In a two tier hierarchy, the command will pull down four certificate files.
<ul>
 	<li>contosoCA.crt-0                               The certificate for the issuing subordinate CA root Registration Authority (RA)</li>
 	<li>contosoCA.crt-1                                The certificate for the subordinate CA root CEP Encryption (CE)</li>
 	<li>contosoCA.crt-2                               The certificate for the CA root.</li>
 	<li>contosoCA.crt-3                               The certificate for the issuing subordinate CA root.</li>
</ul>
For an understanding of the LINUX system PKI file structure, see <a href="https://www.mankier.com/8/update-ca-trust">https://www.mankier.com/8/update-ca-trust</a>   If you are running CentOS 6, you may have to enable your CA trust store to be updated by running:
<pre>update-ca-trust enable</pre>
Next, execute the following command:
<pre>update-ca-trust extract</pre>
This will add the downloaded CA chain to the Linux system’s trusted CA list.

&nbsp;
<ol start="5">
 	<li><strong>GENERATE A CSR FOR THE INITIAL ENROLLMENT</strong></li>
</ol>
Log into the issuing CA server website with the required credentials of a certificate administrator. The example URL is <a href="https://ndes.contoso.corp/certsrv/mscep_admin">https://ndes.contoso.corp/certsrv/mscep_admin</a>

Obtain the NDES enrollment challenge password. In the NDES WIKI example, the password is 302034237AE9A1D1 (See the <a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_technet/askds/WindowsLiveWriter/ConfiguringNetworkDeviceEnrollmentServic_BF80/clip_image010_2.jpg">picture</a>) . By default, the enrollment challenge password is for one time use and has a time expiration. This can be changed to allow longer time periods and multi-device use. Those changes however may not meet your organization security requirements.

On the LINUX client, run the command mkrequest to generate a Certificate Signing Request (CSR). Insert the issued enrollment challenge password. Example:
<pre>mkrequest -dns $(hostname) 302034237AE9A1D1</pre>
The mkrequest script will generate two files by default. The two files are the CSR and the certificate private key. (local.csr and local.key).

&nbsp;
<ol start="6">
 	<li><strong>EXECUTE THE NDES INITIAL ENROLLMENT</strong></li>
</ol>
The next step is to execute the actual NDES enrollment using the SCEP client. An example enrollment would be:
<pre>sscep enroll -E 3des -S sha1 -c /etc/pki/ca-trust/source/anchors/contosoCA.crt-0 -e /etc/pki/ca-trust/source/anchors/contosoCA.crt-1 -k local.key -r local.csr -l $(hostname).crt -u '<a href="https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe?">https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe?</a>' -d -v</pre>
This command will execute a certificate enrollment using the CSR, the certificate private key and the one time enrollment password.  Again, note the -E and -S switches.  -E is the PKCS#7 encryption algorithm, and the -S is the signature algorithm.  Again, refer to section 8.8 of the current draft.  This is the encryption used with NDES, not the encryption settings for the certificate that the client will receive.  That is specified in the template and will be SHA256 or higher (based on your template).

&nbsp;
<h3>CERTIFICATE RENEWAL</h3>
Certificate renewal is a very similar process. However instead of using an enrollment challenge password, the enrollment uses the private key of the existing certificate and the valid existing certificate as the authorization credential.
<ol>
 	<li><strong>GENERATE A CSR FOR THE RENEWAL</strong></li>
</ol>
For a renewal, no password is required. You will be using a combination of the old key, new key, old certificate and a new CSR. If you are executing this command in the same directory containing the original private key, it must be renamed so that it is not overwritten. Execute the mkrequest script including just the DNS name for the certificate. Example:
<pre>mkrequest -dns $(hostname)</pre>
&nbsp;
<ol start="2">
 	<li><strong>EXECUTE THE RENEWAL (REPLACEMENT CERTIFICATE)</strong></li>
</ol>
For a renewal, you will need the existing certificate, existing private key, the new CSR and the new private key.
<pre>sscep enroll -E 3des -S sha1 -c /etc/pki/ca-trust/source/anchors/contosoCA.crt-0 -e /etc/pki/ca-trust/source/anchors/contosoCA.crt-1 -k local.key -K existinglocal.key -O existing.crt -r local.csr -l new.crt -u '<a href="https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe?">https://ndes.contoso.corp/certsrv/mscep/mscep.dll/pkiclient.exe?</a>' -d -v</pre>
<h3></h3>
<h3>AUTOMATING THE SOLUTION</h3>
The primary objective is to automate certificate enrollment and renewal. This can be accomplished a number of ways depending on what existing capabilities your organization may already have. The automation can be:
<ul>
 	<li>A simple CRON job executing a script</li>
 	<li>PowerShell Desired State Configuration (DSC) for Linux</li>
 	<li>A Puppet module</li>
</ul>
The following shell script demonstrates what the workflow for initial enrollment and renewal would look like.
<span style="color: #ff0000">(Updated APR 2018)</span>

&nbsp;
<pre><span style="color: #008000">#!/bin/bash</span>
<span style="color: #008000"># Linux Certificate Enrollment Using NDES and SCEP</span>
<span style="color: #008000">##################################################################</span>
<span style="color: #008000"># This script is provided as an example for illustration only,</span>
<span style="color: #008000"># without warranty either expressed or implied, including, but not</span>
<span style="color: #008000"># limited to, the implied warranties of merchantability and/or</span>
<span style="color: #008000"># fitness for a particular purpose.</span>
<span style="color: #008000">##################################################################</span>
<span style="color: #008000">#</span>
<span style="color: #008000"># Insert the NDES Enrollment Password here.</span>
ndeskey=ABC123DEF456ABC789DEF012ABC
<span style="color: #008000"># Insert the NDES server FQDN</span>
ndesserver=ndes.contoso.corp
<span style="color: #008000"># CA Filename</span>
cafilename=contoso
<span style="color: #008000"># Number of days ahead of cert expiration to renew</span>
warning_days=<span style="color: #ff0000">45
</span><span style="color: #339966">###############################################################################
#EDIT ONLY THE VALUES ABOVE
###############################################################################</span>
shopt -s -o nounset
<span style="color: #008000"># Create a log file directory</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">[ !</span> -d <span style="color: #800000">/</span>var<span style="color: #800000">/</span>log<span style="color: #800000">/</span>pki<span style="color: #800000">/</span>ndes <span style="color: #800000">];</span> <span style="color: #0000ff">then</span>
    <span style="color: #0000ff">mkdir</span> -p <span style="color: #800000">/</span>var<span style="color: #800000">/</span>log<span style="color: #800000">/</span>pki<span style="color: #800000">/</span>ndes<span style="color: #800000">/</span>
<span style="color: #0000ff">fi</span>
DTG=<span style="color: #800000">$(date +%Y%m%d%H%M)</span>
LOGFILE=/var/log/pki/ndes/ndes-enrollment<span style="color: #ff6600">$DTG</span>.log
<span style="color: #0000ff">if</span> <span style="color: #800000">[ !</span> -f <span style="color: #ff6600">$LOGFILE</span> <span style="color: #800000">]</span>; <span style="color: #0000ff">then</span>
    <span style="color: #0000ff">touch</span> <span style="color: #ff6600">$LOGFILE</span>
<span style="color: #0000ff">fi
<span style="color: #339966">###############################################################################</span>
<span style="color: #339966"># LOG FUNCTION TO WRITE LOCAL LOG FILE AND TO /VAR/LOG/MESSAGES</span>
<span style="color: #339966">###############################################################################</span>
<span style="color: #000000">writelog</span><span style="color: #800000">() {</span>
    echo <span style="color: #00ccff">${*}</span> <span style="color: #000000"><span style="color: #ff0000">2</span><span style="font: 400 16px/24px Georgia,'Times New Roman','Bitstream Charter',Times,serif;text-align: left;text-indent: 0px;letter-spacing: normal;text-decoration: none;cursor: text;float: none;background-color: transparent">&gt;&amp;</span><span style="color: #ff0000">1</span></span> &gt;&gt; $LOGFILE
    if <span style="color: #800000">[</span> -f <span style="color: #000000"><span style="color: #800000">/</span>bin<span style="color: #800000">/</span>logger</span> <span style="color: #800000">]</span> 
    then 
       <span style="color: #000000">logger</span> <span style="color: #00ccff">${*}</span>
    fi 
<span style="color: #800000">}</span>
<span style="color: #339966">###############################################################################</span></span>
writelog  <span style="color: #808080">"sscep: Checking for required packages"</span>
<span style="color: #0000ff">if</span> rpm -qa | <span style="color: #0000ff">grep</span> epel-release  <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;</span> /dev/null;
        <span style="color: #0000ff">then</span>
        writelog <span style="color: #808080">"sscep: epel-release is installed."</span>
<span style="color: #0000ff">else</span>
    yum -y install epel-release <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
<span style="color: #0000ff">fi</span>
<span style="color: #0000ff">if</span> rpm -qa | <span style="color: #0000ff">grep</span> sscep  <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;</span> /dev/null;
      <span style="color: #0000ff">  then</span>
<span style="color: #0000ff">        </span>writelog <span style="color: #0000ff"><span><span style="color: #808080">"sscep:</span> </span></span><span style="color: #808080">sscep is installed."</span>
<span style="color: #0000ff">else</span>
    <span style="color: #0000ff">yum</span> -y install sscep <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> &gt;&gt; <span style="color: #ff6600">$LOGFILE</span>
<span style="color: #0000ff">fi</span>

MKREQUESTSCRIPT<span style="color: #800000">=/</span>usr<span style="color: #800000">/</span>bin<span style="color: #800000">/</span>mkrequest
<span style="color: #0000ff">sed</span> -i <span style="color: #808080">'s/KEYBITS=1024/KEYBITS=2048/g'</span> <span style="color: #ff6600">$MKREQUESTSCRIPT</span>
<span style="color: #0000ff">if</span> <span style="color: #800000">!</span> grep -q <span style="color: #808080">"string_mask = nombstr"</span> <span style="color: #ff6600">$MKREQUESTSCRIPT <span style="color: #000000">;<span style="color: #005000"> </span></span></span><span style="color: #0000ff">then</span>
       <span style="color: #0000ff">sed</span> -i <span style="color: #808080">'/\[ req \]/a string_mask = nombstr'</span> <span style="color: #ff6600">$MKREQUESTSCRIPT</span>
<span style="color: #0000ff">fi</span>

<span style="color: #0000ff">if</span> <span style="color: #800000">[ !</span> -f /etc/pki/tls/certs/<span style="color: #800000">$(hostname).</span>crt <span style="color: #800000">]</span> ; <span style="color: #0000ff">then</span>
        writelog <span style="color: #808080">"sscep: $(hostname) does not have an existing certificate.  Executing initial enrollment."</span>
        writelog <span style="color: #808080">"sscep: Requesting CA cert</span>ificate chain<span style="color: #808080"> as x509 .crt files."</span>
        sscep getca -F sha1 -c /etc/pki/ca-trust/source/anchors/<span style="color: #00ccff">${cafilename}</span>CA.crt -u https://<span style="color: #00ccff">${ndesserver}</span>/certsrv/mscep/mscep.dll/pkiclient.exe? <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
        writelog <span style="color: #808080">"sscep:</span> <span style="color: #808080">Adding the CA chain to the host CA trusted chain."
        <span style="color: #000000">update-ca-trust enable</span> <span style="color: #000000"><span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span></span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span></span>
        update-ca-trust extract <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
        writelog <span style="color: #808080">"sscep: Generating CSR."
</span>        mkrequest -dns <span style="color: #800000">$(hostname)</span> <span style="color: #ff6600">$ndeskey</span> <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
        writelog <span style="color: #808080">"sscep: Moving CSR and new private key."</span> 
        <span style="color: #0000ff">mv</span> local.key /etc/pki/tls/private/<span style="color: #800000">$(hostname)<span style="color: #000000">.</span></span><span style="color: #000000">key</span>
        <span style="color: #0000ff">mv</span> local.csr /etc/pki/tls/private/<span style="color: #800000">$(hostname)</span><span style="color: #000000">.csr</span>
        writelog <span style="color: #808080">"sscep: Executing enrollment using NDES key."
</span>        sscep enroll -E 3des -S sha1 -c /etc/pki/ca-trust/source/anchors/<span style="color: #00ccff">${cafilename}</span>CA.crt-0 -e /etc/pki/ca-trust/source/anchors/<span style="color: #00ccff">${cafilename}</span>CA.crt-1 -k /etc/pki/tls/private/<span style="color: #ff0000">$(hostname)</span>.key -r /etc/pki/tls/private/local.csr -l /etc/pki/tls/private/<span style="color: #ff0000">$(hostname)</span>.crt -u https://<span style="color: #00ccff">${ndesserver}</span>/certsrv/mscep/mscep.dll/pkiclient.exe? -d -v <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
        writelog <span style="color: #808080">"sscep: Checking generated certificate status."
</span>        CERTSTATUS=<span style="color: #800000">$(openssl verify /etc/pki/tls/private/$(hostname).crt | cut -d: -f2)</span>
        <span style="color: #0000ff">if</span> <span style="color: #800000">[</span> <span style="color: #ff6600">$CERTSTATUS</span> <span style="color: #800000">==</span> <span style="color: #808080">"OK"</span> <span style="color: #800000">]</span>; <span style="color: #0000ff">then</span>
<span style="color: #0000ff">                </span>writelog <span style="color: #808080">"sscep: Certificate status is: "</span> <span style="color: #ff6600">$CERTSTATUS</span>
                writelog <span style="color: #808080">"sscep: Copying new certificate to /etc/pki/tls/certs/$(hostname).crt"</span> 
                <span style="color: #0000ff">cp</span> /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt /etc/pki/tls/certs/<span style="color: #800000">$(hostname).</span>crt <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
        <span style="color: #0000ff">else</span>
                writelog <span style="color: #808080">"sscep: The certificate is not valid per $CERTSTATUS"</span>
        <span style="color: #0000ff">fi</span>
<span style="color: #0000ff">else</span>
        output=<span style="color: #800000">$(openssl x509 -in /etc/pki/tls/certs/$(hostname).crt -noout -subject -dates 2&gt;/dev/null)</span>
        cert=<span style="color: #800000">$(echo $output | sed 's/.*CN=\(.*\).*not.*/\1/g')</span>
        start_date=<span style="color: #800000">$(echo $output | sed 's/.*notBefore=\(.*\).*not.*/\1/g')</span>
        end_date=<span style="color: #800000">$(echo $output | sed 's/.*notAfter=\(.*\)$/\1/g')</span>
        start_epoch=<span style="color: #800000">$(date +%s -d "$start_date")</span>
        end_epoch=<span style="color: #800000">$(date +%s -d "$end_date")</span>
        epoch_now=<span style="color: #800000">$(date +%s)</span>
        <span style="color: #0000ff">if</span> <span style="color: #800000">[</span> "$start_epoch" -gt "$epoch_now" <span style="color: #800000">];</span> <span style="color: #0000ff">then</span>
                writelog <span style="color: #999999">"sscep: Certificate for [$cert] is not yet valid"
</span>                writelog <span style="color: #800000">$output</span>
       <span style="color: #0000ff"> fi</span>
        seconds_to_expire=<span style="color: #800000">$(($end_epoch - $epoch_now))</span>
        days_to_expire=<span style="color: #800000">$(($seconds_to_expire / <span style="color: #ff0000">86400</span>))</span>
        writelog <span style="color: #808080">"sscep: Days to expiry: ($days_to_expire)"</span>
        warning_seconds=<span style="color: #800000">$((<span style="color: #ff0000">86400</span> * $warning_days))
</span>       <span style="color: #0000ff"> if</span> <span style="color: #800000">[</span> <span style="color: #999999">"$seconds_to_expire"</span> -lt <span style="color: #ff0000">0</span> <span style="color: #800000">];</span> <span style="color: #0000ff">then</span>
                writelog <span style="color: #808080">"sscep: Certificate [$cert] has expired.  Remove the certificate and rerun to start a new enrollment."
</span>        <span style="color: #0000ff">else</span>
<span style="color: #0000ff">                if</span> <span style="color: #800000">[</span> "$seconds_to_expire" -lt "$warning_seconds" <span style="color: #800000">];</span> <span style="color: #0000ff">then</span>
                        writelog <span style="color: #808080">"sscep: Certificate [$cert] is soon to expire ($seconds_to_expire seconds)"</span>
                        writelog <span style="color: #808080">"sscep: Existing certificate found for $(hostname).  Executing re-enrollment."</span>
                        writelog <span style="color: #808080">"sscep: Backing up current private key."</span>
                        <span style="color: #0000ff">mv</span> -f /etc/pki/tls/private/<span style="color: #800000">$(hostname)</span>.crt /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt.bak
                        <span style="color: #0000ff">mv</span> -f /etc/pki/tls/private/<span style="color: #800000">$(hostname)</span>.key /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key.bak
                        writelog <span style="color: #808080">"sscep: Generating CSR."</span>
                        mkrequest -dns <span style="color: #800000">$(hostname)</span> <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
                        writelog <span style="color: #808080">"sscep: Moving CSR and new private key."</span>
                        <span style="color: #0000ff">mv</span> -f local.key /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key
                        <span style="color: #0000ff">mv</span> -f local.csr /etc/pki/tls/private/<span style="color: #800000">$(hostname)</span>.csr
                        writelog <span style="color: #808080">"sscep: Executing enrollment using existing certificate."</span>
                        sscep enroll -E 3des -S sha1 -c /etc/pki/ca-trust/source/anchors/<span style="color: #00ccff">${cafilename}</span>CA.crt-0 -e /etc/pki/ca-trust/source/anchors/<span style="color: #00ccff">${cafilename}</span>CA.crt-1 -k /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key -K /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key.bak -O /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt.bak -r /etc/pki/tls/private/<span style="color: #800000">$(hostname)</span>.csr -l /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt -u https://<span style="color: #00ccff">${ndesserver}</span>/certsrv/mscep/mscep.dll/pkiclient.exe? -d -v  <span style="color: #ff0000">2</span>&gt;&amp;<span style="color: #ff0000">1</span> <span style="color: #800000">&gt;&gt;</span> <span style="color: #ff6600">$LOGFILE</span>
                        writelog <span style="color: #808080">"sscep: Checking generated certificate status."</span>
                        CERTSTATUS=<span style="color: #800000">$(openssl verify /etc/pki/tls/private/$(hostname).crt | cut -d: -f2)</span>
                        if <span style="color: #800000">[</span> <span style="color: #ff6600">$CERTSTATUS</span> <span style="color: #800000">==</span> <span style="color: #808080">"OK"</span> <span style="color: #800000">];</span> <span style="color: #0000ff">then</span>
                                writelog <span style="color: #808080">"sscep: Certificate status is:</span> " <span style="color: #ff6600">$CERTSTATUS</span>
                                writelog <span style="color: #808080">"sscep: Copying new certificate to /etc/pki/tls/private/$(hostname).crt"</span>
                                <span style="color: #0000ff">cp</span> -f /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt /etc/pki/tls/certs/<span style="color: #800000">$(hostname).</span>crt
                       <span style="color: #0000ff"> else</span>
                                writelog <span style="color: #808080">"sscep: The certificate is not valid per $CERTSTATUS"</span>
                                writelog <span style="color: #808080">"sscep: Restoring the backup existing certificate and keys."</span>
                                <span style="color: #0000ff">mv</span> -f /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt.bak /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>crt
                                <span style="color: #0000ff">mv</span> -f /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key.bak /etc/pki/tls/private/<span style="color: #800000">$(hostname).</span>key
<span style="color: #0000ff">                        fi</span>
<span style="color: #0000ff">                fi</span>
<span style="color: #0000ff">        fi</span>
<span style="color: #0000ff">fi</span></pre>
A useful workflow would include:
<ul>
 	<li>Installation of the SSCEP client; if not already installed.</li>
 	<li>Check to see if a certificate exists; if not, execute initial enrollment.</li>
 	<li>If a certificate exists, check its expiration date. If it is within the defined renewal period, renew the certificate.</li>
 	<li>The logic would have to handle rotation of the private keys and matching certificates used for each subsequent renewal.</li>
</ul>
<h3></h3>
<h3>TUNING THE LAB TO MEET YOUR REQUIREMENTS</h3>
<span style="color: #ff0000">(APR 2018)</span> At this time, SHA1 has been deprecated and the expected minimum key length is 2048. Hash algorithms should be SHA2 (SHA-256) or higher.

Changing the certificate length is easy. The /usr/bin/mkrequest file is actually a script. The default value of for KEYBITS=1024 can be changed to KEYBITS=2048. On the Windows CA, the CA template used for NDES would need to be updated to be set to 2048 bit as well.  The sample script above modifies the KEYBITS value during execution to update the value automatically.

In my previous version of this post, I outlined some of the cryptographic limitations of the SSCEP client.  Many of those have now been resolved as the clients have received a number of revision updates.

&nbsp;
<h3>ALTERNATE OPTIONS</h3>
If the above solution does not meet your requirements, you might consider some of the other certificate solutions that are beyond the scope of this article. There are third party LINUX agents / add-ons that allow Linux clients to emulate Windows client capabilities to leverage group policy and certificate auto-enrollment. (For example, see <a href="https://www.centrify.com/">https://www.centrify.com</a>)

&nbsp;
<h3>Q&amp;A</h3>
Q:        My environment has hundreds of Linux systems that need certificates. How can I do this with each one requiring a unique enrollment challenge password?

A:        This is a conversation with your organization security official. NDES can be configured to provide a multi-use enrollment challenge password. Additionally the use time limit can be extended. Your organization has to evaluate the risk of that key being compromised and certificates being obtained by systems you do not trust.

&nbsp;

Q:        Can I use this solution to deploy certificates to my mobile devices?

A:        NDES was designed for closed (internal trusted protected) network devices. Mobile devices should be managed with a Mobile Device Management (MDM) solution like Microsoft Intune. https://www.microsoft.com/en-us/cloud-platform/mobile-device-management

&nbsp;

Q:        My organization determined that using the enrollment challenge password is not acceptable and I have not found another cost effective solution. What can I do to decrease the security risk?

A:        There are a number of options. One simple option would be to manually issue / install the initial certificate onto the Linux system but continue to configure it to use NDES for renewal. This ensures that you have installed certificates on fully trusted machines and the renewals will occur using a valid existing certificate and matching unique private key.

&nbsp;

Q:        How do I test enrollment and renewal in the lab? I don’t want to wait a year or two until the certificate expires.

A:        In the lab, configure your deployed certificate template used by NDES to have a shorter validity period (4 hours for example).

&nbsp;

Q:        Have I looked at CERTMONGER as an alternative to the SSCEP client?

A:        See <a href="https://blogs.technet.microsoft.com/jeffbutte/2018/04/05/linux-certificate-enrollment-and-automated-renewal-using-ndes-v2/">https://blogs.technet.microsoft.com/jeffbutte/2018/04/05/linux-certificate-enrollment-and-automated-renewal-using-ndes-v2/</a>

&nbsp;

Q:        I am getting the following error:
<pre style="padding-left: 30px">sscep: pkistatus: FAILURE
sscep: finding attribute failInfo
sscep: allocating 1 bytes for attribute
sscep: reason: Transaction not permitted or supported
sscep: illegal size of payload</pre>
On the issuing CA, I see Event 29 in the Application event log.
<pre style="padding-left: 30px">The password in the certificate request cannot be verified. It may have been used already. Obtain a new password to submit with this request.</pre>
A:      This issue is most frequently caused by the version of OpenSSL that the system is running.  Since the creation of sscep, OpenSSL has undergone some significant revisions.  Recent security relevant updates to OpenSSL no longer allow UTF-8 fields added to the CSR.  Additional fields  like the SCEP password must be sent in PrintableString.  The resolution is to edit the /usr/bin/mkrequest file and add ‘string_mask = nombstr’ in the [req] section (Contributed by Todd Mote)

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Deploying a script or package to a LINUX host with System Center Configuration Manager 2012 R2</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/deploying-a-script-or-package-to-a-linux-host-with-system-center-configuration-manager-2012-r2</link>
      <pubDate>Mon, 01 Feb 2016 00:40:04 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=81</guid>
      <description><![CDATA[This blog is for those rarely seen or photographed IT professionals; the mythical Windows Admins...]]></description>
      <content:encoded><![CDATA[This blog is for those rarely seen or photographed IT professionals; the mythical Windows Admins that do Linux administration or Linux admins that do Windows administration.  More importantly, the post is for the System Center Configuration Manager admin that manages LINUX!

Seldom do you come across a data center that is homogeneous (one hardware platform, one OS (Windows, Linux, Mac), one network platform, etc.). I have seen very few and most were small businesses.

Most environments are heterogeneous, in that they run multiple operating systems, a mix of 3<sup>rd</sup> party vendor and Free Open Source Software (FOSS) tools.  Today, I am going to cover leveraging your investment in Microsoft products if you operate and manage a heterogeneous environment.

Microsoft System Center Configuration Manager supports many non-Windows OS. (see <a target="_blank" href="https://www.microsoft.com/en-us/download/details.aspx?id=39360" title="Microsoft System Center 2012 R2 Configuration Manager - Clients for Additional Operating Systems ">https://www.microsoft.com/en-us/download/details.aspx?id=39360</a> ) In this example, we will focus on CENTOS 6.x.

Installation of the client is straight forward and simple. (see <a target="_blank" href="https://technet.microsoft.com/en-us/library/jj573939.aspx" title="How to Install Clients on Linux and UNIX Computers in Configuration Manager">https://technet.microsoft.com/en-us/library/jj573939.aspx</a> ) However, the one item the installation lacks is log maintenance. It does NOT create a logrotate entry. (see <a target="_blank" href="https://technet.microsoft.com/en-us/library/hh427342.aspx#BKMK_LogFilesforLnU%20" title="Technical Reference for Log Files in Configuration Manager">https://technet.microsoft.com/en-us/library/hh427342.aspx#BKMK_LogFilesforLnU </a>) If left unattended (over a long period of time), the SCCM client can run a system out of disk space. Wouldn’t it be great if we could deploy a package to fix that? Wait… we have found our first example package!

<strong><span style="text-decoration: underline">Disclaimer:</span></strong> The information provided below is an EXAMPLE using a single method for a single operating system with the expectation that you have a healthy SCCM environment in a supported configuration. It is highly recommended that you test your configurations in a non-production environment, tailoring the configuration to your environment.

To start, we will create two script use for the deployment. In this example I created two files:
<ul>
 	<li>sccm.txt – the basis for the logrotate entry.</li>
 	<li>sccm_logrotate.sh – the script that will deploy the logrotate entry.</li>
</ul>
Why sccm.txt you ask? Many legacy components in the Windows platform rely on the file extension to determine what a file is and how to handle it. Linux systems for use an array of tests to determine a file type. It is best to deploy files with a temporary extension through SCCM and then rename them, removing the extensions once they are on the LINUX platform.

You can create the two entries using an editor in LINUX or Windows (personal choice).

<span style="color: #ff0000"><strong> **WARNING**</strong></span> Use a Windows based editor that saves the file in UNIX format with an encoding of UTF-8 without Byte Order Marks. By default, most Windows file editors add carriage returns AND line feeds to scripts (CRLF) as well as encodes the files in Unicode. If you choose to edit the files in Windows, see another post ( <a target="_blank" href="https://blogs.technet.microsoft.com/jeffbutte/2016/01/31/editing-converting-linux-scripts-from-a-windows-system/" title="Editing - Converting LINUX Scripts from a Windows System"><strong>Editing / Converting LINUX scripts from a Windows System </strong></a>) to ensure they are formatted correctly for LINUX.

<strong><span style="text-decoration: underline">Preparing the Script Files</span></strong>

1. Create a file called sccm.txt
<pre>/var/opt/microsoft/*.log {    
     weekly
     missingok
     notifempty
     rotate 2
     compress
     delaycompress
     copytruncate 
}</pre>
The sccm logrotate configuration file defines the steps required to properly manage the SCCM client log file. The key directive in the configuration file is copytruncate. It truncates the original log file in place after creating a copy, instead of moving the old log file and optionally creating a new one.  Other methods that rename the log file will not work. The SCCM client retain a lock on the renamed file and will continue writing (appending) to the previous log file until the service is restarted.  Copytruncate addresses this without need to restart the client.

2. Create a new file called sccm_logrotate.sh
<pre>#!/bin/sh</pre>
<pre>if [ ! -d /var/log/microsoft/packagelog ]
  then
    mkdir -p /var/log/microsoft/packagelog/
fi
LOG=/var/log/microsoft/packagelog/sccm_logrotate_package.log
touch $LOG</pre>
<pre>if [ -d /etc/logrotate.d/ ];
then
    cp sccm.txt /etc/logrotate.d/ 2&gt;&amp;1 &gt;&gt; $LOG
    mv /etc/logrotate.d/sccm.txt /etc/logrotate.d/sccm 2&gt;&amp;1 &gt;&gt; $LOG
    chmod 644 /etc/logrotate.d/sccm 2&gt;&amp;1 &gt;&gt; $LOG
    chown root.root /etc/logrotate.d/sccm 2&gt;&amp;1 &gt;&gt; $LOG
    echo "Created the /etc/logrotate.d/ configuration entry." 2&gt;&amp;1 &gt;&gt; $LOG
else
   echo "Directory /etc/logrotate.d/ does not exist.  Determine the logrotate method and adjust accordingly"  2&gt;&amp;1 &gt;&gt; $LOG
fi</pre>
This script just facilitates dropping the configuration file into the <span style="color: #0000ff">/etc/logrotate.d</span> directory.

<strong>Manually Test</strong>

Copy the scripts over to a test machine. (Don’t forget <span style="color: #0000ff">chmod +x sccm_logrotate.sh</span>) Ensure the SCCM client is installed on the test machine. Now, manually run the <span style="color: #0000ff">sccm_logrotate.sh</span> script to confirm that it successfully runs and that the logrotate configuration file is copied.

To manually run the logrotation, execute the command <span style="color: #0000ff">logrotate -vf /etc/logrotate.d/sccm </span>Confirm that the log files in <span style="color: #0000ff">/var/opt/microsoft/</span> have rotated.

If the scripts do not work manually, it will <strong><span style="text-decoration: underline">not</span></strong> improve through a deployment tool or with age.

<strong><span style="text-decoration: underline">Create a Package</span></strong> Once your scripts are tested, create a SCCM package (see <a target="_blank" href="https://technet.microsoft.com/en-us/library/gg682112.aspx" title="How to Create Packages and Programs in Configuration Manager">https://technet.microsoft.com/en-us/library/gg682112.aspx</a> ). SCCM supports only package deployment to UNIX / LINUX systems. Applications are a Windows specific concept and are not support on non-windows platforms. (see Deploying Software to Linux and UNIX Servers in Configuration Manager <a target="_blank" href="https://technet.microsoft.com/en-us/library/jj573943.aspx" title="Deploying Software to Linux and UNIX Servers in Configuration Manager">https://technet.microsoft.com/en-us/library/jj573943.aspx</a> )
<ol>
 	<li>Place your scripts in your SCCM package source share folder. (\\servername\sharename\path) Example \\fileserver\packagesource$\Microsoft\SystemCenter\ConfigManager\Linux\logrotate</li>
 	<li>Start the Create Package Wizard. Fill out the fields with the appropriate values and select the package source folder where you stored your shell scripts.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/CreatePackageAndProgramWizard.png"><img width="804" height="678" class="alignnone size-full wp-image-71" alt="Create Package And Program Wizard" src="https://msdnshared.blob.core.windows.net/media/2016/02/CreatePackageAndProgramWizard.png" /></a></li>
 	<li>On the Program Type page, select “Standard program”.</li>
 	<li>In the program command line, define the shell you intend to use and the script specified in your package. Example: <span style="color: #0000ff">/bin/sh ./sccm_logrotate.sh</span> Set the program to run “normal”. The ”Program can run” value must be set to “Whether or not a user is logged on”.  SCCM client execution does not support the user context.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/StandardProgram1.png"><img width="802" height="678" class="alignnone size-full wp-image-211" alt="Standard Program" src="https://msdnshared.blob.core.windows.net/media/2016/02/StandardProgram1.png" /></a></li>
 	<li>On the Requirements page, select the appropriate values for your environment. The Platform requirements can be set to either “This program can be run on any platform” or a platform specific setting.  It is recommended that you either filter at the collection level and or by the package requirements. In this example, the program is set to run only on RHEL and CentOS 6.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/Requirements.png"><img width="802" height="678" class="alignnone size-full wp-image-181" alt="Requirements" src="https://msdnshared.blob.core.windows.net/media/2016/02/Requirements.png" /></a></li>
 	<li>Complete the wizard screens (next… next… close).</li>
</ol>
&nbsp;

<strong><span style="text-decoration: underline">Distribute the Package</span></strong>

Ensure that you distribute the package to all the required DPs. (<a target="_blank" href="https://technet.microsoft.com/en-us/library/gg682083.aspx" title="Introduction to Content Management in Configuration Manager">https://technet.microsoft.com/en-us/library/gg682083.aspx</a>)

<strong><span style="text-decoration: underline">Deploy the Package</span></strong>
<ol>
 	<li>Utilize an existing collection that contains the target LINUX machines or or create a new collection that will contain LINUX cliented systems.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/DeploySoftwareWizard.png"><img width="791" height="660" class="alignnone size-full wp-image-102" alt="DeploySoftwareWizard" src="https://msdnshared.blob.core.windows.net/media/2016/02/DeploySoftwareWizard.png" /></a></li>
 	<li>Select Next, on the “Specify the content destination” page.</li>
 	<li>On the “Specify settings to control how this software is deployed”, ensure that the “Purpose:” is set to “Required”.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/DeploymentSettings.png"><img width="790" height="659" class="alignnone size-full wp-image-92" alt="DeploymentSettings" src="https://msdnshared.blob.core.windows.net/media/2016/02/DeploymentSettings.png" /></a></li>
 	<li>On the Scheduling page, select “Schedule when this deployment will become available:” and choose the default date. For the “Assignment schedule”, select “New…”, utilizing the default date or choose “Assign immediately after this event” --&gt; “As soon as possible”, The values “log on and “log off” are not supported in LINUX deployments.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/Scheduling.png"><img width="791" height="659" class="alignnone size-full wp-image-191" alt="Scheduling" src="https://msdnshared.blob.core.windows.net/media/2016/02/Scheduling.png" /></a></li>
 	<li>Click “Next &gt;” on the User Experience page.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/UserExperience.png"><img width="791" height="659" class="alignnone size-full wp-image-212" alt="UserExperience" src="https://msdnshared.blob.core.windows.net/media/2016/02/UserExperience.png" /></a></li>
 	<li>On the “Distribution Points” page, ensure the “Deployment options” are set to “Download content from distribution point and run locally”.  Deselect the option to “Allow clients to share content”.  Linux clients do not support branch cache. Click Next &gt;
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/DistrubutionPoints.png"><img width="791" height="659" class="alignnone size-full wp-image-112" alt="DistrubutionPoints" src="https://msdnshared.blob.core.windows.net/media/2016/02/DistrubutionPoints.png" /></a></li>
 	<li>On the Summary page, click Next&gt;</li>
 	<li>Click Close.</li>
 	<li>(OPTIONAL) Open the properties page of the package.</li>
 	<li>(OPTIONAL) Select the Data Source Page. Check the box for Persist content in the client cache. This option will allow you to confirm that your package is downloaded to the client and will allow you to do further troubleshooting if needed.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/PersistentCache.png"><img width="608" height="616" class="alignnone size-full wp-image-171" alt="PersistentCache" src="https://msdnshared.blob.core.windows.net/media/2016/02/PersistentCache.png" /></a></li>
</ol>
<strong><span style="text-decoration: underline">Monitoring Deployment</span></strong>

Remember, similar to Windows deployments, LINUX deployments are not instantaneous. LINUX clients are VERY similar to Windows clients and process policy, content and installations in very much the same way.

If you are very impatient, you can force the client to pull policy. From the LINUX client, execute:
<pre>[root@usmdua8038 ~]# /opt/microsoft/configmgr/bin/ccmexec -rs policy</pre>
In real time you can watch the logs:
<pre>[root@usmdua8038 ~]# tail -f /var/opt/microsoft/scxcm.log</pre>
From the SCCM console, look under <strong>Monitoring </strong><strong>--&gt; Deployments</strong> and filter by the Package name or a keyword from the package.
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/Monitoring.png"><img width="937" height="619" class="alignnone size-full wp-image-132" alt="Monitoring" src="https://msdnshared.blob.core.windows.net/media/2016/02/Monitoring.png" /></a>
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/MonitoringDetail.png"><img width="808" height="407" class="alignnone size-full wp-image-142" alt="MonitoringDetail" src="https://msdnshared.blob.core.windows.net/media/2016/02/MonitoringDetail.png" /></a>

<strong><span style="text-decoration: underline">Troubleshooting Deployment</span></strong>

If your first deployment does not go as expected, the logs available to you are pretty extensive. You should also visit <a target="_blank" href="https://social.technet.microsoft.com/wiki/contents/articles/28548.unix-and-linux-clients-for-system-center-2012-r2-configuration-manager-common-error-wiki.aspx" title="UNIX and Linux clients for System Center 2012 R2 Configuration Manager common error wiki">https://social.technet.microsoft.com/wiki/contents/articles/28548.unix-and-linux-clients-for-system-center-2012-r2-configuration-manager-common-error-wiki.aspx</a>

On the server side, did you approve your LINUX client?  By default, only domain joined Windows clients are automatically approved.  Select the client agent and approve it or change the approval policy.  (see <a target="_blank" href="https://technet.microsoft.com/en-us/library/bb633214.aspx" title="How to Approve Configuration Manager Clients">https://technet.microsoft.com/en-us/library/bb633214.aspx</a>)

On the client side, the log scxcm.log is the most useful. The default path to the /var/opt/microsoft/scxcm.log (see <a href="https://technet.microsoft.com/en-us/library/hh427342.aspx">https://technet.microsoft.com/en-us/library/hh427342.aspx</a> )

The configuration file for the logs is<strong><span style="color: #000000"> /opt/microsoft/configmgr/etc/scxcm.conf </span></strong>it supports the log settings of: ERROR,WARNING INFO and TRACE.

To change the log level, edit <strong>/opt/microsoft/configmgr/etc/scxcm.conf</strong> and change each instance of the tag <strong>MODULE</strong> to the desired log level.

Set the log level to TRACE. Ensure that you ONLY use TRACE during troubleshooting. The trace log is very verbose and can fill up a small disk quickly if you are not paying attention.

It is recommended that you delete the deployment after changing the logging level and recreate the deployment. This will give you a trace log of the entire transaction from start to failure.

Confirm the configuration of your Distribution Points and Management Points. LINUX clients support both HTTP and HTTPS. However unlike Windows clients that can be auto-issued certificates, the LINUX clients will need to have the client side authentication certificates installed manually. For simple testing, I recommend utilizing HTTP MPs.

Confirm that you can communicate to each MP. From the LINUX client, execute:
<pre>wget <span style="color: #0000ff;text-decoration: underline">https://&lt;mpserverfqdn&gt;/SMS_MP/.sms_aut?mplist</span></pre>
From each MP in the list, confirm that you can connect to its certificate
<pre>wget <span style="color: #0000ff;text-decoration: underline">https://&lt;mpserverfqdn&gt;/SMS_MP/.sms_aut?mpcert</span></pre>
Confirm the package is available from your Distribution Point.
<pre>wget <span style="color: #0000ff;text-decoration: underline">https://&lt;mpserverfqdn&gt;/SMS_DP_SMSPKG$/&lt;packageid.version&gt;/sccm_logrotate.sh</span></pre>
If you performed the optional step of setting the package to persist in client cache, look to see if the client downloaded the files into the SCCM client cache located at:
<pre>/opt/microsoft/configmgr/.cache/&lt;packageid.version&gt;/</pre>
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/cache.png"><img width="500" height="119" class="alignnone size-full wp-image-82" alt="cache" src="https://msdnshared.blob.core.windows.net/media/2016/02/cache.png" /></a>

A trace log can become very large. You can GREP (or EGREP) for several key words to quickly or CAT the file with LESS allowing you to search for key words.

You can always search on the package ID and advertisement ID. Here are some key words to look for in a successful deployment:

“Requesting bytes”
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/RequestingBytes.png"><img width="922" height="116" class="alignnone size-full wp-image-172" alt="RequestingBytes" src="https://msdnshared.blob.core.windows.net/media/2016/02/RequestingBytes.png" /></a>

“Opening file path”
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/OpeningFilePath.png"><img width="922" height="114" class="alignnone size-full wp-image-161" alt="OpeningFilePath" src="https://msdnshared.blob.core.windows.net/media/2016/02/OpeningFilePath.png" /></a>

”now complete”
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/NowComplete.png"><img width="923" height="115" class="alignnone size-full wp-image-151" alt="NowComplete" src="https://msdnshared.blob.core.windows.net/media/2016/02/NowComplete.png" /></a>

”Executing program”
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/ExecutingProgram.png"><img width="922" height="67" class="alignnone size-full wp-image-122" alt="ExecutingProgram" src="https://msdnshared.blob.core.windows.net/media/2016/02/ExecutingProgram.png" /></a>

”SoftwareDistProgramStarted”
<a href="https://msdnshared.blob.core.windows.net/media/2016/02/SoftwareDistProgramStarted.png"><img width="921" height="147" class="alignnone size-full wp-image-201" alt="SoftwareDistProgramStarted" src="https://msdnshared.blob.core.windows.net/media/2016/02/SoftwareDistProgramStarted.png" /></a>

&nbsp;

For further deployment troubleshooting, consult other TechNet articles like <a target="_blank" href="https://technet.microsoft.com/en-us/library/bb693982.aspx" title="Troubleshooting Configuration Manager Client Issues">https://technet.microsoft.com/en-us/library/bb693982.aspx</a>  While most refer to Windows clients, many of the same issues occur with the LINUX client.

<strong>WMI Filter Issues</strong>

For WMI filter related issues, leverage the LINUX client omicli tool. Similar to WMI, OMI queries a similar structure. For example,
<pre>/opt/microsoft/omi/bin/omicli wql root/cimv2 "SELECT * FROM SCXCM_OperatingSystem WHERE Version like '6.%' AND OSType=36 AND Caption like '%CentOS%'"</pre>
The client has a mapping table that maps the WIN32_ classes to the client SCXCM_ classes. This allows the console queries to work cross platform.

&nbsp;

Hopefully this demonstration provides you some visibility into System Center Configuration Manager as an “Enterprise Management Tool”.

&nbsp;

<span style="text-decoration: underline"><strong>Test Environment</strong></span>

The components were used to build out this scenario:
<ul>
 	<li>Windows Server 2012 R2</li>
 	<li>System Center Configuration Manager 2012 R2 CU2</li>
 	<li>CentOS 6.7</li>
 	<li>SCCM LINUX Agent Edition 5.0.7958.1024</li>
</ul>
<span style="color: #000000;font-family: Calibri"> </span>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Editing / Converting LINUX Scripts from a Windows System</title>
      <link>https://docs.microsoft.com/archive/blogs/jeffbutte/editing-converting-linux-scripts-from-a-windows-system</link>
      <pubDate>Sun, 31 Jan 2016 22:16:33 GMT</pubDate>
      <dc:creator><![CDATA[Jeff Butte (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jeffbutte/?p=22</guid>
      <description><![CDATA[&nbsp;

If you are a Windows Administrator that performs support for LINUX systems or a LINUX...]]></description>
      <content:encoded><![CDATA[&nbsp;

If you are a Windows Administrator that performs support for LINUX systems or a LINUX administrator that performs work on Windows systems, you may have stumbled into the dreaded<span style="color: #0000ff"> /bin/bash^M: bad interpreter: no such file or directory.</span>

The default text editor on a Windows system is Notepad. While a fine editor for Windows text files, it actually removes hair from cross-platform administrators who use it. Notepad would not be considered a modern multi-platform text editor. It can change a file format without your knowledge and confound you for an hour or two.

There are two primary differences between Windows and LINUX file formats.

The first difference is how lines are ended. LINUX systems end a line in a text file with a Line Feed (LF) character. Windows systems end their lines in text files with a Carriage Return and Line Feed (CRLF) (also known as EOL or End Of Line).
<table>
<tbody>
<tr>
<td width="312">Carriage Return (CR):</td>
<td width="312">Line Feed (LF):</td>
</tr>
<tr>
<td width="312"></td>
<td width="312"></td>
</tr>
<tr>
<td width="312">ASCII / Unicode                =             13</td>
<td width="312">ASCII / Unicode                =             10</td>
</tr>
<tr>
<td width="312"></td>
<td width="312"></td>
</tr>
<tr>
<td width="312">Hexadecimal                      =             0x0D</td>
<td width="312">Hexadecimal                      =             0x0A</td>
</tr>
<tr>
<td width="312"></td>
<td width="312"></td>
</tr>
<tr>
<td width="312">PowerShell                        =             \r or `r</td>
<td width="312">PowerShell                         =             \n or `n</td>
</tr>
</tbody>
</table>
&nbsp;

The second difference is encoding type. File editors in Windows may save files with different default file encoding types. For example, Notepad saves the file in Windows/ ANSI codepage format (Unicode). Unicode files contain a BOM or Byte Order Mark. The BOM is an additional Unicode character that is placed at the beginning of a file to signal the Unicode scheme.

LINUX file editors like VIM save with a default of UTF-8 w/o BOM or without the  Byte Order Mark. Shell interpreters that do not expect the BOM character will throw an error.  As a Windows administrator performing cross platform work, be careful where you edit files.

The best recommendation is to edit LINUX shell scripts and files within a LINUX editor. Since you are reading this… you have likely edited the files on another platform.  :-)

There are several articles, blogs and technical help sites that attempt to assist you. However, most articles address the LF / CRLF problem; not the file encoding problem.

On the UNIX / LINUX side, you can load packages like dos2unix to change the format and encoding of to a compatible version. This program allows you to convert files that you transferred to the LINUX platform.

On the Windows platform, there are multiple options as well. For those graphical users, Notepad++ (<a href="https://notepad-plus-plus.org/">https://notepad-plus-plus.org/</a> ) is a powerful Free Open Source Software (FOSS) modern editor that supports conversion to UNIX format and UTF-8 w/o BOM encoding.

As a cross platform administrator, transferring files between platforms, editing and then transferring them back isn’t efficient. If you are attempting automation, a graphical editor may not work. PowerShell can easily meet your requirements.

Create a new script in PowerShell.  My script is called psdos2unix.ps1 (to give credit to those original creators on the UNIX side that got the name first).

<span style="color: #0000ff">param</span> (

<span style="color: #808080">     [</span><span style="color: #33cccc">Parameter</span>(Mandatory=<span style="color: #ff0000">$true</span>)<span style="color: #808080">][</span><span style="color: #008080">string</span><span style="color: #808080">]</span><span style="color: #ff0000">$InputFile</span>

)

<span style="color: #0000ff">if</span> ((<span style="color: #0000ff">Test-Path</span> <span style="color: #333399">-Path</span> <span style="color: #ff0000">$InputFile</span>) <span style="color: #808080">-eq</span> <span style="color: #ff0000">$true</span>) {

<span style="color: #ff0000">     $CarriageReturnLineFeed</span> <span style="color: #808080">=</span> <span style="color: #800000">"`r`n?"</span>

<span style="color: #ff0000">     $LineFeed </span><span style="color: #808080">=</span> <span style="color: #800000">"`n"</span>

<span style="color: #008000">     # Read in the content of your file in a raw single string and replace the CarriageReturn+LineFeed with just the LineFeed</span>

<span style="color: #ff0000">     $FileInMemory </span><span style="color: #808080">=</span> (<span style="color: #0000ff">Get-Content</span> <span style="color: #333399">-Path</span> <span style="color: #ff0000">$InputFile</span> <span style="color: #0000ff">-Raw</span>) <span style="color: #808080">-replace</span> <span style="color: #ff0000">$CarriageReturnLineFeed</span>,<span style="color: #ff0000">$LineFeed</span>

<span style="color: #008000">     # Write out the file you just edited in memory back out but also specify the format as Encoding type UTF-8 no BOM.</span>

<span style="color: #008000">     # https://msdn.microsoft.com/en-us/library/s064f8w2(v=vs.110).aspx</span>

<span style="color: #ff0000">     $UTF8NoBomEncoding</span> <span style="color: #808080">=</span> <span style="color: #0000ff">New-Object</span> <span style="color: #800080">System.Text.UTF8Encoding</span>(<span style="color: #ff0000">$False</span>)

<span style="color: #808080">     [</span><span style="color: #008080">System.IO.File</span><span style="color: #808080">]::</span>WriteAllLines(<span style="color: #ff0000">$InputFile</span>, <span style="color: #ff0000">$FileInMemory</span>, <span style="color: #ff0000">$UTF8NoBomEncoding</span>)

<span style="color: #0000ff">     Write-Host</span> <span style="color: #800000">"Conversion complete."</span>

}<span style="color: #0000ff">else</span>{

<span style="color: #0000ff">     Write-Warning</span> <span style="color: #800000">"The filename or path to the file name specified is incorrect."</span>

}

&nbsp;

Now you can easily convert your LINUX files via PowerShell by running:    <span style="color: #0000ff">.\psdos2unix.ps1</span> <span style="color: #333399">-InputFile</span> &lt;<span style="color: #800080">input.file</span>&gt;

PowerShell should not be confused as a hair restoration product. It just leads to you pulling less of yours out.]]></content:encoded>
    </item>
  </channel>
</rss>