Salt execution modules and states for administering Windows systems, maintained by Alkivi.
These modules cover ground the official win_* catalogue does not: BitLocker volume state, Azure AD account reconciliation, hotfix history with release dates, IIS management, workstation provisioning, and a declarative layer over the Windows Firewall.
All modules are Windows-only — __virtual__ returns False on any other platform, so they are safe to sync to a mixed fleet.
modules/ execution modules -> deploy as _modules/
states/ state modules -> deploy as _states/
Directories are deliberately named without the leading underscore so the repository can be vendored as a submodule and symlinked into a Salt fileserver root (see Installation).
Note that the file name is not the invocation name: each module declares a __virtualname__, and that is what you call.
| File | Call it as | Purpose |
|---|---|---|
modules/alkivi_win_firewall.py |
alkivi_win_firewall |
Windows Firewall rules and profiles, via PowerShell/NetSecurity |
modules/win_bitlocker.py |
bitlocker |
BitLocker volume status and recovery key handling |
modules/win_azuread.py |
azuread |
Reconcile an Azure AD account export against pillar users |
modules/win_updates.py |
win_updates |
Installed hotfix history, enriched with release dates |
modules/win_iis.py |
win_iis |
IIS sites and application pools |
modules/win_install.py |
install |
Windows workstation provisioning |
modules/win_collect.py |
collect |
Drive letters to include in backups |
states/win_firewall_rule.py |
win_firewall_rule |
Declarative Windows Firewall rules |
- A Windows minion.
- PowerShell. Most modules shell out to it;
bitlockerchecks for it explicitly in__virtual__and refuses to load otherwise. - The
NetSecuritymodule (ships with Windows 8/2012 and later) for thealkivi_win_firewall.ps_*functions and thewin_firewall_rulestate. win_updates.historyneeds outbound HTTPS tosupport.microsoft.com(see Limitations).
This is how the repository is consumed in Alkivi's Salt tree, and why modules/ and states/ carry no underscore:
git submodule add git@github.com:alkivi-sas/salt-windows.git github/salt-windows
ln -s ../github/salt-windows/modules/win_bitlocker.py _modules/win_bitlocker.py
ln -s ../github/salt-windows/states/win_firewall_rule.py _states/win_firewall_rule.py
# ... one symlink per module you want to exposeSymlinking per file lets each Salt tree expose only the modules it needs.
cp modules/*.py /srv/salt/_modules/
cp states/*.py /srv/salt/_states/Either way, sync to the minions:
salt 'win-*' saltutil.sync_allTwo generations of functions coexist. The ps_* functions drive PowerShell/NetSecurity cmdlets and are the ones to use. The older add_rule / add_ping_rule shell out to netsh and are kept for backwards compatibility with existing states.
# Profiles (Domain / Private / Public)
salt 'win-*' alkivi_win_firewall.get_config
# List rules
salt 'win-*' alkivi_win_firewall.ps_get_rules
salt 'win-*' alkivi_win_firewall.ps_get_rules enabled=True direction=outgoing
salt 'win-*' alkivi_win_firewall.ps_get_rule display_name='My Rule'
# Create, modify, delete
salt 'win-*' alkivi_win_firewall.ps_add_rule 'HTTP' direction=Inbound protocol=TCP local_port=80
salt 'win-*' alkivi_win_firewall.ps_set_rule display_name='HTTP' enabled=False
salt 'win-*' alkivi_win_firewall.ps_del_rule display_name='Old rule'
# Bulk delete by substring — wildcards are escaped and matched literally
salt 'win-*' alkivi_win_firewall.ps_del_rule display_name_contains='(mDNS-In)'ps_del_rule returns the list of rules it deleted (Name, DisplayName, DisplayGroup, Group), or an empty list when nothing matched.
Rules are identified by DisplayName. Only the parameters you actually declare are compared and updated — anything you leave out is preserved on an existing rule. Defaults apply solely at creation time.
allow_http:
win_firewall_rule.present:
- name: HTTP
- direction: Inbound
- protocol: TCP
- local_port: 80
- action: Allow
sip_ports:
win_firewall_rule.present:
- name: SIP
- protocol: UDP
- local_port:
- 5060
- "40000-60000"
- remote_address:
- 192.168.0.0/24
- 10.0.0.0/8
remove_legacy_rule:
win_firewall_rule.absent:
- name: OldRuleNameValues are normalised before comparison, so the state stays idempotent across cosmetic differences:
- Port and address lists compare as unordered sets — YAML order does not matter.
- A scalar and a single-element list are equivalent.
- Subnets are canonicalised, so
51.83.58.98/28and51.83.58.96/255.255.255.240are recognised as the same network and do not produce perpetual changes.
test=True is supported and reports which keys would change.
salt 'win-*' bitlocker.get_status
salt 'win-*' bitlocker.get_status 'D:'
salt 'win-*' bitlocker.get_recovery_key
salt 'win-*' bitlocker.resume_protectionsync_recovery_key reads the recovery password and publishes it on the Salt event bus as alkivi/password/set, rather than writing to a directory from the minion. The minion therefore needs no directory credentials; archiving is the master's responsibility, via a reactor bound to that event.
salt 'win-*' bitlocker.sync_recovery_keyRecovery keys are sensitive. get_recovery_key returns one in cleartext to the caller, and sync_recovery_key puts one on the event bus — restrict who can run these and who can subscribe to the bus.
salt 'win-*' win_updates.historyReturns installed hotfixes (HotFixID, Description, InstalledOn) from Get-Hotfix, each enriched with the ReleaseDate scraped from its KB page — which is what lets you reason about patch lag rather than just presence.
salt 'win-*' azuread.matches 'C:\path\to\accounts.xml'Parses an XML export of Azure AD accounts and matches it against the users pillar by display name, returning SourceAccount / TargetAccount pairs. Accounts whose display name contains alkivi, and UPNs containing package, are skipped. Working from an export rather than Microsoft Graph keeps token handling out of the minion.
salt 'win-*' win_iis.list_sites
salt 'win-*' win_iis.create_site name='MySite' protocol='http' sourcepath='C:\inetpub\mysite' port=80
salt 'win-*' win_iis.remove_site 'MySite'
salt 'win-*' win_iis.list_apppools
salt 'win-*' win_iis.create_apppool 'MyPool'
salt 'win-*' win_iis.remove_apppool 'MyPool'Workstation provisioning helpers, each covering one step of an Alkivi Windows build: users, system, clean_mcafee, clean_dell, openvpn, firewall, zabbix, backup, ninite, office365, network_credentials.
These are opinionated and tailored to Alkivi's build — read the function before running it, and expect to adapt it to your own environment.
salt 'win-*' collect.disksbitlockeris read-mostly. It reports status, retrieves the recovery key and resumes protection. It does not enable encryption or rotate keys.- PowerShell enums do not survive
ConvertTo-Jsonas text. They serialise numerically, so state read back from PowerShell needs normalising before it can be compared against a target expressed in business terms.alkivi_win_firewallhandles this by casting enums to strings in the PowerShell layer; be aware of it if you extend these modules.bitlocker.get_statusreturns values as PowerShell serialises them, and does not normalise them. win_updates.historydepends on an external page. Release dates come from scrapingsupport.microsoft.com; the field falls back to"Release date not found"when the page is unreachable or its markup changes. It also issues one HTTP request per installed hotfix, so it is slow on a well-patched host.azuread.matchesmatches on a display-name substring, which can pair the wrong accounts when names are similar. Review its output before acting on it.collectis a common virtual name. If another Salt tree already provides acollectmodule, the two will collide — expose this one only where you need it.
Match the surrounding style: modules are Windows-gated through __virtual__, PowerShell values are escaped with the module's _ps_escape* helpers rather than by string interpolation, and states must honour __opts__['test'] and report accurate changes.
Not yet specified. Contact Alkivi before redistributing.