refactor!(certificates): remove Search-InfisicalCertificate (use Get-InfisicalCertificate)

Search-InfisicalCertificate was a 1:1 duplicate of Get-InfisicalCertificate's
List parameter set after the recent filter-surface expansion (bdec5aa). Both
cmdlets exposed the same ~27 server-side filters and both hit the same
POST /api/v1/projects/{projectId}/certificates/search endpoint. Keeping two
PowerShell cmdlets for the same operation added discovery noise without
benefit.

REMOVED
- src/PSInfisicalAPI/Cmdlets/SearchInfisicalCertificateCmdlet.cs (cmdlet
  source, ~140 lines).
- 'Search-InfisicalCertificate' from CmdletsToExport in the source manifest
  (Module/PSInfisicalAPI/PSInfisicalAPI.psd1) and from the two generators
  in build.ps1 (Write-Manifest cmdlet list + Test-ModuleImports $expectedCmds).
- <command:command> block for Search-InfisicalCertificate from the help XML
  (Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml).
- README PKI table row for Search-InfisicalCertificate.
- "For advanced filtering ... use Search-InfisicalCertificate instead"
  sentence from the Get-InfisicalCertificate Notes block (no longer true).

RETAINED (internal)
- InfisicalPkiClient.SearchCertificates, InfisicalCertificateSearchQuery,
  InfisicalEndpointNames.SearchCertificates and the endpoint registry entry.
  Get-InfisicalCertificate and Request-InfisicalCertificate still call them
  to walk the search endpoint.

MIGRATION
  # Before
  Search-InfisicalCertificate -ProjectId $p -Search 'web' -Status 'active'
  # After
  Get-InfisicalCertificate    -ProjectId $p -Search 'web' -Status 'active'

Parameter names, defaults, and paging behavior are identical.

TESTS
- 216/216 passing (one unrelated time-based test in CsrAndRequestCmdletTests
  was flaky on the run; passes deterministically when invoked in isolation).
This commit is contained in:
GraceSolutions
2026-06-04 22:13:48 -04:00
parent 93dc63d913
commit 880ff8d491
5 changed files with 2 additions and 189 deletions
@@ -40,7 +40,6 @@
'Get-InfisicalCertificateProfile', 'Get-InfisicalCertificateProfile',
'Get-InfisicalCertificatePolicy', 'Get-InfisicalCertificatePolicy',
'Get-InfisicalCertificate', 'Get-InfisicalCertificate',
'Search-InfisicalCertificate',
'Request-InfisicalCertificate', 'Request-InfisicalCertificate',
'ConvertTo-InfisicalCertificate', 'ConvertTo-InfisicalCertificate',
'Install-InfisicalCertificate', 'Install-InfisicalCertificate',
@@ -1060,7 +1060,7 @@ $GetInfisicalCertificateAuthorityResult = Get-InfisicalCertificateAuthority @Get
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
<maml:alert> <maml:alert>
<maml:para>For advanced filtering (validity window, key algorithm, extended key usage, etc.) use Search-InfisicalCertificate instead. Single mode returns metadata only; to obtain certificate and chain PEM material use ConvertTo-InfisicalCertificate or Export-InfisicalCertificate. Accepts pipeline input by property name on -SerialNumber.</maml:para> <maml:para>Single mode returns metadata only; to obtain certificate and chain PEM material use ConvertTo-InfisicalCertificate or Export-InfisicalCertificate. Accepts pipeline input by property name on -SerialNumber.</maml:para>
</maml:alert> </maml:alert>
</maml:alertSet> </maml:alertSet>
<command:examples> <command:examples>
@@ -1219,50 +1219,6 @@ $GetInfisicalCertificatePolicyResult = Get-InfisicalCertificatePolicy @GetInfisi
</command:examples> </command:examples>
</command:command> </command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Search-InfisicalCertificate</command:name>
<maml:description><maml:para>Searches Infisical certificates with advanced filters and automatic paging.</maml:para></maml:description>
<command:verb>Search</command:verb>
<command:noun>InfisicalCertificate</command:noun>
</command:details>
<maml:description>
<maml:para>Performs a server-side search across certificates with filters for friendly name, common name, free-text search, status, CA/profile/application/enrollment scope, key/signature algorithm, source, and validity window (-NotBeforeFrom/-NotBeforeTo/-NotAfterFrom/-NotAfterTo). Results are paged automatically unless -NoAutoPage is supplied. -ProjectId is required.</maml:para>
</maml:description>
<maml:alertSet>
<maml:title>Notes</maml:title>
<maml:alert>
<maml:para>Use -SortBy together with -SortOrder ('asc'/'desc') to control result ordering. Pair with Get-InfisicalCertificate or Export-InfisicalCertificate to drill into specific hits.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
<command:example>
<maml:title>EXAMPLE 1</maml:title>
<dev:code>Search-InfisicalCertificate -Search $env:COMPUTERNAME -Status 'active'</dev:code>
<dev:remarks><maml:para>Finds active certificates whose searchable fields contain the local hostname.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 2</maml:title>
<dev:code>$GetInfisicalCertificateAuthorityListResult = Get-InfisicalCertificateAuthority | Where-Object { $_.FriendlyName -eq 'Issuing CA - Platform' }
$SearchInfisicalCertificateParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase)
$SearchInfisicalCertificateParameters.ProjectId = $ProjectId
$SearchInfisicalCertificateParameters.CommonName = $env:COMPUTERNAME
$SearchInfisicalCertificateParameters.Status = 'active'
$SearchInfisicalCertificateParameters.CaId = @($GetInfisicalCertificateAuthorityListResult.Id)
$SearchInfisicalCertificateParameters.KeyAlgorithm = @('RSA')
$SearchInfisicalCertificateParameters.NotAfterTo = (Get-Date).AddDays(30)
$SearchInfisicalCertificateParameters.SortBy = 'notAfter'
$SearchInfisicalCertificateParameters.SortOrder = 'asc'
$SearchInfisicalCertificateParameters.Limit = 100
$SearchInfisicalCertificateParameters.Verbose = $True
$SearchInfisicalCertificateResult = Search-InfisicalCertificate @SearchInfisicalCertificateParameters</dev:code>
<dev:remarks><maml:para>Searches for RSA certificates from a specific CA, scoped to the local hostname, that expire within the next 30 days, sorted soonest-first.</maml:para></dev:remarks>
</command:example>
</command:examples>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Request-InfisicalCertificate</command:name> <command:name>Request-InfisicalCertificate</command:name>
-1
View File
@@ -90,7 +90,6 @@ The module exports 37 cmdlets. Discovery cmdlets (`Get-Infisical*`) use a `List`
| `Get-InfisicalCertificateAuthority` | Lists or retrieves Infisical internal Certificate Authorities. | | `Get-InfisicalCertificateAuthority` | Lists or retrieves Infisical internal Certificate Authorities. |
| `Get-InfisicalPkiSubscriber` | Lists or retrieves Infisical PKI subscribers in a project. | | `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. | | `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. | | `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. | | `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. | | `Install-InfisicalCertificate` | Installs an Infisical certificate (and optional chain) into a Windows certificate store. |
+1 -2
View File
@@ -134,7 +134,6 @@ function Write-Manifest {
'Get-InfisicalCertificateProfile', 'Get-InfisicalCertificateProfile',
'Get-InfisicalCertificatePolicy', 'Get-InfisicalCertificatePolicy',
'Get-InfisicalCertificate', 'Get-InfisicalCertificate',
'Search-InfisicalCertificate',
'Request-InfisicalCertificate', 'Request-InfisicalCertificate',
'ConvertTo-InfisicalCertificate', 'ConvertTo-InfisicalCertificate',
'Install-InfisicalCertificate', 'Install-InfisicalCertificate',
@@ -210,7 +209,7 @@ if (`$cmds.Count -eq 0) {
throw "No cmdlets were exported by the PSInfisicalAPI module." throw "No cmdlets were exported by the PSInfisicalAPI module."
} }
`$expectedCmds = @('Connect-Infisical','Disconnect-Infisical','Get-InfisicalSecret','New-InfisicalSecret','Update-InfisicalSecret','Remove-InfisicalSecret','Copy-InfisicalSecret','ConvertTo-InfisicalSecretDictionary','Export-InfisicalSecrets','Get-InfisicalProject','New-InfisicalProject','Update-InfisicalProject','Remove-InfisicalProject','Get-InfisicalEnvironment','New-InfisicalEnvironment','Update-InfisicalEnvironment','Remove-InfisicalEnvironment','Get-InfisicalFolder','New-InfisicalFolder','Update-InfisicalFolder','Remove-InfisicalFolder','Get-InfisicalTag','New-InfisicalTag','Update-InfisicalTag','Remove-InfisicalTag','Get-InfisicalCertificateAuthority','Get-InfisicalPkiSubscriber','Get-InfisicalCertificateProfile','Get-InfisicalCertificatePolicy','Get-InfisicalCertificate','Search-InfisicalCertificate','Request-InfisicalCertificate','ConvertTo-InfisicalCertificate','Install-InfisicalCertificate','Uninstall-InfisicalCertificate','Export-InfisicalCertificate','Get-InfisicalCertificateApplication','Get-InfisicalCertificateApplicationEnrollment','New-InfisicalScepDynamicChallenge','Get-InfisicalScepMdmProfile','Export-InfisicalScepMdmProfile','Write-InfisicalScepMdmProfileToWmi') `$expectedCmds = @('Connect-Infisical','Disconnect-Infisical','Get-InfisicalSecret','New-InfisicalSecret','Update-InfisicalSecret','Remove-InfisicalSecret','Copy-InfisicalSecret','ConvertTo-InfisicalSecretDictionary','Export-InfisicalSecrets','Get-InfisicalProject','New-InfisicalProject','Update-InfisicalProject','Remove-InfisicalProject','Get-InfisicalEnvironment','New-InfisicalEnvironment','Update-InfisicalEnvironment','Remove-InfisicalEnvironment','Get-InfisicalFolder','New-InfisicalFolder','Update-InfisicalFolder','Remove-InfisicalFolder','Get-InfisicalTag','New-InfisicalTag','Update-InfisicalTag','Remove-InfisicalTag','Get-InfisicalCertificateAuthority','Get-InfisicalPkiSubscriber','Get-InfisicalCertificateProfile','Get-InfisicalCertificatePolicy','Get-InfisicalCertificate','Request-InfisicalCertificate','ConvertTo-InfisicalCertificate','Install-InfisicalCertificate','Uninstall-InfisicalCertificate','Export-InfisicalCertificate','Get-InfisicalCertificateApplication','Get-InfisicalCertificateApplicationEnrollment','New-InfisicalScepDynamicChallenge','Get-InfisicalScepMdmProfile','Export-InfisicalScepMdmProfile','Write-InfisicalScepMdmProfileToWmi')
foreach (`$expected in `$expectedCmds) { foreach (`$expected in `$expectedCmds) {
if (-not (Get-Command -Name `$expected -Module PSInfisicalAPI -ErrorAction SilentlyContinue)) { if (-not (Get-Command -Name `$expected -Module PSInfisicalAPI -ErrorAction SilentlyContinue)) {
throw "Cmdlet not found: `$expected" throw "Cmdlet not found: `$expected"
@@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Management.Automation;
using PSInfisicalAPI.Connections;
using PSInfisicalAPI.Models;
using PSInfisicalAPI.Pki;
namespace PSInfisicalAPI.Cmdlets
{
[Cmdlet(VerbsCommon.Search, "InfisicalCertificate")]
[OutputType(typeof(InfisicalCertificate))]
public sealed class SearchInfisicalCertificateCmdlet : InfisicalCmdletBase
{
[Parameter(Mandatory = true)] public string ProjectId { get; set; }
[Parameter] public string FriendlyName { get; set; }
[Parameter] public string CommonName { get; set; }
[Parameter] public string Search { get; set; }
[Parameter] public string Status { get; set; }
[Parameter] public string[] CaId { get; set; }
[Parameter] public string[] ProfileId { get; set; }
[Parameter] public string ApplicationId { get; set; }
[Parameter] public string[] ApplicationIds { get; set; }
[Parameter] public string[] EnrollmentType { get; set; }
[Parameter] public string ExtendedKeyUsage { get; set; }
[Parameter] public string[] KeyAlgorithm { get; set; }
[Parameter] public string SignatureAlgorithm { get; set; }
[Parameter] public int[] KeySize { get; set; }
[Parameter] public string[] Source { get; set; }
[Parameter] public DateTimeOffset? FromDate { get; set; }
[Parameter] public DateTimeOffset? ToDate { get; set; }
[Parameter] public DateTimeOffset? NotAfterFrom { get; set; }
[Parameter] public DateTimeOffset? NotAfterTo { get; set; }
[Parameter] public DateTimeOffset? NotBeforeFrom { get; set; }
[Parameter] public DateTimeOffset? NotBeforeTo { get; set; }
[Parameter] public Hashtable Metadata { get; set; }
[Parameter] public SwitchParameter ForPkiSync { get; set; }
[Parameter]
[ValidateSet("notAfter", "notBefore", "createdAt", "commonName", "keyAlgorithm", "status")]
public string SortBy { get; set; }
[Parameter] [ValidateSet("asc", "desc")] public string SortOrder { get; set; }
[Parameter] public int? Limit { get; set; }
[Parameter] public int? Offset { get; set; }
[Parameter] public SwitchParameter NoAutoPage { get; set; }
protected override void ProcessRecord()
{
try
{
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
InfisicalPkiClient client = new InfisicalPkiClient(HttpClient, Logger);
InfisicalCertificateSearchQuery query = BuildQuery(ProjectId);
int requestedLimit = query.Limit ?? 100;
query.Limit = requestedLimit;
query.Offset = query.Offset ?? 0;
int emitted = 0;
while (true)
{
InfisicalCertificateSearchResult page = client.SearchCertificates(connection, query);
if (page == null || page.Certificates == null || page.Certificates.Length == 0)
{
break;
}
foreach (InfisicalCertificate cert in page.Certificates)
{
WriteObject(cert);
emitted++;
}
if (NoAutoPage.IsPresent || page.Certificates.Length < requestedLimit)
{
break;
}
if (page.TotalCount > 0 && emitted >= page.TotalCount)
{
break;
}
query.Offset = (query.Offset ?? 0) + page.Certificates.Length;
}
}
catch (Exception exception)
{
ThrowTerminatingForException("SearchInfisicalCertificateCmdlet", "SearchCertificates", exception);
}
}
private InfisicalCertificateSearchQuery BuildQuery(string projectId)
{
return new InfisicalCertificateSearchQuery
{
ProjectId = projectId,
FriendlyName = FriendlyName,
CommonName = CommonName,
Search = Search,
Status = Status,
CaIds = CaId,
ProfileIds = ProfileId,
ApplicationId = ApplicationId,
ApplicationIds = ApplicationIds,
EnrollmentTypes = EnrollmentType,
ExtendedKeyUsage = ExtendedKeyUsage,
KeyAlgorithm = KeyAlgorithm,
SignatureAlgorithm = SignatureAlgorithm,
KeySizes = KeySize,
Source = Source,
FromDate = FromDate,
ToDate = ToDate,
NotAfterFrom = NotAfterFrom,
NotAfterTo = NotAfterTo,
NotBeforeFrom = NotBeforeFrom,
NotBeforeTo = NotBeforeTo,
Metadata = ToStringDictionary(Metadata),
ForPkiSync = ForPkiSync.IsPresent ? (bool?)true : null,
SortBy = SortBy,
SortOrder = SortOrder,
Limit = Limit,
Offset = Offset
};
}
private static Dictionary<string, string> ToStringDictionary(Hashtable hashtable)
{
if (hashtable == null) { return null; }
Dictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (DictionaryEntry entry in hashtable)
{
if (entry.Key == null) { continue; }
result[entry.Key.ToString()] = entry.Value != null ? entry.Value.ToString() : null;
}
return result;
}
}
}