Saturday, March 3, 2018

ConfigMgr Agent Self-Installer

We have a large percentage of remote workers and they work fine via ConfigMgr ibcm (not to be confused with icbm!). However with any system, soemtimes the agent needs to be re-installed or installed to begin with so to make life easier on both the end user and the techs working the ticket I created a self installer for the agent. Users get the perception its installing "something" and the tech can give them a download URL and instruct them to download and run it knowing it will take care of the issue.

For the user they see a familair experience as this installer is used for many products, both free and commercial.

Behind the scenes this extracts the agent files to the users %TEMP% and then runs the agent installer after extraction is completed.

First step is to put the agent install into a working directory. In my case I pulled it from GPO as a VBS does all sorts of checks and balances as well as manages other components such as 1E Nomad, WUA versions, or fix WMI. Similar to Jasons starutp script. If you dont have it wrapped you can just install CCMSETUP.EXE with your ibcm info as you would manually run.

To create this I am using HM NSI Edit and NullSoft installer. HM NSI has a nice wizard interface to generate the install text file and from habit I use Nullsoft installer to compile it into something useable. HM NSI Edit has a compiler but it doesnt support everything Nullsoft does directly. There are other tools that work with NSI but I've used these for years with great success.

Start HM Edit and choose File | New Script from Wizard to start its Wizard. On the app info dialog I leave the website blank but you can point to say a KB article URL or support desk.

On the Setup Options dialog you can point to an icon file for a company logo and point to the setup file. This is what you are going to generate. Additionally if you want to add support for multiple languages you can do that. I just use English. The Modern GUI is the best looking one and I would suggest LZMA for compression as it packs the tightest. we'll make a minor tweak to this later.

For the Application directory and license dialog I just use '$TEMP\SCCMAgentInstall' for the App default directory. As NSI is an installer that will put files into Program Files, registry, add/remove etc  however in this case we are only extracting it and having it run the agent install silently. Since its an internal app the license file is blank.

Now you get to tell it what to do. On the Application Files dialog you remove the two entires on the right.

Click the Directory icon

and point to the directory you cached the agent install previously. Validate the Destination directly is set to $INSTDIR so it gets put into the temp dir you set a few steps above. If you use this to acutally install software you can use different sections and actions. For this use case the defaults are fine.

It then populates all the files from your cache dir. Otherwise leave this dialog alone

On the Application Icons dialog you want to remove the checkboxes and shortcuts so this is all blank.

Now you get to set your switches around your install. If you have a wrapper like me then you just enter the exe and move on, but if you do not and are calling CCMSETUP.EXE directly you can put your switches here as shown below. Additionally there is option for a readme if you have some sort of support KB. Note it is text and needs to be in the files you imported.

For the uninstaller dialog just uncheck the box as there is no uninstaller in this case.

Finally on the finish dialog select to save the script and convert relative paths. Do not compile as we will make some changes within the script file first.

Open the saved script file in your favorite text editor.  First change is to not put this "install" into the registry. Just comment (or delete) out the PRODUCT_DIR_REGKEY line. Note NSI files use semi-colon as comment code.

 ;!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\CMSEtup.EXE"  

Modify the SetCompresor setting add /solid switch. This will cause it to treat the files as one big blob vs individual files so you get greater compression.

 SetCompressor /SOLID lzma  

Comment (or delete) the MUI_FINISHPAGE_RUN line. This puts a checkbox in the final diaog of the installer to run the program after closing, in this case CMSetup.exe. You silently run CMSetup.EXE (or CCMSETUP) later in the file so no need to give the user an option to uncheck it since we are forcefully running it.

 ; By uncommenting the next line you can run CMSCript after NSIS exits via Run checkbox. If so then you need to  
 ; comment the secion CMScript below  
 ;!define MUI_FINISHPAGE_RUN "$INSTDIR\CMScript.exe"  

This is simply referencing this section. This will run CMScript.EXE silently without any user choice. Since we are installing the ConfigMgr agent this is the behavior we want.

 Section "CMScript"  
  File "SCCMAgentInstall\CMScript.exe"  
  Exec "$INSTDIR\CMScript.exe"  

That should be all the changes you need to make however you can tweak as you test before making available to end users. To compile I use NSIS but HM will do it as well. Just open NSIS, click Compile NSI scripts then drag the script file to the new window it created and away it goes.

Once complete just close it out and go test your installer to make sure the behaviour is what you want and that the agent is actually installed. Note this compressed the install 77% so its pretty small and self contained in an EXE.

So what do you do when you update the agent install due to the backend being upgraded? You can go through the entire process above or just edit the your MSI file to update source files. I have not found an easy way to modify the text file so I actually go through the wizard and ignore all steps and stop on the Application Files dialog to import the updated files.

Then just copy the MainSection from the new file and replace in the original script file.

 Section "MainSection" SEC01  
  SetOutPath "$INSTDIR"  
  SetOverwrite try  

Be sure to update other sections of the file such as the version. Then compile again and test.

If you want to get real creative there is a huge community and documentation around Nullsoft Installer to get suggestions. In my case I just needed to create a simple way for remote users to install or re-install the latest agent under instruction from support staff. For example, I wanted to polish it a little and change the users install dialog to hide the details so I changed this setting from show to hide:

 ShowInstDetails hide  


Friday, February 23, 2018

FreeNAS and ESXi config backup

My FreeNAS was running off a single USB so I grabbed another one to setup a mirror but it was a few blocks smaller then the current one so would not mirror. Instead of spending time to make it work, I just took a backup of the config, re-installed to the mirror and restored the config. Super simple. This made me think I should get some automation in place to backup its config vs me doing it manually when I make changes in the GUI.

Doing some research on the FreeNAS forums you can just copy the config db from /data/freenas-v1.db to somewhere else. Since I'm using v11 its a simple 'cp -a' script. Being FreeNAS I thought using snapshots would be useful for change control etc so I created a new dataset (sysadmin) with max compression and copied the config to that location.

Then I thought someone else did something more eloquent so I went looking around and found a nice script from Spearfoot on GitHub that handles this and had the bonus of backing up the config of a ESXi host which I also needed to get some config backups.

I created the directory /root/bin as its in path so easy to keep track of and put the script there.

I ended up changing the script as it puts a timestamp in the file however due to my snapshots I didnt need it. Here is old vs new.


I'll still have to manually cleanup files when the version changes however I wanted to retain the version for compatability reasons. This gives me a nice single daily file and then the snapshot handles revision control.

 -rw-r----- 1 root wheel 933888 Feb 22 03:00 freenas-FreeNAS-11.1-U1-f7e246b8f.db  

For the ESXI host this script will SSH to it and then pulls the config. In order to automate I had to first setup certificates between these two systems. Interactive logins are disabled on all my hosts but I didnt expect these two to talk to each this way so had to setup certificates. You can go here or here for more detail on the process if you are unfamilar. These are the commands.

 #cd /root/.ssh  
 #ssh-keygen -N "" -f id_esxi  
 #cat | ssh root@ESXI_HOSTNAME_OR_IP_ADDRESS 'cat >>/etc/ssh/keys-root/authorized_keys'  

First line  just puts you into roots ssh dir. The second generates a passphrase less key pair. Think hard here on whether this works in your environment. Being my homelab and interactice logins disabled everywhere I was ok with the risk. Third line will copy the public key to the ESXi host. Once the keys are done and on each system you just ssh with this switch:

 ssh -i id_esxi root@ESXI_HOSTNAME_OR_IP_ADDRESS  

For the GitHub script I had to add the -i switch (highlighted above) to use the certificate.

 #esxihostname=$(ssh -i /root/.ssh/id_esxi root@"${esxihost}" hostname)   
 #esxiversion=$(ssh -i /root/.ssh/id_esxi root@"${esxihost}" uname -a | sed -e "s|VMkernel ||;s|$esxihostname ||")   
 #esxiconfig_url=$(ssh -i /root/.ssh/id_esxi root@"${esxihost}" vim-cmd hostsvc/firmware/backup_config | awk '{print $  7}' | sed -e "s|*|$esxihostname|")  

This all works via shell and I now have backups of my two main systems.

 -rw-r--r-- 1 root wheel  20623 Feb 22 03:00 esxi-configBundle.tgz  
 -rw-r----- 1 root wheel 933888 Feb 22 03:00 freenas-FreeNAS-11.1-U1-f7e246b8f.db  

Next up was to get the cronjob going so we head over to the FreeNAS GUI under Tasks | Cron Jobs and create it. I did it for 3AM. For the command I am using:

 sh /root/bin/  

Finally create the snapshot for 4AM.

The script will also send an email which is nice.

 Configuration file saved successfully on Thu Feb 22 03:00:00 MST 2018  
 Version: FreeNAS-11.1-U1 (f7e246b8f)  
 File: /mnt/Pool/sysadmin/freenas-FreeNAS-11.1-U1-f7e246b8f.db  
 Version: 6.5.0 #1 SMP Release build-5969303 Jul 6 2017 21:22:25 x86_64 x86_64 x86_64 ESXi  
 File: /mnt/Pool/sysadmin/esxi-configBundle.tgz  

Almost done. RAID is not a backup so I still need to do something for fire/theft etc. To address that, I created a weekly cronjob to copy this from the sysadmin dataset into my main dataset which gets rsynced offsite daily. I may change this to daily so I have the most current configs offsite.

Just having about a weeks worth of backups its looking good


Wednesday, February 14, 2018

Dell OneShot Driver Update

Sometimes when there is a problem with a machine an older driver is at fault. For firms that have standardized on Dell they have provided a nice tool call Dell Command  | Update. This is a nice tool Dell made to keep their business lines (OptiPlex, Precision, or Latitude for example) driver sets up to date.

It installs an agent that runs on a schedule (monthly by default) to keep the system up to date on drivers. It queries drivers from Dell directly (or via an on site repository) so you can get the latest drivers easily and automatically. As my firm has very few egress points, I chose not to use it in this capacity however it does have a CLI executable! While we use ConfigMgr to do driver management as issues dictate (needing newer nVidia non ISV driver for example), I put together a package in ConfigMgr for the techs to manually update all drivers on a device when it comes in for service. Known as the "OneShot Driver Update".

You can find install instructions to get Command | Update installed on a PC. Once installed, just copy the install folder to a source folder in SCCM. I created two BAT Files that perform the following:

  • Remove logs from a previous run
  • Pause Bitlocker
  • Update Drivers
  • Resume Bitlocker if no restart needed
  • Optionally copy the logs to a server location

As you are generally updating drivers that impact the boot chain (yes the video driver at times) you need to pause Bitlocker. Older versions of the tool did not handle Bitlocker, which is what started me down the path of a simple BAT wrapper for the tool. The Update drivers bullet above is handled via a specific BAT and custom XML file though I have though about doing a menu in the BAT at some point to combine them. For the XML, you can create it in the GUI version of the tool then save it out and therefore use it to update only the categories you want.

I have created two file sets. One that does all device drivers yet skips applications. The second only updates the system firmware, aka BIOS or UEFI. You just run the appropriate BAT as an admin. They are even called '_RunAsAdmin.BAT'.

For SCCM we just have a package with both BATs called out as Programs and have them published via our internal Package Downloader Tool (PDT). Otherwise you can simply advertise it as available to be ran from Software Center. Or just put on a network location somewhere.


This Script is provided as-is, no warranty is provided or implied.The author is NOT responsible for any damages or data loss that may occur through the use of this Script.  Always test, test, test before rolling anything into a production environment.

You can find these two scripts here.