As usual the code for my module is available on my Github so you can grab those files for a quick start if you like.
So I’ve been using MunkiReport-PHP a bit lately and found it is pretty useful.
However I found there was some information that I would like to gather from the client and display it in MunkiReport so I went about creating a custom reporting module.
It was pretty straight forward, but the documentation on the MunkiReport site is a bit vague, so hopefully this helps fill in the gaps.
First of all we need to work out what information we want to gather and display in Munki Report. In my situation I decided I wanted to show some status information from the SCCM Agent such as wether or not the client is enrolled, when the last check in time was, the management point and the client certificate expiration date. Basically the important stuff from the pref pane
To gather this information I started with a script that looked a bit like this:
#!/bin/bash # Location of the SCCM Plist ccmpref="/var/root/Library/Preferences/com.microsoft.ccmclient.plist" # Lets get the enrollment status status=`defaults read $ccmpref EnrollmentStatus` getmoreinfo() # If we are enrolled, lets pull some more info { echo "Status = Enrolled" # Get the Management point mp=`defaults read $ccmpref MP` echo "Management_Point = $mp" # Get the user name of the user who enrolled device enrolluser=`defaults read $ccmpref EnrollmentUserName` echo "Enrollment_User_Name = $enrolluser" # Get the Enrollment Server Address enrollserver=`defaults read $ccmpref EnrollmentServerName` echo "Enrollment_Server_Address = $enrollserver" # Get the last Check in time checkin=`defaults read $ccmpref OMALastConnectTime` echo "Last_Check_In_Time = $checkin" # Get the Certificate Expiration date certexp=`defaults read $ccmpref CertExpDate` echo "Client_Certificate_Expiry_Date = $certexp" } # Determine if we are enrolled if [ $status = "0" ]; then echo "Status = Not Enrolled" elif [ $status = "1" ]; then getmoreinfo fi
So now atleast we can gather the information we need. On to the next step of getting this into a MunkiReport module
I found the easiest way to create the module was to simply copy an existing one.
So on our MunkiReport server, go into /var/www/munkireport/app/modules and copy one of the modules to a new directory
I used the bluetooth module as a starting point.
cp -r /var/www/munkireport/app/modules/bluetooth /var/www/munkireport/app/modules/sccm_status
I then went ahead and just renamed all our files in our new module
Lets start with the script to gather the information, its essentially the same one I used above except we output the results to a text file on the client machine
#!/bin/bash # Skip manual check if [ "$1" = 'manualcheck' ]; then echo 'Manual check: skipping' exit 0 fi # Create cache dir if it does not exit DIR=$(dirname $0) mkdir -p "$DIR/cache" # Location of our output sccm_file="/usr/local/munki/preflight.d/cache/sccm_status.txt" # Location of the SCCM Plist ccmpref="/var/root/Library/Preferences/com.microsoft.ccmclient.plist" # Lets get the enrollment status status=`defaults read $ccmpref EnrollmentStatus` getmoreinfo() # If we are enrolled, lets pull some more info { echo "Status = Enrolled" # Get the Management point mp=`defaults read $ccmpref MP` echo "Management_Point = $mp" # Get the user name of the user who enrolled device enrolluser=`defaults read $ccmpref EnrollmentUserName` echo "Enrollment_User_Name = $enrolluser" # Get the Enrollment Server Address enrollserver=`defaults read $ccmpref EnrollmentServerName` echo "Enrollment_Server_Address = $enrollserver" # Get the last Check in time checkin=`defaults read $ccmpref OMALastConnectTime` echo "Last_Check_In_Time = $checkin" # Get the Certificate Expiration date certexp=`defaults read $ccmpref CertExpDate` echo "Client_Certificate_Expiry_Date = $certexp" } # Determine if we are enrolled if [ $status = "0" ]; then echo "Status = Not Enrolled" > "$sccm_file" elif [ $status = "1" ]; then getmoreinfo > "$sccm_file" fi exit 0
When you install munkireport on your client machine, it will go through all modules that are installed on the server in /var/www/munkireport/app/modules/ looking for install and uninstall scripts for each module.
So we need to create these install and uninstall scripts for our module
install.sh
#!/bin/bash # bluetooth controller CTL="${BASEURL}index.php?/module/sccm_status/" # Get the scripts in the proper directories ${CURL} "${CTL}get_script/sccm_status_info.sh" -o "${MUNKIPATH}preflight.d/sccm_status_info.sh" # Check exit status of curl if [ $? = 0 ]; then # Make executable chmod a+x "${MUNKIPATH}preflight.d/sccm_status_info.sh" # Set preference to include this file in the preflight check defaults write "${PREFPATH}" ReportItems -dict-add sccm_status "${MUNKIPATH}preflight.d/cache/sccm_status.txt" else echo "Failed to download all required components!" rm -f "${MUNKIPATH}preflight.d/sccm_status_info.sh" # Signal that we had an error ERR=1 fi
uninstall.sh
#!/bin/bash # Remove SCCM Status script rm -f "${MUNKIPATH}preflight.d/sccm_status_info.sh" # Remove SCCM Status file rm -f "${MUNKIPATH}preflight.d/cache/sccm_status.txt"
Now on a client machine, we just need run the munkireport installer and it will install our script.
# /bin/bash -c "$(curl -s --max-time 10 http://YOURMUNKIREPORTSERVER.EXAMPLE.COM/munkireport/index.php?/install)"
So thats the client side of things taken care of.
Now we need to create some php code for our module so the server knows what to do with this new data.
We need a controller and a model file. These are special files that MunkiReport knows about so we need to ensure we have these files in our module folder
and that they are named with our module name and then _controller.php and _model.php
First up the controller file
<?php /** * SCCM Agent status module class * * @package munkireport * @author **/ class sccm_status_controller extends Module_controller { /*** Protect methods with auth! ****/ function __construct() { // Store module path $this->module_path = dirname(__FILE__); } /** * Default method * * @author Calum Hunter **/ function index() { echo "You've loaded the sccm_status module!"; } } // END class default_module
Next is the model file – this is the important bit, this is where we define our fields to create in the munki report database.
We also define what text to match from output of our script on the client and then import that information into those new data base fields
I think its pretty straight forward to see whats going on here. Just add or remove the fields as you need.
<?php class sccm_status_model extends Model { function __construct($serial='') { parent::__construct('id', 'sccm_status'); //primary key, tablename $this->rs['id'] = ''; $this->rs['serial_number'] = $serial; $this->rt['serial_number'] = 'VARCHAR(255) UNIQUE'; $this->rs['agent_status'] = ''; $this->rs['mgmt_point'] = ''; $this->rs['enrollment_name'] = ''; $this->rs['enrollment_server'] = ''; $this->rs['last_checkin'] = ''; $this->rs['cert_exp'] = ''; // Schema version, increment when creating a db migration $this->schema_version = 0; // Create table if it does not exist $this->create_table(); if ($serial) $this->retrieve_one('serial_number=?', $serial); $this->serial = $serial; } // ------------------------------------------------------------------------ /** * Process data sent by postflight * * @param string data * **/ function process($data) { // Translate network strings to db fields $translate = array( 'Status = ' => 'agent_status', 'Management_Point = ' => 'mgmt_point', 'Enrollment_User_Name = ' => 'enrollment_name', 'Enrollment_Server_Address = ' => 'enrollment_server', 'Last_Check_In_Time = ' => 'last_checkin', 'Client_Certificate_Expiry_Date = ' => 'cert_exp'); //clear any previous data we had foreach($translate as $search => $field) { $this->$field = ''; } // Parse data foreach(explode("\n", $data) as $line) { // Translate standard entries foreach($translate as $search => $field) { if(strpos($line, $search) === 0) { $value = substr($line, strlen($search)); $this->$field = $value; break; } } } //end foreach explode lines $this->save(); } }
Ok now we have our module all created and ready to go. We now just need to get MunkiReport to show this information.
First we need to edit the client_details.php file to add a new line to tell it about our new module
# pico /var/www/munkireport/app/views/client/client_detail.php
Look for these lines
<li> <a href="#ard-tab" data-toggle="tab">ARD</a> </li>
Copy and paste an extra one in and replace the text with the name of our module so it looks like this
<li> <a href="#sccm_status-tab" data-toggle="tab">SCCM_Status</a> </li>
Now in the same file look for the div class definitions
<div class="tab-pane" id='bluetooth-tab'> <?$this->view('client/bluetooth_tab')?> </div>
Copy and paste another one of these in there and rename it to suit
<div class="tab-pane" id='sccm_status-tab'> <?$this->view('client/sccm_status_tab')?> </div>
Now we need to create the tab file that we referenced above
So again the easiest way is just to copy an existing tab file
# cp /var/www/munkireport/app/views/client/bluetooth_tab.php /var/www/munkireport/app/views/client/sccm_status_tab.php
Now we edit the contents of the new tab file and change it as needed
<?php //Initialize models needed for the table $sccm_status = new sccm_status_model($serial_number); ?> <h2>sccm_status</h2> <table class="table table-striped"> <tbody> <tr> <td>Enrollment Status</td> <td><?=$sccm_status->agent_status?></td> </tr> <tr> <td>Management Point</td> <td><?=$sccm_status->mgmt_point?></td> </tr> <tr> <td>Enrollment User Name</td> <td><?=$sccm_status->enrollment_name?></td> </tr> <tr> <td>Last Agent Checkin</td> <td><?=$sccm_status->last_checkin?></td> </tr> <tr> <td>Client Cert Expiry</td> <td><?=$sccm_status->cert_exp?></td> </tr> <tr> <td>Enrollment User Name</td> <td><?=$sccm_status->enrollment_name?></td> </tr> <tr> <td>Enrollment Server</td> <td><?=$sccm_status->enrollment_server?></td> </tr> </tbody> </table>
Essentially this is just defining our columns and where to pull that data from in the database.
Cool, so now it will appear in the client view. But it would be nice to have this available from the listings as well
So for that we create a list view, luckily we can again just copy an existing listing view and modify to suit
# cp /var/www/munkireport/app/views/listing/bluetooth.php /var/www/munkireport/app/views/listing/sccm_status.php
Change the fields and names to suit
<?$this->view('partials/head')?> <? //Initialize models needed for the table new Machine_model; new Reportdata_model; new Sccm_status_model; ?> <div class="container"> <div class="row"> <div class="col-lg-12"> <script type="text/javascript"> $(document).ready(function() { // Get modifiers from data attribute var myCols = [], // Colnames mySort = [], // Initial sort hideThese = [], // Hidden columns col = 0; // Column counter $('.table th').map(function(){ myCols.push({'mData' : $(this).data('colname')}); if($(this).data('sort')) { mySort.push([col, $(this).data('sort')]) } if($(this).data('hide')) { hideThese.push(col); } col++ }); oTable = $('.table').dataTable( { "bProcessing": true, "bServerSide": true, "sAjaxSource": "<?=url('datatables/data')?>", "aaSorting": mySort, "aoColumns": myCols, "aoColumnDefs": [ { 'bVisible': false, "aTargets": hideThese } ], "fnCreatedRow": function( nRow, aData, iDataIndex ) { // Update name in first column to link var name=$('td:eq(0)', nRow).html(); if(name == ''){name = "No Name"}; var sn=$('td:eq(1)', nRow).html(); var link = get_client_detail_link(name, sn, '<?=url()?>/', '#tab_sccm_status-tab'); $('td:eq(0)', nRow).html(link); // Translate bool. todo function for any bool we find var status=$('td:eq(7)', nRow).html(); status = status == 1 ? 'Yes' : (status === '0' ? 'No' : '') $('td:eq(7)', nRow).html(status) } } ); // Use hash as searchquery if(window.location.hash.substring(1)) { oTable.fnFilter( decodeURIComponent(window.location.hash.substring(1)) ); } } ); </script> <h3>SCCM Agent Status report <span id="total-count" class='label label-primary'>…</span></h3> <table class="table table-striped table-condensed table-bordered"> <thead> <tr> <th data-colname='machine#computer_name'>Name</th> <th data-colname='machine#serial_number'>Serial</th> <th data-colname='sccm_status#agent_status'>SCCM Agent Status</th> <th data-colname='sccm_status#mgmt_point'>Management Point</th> <th data-colname='sccm_status#enrollment_name'>Enrollment User Name</th> <th data-colname='sccm_status#enrollment_server'>Enrollment Server</th> <th data-colname='sccm_status#last_checkin'>Last SCCM Check In</th> <th data-colname='sccm_status#cert_exp'>SCCM Client Cert Expiry</th> </tr> </thead> <tbody> <tr> <td colspan="5" class="dataTables_empty">Loading data from server</td> </tr> </tbody> </table> </div> <!-- /span 12 --> </div> <!-- /row --> </div> <!-- /container --> <?$this->view('partials/foot')?>
DONE!
Now run a preflight and postflight on our client and check out our new sccm module in Munki Report
Hi
I am stuck by:” First we need to edit the client_details.php file to add a new line to tell it about our new module” Can u help?
LikeLike