Skip to content

Instantly share code, notes, and snippets.

@BananaAcid
Last active January 18, 2026 17:03
Show Gist options
  • Select an option

  • Save BananaAcid/d6c4dbe51a7735905a97daf4ef0461f3 to your computer and use it in GitHub Desktop.

Select an option

Save BananaAcid/d6c4dbe51a7735905a97daf4ef0461f3 to your computer and use it in GitHub Desktop.
Powershell -- ask AiHorde for an image

Ask AiHorde for an image

... in pure Powershell -- for free (no registration, no moneys)

Usage

ask.ai.aihorde_image.ps1 -content <string> [[-system] <string>] [[-n] <int>] [[-model] <string>] [[-AIHORDE_API_KEY] <string>]
ask.ai.aihorde_image.ps1 -listModels
ask.ai.aihorde_image.ps1 -awaitId <int>

Make it available to your shell as a function

Function AIHorde-Img { & <absolute path>\ask.ai.aihorde_image.ps1 @args }

Same params apply.

Doing this, you can use AIHorde-Img -listModels in any folder (while in the same session), instead of .\ask.ai.aihorde_image.ps1 -listModels within the script folder only.

To make it always available in a powershell session, add it a file shown with $Profile | Select-Object * (CurrentUserAllHosts is a good place).

Params

arg default example desc
-content <string>
-prompt <string>
(required) "Some Text-Prompt" The content to be created.
-system <string>
-systemPrompt <string>
(optional) "Always create realistic and professional photos." How the content should be proccessed. If empty, ask.ai.prompts.ps1 is used.
-n <int> 1 5 The number of pictures to request from AIHorde to be generated
-model <string> "AlbedoBase XL (SDXL)" "WAI-NSFW-illustrious-SDXL" The model to use.
-AIHORDE_API_KEY <string>
-key <string>
0000000000 (free key) 0123456789 Use an AIHorde API Key - if left set to "", $env:AIHORDE_API_KEY is being checked
-listModels
-list
Outputs a table of models, that are currently available on AIHorde
-awaitId <string>
-id <string>
42ba146b-7945-4776-b188-c5586aa3150b Outputs a table of models, that are currently available on AIHorde

Caution

Returns:

  • A single URL to a generated image
  • An array of URLs to the images

🛑 These URLs will expire after a few minutes.

⚠️ Because the comandlet returns the paths or data, you can use it within another script!

Note

You can always shorten a param (use -c or -con instead of -content)

Example

.\ask.ai.aihorde_image.ps1 -content "A woman standing on a hill, next to a tree"
.\ask.ai.aihorde_image.ps1 -content "A woman standing on a hill, next to a tree" -system "Create a black and white picture."

How it works

  1. request an image: /async -> returns the job's .id
  2. check if periodically if it is ready: /check/{id} -> .done == true? (and stats)
  3. get the image(s): /status/{id} -> .generations[].img

Note

Docs: https://aihorde.net/api/

API Base Uri: https://aihorde.net/api/v2/generate

Continue after you canceled the script

./ask.ai.aihorde_image.ps1 -id "e9840123-e123-411f-b690-123b41129123" # content is ignored, if an $awaitId from last run is used

This will jump to the progress part and continue.


License: MIT

# Nabil Redmann - 2025-11-04
# License: MIT
# https://gist.github.com/BananaAcid/d6c4dbe51a7735905a97daf4ef0461f3
[CmdletBinding(DefaultParameterSetName="None")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', Scope = 'Function', Target = '*')]
param (
[string][Parameter(Mandatory=$true, ParameterSetName='None')][Alias("prompt")]$content, # == Prompt
[string][Parameter(Mandatory=$false, ParameterSetName='None')]$systemPrompt, # Fallback -> .\ask.ai.prompts.ps1
[int][Parameter(Mandatory=$false, ParameterSetName='None')][ValidateRange(1, [int]::MaxValue)]$n = 1, # Pictures, default 1
[string][Parameter(Mandatory=$false, ParameterSetName='None')]$model = "AlbedoBase XL (SDXL)", # "WAI-NSFW-illustrious-SDXL" ...
[string][Parameter(Mandatory=$false, ParameterSetName='None')][Alias("key")]$AIHORDE_API_KEY = $env:AIHORDE_API_KEY ? $env:AIHORDE_API_KEY : "0000000000",
[switch][Parameter(Mandatory=$true, ParameterSetName='OnlyListModels')]$listModels = $false, # list available models: more then 2 servers, type of image
[string][Parameter(Mandatory=$true, ParameterSetName='OnlyAwaitId')][Alias("id")]$awaitId # to continue a job
)
$headers = @{
"Client-Agent" = "unknown:0:unknown" # unknown:0:unknown is the default by the Aihorde API
"Accept" = "application/json"
}
if ($listModels -eq $true) {
# only models with more then 2 nodes
$modelsList = Invoke-RestMethod -Uri "https://aihorde.net/api/v2/status/models" -Method Get -Headers ($headers + @{type = "image"}) |% {[PSCustomObject]$_} |? { $_.count -gt 2 } | Sort-Object -Property count |% { [PSCustomObject]@{name = $_.name; servers = $_.count; jobs = [int]$_.jobs; eta = [int]$_.eta; performance = [int]$_.performance } }
return $modelsList | Format-Table
}
# Set the empty API key to $null for comparison
if (-not $AIHORDE_API_KEY) { throw "⚠️ AIHORDE API KEY is missing! (-AIHORDE_API_KEY or `$env:AIHORDE_API_KEY)" }
# import system prompt text if no argument is given
if (-not $systemPrompt) {
try {
# import ...
. .\ask.ai.prompts.ps1
if ($systemPrompt -like "") { Write-Warning "⚠️ NO SYSTEM-PROMPT found in file! (.\ask.ai.prompts.ps1 with `$systemPrompt=`"`")" }
}
catch { Write-Warning "⚠️ NO FILE FOUND FOR SYSTEM-PROMPT! (.\ask.ai.prompts.ps1)" }
}
# docs: https://aihorde.net/api/
# Base URL for image generation
$url = "https://aihorde.net/api/v2/generate"
# DEBUG: if $awaitId is given, $content is ignored - and generation is skipped (if this file is run as `. .\ask.ai.aihorde_image.ps1 -content "123"` (sourced!), the $awaitId will be stored in the cli session )
if (-not $awaitId) {
<#
POST https://aihorde.net/api/v2/generate/async
200 -> AuthHeader + Body: {
"id": string of image in queue,
"kudos": integer of kudos available for fast generation
}
400, 500, ... -> {
"message": "string",
"rc": "ExampleHordeError"
}
#>
$headersPostAuth = @{
"Content-Type" = "application/json"
"apikey" = $AIHORDE_API_KEY
}
$body = @{ # params taken from https://artbot.site/create
prompt = $systemPrompt + "`n`n" + $content # + " ### " + $content_negative
params = @{
cfg_scale = 2
seed = ""
sampler_name = "k_euler_a"
height = 1024
width = 1024
post_processing = @()
steps = 8
tilting = $false
karras = $true
hires_fix = $false
clip_skip = 1
n = $n
loras = @(
@{
name = "246747"
model = 1
clip = 1
is_version = $true
}
)
}
allow_downgrade = $true
nsfw = $true
censor_nsfw = $false
trusted_workers = $true
models = @($model)
r2 = $true
replacement_filter = $false
shared = $false
slow_workers = $true
dry_run = $false
} | ConvertTo-Json -Depth 10
$response = Invoke-RestMethod -Uri "$url/async" -Method Post -Headers ($headers + $headersPostAuth) -Body $body -Erroraction SilentlyContinue
if ($response.rc) { throw $response }
$awaitId = $response.id
## info output:
[PSCustomObject]$response | Format-List
}
else {
[PSCustomObject]@{
"id (existing)" = $awaitId
kudos = $response.kudos ? $response.kudos : "unchanged"
} | Format-List
}
<#
GET https://aihorde.net/api/v2/generate/check/$awaitId
200 -> {
"finished": 0,
"processing": 0,
"restarted": 0,
"waiting": 0,
"done": true,
"faulted": false,
"wait_time": 0,
"queue_position": 0,
"kudos": 0,
"is_possible": true
}
400 -> {
"message": "string",
"rc": "ExampleHordeError"
}
#>
$queuePositionStart = 0
#$i = 0
do {
$response = Invoke-RestMethod -Uri "$url/check/$awaitId" -Method Get -Headers $headers -Erroraction SilentlyContinue
if ($response.queue_position -gt $queuePositionStart) {$queuePositionStart = $response.queue_position}
if ($response.queue_position) {
# $i++
# if ($i -gt [System.Console]::BufferWidth - 14 - 5) { $i = 1 } # reset when overflowing the console width
# Write-Host -NoNewline "`r[#$($response.queue_position), $($response.wait_time)s] $('.' * $i)"
$i = [Math]::Round((( $queuePositionStart - $response.queue_position) / $queuePositionStart) * 100)
Write-Progress -Activity "Queue position $($response.queue_position)" -PercentComplete $i -SecondsRemaining $response.wait_time
Start-Sleep -Seconds 1
}
} until ($response.done -or $response.rc)
## Debug output:
#$response | ConvertTo-Json -Depth 10
if ($response.rc) { throw $response }
<#
GET /v2/generate/status/{id}
200 -> {
"finished": 0,
"processing": 0,
"restarted": 0,
"waiting": 0,
"done": true,
"faulted": false,
"wait_time": 0,
"queue_position": 0,
"kudos": 0,
"is_possible": true,
"generations": [
{
"worker_id": "string",
"worker_name": "string",
"model": "string",
"state": "ok",
"img": "string", <-- base64 encoded image / URL (default)
"seed": "string",
"id": "string",
"censored": true,
"gen_metadata": [
{
"type": "lora",
"value": "download_failed",
"ref": "string"
}
]
}
],
"shared": true
}
400 -> {
"message": "string",
"rc": "ExampleHordeError"
}
#>
$response = Invoke-RestMethod -Uri "$url/status/$awaitId" -Method Get -Headers $headers
## Debug output:
#$response | ConvertTo-Json -Depth 10
if ($response.rc) { throw $response }
$result = $response.generations |% { $_.img }
return $result
$systemPrompt = @"
Create a realistic and professional hight quality image, 4k, realistic, amazing scenery, perfect lighting.
Take care to not deform the body, do not have to many limbs, do not have too many fingers.
"@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment