Bring the README examples in line with optional -ProjectId and add renewal

Several examples still passed -ProjectId ($Project.Id) from a project lookup the
walkthrough no longer performs, so they read as though the parameter were still
required. Removed from the profile, policy, subscriber, and certificate
authority examples, and from the offline-fallback snippet.

The end-to-end example loses the site-specific application name, and the profile
selection collapses to one line. Its "Example output" section still showed the
project and certificate authority records the example stopped fetching, so it now
matches what the script actually emits, including the project-resolution line.

Adds a renewal example directly beneath, reusing the parameters built above so
the difference is visible as two added keys rather than a second wall of setup.
It notes that the call is safe to repeat, that reuse is matched on the issuing
profile and the SAN set so a changed profile or added name reissues, and that
-Force ignores both.

Also drops the note about $CertificateProfile versus the $Profile automatic
variable, which explained a naming choice the reader has no reason to care
about, and points the extension docs at ResolveCertManagerProjectId rather than
the ResolveProjectId name that no longer exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 16:13:58 -04:00
parent a1e1d22e72
commit e7674af161
+44 -42
View File
@@ -161,11 +161,9 @@ $ConnectInfisicalParameters = New-Object -TypeName 'System.Collections.Specializ
$Connection = Connect-Infisical @ConnectInfisicalParameters
$Application = Get-InfisicalCertificateApplication | Where-Object {($_.Name -ieq '2pint')}
$Application = Get-InfisicalCertificateApplication | Where-Object {($_.Name -ieq 'platform')}
$CertificateProfile = Get-InfisicalCertificateProfile -ApplicationId ($Application.Id) -IncludeConfigs |
Where-Object {($_.EnrollmentType -ieq 'api') -and ($_.Slug -imatch 'server')} |
Select-Object -First 1
$CertificateProfile = Get-InfisicalCertificateProfile -ApplicationId ($Application.Id) -IncludeConfigs | Where-Object {($_.EnrollmentType -ieq 'api') -and ($_.Slug -imatch 'server')} | Select-Object -First 1
$SanList = Get-InfisicalSANList
@@ -188,10 +186,30 @@ $Null = Disconnect-Infisical -Verbose
Four calls: find the application, pick its profile, gather SANs, request. No project lookup — `-ProjectId` resolves itself — and no CA lookup, because the profile already binds its issuing CA and `-InstallChain` installs the whole chain regardless.
Note `$CertificateProfile` rather than `$Profile`: `$Profile` is an automatic variable in PowerShell (the path to the current profile script), and assigning to it works but shadows something the host relies on.
`-StoreName`/`-StoreLocation` are omitted deliberately — see [Where certificates get installed](#where-certificates-get-installed).
## Renewing that certificate
Run the same request again with `-AllowRenewal`. Nothing else changes — the parameters below are the ones built above, so this is the shape to put on a schedule:
```powershell
$RequestInfisicalCertificateParameters.AllowRenewal = $True
$RequestInfisicalCertificateParameters.RenewalThresholdDays = 30
$Certificate = Request-InfisicalCertificate @RequestInfisicalCertificateParameters
```
The call is safe to repeat. Outside the renewal window it finds the installed certificate and returns it untouched; inside the window it issues a replacement and installs it:
```text
VERBOSE: Reuse search for CN=WEB01 scoped to certificate profile 'a42f8446-...' returned 1 active certificate(s).
VERBOSE: Reusing existing certificate (Thumbprint=F480A920..., NotAfter=2026-10-28 19:36:49Z).
```
Reuse is matched on the issuing profile *and* the requested SAN set, so the same script issues a new certificate — rather than silently returning the old one — whenever the profile changes or a name is added to `-DnsName`. `-Force` issues unconditionally, ignoring both the renewal window and any existing certificate.
Run it daily and it does nothing until the certificate is within 30 days of expiry, then rotates it. Nothing to gate it with, and no state to keep.
### Project scoping
Opening **Certificate Manager** in the Infisical console never asks which project to use. The project is in the URL — `/organizations/{orgId}/projects/cert-manager/{projectId}/applications` — but it is chosen for you, and everything below it is presented as **applications**. That is because Infisical's own resolver takes the single Certificate Manager project when an organization has exactly one:
@@ -256,12 +274,12 @@ The two are different levels, which is worth keeping straight when reading outpu
| **Project** | The Certificate Manager project itself. One per organization in most setups. | `Get-InfisicalProject -Type cert-manager` |
| **Application** | A grouping of profiles, members, and certificates inside that project. | `Get-InfisicalCertificateApplication` |
So a project named `mecm` can contain applications named `2pint` and `microsoft-endpoint-configuration-manager`; listing projects returns only `mecm`, because the others are not projects. Every application carries the `ProjectId` it belongs to.
So a project named `pki` can contain applications named `platform` and `endpoint-management`; listing projects returns only `pki`, because the others are not projects. Every application carries the `ProjectId` it belongs to, which is why that field is real rather than vestigial.
Profiles can be filtered to an application, matching how the console groups them:
```powershell
$Application = Get-InfisicalCertificateApplication | Where-Object {($_.Name -eq '2pint')}
$Application = Get-InfisicalCertificateApplication | Where-Object {($_.Name -ieq 'platform')}
Get-InfisicalCertificateProfile -ApplicationId $Application.Id -IncludeConfigs
Get-InfisicalCertificate -ApplicationId $Application.Id
```
@@ -269,32 +287,15 @@ Get-InfisicalCertificate -ApplicationId $Application.Id
### Example output
```text
Id : 00000000-0000-0000-0000-000000000000
Name : Microsoft Endpoint Configuration Manager
Slug : mecm
Description :
OrganizationId : 11111111-1111-1111-1111-111111111111
Type : cert-manager
AutoCapitalization : False
EnvironmentSlugs : {dev, staging, prod}
CreatedAtUtc : 3/12/2026 8:32:52 PM +00:00
UpdatedAtUtc : 6/21/2026 7:00:28 PM +00:00
Name : root-ca
CommonName : Contoso Root Certificate Authority
Type : internal
Status : active
KeyAlgorithm : RSA_2048
NotAfter : 03/25/2036 00:00:00
Id : 22222222-2222-2222-2222-222222222222
Name : intermediate-ca
CommonName : Contoso Intermediate Certificate Authority
Type : internal
Status : active
KeyAlgorithm : RSA_2048
NotAfter : 03/25/2031 00:00:00
Id : 33333333-3333-3333-3333-333333333333
Id : 11111111-1111-1111-1111-111111111111
ProjectId : 00000000-0000-0000-0000-000000000000
Name : platform
Description :
ProfileCount : 3
MemberCount : 2
CertificateCount : 0
CreatedAtUtc : 7/30/2026 10:05:37 PM +00:00
UpdatedAtUtc : 7/30/2026 10:05:37 PM +00:00
Id : 44444444-4444-4444-4444-444444444444
ProjectId : 00000000-0000-0000-0000-000000000000
@@ -321,6 +322,7 @@ WEB01.contoso.com
127.0.0.1
::1
VERBOSE: [...] - [Information] - [GetInfisicalCertificateApplicationCmdlet] - -ProjectId was not supplied; resolved the organization's only Certificate Manager project 'Platform PKI' (00000000-0000-0000-0000-000000000000).
VERBOSE: [...] - [Information] - [PkiClient] - Attempting to search Infisical certificates. Please Wait...
VERBOSE: [...] - [Verbose] - [HttpClient] - Attempting HTTP POST to https://infisical.contoso.com/api/v1/projects/00000000-0000-0000-0000-000000000000/certificates/search. Please Wait...
VERBOSE: [...] - [Verbose] - [HttpClient] - HTTP POST completed with status 200.
@@ -467,8 +469,8 @@ Request-InfisicalCertificate @RequestInfisicalCertificateParameters -WhatIf
A certificate profile binds a CA to a certificate policy. The policy constrains the subject, key usages, and extended key usages with `allowed`/`required`/`denied` lists, so the common name still varies per request while staying inside guardrails.
```powershell
Get-InfisicalCertificateProfile -ProjectId ($Project.Id) | Format-Table Id, Name, CaId
Get-InfisicalCertificatePolicy -ProjectId ($Project.Id) | Format-Table Id, Name
Get-InfisicalCertificateProfile | Format-Table Id, Slug, CaId, EnrollmentType
Get-InfisicalCertificatePolicy | Format-Table Id, Name
```
Profile issuance is the only path that does **not** consult the CA's direct-issuance flag — the service short-circuits it:
@@ -482,7 +484,7 @@ So a profile issues successfully against a CA whose `EnableDirectIssuance` is `F
#### Discovering subscribers
```powershell
Get-InfisicalPkiSubscriber -ProjectId ($Project.Id) |
Get-InfisicalPkiSubscriber |
Format-Table Name, CommonName, Status, Ttl, CaId
```
@@ -515,10 +517,10 @@ const ca = await certificateAuthorityDAL.create({ projectId, name: resolvedCaNam
So **every CA created through the API or UI has direct issuance disabled**, and nothing can turn it on afterwards. Use a certificate profile, which ignores the flag entirely.
```powershell
Get-InfisicalCertificateAuthority -ProjectId ($Project.Id) -Kind Internal |
Get-InfisicalCertificateAuthority -Kind Internal |
Format-Table Name, CommonName, Status, EnableDirectIssuance
$Ca = Get-InfisicalCertificateAuthority -ProjectId ($Project.Id) -Kind Internal |
$Ca = Get-InfisicalCertificateAuthority -Kind Internal |
Where-Object {($_.EnableDirectIssuance -eq $True)} |
Select-Object -First 1
@@ -574,7 +576,7 @@ A failing item does not abort the batch:
```powershell
'web01', 'does-not-exist', 'web02' |
ForEach-Object { Get-InfisicalPkiSubscriber -ProjectId $ProjectId -Name $_ -ErrorAction SilentlyContinue }
ForEach-Object { Get-InfisicalPkiSubscriber -Name $_ -ErrorAction SilentlyContinue }
# emits web01 and web02; the failure is available in $Error
```
@@ -674,7 +676,7 @@ To add a route:
### 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:
Cmdlets live in `src/PSInfisicalAPI/Cmdlets/` and derive from `InfisicalCmdletBase`, which exposes `HttpClient`, `Logger`, `ResolveCertManagerProjectId`, and `ThrowTerminatingForException`. Follow the consolidated discovery pattern when the cmdlet supports both list and single-record retrieval:
```csharp
[Cmdlet(VerbsCommon.Get, "InfisicalPkiSubscriber", DefaultParameterSetName = "List")]
@@ -699,7 +701,7 @@ After adding (or removing) a cmdlet:
```powershell
$Params = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase)
$Params.ProjectId = (Get-InfisicalProject | Select-Object -First 1).Id
$Params.ProjectId = (Get-InfisicalProject -Type cert-manager | Select-Object -First 1).Id
$Result = Get-InfisicalPkiSubscriber @Params
```
4. Add a `## Unreleased` entry to `CHANGELOG.md` describing the change (mark removals of public cmdlets or parameters as **BREAKING**).