Honor -ErrorAction, fix pipeline-stop noise, and correct certificate request paths
BREAKING: operation failures are now non-terminating errors, so -ErrorAction (and $ErrorActionPreference) decides the outcome. try/catch around these cmdlets now requires -ErrorAction Stop or $ErrorActionPreference = 'Stop'. A failing pipeline item no longer aborts the batch. Cmdlets no longer report "The pipeline has been stopped." as an error. Select-Object -First, and Where-Object feeding it, stop the upstream cmdlet by design; the shared error path in InfisicalCmdletBase now lets pipeline-control exceptions propagate untouched instead of logging them and raising an error. Error-level diagnostics moved off the warning stream to verbose. Every Logger.Error call site logs and then throws, so the failure already reaches the caller as an ErrorRecord; emitting it again as eight warning lines put failures under -WarningAction instead of -ErrorAction. One error per failure now. Request-InfisicalCertificate: - -CommonName accepts the RDN form (CN=WEB01) and reduces it to the bare value, which previously produced a CN=CN=WEB01 subject plus a bogus DNS SAN. - -DnsName routes IP literals to iPAddress SAN entries, so the mixed output of Get-InfisicalSANList can be splatted in as documented. - The CA path sends the normalized common name to the signing endpoint. - The issuance path is resolved and reported before a keypair is generated, and a CA with direct issuance disabled fails fast with guidance naming -PkiSubscriberSlug and -CertificateProfileId. Infisical exposes no template-based issuance route, so no -CertificateTemplateId is added. Get-InfisicalCertificateAuthority table output gains a DirectIssue column (EnableDirectIssuance) so CAs eligible for -CertificateAuthorityId are visible. README, about_PSInfisicalAPI, and cmdlet help document the stream/-ErrorAction contract, subscriber discovery, and direct-issuance setup. Adds regression tests for pipeline-stop propagation, logger stream routing, SAN splitting, common-name normalization, and the non-terminating convention across all cmdlets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,11 +38,12 @@
|
||||
</ViewSelectedBy>
|
||||
<TableControl>
|
||||
<TableHeaders>
|
||||
<TableColumnHeader><Label>Name</Label><Width>28</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>CommonName</Label><Width>32</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>Type</Label><Width>10</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>Status</Label><Width>10</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>KeyAlgorithm</Label><Width>14</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>Name</Label><Width>24</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>CommonName</Label><Width>28</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>Type</Label><Width>9</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>Status</Label><Width>8</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>DirectIssue</Label><Width>11</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>KeyAlgorithm</Label><Width>13</Width></TableColumnHeader>
|
||||
<TableColumnHeader><Label>NotAfter</Label><Width>22</Width></TableColumnHeader>
|
||||
</TableHeaders>
|
||||
<TableRowEntries>
|
||||
@@ -52,6 +53,7 @@
|
||||
<TableColumnItem><PropertyName>CommonName</PropertyName></TableColumnItem>
|
||||
<TableColumnItem><PropertyName>Type</PropertyName></TableColumnItem>
|
||||
<TableColumnItem><PropertyName>Status</PropertyName></TableColumnItem>
|
||||
<TableColumnItem><PropertyName>EnableDirectIssuance</PropertyName></TableColumnItem>
|
||||
<TableColumnItem><PropertyName>KeyAlgorithm</PropertyName></TableColumnItem>
|
||||
<TableColumnItem><PropertyName>NotAfter</PropertyName></TableColumnItem>
|
||||
</TableColumnItems>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@{
|
||||
RootModule = 'PSInfisicalAPI.psm1'
|
||||
ModuleVersion = '2026.06.16.0217'
|
||||
ModuleVersion = '2026.07.30.2151'
|
||||
GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51'
|
||||
Author = 'Grace Solutions'
|
||||
CompanyName = 'Grace Solutions'
|
||||
@@ -74,7 +74,7 @@
|
||||
LicenseUri = 'https://www.gnu.org/licenses/agpl-3.0.html'
|
||||
ProjectUri = 'https://prod.git.gracesolution.info/gsadmin/PSInfisicalAPI'
|
||||
ReleaseNotes = 'See CHANGELOG.md in the project repository for release history.'
|
||||
CommitHash = '6318d06362ad'
|
||||
CommitHash = '14c8c4f3845b'
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1066,7 +1066,7 @@ $RemoveInfisicalTagResult = Remove-InfisicalTag @RemoveInfisicalTagParameters</d
|
||||
<maml:alertSet>
|
||||
<maml:title>Notes</maml:title>
|
||||
<maml:alert>
|
||||
<maml:para>ByID retrieval currently always resolves against the internal CA endpoint. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate. The Type property distinguishes 'internal' from 'acme' when -Kind Any is used.</maml:para>
|
||||
<maml:para>ByID retrieval currently always resolves against the internal CA endpoint. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate. The Type property distinguishes 'internal' from 'acme' when -Kind Any is used. Only CAs whose EnableDirectIssuance property is True can sign a CSR through -CertificateAuthorityId; the others require a subscriber or certificate profile instead.</maml:para>
|
||||
</maml:alert>
|
||||
</maml:alertSet>
|
||||
<command:examples>
|
||||
@@ -1281,6 +1281,8 @@ $GetInfisicalCertificatePolicyResult = Get-InfisicalCertificatePolicy @GetInfisi
|
||||
<maml:title>Notes</maml:title>
|
||||
<maml:alert>
|
||||
<maml:para>Default -PrivateKeyProtection is 'LocalOnly': the leaf is loaded into memory without persisting the private key and PrivateKeyPem is scrubbed from the emitted result unless -PrivateKeyPath or an explicit -KeyStorageFlags binding overrides it. The reuse path completes its chain from the Infisical bundle when local stores are incomplete; pass -LocalChainOnly to suppress that fetch entirely.</maml:para>
|
||||
<maml:para>-CertificateAuthorityId only works against a CA that permits direct issuance (Get-InfisicalCertificateAuthority reports this as EnableDirectIssuance). The cmdlet resolves the issuer and validates this before generating a keypair, naming the subscriber, CA, or profile it will use on the verbose stream and in the -WhatIf target. There is no -CertificateTemplateId parameter because Infisical's REST API exposes no template-based issuance route; when the API asks for 'a certificate template or subscriber', supply -PkiSubscriberSlug or -CertificateProfileId, or enable direct issuance on the CA.</maml:para>
|
||||
<maml:para>-CommonName takes the bare value ('web01.contoso.com'), not an RDN; a leading 'CN=' is stripped because the CSR builder adds the prefix itself. -DnsName accepts the mixed output of Get-InfisicalSANList: IP literals in that list are emitted as iPAddress SAN entries rather than dNSName entries.</maml:para>
|
||||
</maml:alert>
|
||||
</maml:alertSet>
|
||||
<command:examples>
|
||||
|
||||
@@ -1066,7 +1066,7 @@ $RemoveInfisicalTagResult = Remove-InfisicalTag @RemoveInfisicalTagParameters</d
|
||||
<maml:alertSet>
|
||||
<maml:title>Notes</maml:title>
|
||||
<maml:alert>
|
||||
<maml:para>ByID retrieval currently always resolves against the internal CA endpoint. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate. The Type property distinguishes 'internal' from 'acme' when -Kind Any is used.</maml:para>
|
||||
<maml:para>ByID retrieval currently always resolves against the internal CA endpoint. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate. The Type property distinguishes 'internal' from 'acme' when -Kind Any is used. Only CAs whose EnableDirectIssuance property is True can sign a CSR through -CertificateAuthorityId; the others require a subscriber or certificate profile instead.</maml:para>
|
||||
</maml:alert>
|
||||
</maml:alertSet>
|
||||
<command:examples>
|
||||
@@ -1281,6 +1281,8 @@ $GetInfisicalCertificatePolicyResult = Get-InfisicalCertificatePolicy @GetInfisi
|
||||
<maml:title>Notes</maml:title>
|
||||
<maml:alert>
|
||||
<maml:para>Default -PrivateKeyProtection is 'LocalOnly': the leaf is loaded into memory without persisting the private key and PrivateKeyPem is scrubbed from the emitted result unless -PrivateKeyPath or an explicit -KeyStorageFlags binding overrides it. The reuse path completes its chain from the Infisical bundle when local stores are incomplete; pass -LocalChainOnly to suppress that fetch entirely.</maml:para>
|
||||
<maml:para>-CertificateAuthorityId only works against a CA that permits direct issuance (Get-InfisicalCertificateAuthority reports this as EnableDirectIssuance). The cmdlet resolves the issuer and validates this before generating a keypair, naming the subscriber, CA, or profile it will use on the verbose stream and in the -WhatIf target. There is no -CertificateTemplateId parameter because Infisical's REST API exposes no template-based issuance route; when the API asks for 'a certificate template or subscriber', supply -PkiSubscriberSlug or -CertificateProfileId, or enable direct issuance on the CA.</maml:para>
|
||||
<maml:para>-CommonName takes the bare value ('web01.contoso.com'), not an RDN; a leading 'CN=' is stripped because the CSR builder adds the prefix itself. -DnsName accepts the mixed output of Get-InfisicalSANList: IP literals in that list are emitted as iPAddress SAN entries rather than dNSName entries.</maml:para>
|
||||
</maml:alert>
|
||||
</maml:alertSet>
|
||||
<command:examples>
|
||||
|
||||
@@ -84,6 +84,39 @@ EXAMPLES
|
||||
Get-InfisicalSecrets |
|
||||
Export-InfisicalSecrets -Path .\secrets.env -Format Env
|
||||
|
||||
ERROR HANDLING AND STREAMS
|
||||
Every cmdlet derives from PSCmdlet, so the common parameters are bound:
|
||||
-Verbose, -Debug, -ErrorAction, -ErrorVariable, -WarningAction,
|
||||
-WarningVariable, -InformationAction, -InformationVariable, -OutVariable,
|
||||
and -PipelineVariable, plus -WhatIf/-Confirm where ShouldProcess applies.
|
||||
|
||||
Output is separated by stream so those parameters mean what they say:
|
||||
|
||||
Error The failure itself, once, as a non-terminating ErrorRecord.
|
||||
Warning Advisories that are not failures.
|
||||
Verbose Request/response trace and the trail leading up to a failure.
|
||||
Debug Low-level detail.
|
||||
|
||||
Operation failures are NON-TERMINATING, so -ErrorAction decides the
|
||||
outcome:
|
||||
|
||||
Continue (default) Error is written; a pipeline keeps processing.
|
||||
SilentlyContinue Nothing printed; still in $Error/-ErrorVariable.
|
||||
Ignore Nothing printed and nothing recorded.
|
||||
Stop Promoted to terminating; try/catch catches it.
|
||||
|
||||
To catch a failure you must ask for it:
|
||||
|
||||
try {
|
||||
Request-InfisicalCertificate @Parameters -ErrorAction Stop
|
||||
} catch [PSInfisicalAPI.Errors.InfisicalApiException] {
|
||||
"HTTP $($_.Exception.StatusCode): $($_.Exception.ApiErrorMessage)"
|
||||
}
|
||||
|
||||
The ErrorRecord carries the API detail, so log scraping is unnecessary:
|
||||
$Error[0].Exception exposes StatusCode, ApiErrorCode, ApiErrorMessage, and
|
||||
ApiRequestId on InfisicalApiException.
|
||||
|
||||
SECURITY NOTES
|
||||
- SecureString is used for ClientSecret, AccessToken, and any secret
|
||||
payloads returned by the API.
|
||||
|
||||
Reference in New Issue
Block a user