Powershell on GitHub Actions - run Script as Admin on self-hosted Windows Runners
This came up when I wanted to run a powershell script with elevated Administrator
privileges , sometimes on my dev laptop and sometimes in a CI/CD process.
Running a script as an Administrator
like that should alert you to proceed with caution.
As for CI/CD, I’m using GitHub Actions that run on self-hosted runners on Windows. That means that I need somehow to see script’s output in stdout.
The PowerShell Script
The script executes a command that requires admin rights. It’s stored in the application’s git repository.
1
2
3
4
5
6
7
8
9
10
11
12
# RunAsAdmin.ps1
$LocalTestDir="C:\var\test"
if (Test-Path $LocalTestDir -PathType Container) {
Write-Host "$LocalTestDir exists"
}
else {
New-Item $LocalTestDir -ItemType Directory
}
Set-Content "$LocalTestDir\test.txt" 'Hello World'
Get-Content "$LocalTestDir\test.txt"
[System.IO.Directory]::GetAccessControl("\\.\pipe\docker_engine") | Format-Table
GitHub Actions workflow
The GitHub Action checks out the repository to access RunAsAdmin.ps1
, executes the script, and checks the results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
name: Run as admin test
on:
push:
branches:
- test-run-as-admin
jobs:
run-as-admin-test:
runs-on: [self-hosted, windows]
steps:
- name: Checkout repo
uses: actions/checkout@v2 # repo contains the RunAsAdmin.ps1
- name: Run as Admin
run: |
whoami
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
echo "myWindowsID=$myWindowsID"
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
echo "myWindowsPrincipal=$myWindowsPrincipal"
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
New-Item -Path "$LocalTestDir\sysout.txt -ItemType File
if ($myWindowsPrincipal.IsInRole($adminRole)) `
{
echo "is admin"
} `
else { `
echo "is not admin"; `
$passThruArgs = '-NoProfile -ExecutionPolicy Bypass -command', '&', "$env:GITHUB_WORKSPACE\RunAsAdmin.ps1", $arg, '*>', "`"$LocalTestDir\sysout.txt`""; `
Start-Process powershell -Wait -Verb RunAs -ArgumentList $passThruArgs; `
Get-Content "$LocalTestDir\sysout.txt"; `
}`
dir "C:\var"
- name: check
run: dir "C:\var"
With GitHub’s ephemeral runners, the run environment and context, including the filesystem on which the job runs, disappears. The check
step works because it’s within the same job
.
If you’d like to access C:\test\test.txt
in another job
, one option would be to upload it as an artifact so that it’s accessible in another jobs.
Other useful references
- Helpful as a base: https://github.com/atao/PowerShell-Privileges-Escalation
- API Docs for the `Start-Process: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-7.2
- Displaying the stdout and stderr of such a script: https://stackoverflow.com/questions/50765949/redirect-stdout-stderr-from-powershell-script-as-admin-through-start-process