← Back to all posts

VMware vRealize SaltStack Config as a Windows Server Admin - Part 9

VMware vRealize SaltStack Config as a Windows Server Admin - Part 9

Part 9: Using salt-api with PowerShell for Windows Server Automation


Update: It was brought to my attention that adding cherypy will break the salt master. After a quick test in my lab I had the same issue with the newest version of SaltStack Config. DO NOT use this blog post until I get a working version in my lab.

If you want to work with the VMware Aria Automation Config API please use this newer Blog Post that I created:

This post is to show how to use PowerShell to make RESTful API calls to SaltStack Config. This is something that I have wanted to do for awhile. I could never find any examples in my Google searches, so I took the time to learn how the examples that use curl work and translated that into PowerShell Code. I hope some Windows Server Admins will find this post helpful. I like using salt to do Windows Server Configuration Management more than remote PowerShell. You can run changes against many servers at the exact same time instead of looping thru a list of servers names.

I am also going to look at use salt-api with vRealize Automation ABX action scripts.

In some previous posts I used the POSH-SSH module but when you use the salt-api, the PowerShell Module POSH-SSH is no longer needed.


Configuration Changes to the SaltStack Config Server:

My SaltStack Config Server (SSC) is what VMware provides when using Life Cycle Manager (LCM) running Photon OS.

The following steps are what I needed to do in my Lab environment from the SSC CLI to enable salt-api:


* Always make sure you have a good snap | backup before making any changes to SSC Server


  • Install CherryPy:
  • pip3 install cherrypy
  • Install the PyOpenSSL package:
  • pip3 install pyopenssl
  • Generate a self-signed certificate:
  • salt-call --local tls.create_self_signed_cert
  • open firewall port 8000:
  • iptables -A INPUT -i eth0 -p tcp --dport 8000 -j ACCEPT
  • Edit /etc/salt/master file:
  • vi /etc/salt/master

Add these lines to the /etc/salt/master file:

external_auth:
  pam:
    root:
      - .*

rest_cherrypy:
  port: 8000
  ssl_crt: /etc/pki/tls/certs/localhost.crt
  ssl_key: /etc/pki/tls/certs/localhost.key
  • Restart salt-master and check service status for any errors:
  • systemctl restart salt-master
    systemctl status salt-master
  • Enable | Start salt-api and check service status for any errors:
  • systemctl enable salt-api
    systemctl start salt-api
    systemctl status salt-api

Tests to make sure SaltStack Config Changes are working:

  • I did all this PowerShell code from my mac. To use self-signed certs I use -SkipCertificateCheck. On a Windows OS the code is different.
  • # --- PowerShell Code ---
    Invoke-WebRequest -Uri 'https://192.168.86.141:8000' -SkipCertificateCheck
    
    Results:
    
    StatusCode        : 200
    StatusDescription : OK
    Content           : {"return": "Welcome", "clients": ["local", "local_async", "local_batch", "local_subset", "runner", "runner_async", "ssh", "wheel", "wheel_async"]}
    RawContent        : HTTP/1.1 200 OK
                        Server: CherryPy/8.9.1
                        Date: Sat, 11 Jun 2022 20:57:46 GMT
                        Access-Control-Allow-Origin: *
                        Access-Control-Expose-Headers: GET, POST
                        Access-Control-Allow-Credentials: true
                        Vary: Accept-E…
    Headers           : {[Server, System.String[]], [Date, System.String[]], [Access-Control-Allow-Origin, System.String[]], [Access-Control-Expose-Headers, 
                        System.String[]]…}
    Images            : {}
    InputFields       : {}
    Links             : {}
    RawContentLength  : 146
    RelationLink      : {}
  • Make sure you see StatusCode: 200
  • Next step is to make sure you get a token:
  • # --- PowerShell Code ---
    # --- In my code I show the PassWord. In Production DO NOT DO THIS.
    # --- There are so many different ways to include encrypted PWs in the code. 
    # --- Use what works best in your environment.
    
    $saltServerAddress = 'https://192.168.86.110:8000'
    
    # --- Set the json body
    $body = '{ "username": "root","password": "HackMe!","eauth": "pam"}'
    
    # --- Fetch New Token from salt master
    $url = "$saltServerAddress/login"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    $fetch
    $fetch.return.token
    
    Results:
    
    return
    ------
    {@{token=6696846c802f78d5326a69b79d36e95015d37f5a; expire=1655025071.22838; start=1654981871.22838; user=root; eauth=pam; perms=System.Object[]}}
    6696846c802f78d5326a69b79d36e95015d37f5a
  • You will see "token=" in the return data

PowerShell API Code Examples:

  • Run a test.ping
  • # --- PowerShell Code ---
    $minionName        = '2019DC'
    $saltServerAddress = 'https://192.168.86.110:8000'
    $userName          = 'root'
    $password          = 'HackMe!'
    $fun               = 'test.ping'
    $fetch             = ''
    
    # --- Set the json body
    $body = '{ "username": "' + $userName + '","password": "' + $password + '","eauth": "pam","tgt": "' + $minionName + '","fun": "' + $fun + '","client": "local"}'
    
    # --- Create RESTful API Request
    $url = "$saltServerAddress/run"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    # --- Showing different ways to show the return data
    #$fetch
    $fetch.return
    $fetch.return.$minionName
  • Check disk.usage
  • # --- PowerShell Code ---
    $minionName        = '2019DC'
    $saltServerAddress = 'https://192.168.86.110:8000'
    $userName          = 'root'
    $password          = 'HackMe!'
    $fun               = 'disk.usage' # -salt function
    $fetch             = ''
    
    # --- Set the json body
    $body = '{ "username": "' + $userName + '","password": "' + $password + '","eauth": "pam","tgt": "' + $minionName + '","fun": "' + $fun + '","client": "local"}'
    
    # --- Create RESTful API Request
    $url = "$saltServerAddress/run"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    # --- Showing different ways to show the return data
    $fetch.return
    $fetch.return.$minionName
    $fetch.return.$minionName.'C:\'
    $fetch.return.$minionName.'C:\'.capacity
  • Check Service Status
  • # --- PowerShell Code ---
    $minionName        = '2019DC'
    $saltServerAddress = 'https://192.168.86.110:8000'
    $userName          = 'root'
    $password          = 'HackMe!'
    $fun               = 'service.status' # -salt function
    $arg               = 'spooler' # -Service Name
    $fetch             = ''
    
    # --- Set the json body
    $body = '{"username": "' + $userName + '","password": "' + $password + '","eauth": "pam","tgt": "' + $minionName + '","fun": "' + $fun + '","arg": "' + $arg + '","client": "local"}'
    
    # --- Create RESTful API Request
    $url = "$saltServerAddress/run"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    # --- Service Status | True = Running | False = Stopped
    $fetch.return.$minionName
  • Stop Service
  • # --- PowerShell Code ---
    $minionName        = '2019DC'
    $saltServerAddress = 'https://192.168.86.110:8000'
    $userName          = 'root'
    $password          = 'HackMe!'
    $fun               = 'service.stop' # -salt function
    $arg               = 'spooler' # -Service Name
    $fetch             = ''
    
    # --- Set the json body
    $body = '{"username": "' + $userName + '","password": "' + $password + '","eauth": "pam","tgt": "' + $minionName + '","fun": "' + $fun + '","arg": "' + $arg + '","client": "local"}'
    
    # --- Create RESTful API Request
    $url = "$saltServerAddress/run"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    # --- Service Stopped | True = Stopped | False = Not Stopped
    $fetch.return.$minionName
  • Disable Service
  • # --- PowerShell Code ---
    $minionName        = '2019DC'
    $saltServerAddress = 'https://192.168.86.110:8000'
    $userName          = 'root'
    $password          = 'HackMe!'
    $fun               = 'service.disable' # -salt function
    $arg               = 'spooler' # -Service Name
    $fetch             = ''
    
    # --- Set the json body
    $body = '{"username": "' + $userName + '","password": "' + $password + '","eauth": "pam","tgt": "' + $minionName + '","fun": "' + $fun + '","arg": "' + $arg + '","client": "local"}'
    
    # --- Create RESTful API Request
    $url = "$saltServerAddress/run"
    
    $Params = @{
        Method = "Post"
        Uri = $url
        Body = $Body
        ContentType = "application/json"
    }
    $fetch = Invoke-RestMethod @Params -SkipCertificateCheck
    
    # --- Service Disabled | True = Disabled | False = Not Disabled
    $fetch.return.$minionName
  • I hope the code was helpful to get started.

Lessons Learned:

  • OOTB (Out of the Box) a SaltStack Config Server is NOT setup to use CherryPY to use api calls.
  • Using PowerShell Invoke-RestMethod is a great way to automate SaltStack Config.
  • The more I use salt with Windows Servers the more I like how it works. So fast. Many different ways to do automation | configuration Management.
  • To get the proper args for a salt function I always test from the CLI.
  • SaltStack REST_CHERRYPY Documentation
  • SaltStack EXTERNAL AUTHENTICATION SYSTEM Documentation

Salt Links I found to be very helpful:

When I write about vRealize Automation ("vRA") I always say there are many ways to accomplish the same task. SaltStack Config is the same way. I am showing what I felt was important to see but every organization/environment will be different. There is no right or wrong way to use Salt. This is a GREAT Tool that is included with your vRealize Suite Advanced/Enterprise license. If you own the vRealize Suite, you own SaltStack Config.


  • If you found this Blog article useful and it helped you, Buy me a coffee to start my day.