Orchestrating Automation via PowerShell in GitHub Actions

GitHub transcends its primary identity as a sophisticated user interface for Git repositories by offering integrated features like GitHub Actions. When PowerShell is integrated into this ecosystem, it empowers DevOps teams and IT professionals to automate a vast array of current workflows. This synergy allows for the automation of typical DevOps operations, such as the building and deployment of code, as well as complex administration on enterprise platforms including Microsoft Azure and Microsoft Exchange. By executing PowerShell scripts within GitHub Actions, organizations can orchestrate CI/CD pipeline tasks, programmatically deploy and manage cloud infrastructure, and maintain traditional server-side management tasks.

GitHub Actions serves as a DevOps pipeline tool designed to orchestrate actions centered around a specific code repository. These actions facilitate critical tasks such as code testing, compilation, and deployment, which are typically triggered during a standard development cycle via pull requests or code pushes. Because the platform is fundamentally a code repository, these workflows are defined using YAML (YAML Ain't Markup Language) and are stored as standard files within the repository, ensuring that the automation logic is versioned alongside the application code.

Executing PowerShell within GitHub Workflows

The most efficient method for running PowerShell inside GitHub Actions is to invoke a script or execute inline code using the default action while explicitly specifying the PowerShell shell.

For those requiring the execution of code directly within the YAML configuration file, the following syntax is utilized:

yaml - name: Build Module shell: pwsh run: Invoke-Build -Task ModuleBuild

In this implementation, the shell value is explicitly set to pwsh, which references PowerShell 7 (PowerShell Core). This allows for the execution of arbitrary code, such as the Invoke-Build module used in the example to build a PowerShell module.

When a workflow is executed on a Windows host, users have access to the powershell shell, which specifically refers to Windows PowerShell. The operating system for a job is defined by the runs-on property. For instance, a job configured with runs-on: ubuntu-latest will utilize the latest Ubuntu environment, and any subsequent PowerShell code must be compatible with that environment.

Example of a job configuration:

yaml jobs: PowerShellDemo: name: "PowerShell Demo" runs-on: ubuntu-latest steps: - name: Build Module shell: pwsh run: Invoke-Build -Task ModuleBuild

Advanced Scripting Techniques and Parameterization

For developers dealing with complex logic, GitHub Actions supports multiline scripts. This is achieved by utilizing the pipe character (|) on the run: line, followed by the appropriate indentation for the subsequent script blocks.

Example of a multiline script for file processing:

yaml - name: Get contents of files shell: pwsh run: | foreach ($file in (Get-ChildItem ./path/to/files/*.txt)) { Write-Host "File: $($file.Name)" Get-Content $file.FullName }

To handle highly complex scripts, the recommended architectural approach is to move the logic into a standalone .ps1 file and call that script from the YAML workflow. This improves maintainability and allows for the passage of parameters.

Example of executing an external script with parameters:

yaml - name: Build Module shell: pwsh run: ./build.ps1 -Task ModuleBuild

In this scenario, the build.ps1 script is executed, and the Task parameter is passed the value ModuleBuild, ensuring that the script performs the specific operation required by the pipeline stage.

Managing Pipeline Variables and State

GitHub Actions allows for the dynamic setting of workflow variables, which can be passed between different steps or jobs. This is achieved by writing output in a specific format: ::set-output name=varName::varValue.

In a PowerShell context, this allows a script to read data from a file and export it as a pipeline variable.

Example of setting a pipeline variable from a JSON file:

yaml - name: Set pipeline variable id: set_pipeline_variable shell: pwsh run: | $content = Get-Content ./path/to/file.json Write-Output ::set-output name=jsonData::$content

In the provided example, the script reads the content of a JSON file and assigns that content to the jsonData variable, making it available for subsequent steps in the workflow.

Azure PowerShell Integration and Cloud Automation

Microsoft provides specialized Azure PowerShell actions to streamline the execution of PowerShell commands against Azure resources. This integration is essential for automating cloud infrastructure management.

To initiate this process, a user must create an Azure service principal with the necessary permissions. The resulting credentials must be collected in a JSON format containing the following fields:

  • clientId: A unique GUID for the client.
  • clientSecret: A secure string representing the secret.
  • subscriptionId: The GUID of the Azure subscription.
  • tenantId: The GUID of the Azure tenant.

These credentials should be stored as a GitHub Secret, specifically named AZURE_CREDENTIALS, to prevent sensitive information from being exposed in the YAML files.

The Azure PowerShell action supports a wide range of environments, including the Azure public cloud, Azure Government clouds (such as AzureUSGovernment or AzureChinaCloud), and Azure Stack Hub. Furthermore, the action is compatible with macOS and self-hosted Runners.

Sample workflow for Azure PowerShell:

yaml on: [push] name: AzurePowerShellSample jobs: build: runs-on: ubuntu-latest steps: - name: Login via Az module uses: azure/login@v3 with: creds: ${{secrets.AZURE_CREDENTIALS}} enable-AzPSSession: true - name: Run Azure PowerShell inline script uses: azure/powershell@v3 with: inlineScript: | Get-AzVM -ResourceGroupName "ResourceGroup11" azPSVersion: "latest"

Once the login process is completed via the azure/login action, the azure/powershell action utilizes the same session to execute the specified script.

The Azure PowerShell action provides two optional parameters for fine-tuning execution behavior:

  • errorActionPreference: This defines how the script handles errors. Allowed values are stop, continue, and silentlyContinue. The default value is Stop.
  • failOnStandardError: This parameter determines if the action should fail when something is written to the standard error stream. By default, this is set to false.

Publishing PowerShell Modules and Scripts

For developers creating reusable tools, the natescherer/publish-powershell-action@v1 provides a mechanism to publish PowerShell modules or scripts to various repositories. This action is verified to run on windows-latest, ubuntu-latest, and macos-latest.

The action supports three primary targets: GitHub Packages, the PowerShell Gallery, and NuGet repositories.

Configuration specifications for the publish action:

Name Required Default Description
token true Token used for authentication.
target true Set to packages for GitHub Packages, gallery for PowerShell Gallery, or nuget for NuGet repositories.
path true Path relative to project root. Can be a .psd1 file, .ps1 file, or a directory. If a directory is used, the action searches for .psd1 first, then .ps1.
nugetUrl false The URL for the NuGet v2 or v3 endpoint.

Example implementations for different targets:

Publishing to GitHub Packages:

yaml - name: Publish PowerShell Module uses: natescherer/publish-powershell-action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} target: packages path: src

Publishing to a NuGet Repository:

yaml - name: Publish PowerShell Module uses: natescherer/publish-powershell-action@v1 with: token: ${{ secrets.NUGET_TOKEN }} target: nuget path: src

Publishing to the PowerShell Gallery:

yaml - name: Publish PowerShell Module uses: natescherer/publish-powershell-action@v1 with: token: ${{ secrets.GALLERY_API_KEY }} target: gallery path: src

Comprehensive Example Scenarios and Capabilities

The use of PowerShell in GitHub Actions allows for a wide spectrum of automation patterns. Based on documented examples, these capabilities include:

  • Continuous Integration: Automating the testing and validation of code upon every push.
  • Environment Variables: Managing dynamic data across different pipeline stages.
  • Exit Codes: Using specific return codes to signal success or failure to the GitHub runner.
  • Failures: Implementing custom error handling to trigger pipeline alerts.
  • Inline Execution: Running quick commands directly in the YAML file.
  • Module Management: Utilizing Install-Module to bring in external dependencies and List Installed Modules to verify the environment.
  • Manual Execution: Triggering workflows manually via the GitHub interface.
  • Parameter Handling: Passing dynamic inputs into PowerShell scripts to make them reusable.
  • Secret Management: Utilizing ${{ secrets.VAR_NAME }} to securely handle API keys and credentials.
  • Cross-Platform Support: Executing scripts across Windows, Linux (Ubuntu), and macOS.

Conclusion

The integration of PowerShell into GitHub Actions transforms a simple version control system into a powerful automation engine. By leveraging the pwsh shell for cross-platform compatibility and the powershell shell for Windows-specific tasks, developers can create robust CI/CD pipelines. The ability to interface directly with Microsoft Azure and Exchange through dedicated actions allows for the total automation of cloud infrastructure, from the initial login via service principals to the deployment of virtual machines and the management of enterprise mail systems. Furthermore, the ability to publish modules directly to the PowerShell Gallery or NuGet ensures that the entire lifecycle of a PowerShell project—from development and testing to distribution—is fully automated within the GitHub ecosystem. The shift toward using external .ps1 files for complex logic and the use of ::set-output for variable persistence provides a scalable architecture for any enterprise-grade DevOps operation.

Sources

  1. Automate workflows by running PowerShell in GitHub Actions
  2. pwsh-github-actions Repository
  3. Azure PowerShell Action Marketplace
  4. Publish PowerShell Action Marketplace

Related Posts