New ByProfile parameter set bound by -CertificateProfileId (alias ProfileId) POSTs to /api/v1/cert-manager/certificates with the profile id, the locally generated CSR, and an attributes envelope (subject fields, ttl, notBefore, notAfter, keyUsages, extendedKeyUsages). The wrapped response is unwrapped into the existing InfisicalSignedCertificate so reuse, install, chain-completion and key-protection paths remain unchanged. Issuance that returns without a certificate (e.g. status pending_approval) raises a configuration exception that surfaces the reported status and message. Ttl/NotBefore/NotAfter/KeyUsage/ExtendedKeyUsage parameters are now shared by ByCa and ByProfile. MAML help and existing parameter-set test updated.
e15f650 on main exited with code -1 and zero dotnet output).
PSInfisicalAPI
A C# binary PowerShell module for interacting with the Infisical REST API. It provides cmdlets for authentication, secret retrieval, structured export, and includes automatic environment-variable discovery so connections can be established with little or no inline configuration.
- License: AGPL-3.0
- Author: Grace Solutions
- Target framework: .NET Standard 2.0 (compatible with Windows PowerShell 5.1 and PowerShell 7+)
Installation
From the PowerShell Gallery
Install-Module -Name PSInfisicalAPI -Scope CurrentUser
Import-Module -Name PSInfisicalAPI
From source
git clone https://prod.git.gracesolution.info/gsadmin/PSInfisicalAPI.git
cd PSInfisicalAPI
pwsh -NoProfile -ExecutionPolicy Bypass -File .\build.ps1 -RunTests
Import-Module -Name .\Module\PSInfisicalAPI
Cmdlets
The module exports 34 cmdlets. Discovery cmdlets (Get-Infisical*) use a List (default) / single-record parameter-set pair: invoking without the identity parameter returns the collection, supplying the identity parameter returns one record.
Session
| Cmdlet | Purpose |
|---|---|
Connect-Infisical |
Establishes an authenticated session with an Infisical server and stores it for use by subsequent cmdlets. |
Disconnect-Infisical |
Clears the current Infisical session from the module-level session manager. |
Secrets
| Cmdlet | Purpose |
|---|---|
Get-InfisicalSecret |
Lists or retrieves Infisical secrets within a project, environment, and optional folder path. |
New-InfisicalSecret |
Creates a new Infisical secret, with support for SecureString values and bulk creation. |
Update-InfisicalSecret |
Updates an existing Infisical secret value, comment, name, or tags. |
Remove-InfisicalSecret |
Deletes one or many Infisical secrets by name. |
Copy-InfisicalSecret |
Duplicates one or more secrets into a different environment or secret path. |
ConvertTo-InfisicalSecretDictionary |
Converts a stream of InfisicalSecret objects into a name-keyed Dictionary of SecureString or plain text values. |
Export-InfisicalSecrets |
Exports InfisicalSecret objects to disk or environment variables in a chosen file format. |
Projects
| Cmdlet | Purpose |
|---|---|
Get-InfisicalProject |
Lists or retrieves Infisical projects accessible to the current identity. |
New-InfisicalProject |
Creates a new Infisical project in the active organization. |
Update-InfisicalProject |
Updates the name, description, or auto-capitalization flag on an existing project. |
Remove-InfisicalProject |
Deletes an Infisical project. |
Environments
| Cmdlet | Purpose |
|---|---|
Get-InfisicalEnvironment |
Lists or retrieves Infisical environments defined on a project. |
New-InfisicalEnvironment |
Creates a new environment on an Infisical project. |
Update-InfisicalEnvironment |
Updates the name, slug, or sort order of an existing Infisical environment. |
Remove-InfisicalEnvironment |
Deletes an Infisical environment from a project. |
Folders
| Cmdlet | Purpose |
|---|---|
Get-InfisicalFolder |
Lists or retrieves Infisical folders at a given secret path. |
New-InfisicalFolder |
Creates a new Infisical folder under the supplied parent path. |
Update-InfisicalFolder |
Renames an existing Infisical folder. |
Remove-InfisicalFolder |
Deletes an Infisical folder and all secrets it contains. |
Tags
| Cmdlet | Purpose |
|---|---|
Get-InfisicalTag |
Lists or retrieves Infisical tags defined on a project. |
New-InfisicalTag |
Creates a new Infisical tag on a project. |
Update-InfisicalTag |
Updates the slug, name, or color of an existing Infisical tag. |
Remove-InfisicalTag |
Deletes an Infisical tag from a project. |
PKI
| Cmdlet | Purpose |
|---|---|
Get-InfisicalCertificateAuthority |
Lists or retrieves Infisical internal Certificate Authorities. |
Get-InfisicalPkiSubscriber |
Lists or retrieves Infisical PKI subscribers in a project. |
Get-InfisicalCertificate |
Lists or retrieves Infisical certificates in a project, with optional filters and automatic paging. |
Search-InfisicalCertificate |
Searches Infisical certificates with advanced filters and automatic paging. |
Request-InfisicalCertificate |
Requests a new Infisical certificate (local CSR + sign) or reuses a still-valid existing one. |
ConvertTo-InfisicalCertificate |
Materializes an X509Certificate2 from an Infisical certificate record, bundle, or serial number. |
Install-InfisicalCertificate |
Installs an Infisical certificate (and optional chain) into a Windows certificate store. |
Uninstall-InfisicalCertificate |
Removes a certificate from a Windows certificate store by thumbprint, subject, or pipeline input. |
Export-InfisicalCertificate |
Exports an Infisical certificate to disk in PEM, PFX, or CER format. |
Use Get-Help <Cmdlet> -Full for parameter details and Get-Help about_PSInfisicalAPI for the module overview.
Quick start
$secureSecret = Read-Host -AsSecureString 'Client Secret'
$connection = Connect-Infisical `
-BaseUri 'https://app.infisical.com' `
-OrganizationId '00000000-0000-0000-0000-000000000000' `
-ProjectId '11111111-1111-1111-1111-111111111111' `
-Environment 'dev' `
-ClientId 'machine-identity-client-id' `
-ClientSecret $secureSecret `
-PassThru
Get-InfisicalSecret -SecretPath '/'
Disconnect-Infisical
Automatic environment-variable discovery
When Connect-Infisical is invoked with one or more parameters missing (or set to whitespace/empty), the cmdlet searches environment variables and uses the first value it finds. This makes invocation as simple as Connect-Infisical when variables are set up in advance.
Scope precedence
Scopes are searched in order; the first matching variable with a non-blank value wins:
ProcessUserMachine
Patterns
The resolver matches case-insensitively against patterns aligned with Infisical's CLI defaults plus common variants such as CLOUDINIT_INFISICAL_* and custom-prefixed names (e.g., myapp_infisical_client_id).
| Parameter | Example variable names matched |
|---|---|
BaseUri |
INFISICAL_API_URL, INFISICAL_BASE_URL, INFISICAL_HOST |
OrganizationId |
INFISICAL_ORG_ID, INFISICAL_ORGANIZATION_ID |
ProjectId |
INFISICAL_PROJECT_ID, INFISICAL_WORKSPACE_ID |
Environment |
INFISICAL_ENVIRONMENT, INFISICAL_ENV, INFISICAL_ENV_SLUG |
ClientId |
INFISICAL_CLIENT_ID, INFISICAL_UNIVERSAL_AUTH_CLIENT_ID |
ClientSecret |
INFISICAL_CLIENT_SECRET, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET |
AccessToken |
INFISICAL_TOKEN, INFISICAL_ACCESS_TOKEN, INFISICAL_AUTH_TOKEN |
SecretPath |
INFISICAL_SECRET_PATH, INFISICAL_DEFAULT_SECRET_PATH |
ApiVersion |
INFISICAL_API_VERSION |
Sensitive values (ClientSecret, AccessToken) are read directly into a read-only SecureString and never logged.
Zero-configuration example
[Environment]::SetEnvironmentVariable('INFISICAL_API_URL', 'https://app.infisical.com', 'User')
[Environment]::SetEnvironmentVariable('INFISICAL_ORG_ID', '00000000-0000-0000-0000-000000000000', 'User')
[Environment]::SetEnvironmentVariable('INFISICAL_PROJECT_ID', '11111111-1111-1111-1111-111111111111', 'User')
[Environment]::SetEnvironmentVariable('INFISICAL_ENVIRONMENT', 'dev', 'User')
[Environment]::SetEnvironmentVariable('INFISICAL_CLIENT_ID', 'machine-identity-client-id', 'User')
[Environment]::SetEnvironmentVariable('INFISICAL_CLIENT_SECRET', 'super-secret-value', 'User')
Connect-Infisical
Get-InfisicalSecret
Mixed example (explicit values override discovery)
Explicit parameters always win over discovered values; blank/whitespace explicit values trigger discovery.
Connect-Infisical -Environment 'prod' # everything else discovered from environment
Logging
The resolver emits a single verbose line announcing the scan and one informational line per discovered variable (variable name and scope; values are never logged). Use -Verbose to see the scan announcement.
Building
pwsh -NoProfile -ExecutionPolicy Bypass -File .\build.ps1 -RunTests
The script builds the binary, runs unit tests, publishes binaries into Module/PSInfisicalAPI/bin/, regenerates the manifest, and validates that the module imports.
Extending the module
Adding a new API endpoint
All HTTP routes live in two files under src/PSInfisicalAPI/Endpoints/:
InfisicalEndpointNames.csdeclares aconst stringidentifier for each endpoint.InfisicalEndpointRegistry.csmaps each identifier to one or moreInfisicalEndpointDefinitionrecords grouped by resource (RegisterAuthentication,RegisterSecrets,RegisterPki, etc.).
To add a route:
- Add a constant in
InfisicalEndpointNames.cs(e.g.,public const string ListPkiSubscribers = "ListPkiSubscribers";). - In the matching
Register<Resource>method, callAdd(map, new InfisicalEndpointDefinition { ... })withName,Resource,Version,Method,Template, and theRequiresAuthorization/ContainsSecretMaterialInRequest/ContainsSecretMaterialInResponseflags. Use{placeholder}tokens inTemplate; they are substituted from thepathParametersdictionary passed by the caller. - If the same logical operation has more than one upstream path (legacy + current), register both definitions under the same
Name—InvokeWithCandidateFallbacktries each in order until one succeeds. - Invoke the endpoint from the appropriate client (
InfisicalPkiClient,InfisicalSecretsClient, etc.) via_invoker.InvokeWithCandidateFallback(connection, InfisicalEndpointNames.XYZ, "XYZ", pathParameters, query, body).
Adding a new cmdlet
Cmdlets live in src/PSInfisicalAPI/Cmdlets/ and derive from InfisicalCmdletBase, which exposes HttpClient, Logger, ResolveProjectId, and ThrowTerminatingForException. Follow the consolidated discovery pattern when the cmdlet supports both list and single-record retrieval:
[Cmdlet(VerbsCommon.Get, "InfisicalPkiSubscriber", DefaultParameterSetName = "List")]
[OutputType(typeof(InfisicalPkiSubscriber))]
public sealed class GetInfisicalPkiSubscriberCmdlet : InfisicalCmdletBase
{
[Parameter(ParameterSetName = "ByName", Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
[Alias("SubscriberName", "Slug")]
public string Name { get; set; }
[Parameter] public string ProjectId { get; set; }
protected override void ProcessRecord() { /* dispatch on ParameterSetName */ }
}
After adding (or removing) a cmdlet:
-
Update
build.ps1in two places — theCmdletsToExportarray inside the generated manifest block, and the$expectedCmdsarray used byTest-ModuleImports. Both must list the same cmdlets; the build fails fast if they drift. -
Add a
<command:command>entry inModule/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml. Each entry must include a non-empty<maml:description>synopsis (do not let it start with the cmdlet name — the validation gate rejects PowerShell's auto-generated fallback), a non-empty<maml:description>body, and at least one<command:example>with a non-empty<dev:code>block. -
For consolidated
List/ single-record cmdlets, ship three examples: two straight-line invocations (one per parameter set) and oneOrderedDictionarysplat. The splat must construct the dictionary withOrdinalIgnoreCaseso parameter names round-trip case-insensitively:$Params = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase) $Params.ProjectId = (Get-InfisicalProject | Select-Object -First 1).Id $Result = Get-InfisicalPkiSubscriber @Params -
Add a
## Unreleasedentry toCHANGELOG.mddescribing the change (mark removals of public cmdlets or parameters as BREAKING). -
Run
./build.ps1 -RunTests. The script enforces the cmdlet list, runs the xUnit suite, and verifies that every exported cmdlet has a valid synopsis, description, and at least one non-empty example.
Committing source and build artifacts in lockstep
The embedded BuildCommitHash in Module/PSInfisicalAPI/PSInfisicalAPI.psd1 and the bundled DLL is captured from git rev-parse HEAD at build time. To keep the embedded hash truthful, commit source and build artifacts as two ordered commits:
- Stage and commit your source changes first. Suppose this produces commit
S. - Run
./build.ps1 -RunTests -CommitArtifacts. The build picks upSasHEAD, embeds it asBuildCommitHash, then stages and commits only the build outputs (Module/PSInfisicalAPI/bin/**,Module/PSInfisicalAPI/PSInfisicalAPI.psd1, and theCHANGELOG.mdbuild-stamp insertion). The commit message referencesSso the binary commit always traces back to its source. git push.
-CommitArtifacts only touches the three artifact paths above; any other dirty files in your working tree are left alone. Use the older -CommitOnSuccess switch only when you intentionally want a single commit covering everything (git add -A + git commit -m "Build <version>"); the two switches are mutually exclusive.
Continuous integration
.gitea/workflows/publish-psgallery.yml publishes the module to the PowerShell Gallery whenever a pull request is merged into main. The workflow expects a repository secret named PSGALLERY_API_KEY containing a valid Gallery API key.
License
Distributed under the GNU Affero General Public License v3.0. See LICENSE.