Leaning on vmWare PowerCLI for much of my day-to-day system administration needs, I also have need for running PowerCLI scripts regularly. There are many ways to do this, but since I have an OpenShift cluster available, why not run those scripts in containers so you can simply set up a cronjob manifest to run them?
Fortunately, Microsoft released Powershell for Ubuntu, and the PowerCLI cmdlets install and load in it just fine. We’ll run through an example setup, using Ubuntu 22.04 Jammy, Powershell 7.2.5 LTS, and configure some bits to provide auto-login to a VMware cluster.
First, you will require a profile.ps1
. This script is automatically executed on container startup, and will log into a set of one (or more) vCenter servers using the credentials provided in the environment;
Variable | Purpose |
---|---|
VCENTER_SERVER | Comma-delimited list of host vCenters to connect to |
VCENTER_USERNAME | User to connect as, full uid@domain format |
VCENTER_PASSWORD | Password to use to connect |
The profile.ps1
appears below;
# Profile is copied to /profile/.config/powershell/Microsoft.PowerShell_profile.ps1
# Disable history saving for transient containers
Set-PSReadLineOption -HistorySaveStyle SaveNothing
# If vCenter login creds are included, use them
if ($env:VCENTER_SERVER) {
# Username and password must also be included
if ($env:VCENTER_USERNAME -and $env:VCENTER_PASSWORD) {
# Process login to vCenter servers
$secPass = $env:VCENTER_PASSWORD | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $env:VCENTER_USERNAME,$secPass
foreach ($server in ${env:VCENTER_SERVER}.split(",")) { Connect-VIServer -Server $server -Credential $credential }
# Check that we have actually logged into all vCenter servers in the list
if (${env:VCENTER_SERVER}.split(",").Count -ne @($DefaultVIServers).Count) {
Write-Error "ERROR: Did not connect to all vCenter servers requested"
} else {
# Set a global variable to indicate that we are connected to vCenter correctly
$global:VCENTER_CONNECTED=$true
}
} else {
Write-Error "ERROR: vCenter servers provided, usernames and passwords were not"
}
}
# Set a global variable to indicate the default scripts directory
$global:SCRIPTS_DIRECTORY="/profile/scripts"
# End of startup script
Next you’ll need a Dockerfile
, which assumes you have the Powershell install deb in the same directory as it;
#
# Assembles a container image with PowerShell and VMware PowerCLI preinstalled
#
# Based off Ubuntu Jammy
FROM docker.io/library/ubuntu:jammy
# Install required libraries and tools
RUN apt-get update && apt-get install -y \
wget \
libicu70 \
&& rm -rf /var/lib/apt/lists/*
# Define a profile directory, set HOME to it, and make it permission 777
RUN mkdir /profile && chown nobody:nogroup /profile && chmod a+rwx /profile && cd /profile
ENV HOME=/profile
WORKDIR /profile
# Install a specific version of Powershell
ADD powershell-lts_7.2.5-1.deb_amd64.deb /powershell-lts_7.2.5-1.deb_amd64.deb
RUN dpkg -i /powershell-*.deb && rm -f /powershell-*.deb
# Install PowerCLI and configure it
RUN pwsh -nol -noni -Command "Set-PSReadLineOption -HistorySaveStyle SaveNothing"
RUN pwsh -nol -noni -Command "Set-PSRepository -Name PSGallery -InstallationPolicy Trusted"
RUN pwsh -nol -noni -Command "Install-Module VMware.PowerCLI -Scope AllUsers -AcceptLicense -Confirm:\$false"
RUN pwsh -nol -noni -Command "Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP \$false -Confirm:\$false"
RUN pwsh -nol -noni -Command "Set-PowerCLIConfiguration -Scope AllUsers -DefaultVIServerMode Multiple -Confirm:\$false"
# Create a profile directory and put the profile into it
RUN mkdir -p /profile/.config/powershell
ADD profile.ps1 /profile/.config/powershell/Microsoft.PowerShell_profile.ps1
# Reset all permissions on the profile folder
RUN chown -R nobody:nogroup /profile && chmod -R a+rwx /profile
# Configure entrypoint to use PowerShell with no logo
ENTRYPOINT [ "/opt/microsoft/powershell/7-lts/pwsh", "-nol" ]
With that done, you can then build the image however you normally would and make use of it. Your command line should look like -nol -Command "/profile/scripts/your-script.ps1"
.
If you want to bring up a pod on Kubernetes, your manifest will look something like this;
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- args:
- -nol
- -Command
- "/profile/scripts/YOURSCRIPT.ps1"
env:
- name: VCENTER_SERVER
valueFrom:
secretKeyRef:
key: VCENTER_SERVER
name: creds-vcenter
- name: VCENTER_USERNAME
valueFrom:
secretKeyRef:
key: VCENTER_USERNAME
name: creds-vcenter
- name: VCENTER_PASSWORD
valueFrom:
secretKeyRef:
key: VCENTER_PASSWORD
name: creds-vcenter
image: YOURIMAGEGOESHERE:latest
imagePullPolicy: Always
name: test-pod
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 250m
memory: 256Mi
volumeMounts:
- name: scripts-volume
mountPath: /profile/scripts
volumes:
- name: scripts-volume
configMap:
name: script-example-script
dnsPolicy: ClusterFirst
restartPolicy: Never
serviceAccount: default
As should be obvious, you’ll need a secret
named creds-vcenter
holding the required vCenter credentials, and you’ll need to also have a configmap with an entry in it for a filename which contains your file to run.
This functionality should be quite extensible and robust.