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. |
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:
- Windows functions: PowerShell functions for Windows
- Citrix functions: PowerShell functions for Citrix
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #========================================================================== # # <APPLICATION NAME> # # AUTHOR: <AUTHOR> # DATE : <DATE> # # COMMENT: <COMMENT> # # Note: see the article 'https://dennisspan.com/powershell-scripting-template-for-sccm-packages/' for a detailed description how to use this template # # Note: for an overview of all functions in the PowerShell function library 'DS_PowerShell_Function_Library.psm1' see: # -Windows functions: https://dennisspan.com/powershell-function-library/powershell-functions-for-windows/ # -Citrix functions: https://dennisspan.com/powershell-function-library/powershell-functions-for-citrix/ # # Change log: # ----------- # <DATE> <NAME>: <CHANGE DESCRIPTION> #========================================================================== # Get the script parameters if there are any param ( # The only parameter which is really required is 'Uninstall' # If no parameters are present or if the parameter is not # 'uninstall', an installation process is triggered [string]$Installationtype ) # define Error handling # note: do not change these values $global:ErrorActionPreference = "Stop" if($verbose){ $global:VerbosePreference = "Continue" } ############################ # Preparation # ############################ # Disable File Security $env:SEE_MASK_NOZONECHECKS = 1 # Custom variables [edit] $BaseLogDir = "C:\Logs" # [edit] add the location of your log directory here $PackageName = "MyApp" # [edit] enter the display name of the software (e.g. 'Acrobat Reader' or 'Microsoft Office') # Global variables $StartDir = $PSScriptRoot # the directory path of the script currently being executed if (!($Installationtype -eq "Uninstall")) { $Installationtype = "Install" } $LogDir = (Join-Path $BaseLogDir $PackageName).Replace(" ","_") $LogFileName = "$($Installationtype)_$($PackageName).log" $LogFile = Join-path $LogDir $LogFileName # Create the log directory if it does not exist if (!(Test-Path $LogDir)) { New-Item -Path $LogDir -ItemType directory | Out-Null } # Create new log file (overwrite existing one) New-Item $LogFile -ItemType "file" -force | Out-Null # Import the Dennis Span PowerShell Function Library Import-Module "C:\Scripts\DS_PowerShell_Function_Library.psm1" DS_WriteLog "I" "START SCRIPT - $Installationtype $PackageName" $LogFile DS_WriteLog "-" "" $LogFile ############################ # Pre-launch commands # ############################ # Delete a registry value DS_DeleteRegistryValue -RegKeyPath "hklm:\SOFTWARE\MyApp" -RegValueName "MyValue" # Create a directory DS_CreateDirectory -Directory "C:\Temp\MyNewFolder" # Stop a service (+ dependencies) DS_StopService -ServiceName "Spooler" ############################ # Installation # ############################ # Install or uninstall software $FileName = "MyApp.msi" # [edit] enter the name of the installation file (e.g. 'MyApp.msi' or 'setup.exe') if ( $Installationtype -eq "Uninstall" ) { $Arguments = "" # [edit] enter arguments (for MSI file the following arguments are added by default: /i #File# /qn /norestart / l*v #LogFile#) } else { $Arguments = "Transforms=""MyApp.mst"" LANG_LIST=""en_US,de_DE""" # [edit] enter arguments (for MSI file the following arguments are added by default: /i #File# /qn /norestart / l*v #LogFile#) } $FileSubfolder = "Files" # [edit] enter the name of the subfolder which contains the installation file (e.g. 'Files' or 'MSI') $FileFullPath = Join-Path $StartDir $FileSubfolder # Concatenate the two directories $StartDit and $InstallFileFolder DS_InstallOrUninstallSoftware -File ( Join-Path $FileFullPath $FileName ) -InstallationType $Installationtype -Arguments $Arguments ############################ # Post-launch commands # ############################ # Delete a registry key DS_DeleteRegistryKey -RegKeyPath "hklm:\Software\MyApp" # Start a service (+ dependencies) DS_StartService -ServiceName "Spooler" ############################ # Finalize # ############################ # Enable File Security Remove-Item env:\SEE_MASK_NOZONECHECKS DS_WriteLog "-" "" $LogFile DS_WriteLog "I" "End of script" $LogFile |
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 43 and 44, for example:
- $BaseLogDir = "C:\Logs"
- $PackageName = "Adobe Acrobat Reader"
Or
- $BaseLogDir = "C:\Script\Logs"
- $PackageName = "Environment_Config"
1 2 3 | # Custom variables [edit] $BaseLogDir = "C:\Logs" # [edit] add the location of your log directory here $PackageName = "Adobe Acrobat Reader" # [edit] enter the display name of the software (e.g. 'Acrobat Reader' or 'Microsoft Office') |
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:
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 60, 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 83: $FileName = "AcrobatReader.msi"
- Line 85/87: $Arguments =
- "Transforms=""AcrobatReader.mst"" LANG_LIST=""en_US,de_DE"""
or - "/silent /uninstall"
or - "/QN" (for setup.exe files only)
- "Transforms=""AcrobatReader.mst"" LANG_LIST=""en_US,de_DE"""
- Line 89: $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"""
1 2 3 4 5 6 7 8 9 10 | # Install or uninstall software $FileName = "MyApp.msi" # [edit] enter the name of the installation file (e.g. 'MyApp.msi' or 'setup.exe') if ( $Installationtype -eq "Uninstall" ) { $Arguments = "" # [edit] enter arguments (for MSI file the following arguments are added by default: /i #File# /qn /norestart / l*v #LogFile#) } else { $Arguments = "Transforms=""MyApp.mst"" LANG_LIST=""en_US,de_DE""" # [edit] enter arguments (for MSI file the following arguments are added by default: /i #File# /qn /norestart / l*v #LogFile#) } $FileSubfolder = "Files" # [edit] enter the name of the subfolder which contains the installation file (e.g. 'Files' or 'MSI') $FileFullPath = Join-Path $StartDir $FileSubfolder # Concatenate the two directories $StartDit and $InstallFileFolder DS_InstallOrUninstallSoftware -File ( Join-Path $FileFullPath $FileName ) -InstallationType $Installationtype -Arguments $Arguments |
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!
Great work, would this work for MDT as ell or it is just solely for SCCM?
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%).
Pingback: Google Chrome on Citrix deep-dive - Dennis Span
Pingback: Scripting the complete list of Citrix components with PowerShell - Dennis Span
Pingback: Printer Drivers Installation and Troubleshooting Guide - Dennis Span
Pingback: Citrix Delivery Controller unattended installation with PowerShell and SCCM - Dennis Span
Pingback: Citrix License Server unattended installation with PowerShell and SCCM - Dennis Span
Pingback: Citrix Provisioning Server unattended installation - Dennis Span
Pingback: Citrix Director unattended installation with PowerShell - Dennis Span
Pingback: Citrix App Layering Agent unattended installation - Dennis Span
Pingback: How to configure and run BIS-F in an SCCM task sequence - Dennis Span
Pingback: Citrix StoreFront unattended installation with PowerShell - Dennis Span
Pingback: Citrix Receiver unattended installation with PowerShell - Dennis Span
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.
Pingback: Encrypting passwords in a PowerShell script - Dennis Span
Pingback: Citrix Application Probe Agent unattended installation - Dennis Span
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
Hi Lieven, please send me the code snippet or the script to my e-mail (dennis@dennisspan.com). I can take a look at it if you want to.
Bye,
Dennis
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