Usage
After completing the configuration and initialization, you can use the Salt
package manager commands to manage software on Windows minions.
Note
The following example commands can be run from the master using salt
or
on a masterless minion using salt-call
|
Command |
Description |
1 |
pkg.list_pkgs |
Displays a list of all packages installed in the system. |
2 |
pkg.list_available |
Displays the versions available of a particular package to be installed. |
3 |
pkg.install |
Installs a given package. |
4 |
pkg.remove |
Uninstalls a given package. |
List installed packages
Use pkg.list_pkgs
to display a list of
packages installed on the system.
# From the master
salt -G 'os:windows' pkg.list_pkgs
# From the minion in masterless mode
salt-call --local pkg.list_pkgs
The command displays the software name and the version for every package
installed on the system irrespective of whether it was installed by the Salt
package manager.
local:
----------
Frhed 1.6.0:
1.6.0
GNU Privacy Guard:
2.2.16
Gpg4win (3.1.9):
3.1.9
git:
2.17.1.2
nsis:
3.03
python3_x64:
3.7.4150.0
salt-minion-py3:
2019.2.3
The software name indicates whether the software is managed by Salt or not.
If Salt finds a match in the winrepo database, then the software name is the
short name as defined in the package definition file. It is usually a
single-word, lower-case name.
All other software names are displayed as the full name as shown in
Add/Remove Programs. In the above example, Git (git), Nullsoft Installer (nsis),
Python 3.7 (python3_x64), and Salt (salt-minion-py3) have corresponding package
definition files and are managed by Salt, while Frhed 1.6.0, GNU Privacy guard,
and GPG4win are not.
List available versions
Use pkg.list_available
to display
a list of versions of a package available for installation. You can pass the
name of the software in the command. You can refer to the software by its
name
or its full_name
surrounded by quotes.
# From the master
salt winminion pkg.list_available firefox_x64
# From the minion in masterless mode
salt-call --local pkg.list_available firefox_x64
The command lists all versions of Firefox available for installation.
winminion:
- 69.0
- 69.0.1
- 69.0.2
- 69.0.3
- 70.0
- 70.0.1
- 71.0
- 72.0
- 72.0.1
- 72.0.2
- 73.0
- 73.0.1
- 74.0
Note
For a Linux master, you can surround the file name with single quotes.
However, for the cmd
shell on Windows, use double quotes when wrapping
strings that may contain spaces. Powershell accepts either single quotes or
double quotes.
Install a package
Use pkg.install
: to install a package.
# From the master
salt winminion pkg.install 'firefox_x64'
# From the minion in masterless mode
salt-call --local pkg.install "firefox_x64"
The command installs the latest version of Firefox.
# From the master
salt winminion pkg.install 'firefox_x64' version=74.0
# From the minion in masterless mode
salt-call --local pkg.install "firefox_x64" version=74.0
The command installs version 74.0 of Firefox.
If a different version of the package is already installed, then the old version
is replaced with the version in the winrepo (only if the package supports live
updating).
You can also specify the full name of the software while installing:
# From the master
salt winminion pkg.install 'Mozilla Firefox 17.0.1 (x86 en-US)'
# From the minion in masterless mode
salt-call --local pkg.install "Mozilla Firefox 17.0.1 (x86 en-US)"
Remove a package
Use pkg.remove
to remove a package.
# From the master
salt winminion pkg.remove firefox_x64
# From the minion in masterless mode
salt-call --local pkg.remove firefox_x64
Package definition file directory structure and naming
All package definition files are stored in the location configured in the
winrepo_dir_ng
setting. All files in this directory with a .sls
file
extension are considered package definition files. These files are evaluated to
create the metadata file on the minion.
You can maintain standalone package definition files that point to software on
other servers or on the internet. In this case the file name is the short name
of the software with the .sls
extension, for example,``firefox.sls``.
You can also store the binaries for your software together with their software
definition files in their own directory. In this scenario, the directory name
is the short name for the software and the package definition file stored that
directory is named init.sls
.
Look at the following example directory structure on a Linux master assuming
default config settings:
srv/
|---salt/
| |---win/
| | |---repo-ng/
| | | |---custom_defs/
| | | | |---ms_office_2013_x64/
| | | | | |---access.en-us/
| | | | | |---excel.en-us/
| | | | | |---outlook.en-us/
| | | | | |---powerpoint.en-us/
| | | | | |---word.en-us/
| | | | | |---init.sls
| | | | | |---setup.dll
| | | | | |---setup.exe
| | | | |---openssl.sls
| | | | |---zoom.sls
| | | |---salt-winrepo-ng/
| | | | |---auditbeat/
| | | | | |---init.sls
| | | | | |---install.cmd
| | | | | |---install.ps1
| | | | | |---remove.cmd
| | | | |---gpg4win/
| | | | | |---init.sls
| | | | | |---silent.ini
| | | | |---7zip.sls
| | | | |---adobereader.sls
| | | | |---audacity.sls
| | | | |---ccleaner.sls
| | | | |---chrome.sls
| | | | |---firefox.sls
In the above directory structure:
Warning
Do not modify the files in the salt-winrepo-ng
directory as it breaks
future runs of winrepo.update_git_repos
.
Warning
Do not place any custom software definition files in the salt-winrepo-ng
directory as the winrepo.update_git_repos
command wipes out the contents
of the salt-winrepo-ng
directory each time it is run and any extra files
stored in the Salt winrepo are lost.
Writing package definition files
You can write your own software definition file if you know:
The full name of the software as shown in Add/Remove Programs
The exact version number as shown in Add/Remove Programs
How to install your software silently from the command line
Here is a YAML software definition file for Firefox:
firefox_x64:
'74.0':
full_name: Mozilla Firefox 74.0 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en-US/Firefox%20Setup%2074.0.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'73.0.1':
full_name: Mozilla Firefox 73.0.1 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en-US/Firefox%20Setup%2073.0.1.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
The package definition file itself is a data structure written in YAML with
three indentation levels:
The first level item is a short name that Salt uses to reference the software.
This short name is used to install and remove the software and it must be
unique across all package definition files in the repo. Also, there must be
only one short name in the file.
The second level item is the version number. There can be multiple version
numbers for a package but they must be unique within the file.
Note
When running pkg.list_pkgs
, the short name and version number are
displayed when Salt finds a match in the repo. Otherwise, the full package
name is displayed.
Example package definition files
This section provides some examples of package definition files for different
use cases such as:
These examples enable you to gain a better understanding of the usage of
different file parameters. To understand the examples, you need a basic
Understanding Jinja.
For an exhaustive dive into Jinja, refer to the official
Jinja Template Designer documentation.
Example: Simple
Here is a pure YAML example of a simple package definition file for Firefox:
firefox_x64:
'74.0':
full_name: Mozilla Firefox 74.0 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en-US/Firefox%20Setup%2074.0.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'73.0.1':
full_name: Mozilla Firefox 73.0.1 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en-US/Firefox%20Setup%2073.0.1.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
The first line is the short name of the software which is firefox_x64
.
Important
The short name must be unique across all other short names in the software
repository. The full_name
combined with the version must also be unique.
The second line is the software version
and is indented two spaces.
Important
The version number must be enclosed in quotes or the YAML parser removes the
trailing zeros. For example, if the version number 74.0
is not enclosed
within quotes, then the version number is rendered as 74
.
The lines following the version
are indented two more spaces and contain all
the information needed to install the Firefox package.
Important
You can specify multiple versions of software by specifying multiple version
numbers at the same indentation level as the first with its software
definition below it.
Important
The full_name
must match exactly what is shown in Add/Remove Programs
(appwiz.cpl
)
Example: JINJA templated package definition file
JINJA is the default templating language used in package definition files. You
can use JINJA to add variables and expressions to package definition files that
get replaced with values when the .sls
go through the Salt renderer.
When there are tens or hundreds of versions available for a piece of software,
the definition file can become large and cumbersome to maintain. In this
scenario, JINJA can be used to add logic, variables, and expressions to
automatically create the package definition file for software with multiple
versions.
Here is a an example of a package definition file for Firefox that uses JINJA:
{%- set lang = salt['config.get']('firefox:pkg:lang', 'en-US') %}
firefox_x64:
{% for version in ['74.0',
'73.0.1', '73.0',
'72.0.2', '72.0.1', '72.0',
'71.0', '70.0.1', '70.0',
'69.0.3', '69.0.2', '69.0.1'] %}
'{{ version }}':
full_name: 'Mozilla Firefox {{ version }} (x64 {{ lang }})'
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/{{ version }}/win64/{{ lang }}/Firefox%20Setup%20{{ version }}.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles%\Mozilla Firefox\uninstall\helper.exe'
uninstall_flags: '/S'
{% endfor %}
In this example, JINJA is used to generate a package definition file that
defines how to install 12 versions of Firefox. Jinja is used to create a list of
available versions. The list is iterated through a for loop
where each
version is placed in the version
variable. The version is inserted
everywhere there is a {{ version }}
marker inside the for loop
.
The single variable (lang
) defined at the top of the package definition
identifies the language of the package. You can access the Salt modules using
the salt
keyword. In this case, the config.get
function is invoked to
retrieve the language setting. If the lang
variable is not defined then the
default value is en-US
.
Example: Package definition file to install the latest version
Some software vendors do not provide access to all versions of their software.
Instead, they provide a single URL to what is always the latest version. In some
cases, the software keeps itself up to date. One example of this is the Google
Chrome web browser.
To handle situations such as these, set the version to latest. Here's an
example of a package definition file to install the latest version of Chrome.
chrome:
latest:
full_name: 'Google Chrome'
installer: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi'
install_flags: '/qn /norestart'
uninstaller: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
In the above example:
Version
is set to latest
. Salt then installs the latest version of
Chrome at the URL and displays that version.
msiexec
is set to True
, hence the software is installed using an MSI.
Example: Package definition file to install an MSI patch
For MSI installers, when the msiexec
parameter is set to true, the /i
option is used for installation, and the /x
option is used for
uninstallation. However, when installing an MSI patch, the /i
and /x
options cannot be combined.
Here is an example of a package definition file to install an MSI patch:
MyApp:
'1.0':
full_name: MyApp
installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi'
install_flags: '/qn /norestart'
uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}'
uninstall_flags: '/qn /norestart'
msiexec: True
'1.1':
full_name: MyApp
installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi'
install_flags: '/qn /norestart /update "%cd%\\MyApp.1.1.msp" '
uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}'
uninstall_flags: '/qn /norestart'
msiexec: True
cache_file: salt://win/repo-ng/MyApp/MyApp.1.1.msp
In the above example:
Version 1.0
of the software installs the application using the 1.0
MSI defined in the installer
parameter.
There is no file to be cached and the install_flags
parameter does not
include any special values.
Version 1.1
of the software uses the same installer file as Version
1.0
. Now, to apply a patch to Version 1.0, make the following changes in
the package definition file:
Place the patch file (MSP file) in the same directory as the installer file
(MSI file) on the file_roots
In the cache_file
parameter, specify the path to the single patch file.
In the install_flags
parameter, add the /update
flag and include the
path to the MSP file using the %cd%
environment variable. %cd%
resolves to the current working directory, which is the location in the minion
cache where the installer file is cached.
For more information, see issue #32780.
The same approach could be used for applying MST files for MSIs and answer files
for other types of .exe-based installers.
Parameters
This section describes the parameters placed under the version
in the
package definition file. Examples can be found on the Salt winrepo repository.
full_name (str)
The full name of the software as shown in "Add/Remove Programs". You can also
retrieve the full name of the package by installing the package manually and
then running pkg.list_pkgs
. Here's an example of the output from
pkg.list_pkgs
:
salt 'test-2008' pkg.list_pkgs
test-2008
----------
7-Zip 9.20 (x64 edition):
9.20.00.0
Mozilla Firefox 74.0 (x64 en-US)
74.0
Mozilla Maintenance Service:
74.0
salt-minion-py3:
3001
Notice the full Name for Firefox: Mozilla Firefox 74.0 (x64 en-US)
. The
full_name
parameter in the package definition file must match this name.
The example below shows the pkg.list_pkgs
for a machine that has Mozilla
Firefox 74.0 installed with a package definition file for that version of
Firefox.
test-2008:
----------
7zip:
9.20.00.0
Mozilla Maintenance Service:
74.0
firefox_x64:
74.0
salt-minion-py3:
3001
On running pkg.list_pkgs
, if any of the software installed on the machine
matches the full name defined in any one of the software definition files in the
repository, then the package name is displayed in the output.
Important
The version number and full_name
must match the output of
pkg.list_pkgs
so that the installation status can be verified by the
state system.
Note
You can successfully install packages using pkg.install
, even if the
full_name
or the version number doesn't match. The module will complete
successfully, but continue to display the full name in pkg.list_pkgs
.
If this is happening, verify that the full_name
and the version
match exactly what is displayed in Add/Remove Programs.
Tip
To force Salt to display the full name when there's already an existing
package definition file on the system, you can pass a bogus saltenv
parameter to the command like so: pkg.list_pkgs saltenv=NotARealEnv
Tip
It's important use pkg.refresh_db
to check for errors and ensure the latest package definition is on any
minion you're testing new definitions on.
installer (str)
The path to the binary (.exe
, .msi
) that installs the package.
This can be a local path or a URL. If it is a URL or a Salt path (salt://
),
then the package is cached locally and then executed. If it is a path to a file
on disk or a file share, then it is executed directly.
Note
When storing software in the same location as the winrepo:
Note
The pkg.refresh_db
command processes all .sls
files in all sub
directories in the winrepo_dir_ng
directory.
install_flags (str)
The flags passed to the installer for silent installation.
You may be able to find these flags by adding /?
or /h
when running the
installer from the command line. See WPKG project wiki for information on silent install flags.
Warning
Always ensure that the installer has the ability to install silently,
otherwise Salt appears to hang while the installer waits for user input.
uninstaller (str)
The path to the program to uninstall the software.
This can be the path to the same .exe
or .msi
used to install the
software. If you use a .msi
to install the software, then you can either
use the GUID of the software or the same .msi
to uninstall the software.
You can find the uninstall information in the registry:
Here's an example that uses the GUID to uninstall software:
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo-ng/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: '{23170F69-40C1-2702-0920-000001000000}'
uninstall_flags: '/qn /norestart'
msiexec: True
Here's an example that uses the MSI installer to uninstall software:
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo-ng/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: salt://win/repo-ng/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
msiexec: True
uninstall_flags (str)
The flags passed to the uninstaller for silent uninstallation.
You may be able to find these flags by adding /?
or /h
when running the
uninstaller from the command-line. See WPKG project wiki for information on silent uninstall flags.
Warning
Always ensure that the installer has the ability to uninstall silently,
otherwise Salt appears to hang while the uninstaller waits for user input.
msiexec (bool, str)
This setting informs Salt to use msiexec /i
to install the package and msiexec /x
to uninstall. This setting only applies to .msi
installations.
Possible options are:
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: salt://win/repo/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
msiexec: 'C:\Windows\System32\msiexec.exe'
allusers (bool)
This parameter is specific to .msi
installations. It tells msiexec
to
install the software for all users. The default is True
.
cache_dir (bool)
This setting requires the software to be stored on the file_roots
and only
applies to URLs that begin with salt://
. If set to True
, then the
entire directory where the installer resides is recursively cached. This is
useful for installers that depend on other files in the same directory for
installation.
Warning
If set to True
, then all files and directories in the same location as
the installer file are copied down to the minion. For example, if you place
your package definition file with cache_dir: True
in the root of winrepo
(/srv/salt/win/repo-ng
) then the entire contents of winrepo is cached to
the minion. Therefore, it is best practice to place your package definition
file along with its installer files in a subdirectory if they are stored in
winrepo.
Here's an example using cache_dir:
sqlexpress:
'12.0.2000.8':
full_name: Microsoft SQL Server 2014 Setup (English)
installer: 'salt://win/repo/sqlexpress/setup.exe'
install_flags: '/ACTION=install /IACCEPTSQLSERVERLICENSETERMS /Q'
cache_dir: True
cache_file (str)
This setting requires the file to be stored on the file_roots
and only
applies to URLs that begin with salt://
. It indicates that the single file
specified is copied down for use with the installer. It is copied to the same
location as the installer. Use this setting instead of cache_dir
when you
only need to cache a single file.
use_scheduler (bool)
If set to True
, Windows uses the task scheduler to run the installation. A
one-time task is created in the task scheduler and launched. The return to the
minion is that the task was launched successfully, not that the software was
installed successfully.
Note
This is used in the package definition for Salt itself. The first thing the
Salt installer does is kill the Salt service, which then kills all child
processes. If the Salt installer is launched via Salt, then the installer
is killed with the salt-minion service, leaving Salt on the machine but not
running. Using the task scheduler allows an external process to launch the
Salt installer so its processes aren't killed when the Salt service is
stopped.
source_hash (str)
This setting informs Salt to compare a hash sum of the installer to the provided
hash sum before execution. The value can be formatted as <hash_algorithm>=<hash_sum>
,
or it can be a URI to a file containing the hash sum.
For a list of supported algorithms, see the hashlib documentation.
Here's an example using source_hash
:
messageanalyzer:
'4.0.7551.0':
full_name: 'Microsoft Message Analyzer'
installer: 'salt://win/repo/messageanalyzer/MessageAnalyzer64.msi'
install_flags: '/quiet /norestart'
uninstaller: '{1CC02C23-8FCD-487E-860C-311EC0A0C933}'
uninstall_flags: '/quiet /norestart'
msiexec: True
source_hash: 'sha1=62875ff451f13b10a8ff988f2943e76a4735d3d4'
Not Implemented
The following parameters are often seen in the software definition files hosted
on the Git repo. However, they are not implemented and do not affect the
installation process.
- param bool reboot:
Not implemented
- param str locale:
Not implemented
pygit2 / GitPython Support for Maintaining Git Repos
pygit2 and GitPython are the supported python interfaces to Git. The runner
winrepo.update_git_repos
uses the
same underlying code as Git Fileserver Backend and
Git External Pillar
to maintain and update its
local clones of git repositories.
Note
If compatible versions of both pygit2 and GitPython are installed, then
Salt will prefer pygit2. To override this behavior use the
winrepo_provider
configuration parameter, ie:
winrepo_provider: gitpython
Maintaining Git repos
A clean
argument is added to the
winrepo.update_git_repos
runner to maintain the Git repos. When clean=True
the runner removes
directories under the winrepo_dir_ng
/winrepo_dir_ng
that are not explicitly configured. This eliminates the need to manually remove
these directories when a repo is removed from the config file.
salt-run winrepo.update_git_repos clean=True
If a mix of git and non-git Windows Repo definition files are used, then
do not pass clean=True
, as it removes the directories containing non-git
definitions.