Lightweight rest api that allows users to run Powershell commands over HTTP. Requests require a valid JWT and responses are returned in JSON format.
Test the application by running the test.sh script on Linux or WSL:
You can pass in a version as $1 parameter if you do not want to auto-generate a version based on the timestamp.
$ ./test.sh
[TESTS] π΅ Running Tests
=== RUN TestCheckIPAddressNotValid
--- PASS: TestCheckIPAddressNotValid (0.00s)
021/12/11 14:02:59 INFO: IP Address: 0.0.0.0 is Valid
--- PASS: TestValidateConfigs_EnvTypeSetNotValid (0.00s)
PASS
ok powershell-proxy (cached)
[TESTS] π’ Tests All Passed
[SUCCESS] β
Test Powershell Proxy | Version: '2021.12.11.1639253011' | Build Time: '0 sec'
Build the application by running the build.sh script on Linux or WSL:
You can pass in a version as $1 parameter if you do not want to auto-generate a version based on the timestamp.
$ ./build.sh
[BUILD START] π₯ Building Powershell Proxy - Version: 2021.12.11.1639253011
[BUILD] π΅ Cleaning Build Directory ./build
[BUILD] π’ Build Directory Cleaned
[BUILD] π΅ Compiling Windows Binary
[BUILD] π’ Windows Binary Compiled to ./build/win/powershell-proxy_win_arm64.exe
[BUILD] π΅ Compiling Linux Binary
[BUILD] π’ Linux Binary Compiled to ./build/linux/powershell-proxy_linux_arm64
[BUILD] β¬οΈ Binaries Successfully Created
./build:
linux win
./build/linux:
powershell-proxy_0.0.1639180082
./build/win:
powershell-proxy_0.0.1639180082.exe
[BUILD SUCCESS] β
Built Powershell Proxy | Version: '2021.12.11.1639253011' | Build Time: '1 sec'
To run this application, you will need to add the following environment variables:
PWSHPRXY_LISTEN_ADDR
- optional - default: 0.0.0.0
PWSHPRXY_LISTEN_PORT
- optional - default: 8000
PWSHPRXY_TYPE
- required - valid values: "core" or "windows"
PWSHPRXY_OKTA_CLIENT_ID
- required
PWSHPRXY_OKTA_ISSUER
- required
PWSHPRXY_OKTA_AUDIENCE
- required
To run the application ensure all the required environment variables are set then execute the binary:
C:\> powershell-proxy.exe
$ ./powershell-proxy
2021/12/10 19:02:40 π΅ Starting
2021/12/10 19:02:40 INFO: Env Variable 'PWSHPRXY_LISTEN_ADDR' not set, defaulting to 0.0.0.0
2021/12/10 19:02:40 INFO: IP Address: 0.0.0.0 is Valid
2021/12/10 19:02:40 INFO: Env Variable 'PWSHPRXY_APP_NAME' not set, defaulting to 8000
2021/12/10 19:02:40 INFO: Using Powershell Type: pwsh
2021/12/10 19:02:40 INFO: Using AppName: Powershell Proxy API
2021/12/10 19:02:40 INFO: Using ListenPort: 8888
2021/12/10 19:02:40 INFO: Using ListenAddress: 0.0.0.0
2021/12/10 19:02:40 INFO: Using OktaClientId: ***********
2021/12/10 19:02:40 INFO: Using OktaAudience: api:https://default
2021/12/10 19:02:40 INFO: Using OktaIssuer: https://tenant.okta.com/oauth2/default
2021/12/10 19:02:40 π’ Started Powershell Proxy API
GET /api
curl
curl -X GET \
'https://127.0.0.1:8000/api'
python
import requests
reqUrl = "https://127.0.0.1:8000/api/"
response = requests.request("GET", reqUrl)
print(response.text)
javascript
fetch("https://127.0.0.1:8000/api", {
method: "GET",
})
.then(function (response) {
return response.text();
})
.then(function (data) {
console.log(data);
});
β Powershell Proxy API
GET /api/auth/authorize
Allows a user to get a device code to authenticate with Okta using Device Authorization Grant.
More info on Okta configs: https://developer.okta.com/docs/guides/device-authorization-grant/main/
curl
curl -X GET \
'https://127.0.0.1:8000/api/auth/authorize'
python
import requests
reqUrl = "https://127.0.0.1:8000/api/auth/authorize"
response = requests.request("GET", reqUrl)
print(response.text)
javascript
fetch("https://127.0.0.1:8000/api/auth/authorize", {
method: "GET",
})
.then(function (response) {
return response.text();
})
.then(function (data) {
console.log(data);
});
{
"device_code": "50632b5e-9f3d-437f-961f-2b8e25e00894",
"user_code": "TESTTNRD",
"verification_uri": "https://tenant.okta.com/activate",
"verification_uri_complete": "https://tenant.okta.com/activate?user_code=TESTTNRD",
"expires_in": 600,
"interval": 5
}
POST /api/auth/token
Allows a user to get a bearer token once they have successfully authenticated using the user code.
curl
curl -X POST \
'https://127.0.0.1:8000/api/auth/token' \
-H 'Content-Type: application/json' \
-d '{
"device_code": "50632b5e-9f3d-437f-961f-2b8e25e00894"
}'
python
import requests
reqUrl = "https://127.0.0.1:8000/api/auth/token"
headersList = {
"Content-Type": "application/json"
}
payload = "{\n \"device_code\": \"50632b5e-9f3d-437f-961f-2b8e25e00894\"\n}"
response = requests.request("POST", reqUrl, data=payload, headers=headersList)
print(response.text)
javascript
let headersList = {
"Content-Type": "application/json",
};
fetch("https://127.0.0.1:8000/api/auth/token", {
method: "POST",
body: '{\n "device_code": "50632b5e-9f3d-437f-961f-2b8e25e00894"\n}',
headers: headersList,
})
.then(function (response) {
return response.text();
})
.then(function (data) {
console.log(data);
});
{
"message": {
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "<JWT>",
"scope": "openid offline_access profile",
"refresh_token": "<REFRESH_TOKEN>"
},
"level": "info"
}
POST /api/command
Parameter | Type | Description |
---|---|---|
depth |
int |
Optional. Set the depth of json responses. Default: 4 (range: 1-6) |
Header | Description |
---|---|
Authorization |
Required. Valid JWT Access Token generated from Okta |
curl
curl -X POST \
'https://127.0.0.1:8000/api/command?depth=4' \
-H 'Authorization: Bearer <JWT>' \
-H 'Content-Type: application/json' \
-d '{"commands": ["Get-ChildItem | Select-Object Name"]}'
python
import requests
reqUrl = "https://127.0.0.1:8000/api/command?depth=4"
headersList = {
"Authorization": "Bearer <JWT>",
"Content-Type": "application/json"
}
payload = "{\n\"commands\":[\"Get-ChildItem | Select-Object Name\"]\n}"
response = requests.request("POST", reqUrl, data=payload, headers=headersList)
print(response.text)
javascript
let headersList = {
Authorization: "Bearer <JWT>",
"Content-Type": "application/json",
};
fetch("https://127.0.0.1:8000/api/command?depth=4", {
method: "POST",
body: '{\n"commands":["Get-ChildItem | Select-Object Name"]\n}',
headers: headersList,
})
.then(function (response) {
return response.text();
})
.then(function (data) {
console.log(data);
});
[
{
"Name": "build"
},
{
"Name": "build.sh"
},
{
"Name": "go.mod"
},
{
"Name": "go.sum"
},
{
"Name": "main.go"
},
{
"Name": "README.md"
}
]