Levitate.Runtime
1.0.1
dotnet add package Levitate.Runtime --version 1.0.1
NuGet\Install-Package Levitate.Runtime -Version 1.0.1
<PackageReference Include="Levitate.Runtime" Version="1.0.1" />
<PackageVersion Include="Levitate.Runtime" Version="1.0.1" />
<PackageReference Include="Levitate.Runtime" />
paket add Levitate.Runtime --version 1.0.1
#r "nuget: Levitate.Runtime, 1.0.1"
#:package Levitate.Runtime@1.0.1
#addin nuget:?package=Levitate.Runtime&version=1.0.1
#tool nuget:?package=Levitate.Runtime&version=1.0.1

Levitate
Compile C# automation methods into production-grade PowerShell at build time.
Levitate is a Roslyn source generator and automation toolkit for teams that want C# ergonomics with PowerShell output they can inspect, validate, save, execute, and ship. Mark a static C# method with [PowerShellScript]; Levitate translates the supported method body into PowerShell during compilation and generates a strongly named C# accessor for the script.
It is built for infrastructure automation, internal ops tools, admin portals, LLM-assisted runbooks, and deployment workflows where string-built scripts are too fragile.
What Levitate Gives You
| Area | Capability |
|---|---|
| Compile-time generator | Translate [PowerShellScript] methods into PowerShell while the project builds. |
| Runtime execution | Run generated scripts from C# and capture exit code, stdout, stderr, duration, lines, JSON, and key-value output. |
| Fluent builder | Build PowerShell scripts manually with Levitate.Core when source generation is not the right fit. |
| BCL mappings | Map common .NET APIs to PowerShell cmdlets for files, directories, paths, console output, services, registry, certificates, processes, environment variables, and more. |
| Pipelines and LINQ | Compose object pipelines with PS.Command(...) and translate a useful LINQ preview surface. |
| Ops modules | Use marker APIs for IIS, Active Directory, Azure, X509, registry, and service automation. |
| Safety diagnostics | Get diagnostics for unsupported constructs, raw PowerShell injection risk, Windows-only commands, and portability issues. |
| Generated artifacts | Emit generated .ps1 files under obj/Levitate/generated/ or copy them to a configured review folder. |
Install
For compile-time generation:
<ItemGroup>
<PackageReference Include="Levitate.Attributes" Version="1.0.1" />
<PackageReference Include="Levitate.Runtime" Version="1.0.1" />
<PackageReference Include="Levitate.Generator" Version="1.0.1"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"
PrivateAssets="all" />
<PackageReference Include="Levitate.Build" Version="1.0.1" PrivateAssets="all" />
</ItemGroup>
For fluent script building without the source generator:
dotnet add package Levitate.Core --version 1.0.1
dotnet add package Levitate.Runtime --version 1.0.1
For starter projects:
dotnet new install Levitate.Templates::1.0.1
dotnet new levitate-console
dotnet new levitate-ops-tool
First Script
using Levitate;
using System;
using System.IO;
namespace Company.Automation;
public partial class MaintenanceScripts
{
[PowerShellScript]
public static void CleanTempFiles(string tempPath, int olderThanDays)
{
if (!Directory.Exists(tempPath))
{
Console.Error.WriteLine($"Missing path: {tempPath}");
return;
}
Console.WriteLine($"Cleaning {tempPath}");
PS.Raw("Get-ChildItem -Path $tempPath -File | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$olderThanDays) } | Remove-Item -Force");
}
}
Levitate generates a PowerShell script and a C# accessor:
var script = MaintenanceScripts.CleanTempFilesScript.PowerShell;
await MaintenanceScripts.CleanTempFilesScript.ExecuteAsync(
tempPath: @"C:\Temp",
olderThanDays: 14);
MaintenanceScripts.CleanTempFilesScript.SaveTo("clean-temp.ps1");
Generated PowerShell is ordinary, reviewable text:
param(
[Parameter(Mandatory=$true)]
[string]$tempPath,
[Parameter(Mandatory=$true)]
[int]$olderThanDays
)
if (-not (Test-Path $tempPath -PathType Container)) {
Write-Error "Missing path: $tempPath"
return
}
Write-Host "Cleaning $tempPath"
Get-ChildItem -Path $tempPath -File | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$olderThanDays) } | Remove-Item -Force
Package Map
| Package | Purpose |
|---|---|
Levitate.Attributes |
Public marker attributes and compile-time marker APIs: [PowerShellScript], PS.Raw, PS.Command, IIS, AD, Azure, RequiresModule, RequiresPowerShell, TargetPlatform. |
Levitate.Generator |
Roslyn source generator that emits script accessors and .ps1 artifacts. |
Levitate.Analyzers |
IDE/build diagnostics for the Levitate automation profile. |
Levitate.Build |
MSBuild props and targets for generated script output, validation, strict mode, and clean behavior. |
Levitate.Runtime |
Executes scripts through PowerShell and returns structured ExecutionResult data. |
Levitate.Core |
Fluent script builder, AST nodes, emitters, condition helpers, and cmdlet helpers. |
Levitate.Templates |
dotnet new templates for console and ops automation projects. |
Supported C# Translation
Levitate intentionally supports a clear automation profile instead of trying to become a full C# runtime inside PowerShell.
| C# surface | Generated PowerShell |
|---|---|
| Method parameters | param() block with typed, mandatory parameters |
string, int, long, double, bool, object |
PowerShell type annotations |
| Arrays and collections | T[] parameter typing for arrays, List<T>, IEnumerable<T>, and related collection interfaces |
Dictionary<TKey,TValue> |
hashtable |
DateTime, TimeSpan, Guid, Uri |
datetime, timespan, guid, string |
| Nullable value types | Unwrapped to the underlying PowerShell type |
| Variables and assignments | $name = value |
if, else if, else |
if, elseif, else |
foreach, for, while, do while |
PowerShell loop forms |
try, catch, finally |
PowerShell error handling with $ErrorActionPreference = "Stop" where needed |
switch |
PowerShell switch |
return, break, continue |
Native PowerShell keywords |
==, !=, <, <=, >, >= |
-eq, -ne, -lt, -le, -gt, -ge |
&&, ||, ! |
-and, -or, -not |
| Interpolated strings | PowerShell interpolation with subexpressions when needed |
Enums, const, booleans, null |
Folded into typed PowerShell literals |
| Nested namespaces and classes | Correct generated namespace and nested partial class wrappers |
BCL To PowerShell Mappings
Levitate maps common .NET automation calls to idiomatic PowerShell:
| C# call family | Example generated command |
|---|---|
Console.WriteLine, Console.Error.WriteLine |
Write-Host, Write-Error |
Directory.Exists, CreateDirectory, Delete, Copy |
Test-Path, New-Item, Remove-Item, Copy-Item |
File.Exists, ReadAllText, WriteAllText, AppendAllText, Copy, Delete |
Test-Path, Get-Content, Set-Content, Add-Content, Copy-Item, Remove-Item |
Path.Combine, GetFileName, GetDirectoryName |
Join-Path and path expressions |
ServiceController.Get, GetAll, Start, Stop, Restart, Suspend, Resume, WaitForStatus |
Get-Service, Start-Service, Stop-Service, Restart-Service, and related cmdlets |
Process.Start, process helpers |
Start-Process and process cmdlets |
Environment.GetEnvironmentVariable, SetEnvironmentVariable |
$env: reads and writes |
Registry, RegistryKey helpers |
registry provider commands such as Get-ItemProperty, Set-ItemProperty, Remove-ItemProperty, New-Item |
X509Store, X509Certificate2 |
certificate provider and certificate import/export commands |
DateTime.Now, conversion helpers, sleeps |
Get-Date, casts, Start-Sleep |
See docs/bcl-mappings.md for the detailed table.
Pipelines And LINQ Preview
Use PS.Command(...) when the intent is a PowerShell object pipeline:
[PowerShellScript]
public static void RunningServices()
{
PS.Command("Get-Service")
.Where("Status", PsOperator.Eq, "Running")
.Select("Name", "Status")
.SortBy("Name")
.FormatTable();
}
Generated pipeline:
Get-Service | Where-Object { $_.Status -eq "Running" } | Select-Object Name, Status | Sort-Object Name | Format-Table -AutoSize
Supported pipeline stages include:
| API | PowerShell |
|---|---|
Where(prop, op, value) and Where(prop, value) |
Where-Object |
Select("Name", "Status") |
Select-Object Name, Status |
SortBy("Name"), SortBy("Name", descending: true) |
Sort-Object Name, Sort-Object Name -Descending |
GroupBy("Status") |
Group-Object Status |
First(), First(5), Skip(10) |
Select-Object -First, Select-Object -Skip |
FormatTable(), OutFile(path, append) |
Format-Table -AutoSize, Out-File |
The LINQ preview translates common object-pipeline forms including Where, Select, Any, All, Count, First, FirstOrDefault, Last, LastOrDefault, OrderBy, ThenBy, descending variants, GroupBy, Skip, Take, Distinct, ToList, and ToArray.
Module-Aware Ops APIs
Levitate includes marker APIs that compile to module-specific PowerShell commands. They are compile-time markers and intentionally throw if executed directly as normal C#.
| Area | Marker APIs |
|---|---|
| IIS | IIS.GetSite, GetAllSites, StartSite, StopSite, RestartSite, NewSite, RemoveSite, GetAppPool, StartAppPool, StopAppPool, RecycleAppPool |
| Active Directory | AD.GetUser, GetUsers, NewUser, SetUser, RemoveUser, EnableUser, DisableUser, GetGroup, GetGroupMembers, AddGroupMember, RemoveGroupMember, ResetPassword, UnlockAccount |
| Azure | Azure.GetVM, StartVM, StopVM, RestartVM, GetResourceGroups, GetResourceGroup, GetStorageAccount, GetContext, Connect, SetSubscription |
| Certificate store | X509Store and X509Certificate2 mappings for common local machine certificate operations |
Example:
using Levitate;
public partial class CloudScripts
{
[RequiresPowerShell("7.4")]
[RequiresModule("Az")]
[PowerShellScript]
public static void StopDevVm(string name, string resourceGroup)
{
Azure.StopVM(name, resourceGroup);
}
}
Generated prefix and command:
#Requires -Version 7.4
#Requires -Modules Az
param(
[Parameter(Mandatory=$true)]
[string]$name,
[Parameter(Mandatory=$true)]
[string]$resourceGroup
)
Stop-AzVM -Name $name -ResourceGroupName $resourceGroup -Force
Manifest, Platform, And Safety Features
| Feature | C# or MSBuild input | Generated behavior |
|---|---|---|
| PowerShell version requirement | [RequiresPowerShell("7.4")] |
Adds #Requires -Version 7.4 |
| Module requirement | [RequiresModule("ActiveDirectory")] |
Adds #Requires -Modules ActiveDirectory |
| Multiple modules | Repeated [RequiresModule(...)] |
Emits one #Requires -Modules line per attribute |
| Platform intent | [TargetPlatform(PowerShellPlatform.Windows)] |
Documents Windows-only scripts and suppresses Windows-only command warnings |
| Strict mode | <LevitateStrictMode>true</LevitateStrictMode> |
Emits Set-StrictMode -Version Latest after param() |
| Error behavior | <LevitateErrorActionPreference>Stop</LevitateErrorActionPreference> |
Emits $ErrorActionPreference = "Stop" near the top of the script |
| Raw PowerShell guardrail | PS.Raw(...) with non-constant input |
Reports SS401 injection-risk warning |
| Windows-only guardrail | IIS, AD, registry, certificate, or other Windows-specific commands in cross-platform scripts | Reports SS501 unless the method targets Windows |
Generated Artifacts
Levitate can emit scripts as build artifacts so reviewers and CI can inspect the exact PowerShell that will run.
<PropertyGroup>
<LevitateEmitPs1>true</LevitateEmitPs1>
<LevitatePs1OutputPath>Scripts/Generated</LevitatePs1OutputPath>
<LevitateValidateGeneratedScripts>true</LevitateValidateGeneratedScripts>
<LevitateStrictMode>true</LevitateStrictMode>
<LevitateErrorActionPreference>Stop</LevitateErrorActionPreference>
</PropertyGroup>
Default generated location:
obj/Levitate/generated/
Accessor helpers generated for every script method:
| Helper | Purpose |
|---|---|
PowerShell |
Embedded generated script text |
ExecuteAsync(...) |
Execute the script through Levitate.Runtime |
SaveTo(string path) |
Save script to a file path |
SaveTo(FileInfo file) |
Save script to a FileInfo target |
Diagnostics
Levitate diagnostics are designed to be actionable. v1.0 messages include rewrite suggestions for the most common blockers.
| Code | Severity | Meaning |
|---|---|---|
SS001 |
Error | [PowerShellScript] method must be static. |
SS002 |
Error | Containing class must be partial. |
SS003 |
Error | Unsupported C# construct. Suggestion: use PS.Raw("...") for PowerShell-native constructs. |
SS004 |
Error | Unsupported BCL method. Suggestion: use PS.Raw("...") or check docs/bcl-mappings.md. |
SS201 |
Warning | Unsupported automation expression. Suggestion: rewrite with PS.Command(...) or PS.Raw(...). |
SS230 |
Warning | Object construction inside LINQ Select is not supported. |
SS401 |
Warning | PS.Raw() argument is not a compile-time constant. Suggestion: use a named param() variable or a compile-time string. |
SS501 |
Warning | Windows-only command in a cross-platform script. Suggestion: add [TargetPlatform(PowerShellPlatform.Windows)]. |
LLM-Safe Automation Workflow
Levitate works well as a compiler layer between AI-generated C# and executable PowerShell:
- Ask an LLM for Levitate-profile C# instead of raw shell commands.
- Build the project so normal C# compilation, analyzers, and Levitate diagnostics run.
- Inspect generated
.ps1artifacts. - Parse-validate generated PowerShell in tests.
- Execute through
Levitate.Runtimeonly after review.
The recommended LLM profile is documented in docs/llm-guide.md.
Runtime Execution
var result = await MaintenanceScripts.CleanTempFilesScript.ExecuteAsync(
tempPath: @"C:\Temp",
olderThanDays: 14);
if (!result.Success)
{
Console.Error.WriteLine(result.ErrorOutput);
}
foreach (var line in result.AsLines())
{
Console.WriteLine(line);
}
ExecutionResult includes:
| Property or method | Description |
|---|---|
RawOutput |
Captured standard output |
ErrorOutput |
Captured standard error |
ExitCode |
PowerShell process exit code |
Duration |
Runtime duration |
Success, HasError |
Convenience status flags |
AsLines() |
Output split into non-empty lines |
AsJson() and As<T>() |
JSON parsing helpers |
AsKeyValue() |
Parse key: value style output |
Fluent Builder
When you want to generate PowerShell without source generation, use Levitate.Core directly:
using Levitate.Core;
using Levitate.Core.Conditions;
var ps = Shell.New()
.Echo("Levitate works")
.If(new FileExistsCondition("$profile"), thenBlock => thenBlock
.Raw("Write-Host \"Profile exists\""))
.Build();
The builder layer includes AST nodes for commands, pipelines, functions, script blocks, variables, conditionals, loops, switch statements, try/catch blocks, here-strings, JSON/XML operations, jobs, sessions, scheduled tasks, certificates, services, registry, networking, storage, and more.
Cross-Platform Guidance
Levitate targets PowerShell 7 where possible and can fall back to Windows PowerShell on Windows through the runtime. Cross-platform scripts should prefer file/path/process/environment APIs, portable pwsh cmdlets, and explicit module requirements.
Windows-specific automation is supported, but should be marked clearly:
[RequiresModule("WebAdministration")]
[TargetPlatform(PowerShellPlatform.Windows)]
[PowerShellScript]
public static void RestartSite(string siteName)
{
IIS.RestartSite(siteName);
}
Build And Test
dotnet restore Levitate.slnx
dotnet build Levitate.slnx --configuration Release
dotnet test Levitate.slnx --configuration Release --no-build
dotnet pack Levitate.slnx --configuration Release --no-build --output nupkgs/Levitate/v1.0.1
The v1.0 tree validates generator output with golden tests and PowerShell parser checks.
Documentation
- Getting started
- How it works
- API reference
- Supported constructs
- BCL mappings
- Raw PowerShell guide
- Cross-platform guide
- Library guide
- LLM guide
Release
Levitate v1.0.1 is the Trustworthy Automation Compiler release:
- Stable public package identities under
Levitate.*. - Compile-time source generation with reviewable PowerShell artifacts.
- Runtime execution support for generated scripts.
- BCL, pipeline, LINQ preview, IIS, AD, Azure, registry, service, and certificate mappings.
- Strict mode, manifest attributes, platform diagnostics, and raw PowerShell injection-risk warnings.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Levitate.Core (>= 1.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.0.1 - NuGet gallery README and package icon compatibility fix.