PowerShell scripting template for SCCM packages

This article provides a PowerShell scripting template for SCCM and MDT packages. This template can also be used for stand-alone installations (without using SCCM or MDT)!

An SCCM package is basically a container with source files. I recommend using a wrapper (a script) to execute the installation files and for any configuration you may need. And that is exactly what the PowerShell template below offers!
Even better, the template in this article uses my PowerShell Function Library, which effectively turns it into a complete deployment framework.

Change Log
23.05.2017: updated and renamed functions.
05.06.2018: major overhaul of this article and single functions have been replaced by the Dennis Span PowerShell Function Library.
29.12.2019: solved an issue whereby the scripting template in an MDT task sequence does not work properly. I had to change the scope of the variables LogDir and LogFile in the scripting template. The scope for both of these variables is now set to global. If you are not familiar with the concept of scopes please see the Microsoft article About Scopes.

Scripting Template

The scripting template below is an example that you can use for your installations and configurations. The functions in the template are imported from a PowerShell module for the Dennis Span PowerShell Function Library. The library offers more functions than included in the template (the template is only an example).

Please see the article PowerShell Function Library for detailed information how to install and use the library.

For a complete overview of all PowerShell functions included in the library, see the following articles on this website:

How to use this template

First, copy the above code in your preferred editor (e.g. notepad) and save the file as a PowerShell script (*.PS1), for example MyAppInstaller.ps1. You can choose any file name you want of course.

You have to modify a couple of lines in the script to match your specific requirements. Enter your preferred log directory and package name in lines 44 and 45, for example:

  • $BaseLogDir = “C:\Logs”
  • $PackageName = “Adobe Acrobat Reader”

Or

  • $BaseLogDir = “C:\Script\Logs”
  • $PackageName = “Environment_Config”

When the log directory is created, spaces are automatically replaced with an underscore (“_”), for example: C:\Logs\Adobe_Acrobat_Reader.

Tip:

Changing the main log directory (e.g. C:\Logs) at a later time means that you have to change each script that contains the hard-coded path. There is another, more flexible way:

  • Create an environment variable using a Group Policy Preference called GlobalLogPath (or use a different name). As a value enter your preferred log path, for example “C:\Logs”.
  • In the script, add $env:GlobalLogPath as a value to the PowerShell variable $BaseLogDir: $BaseLogDir = $env:GlobalLogPath

The PowerShell script now reads the log path from the environment variable GlobalLogPath. In case you ever want to change the log directory you simply change the path in the Group Policy Preference environment variable without having to change any of your scripts.

The section How to use the library in a PowerShell script in the article PowerShell Function Library describes how to use the library in a PowerShell script. In line 61, make sure to enter the correct path to the library.

In the script sections “Pre-launch commands”, “Installation” and “Post-launch commands” make sure to enter the functions you require.

Optional: software (un)installation

In case you are installing or uninstalling software, add your source file(s) to a subfolder relative to the root folder (e.g. Files). The subfolder is the relative path to your package source directory. For example, if this is your package source folder:

\\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01

Than the subfolder for your installation source files is:

  • \\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\Files
    or
    \\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\MSI
    or
  • \\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\SETUP

In the PowerShell script, enter the name of your installation file, arguments and sub folder (again, relative to the root folder).

For example:

  • Line 84: $FileName = “AcrobatReader.msi”
  • Line 86/88: $Arguments =
    • “Transforms=””AcrobatReader.mst”” LANG_LIST=””en_US,de_DE”””
      or
    • “/silent /uninstall”
      or
    • “/QN” (for setup.exe files only)
  • Line 90: $FileSubFolder = “Files

In the previous example, the folder Files is used for the variable $FileSubFolder, This is the default value, but you can use any folder name you want (e.g. “MSI”, or “SETUP”). Just make sure that the folder exists relative to the root of the path.

Please note that for MSI packages the following parameters are added by default:

  • For uninstallations:/x “”$File”” /qn /norestart /l*v “”$LogFileAPP”””
  • For installations: /i “”$File”” /qn /norestart /l*v “”$LogFileAPP”””

When you have prepared your PowerShell file copy it in the root of your package source directory. For example:

\\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\AppInstaller.ps1

The PowerShell script is executed as follows:

  • For installations:
    powershell -file “\\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\AppInstaller.ps1″ Install
  • For uninstallations:
    powershell -file “\\FileServer1\PackageSource\Adobe\Acrobat Reader\11.0.18_01\AppInstaller.ps1″ Uninstall

Happy scripting!

26 thoughts on “PowerShell scripting template for SCCM packages

    • Hi Phil, for sure it works with MDT as well. I do not add any SCCM specific functions in my PowerShell scripts. My scripts also work without SCCM or MDT. You can simply trigger them manually (e.g. powershell.exe -file %FileName%).

  1. Pingback: Google Chrome on Citrix deep-dive - Dennis Span

  2. Pingback: Scripting the complete list of Citrix components with PowerShell - Dennis Span

  3. Pingback: Printer Drivers Installation and Troubleshooting Guide - Dennis Span

  4. Pingback: Citrix Delivery Controller unattended installation with PowerShell and SCCM - Dennis Span

  5. Pingback: Citrix License Server unattended installation with PowerShell and SCCM - Dennis Span

  6. Pingback: Citrix Provisioning Server unattended installation - Dennis Span

  7. Pingback: Citrix Director unattended installation with PowerShell - Dennis Span

  8. Pingback: Citrix App Layering Agent unattended installation - Dennis Span

  9. Pingback: How to configure and run BIS-F in an SCCM task sequence - Dennis Span

  10. Pingback: Citrix StoreFront unattended installation with PowerShell - Dennis Span

  11. Pingback: Citrix Receiver unattended installation with PowerShell - Dennis Span

  12. Hello Dennis,

    Thanks for your work!
    I have a problem with SCCM, the package return an error 196608.
    It works if i run manually the script.
    Have you any idea for this error?

    • Hi Xavier, thanks!

      I am not sure what that error means exactly, but I suggest to check the following:
      -Test the installation as a system user (example: https://dennisspan.com/scripting-the-complete-list-of-citrix-components-with-powershell/#CFsDep2.sys).
      -Also, the process ‘smsswd.exe’ that executes the package runs as a 32-bit process. Make sure that when testing manually you emulate this behavior. Open a 32-bit command window (C:\Windows\SysWOW64\cmd.exe) and run the installation from there.

      In case you require more help, please send me an e-mail (dennis@dennisspan.com) with more details (e.g. exact command line, package settings, etc.). Perhaps you can even send me a copy of the script so I can test it myself.

  13. Pingback: Encrypting passwords in a PowerShell script - Dennis Span

  14. Pingback: Citrix Application Probe Agent unattended installation - Dennis Span

  15. Hi,
    in case you want to install a msi in the post (or pre) section. How do you implement that?
    In my case the logfile is not fully written (broken actually), SCCM says Installation Failed and Post-msi is not installed.

    THx for your reply

  16. Hi Dennis,
    I found my mistake by running the .ps1 manually in powershell
    PS: A nice feature would be a function that searches for a running process and kills it if specified. E.g. DS_SearchRunningProces -process iexplore.exe -Kill yes/no

    • Hi Lieven,

      I am happy you found the mistake. And your idea for a new function to kill a running process is a good idea. I will implement it in the next release of my Function Library.

      Thanks!

      Bye,

      Dennis

  17. Thank you very much Dennis for sharing this knowledge. Please, i want to know. If i have to install multiple applications (ie acrobat, office, antivirus etc.), how do i go about it.

    Thanks

  18. Hi Dennis, great work, i highly appreciate it. One thing i would like to ask is: how do you feel about the powershell appdeploy toolkit? I feel this goes even a step further than you have done. Would it be a good suggestion if you would “hook on” to that one and adapt your function library to the psappdeploy toolkit? I do ask this because i feel your scripting template and the psappdeploy-toolkit serve the same purpose.

    • Hi Paul,

      We used the AppDeploy Toolkit at my previous job. It is a very good PowerShell library, but I decided that I wanted something a bit less complicated, a bit “cleaner” if you will. I am talking about a simpler code structure of the PowerShell framework. For example, the AppDeploy Toolkit includes various features to support interactive installations (e.g. on end user’s devices). For a Citrix environment, this is not required. There is no interaction when updating the golden master image; everything is done in system context. I also wanted the log files to be more “readable”. In the end, there were various reasons for me to create my own library. But as said, the AppDeploy Toolkit is very good and in the end, every administrator should choose his or her tool of preference.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.