diff --git a/CHANGELOG.md b/CHANGELOG.md index ff6b704..246134c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos ## Unreleased +## 2026.06.05.0215 + +- Build produced from commit 82f99ea7d4a4. + +## Unreleased (carried forward) + +## 2026.06.05.0205 + +- Build produced from commit 86968c18cb15. + +## Unreleased (carried forward) + ## 2026.06.05.0117 - Build produced from commit cffda99591c9. diff --git a/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 b/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 index a9c70cf..7b58e4f 100644 --- a/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 +++ b/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSInfisicalAPI.psm1' - ModuleVersion = '2026.06.05.0117' + ModuleVersion = '2026.06.05.0215' GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51' Author = 'Grace Solutions' CompanyName = 'Grace Solutions' @@ -40,7 +40,6 @@ 'Get-InfisicalCertificateProfile', 'Get-InfisicalCertificatePolicy', 'Get-InfisicalCertificate', - 'Search-InfisicalCertificate', 'Request-InfisicalCertificate', 'ConvertTo-InfisicalCertificate', 'Install-InfisicalCertificate', @@ -63,7 +62,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 = 'cffda99591c9' + CommitHash = '82f99ea7d4a4' } } } \ No newline at end of file diff --git a/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll b/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll index fd0a393..2b78ce7 100644 Binary files a/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll and b/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll differ diff --git a/Module/PSInfisicalAPI/bin/en-US/PSInfisicalAPI.dll-Help.xml b/Module/PSInfisicalAPI/bin/en-US/PSInfisicalAPI.dll-Help.xml index 5d82499..f67e148 100644 --- a/Module/PSInfisicalAPI/bin/en-US/PSInfisicalAPI.dll-Help.xml +++ b/Module/PSInfisicalAPI/bin/en-US/PSInfisicalAPI.dll-Help.xml @@ -1060,7 +1060,7 @@ $GetInfisicalCertificateAuthorityResult = Get-InfisicalCertificateAuthority @Get Notes - 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. + 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. @@ -1219,50 +1219,6 @@ $GetInfisicalCertificatePolicyResult = Get-InfisicalCertificatePolicy @GetInfisi - - - Search-InfisicalCertificate - Searches Infisical certificates with advanced filters and automatic paging. - Search - InfisicalCertificate - - - 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. - - - Notes - - Use -SortBy together with -SortOrder ('asc'/'desc') to control result ordering. Pair with Get-InfisicalCertificate or Export-InfisicalCertificate to drill into specific hits. - - - - - EXAMPLE 1 - Search-InfisicalCertificate -Search $env:COMPUTERNAME -Status 'active' - Finds active certificates whose searchable fields contain the local hostname. - - - EXAMPLE 2 - $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 - Searches for RSA certificates from a specific CA, scoped to the local hostname, that expire within the next 30 days, sorted soonest-first. - - - - Request-InfisicalCertificate diff --git a/Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml b/Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml index 5d82499..f67e148 100644 --- a/Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml +++ b/Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml @@ -1060,7 +1060,7 @@ $GetInfisicalCertificateAuthorityResult = Get-InfisicalCertificateAuthority @Get Notes - 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. + 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. @@ -1219,50 +1219,6 @@ $GetInfisicalCertificatePolicyResult = Get-InfisicalCertificatePolicy @GetInfisi - - - Search-InfisicalCertificate - Searches Infisical certificates with advanced filters and automatic paging. - Search - InfisicalCertificate - - - 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. - - - Notes - - Use -SortBy together with -SortOrder ('asc'/'desc') to control result ordering. Pair with Get-InfisicalCertificate or Export-InfisicalCertificate to drill into specific hits. - - - - - EXAMPLE 1 - Search-InfisicalCertificate -Search $env:COMPUTERNAME -Status 'active' - Finds active certificates whose searchable fields contain the local hostname. - - - EXAMPLE 2 - $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 - Searches for RSA certificates from a specific CA, scoped to the local hostname, that expire within the next 30 days, sorted soonest-first. - - - - Request-InfisicalCertificate diff --git a/README.md b/README.md index f155e8c..605b084 100644 --- a/README.md +++ b/README.md @@ -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-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. | diff --git a/build.ps1 b/build.ps1 index 5e70b47..8de86d7 100644 --- a/build.ps1 +++ b/build.ps1 @@ -134,7 +134,6 @@ function Write-Manifest { 'Get-InfisicalCertificateProfile', 'Get-InfisicalCertificatePolicy', 'Get-InfisicalCertificate', - 'Search-InfisicalCertificate', 'Request-InfisicalCertificate', 'ConvertTo-InfisicalCertificate', 'Install-InfisicalCertificate', @@ -210,7 +209,7 @@ if (`$cmds.Count -eq 0) { 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) { if (-not (Get-Command -Name `$expected -Module PSInfisicalAPI -ErrorAction SilentlyContinue)) { throw "Cmdlet not found: `$expected" diff --git a/src/PSInfisicalAPI.Tests/PkiEndpointRegistryTests.cs b/src/PSInfisicalAPI.Tests/PkiEndpointRegistryTests.cs index dae7d4b..1098750 100644 --- a/src/PSInfisicalAPI.Tests/PkiEndpointRegistryTests.cs +++ b/src/PSInfisicalAPI.Tests/PkiEndpointRegistryTests.cs @@ -61,11 +61,31 @@ namespace PSInfisicalAPI.Tests Type cmdletType = ModuleAssembly.GetType("PSInfisicalAPI.Cmdlets.GetInfisicalCertificateCmdlet", true); Assert.NotNull(cmdletType.GetProperty("CommonName")); Assert.NotNull(cmdletType.GetProperty("FriendlyName")); + Assert.NotNull(cmdletType.GetProperty("Search")); + Assert.NotNull(cmdletType.GetProperty("Status")); Assert.NotNull(cmdletType.GetProperty("CaId")); + Assert.NotNull(cmdletType.GetProperty("ProfileId")); + Assert.NotNull(cmdletType.GetProperty("ApplicationId")); + Assert.NotNull(cmdletType.GetProperty("ApplicationIds")); + Assert.NotNull(cmdletType.GetProperty("EnrollmentType")); + Assert.NotNull(cmdletType.GetProperty("ExtendedKeyUsage")); + Assert.NotNull(cmdletType.GetProperty("KeyAlgorithm")); + Assert.NotNull(cmdletType.GetProperty("SignatureAlgorithm")); + Assert.NotNull(cmdletType.GetProperty("KeySize")); + Assert.NotNull(cmdletType.GetProperty("Source")); + Assert.NotNull(cmdletType.GetProperty("FromDate")); + Assert.NotNull(cmdletType.GetProperty("ToDate")); + Assert.NotNull(cmdletType.GetProperty("NotAfterFrom")); + Assert.NotNull(cmdletType.GetProperty("NotAfterTo")); + Assert.NotNull(cmdletType.GetProperty("NotBeforeFrom")); + Assert.NotNull(cmdletType.GetProperty("NotBeforeTo")); + Assert.NotNull(cmdletType.GetProperty("Metadata")); + Assert.NotNull(cmdletType.GetProperty("ForPkiSync")); + Assert.NotNull(cmdletType.GetProperty("SortBy")); + Assert.NotNull(cmdletType.GetProperty("SortOrder")); Assert.NotNull(cmdletType.GetProperty("Limit")); Assert.NotNull(cmdletType.GetProperty("Offset")); Assert.NotNull(cmdletType.GetProperty("NoAutoPage")); - Assert.NotNull(cmdletType.GetProperty("List")); } [Fact] diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalCertificateCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalCertificateCmdlet.cs index a9b98d7..079f57b 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalCertificateCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalCertificateCmdlet.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Management.Automation; using PSInfisicalAPI.Connections; using PSInfisicalAPI.Models; @@ -14,12 +16,38 @@ namespace PSInfisicalAPI.Cmdlets [Alias("Id", "Identifier")] public string SerialNumber { get; set; } - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } [Parameter(ParameterSetName = "List", Mandatory = true)] public string ProjectId { get; set; } [Parameter(ParameterSetName = "List")] public string CommonName { get; set; } [Parameter(ParameterSetName = "List")] public string FriendlyName { get; set; } + [Parameter(ParameterSetName = "List")] public string Search { get; set; } [Parameter(ParameterSetName = "List")] public string Status { get; set; } [Parameter(ParameterSetName = "List")] public string[] CaId { get; set; } + [Parameter(ParameterSetName = "List")] public string[] ProfileId { get; set; } + [Parameter(ParameterSetName = "List")] public string ApplicationId { get; set; } + [Parameter(ParameterSetName = "List")] public string[] ApplicationIds { get; set; } + [Parameter(ParameterSetName = "List")] public string[] EnrollmentType { get; set; } + [Parameter(ParameterSetName = "List")] public string ExtendedKeyUsage { get; set; } + [Parameter(ParameterSetName = "List")] public string[] KeyAlgorithm { get; set; } + [Parameter(ParameterSetName = "List")] public string SignatureAlgorithm { get; set; } + [Parameter(ParameterSetName = "List")] public int[] KeySize { get; set; } + [Parameter(ParameterSetName = "List")] public string[] Source { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? FromDate { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? ToDate { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? NotAfterFrom { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? NotAfterTo { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? NotBeforeFrom { get; set; } + [Parameter(ParameterSetName = "List")] public DateTimeOffset? NotBeforeTo { get; set; } + [Parameter(ParameterSetName = "List")] public Hashtable Metadata { get; set; } + [Parameter(ParameterSetName = "List")] public SwitchParameter ForPkiSync { get; set; } + + [Parameter(ParameterSetName = "List")] + [ValidateSet("notAfter", "notBefore", "createdAt", "commonName", "keyAlgorithm", "status")] + public string SortBy { get; set; } + + [Parameter(ParameterSetName = "List")] + [ValidateSet("asc", "desc")] + public string SortOrder { get; set; } + [Parameter(ParameterSetName = "List")] public int? Limit { get; set; } [Parameter(ParameterSetName = "List")] public int? Offset { get; set; } [Parameter(ParameterSetName = "List")] public SwitchParameter NoAutoPage { get; set; } @@ -47,8 +75,28 @@ namespace PSInfisicalAPI.Cmdlets ProjectId = ProjectId, CommonName = CommonName, FriendlyName = FriendlyName, + 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), + SortBy = SortBy, + SortOrder = SortOrder, + ForPkiSync = ForPkiSync.IsPresent ? (bool?)true : null, Limit = Limit ?? 100, Offset = Offset ?? 0 }; @@ -87,5 +135,17 @@ namespace PSInfisicalAPI.Cmdlets ThrowTerminatingForException("GetInfisicalCertificateCmdlet", "GetCertificate", exception); } } + + private static Dictionary ToStringDictionary(Hashtable hashtable) + { + if (hashtable == null) { return null; } + Dictionary result = new Dictionary(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; + } } } diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalEnvironmentCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalEnvironmentCmdlet.cs index c6b4013..1b90d75 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalEnvironmentCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalEnvironmentCmdlet.cs @@ -16,8 +16,6 @@ namespace PSInfisicalAPI.Cmdlets [Parameter(Mandatory = true)] public string ProjectId { get; set; } - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } - protected override void ProcessRecord() { try diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalFolderCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalFolderCmdlet.cs index 2e877c6..457cf00 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalFolderCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalFolderCmdlet.cs @@ -18,8 +18,6 @@ namespace PSInfisicalAPI.Cmdlets [Parameter(Mandatory = true)] public string Environment { get; set; } [Parameter] public string Path { get; set; } - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } - protected override void ProcessRecord() { try diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalProjectCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalProjectCmdlet.cs index 4ab1598..ee58c45 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalProjectCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalProjectCmdlet.cs @@ -14,8 +14,6 @@ namespace PSInfisicalAPI.Cmdlets [Alias("Id")] public string ProjectId { get; set; } - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } - [Parameter(ParameterSetName = "List")] [ValidateSet("secret-manager", "cert-manager", "kms", "ssh", "secret-scanning", "pam", "ai")] public string Type { get; set; } diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalSecretCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalSecretCmdlet.cs index 724a4d3..16cc545 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalSecretCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalSecretCmdlet.cs @@ -26,7 +26,6 @@ namespace PSInfisicalAPI.Cmdlets [Parameter(ParameterSetName = "Single")] public int? Version { get; set; } [Parameter(ParameterSetName = "Single")] public InfisicalSecretType Type { get; set; } = InfisicalSecretType.Shared; - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } [Parameter(ParameterSetName = "List")] public SwitchParameter Recursive { get; set; } [Parameter(ParameterSetName = "List")] public SwitchParameter IncludePersonalOverrides { get; set; } [Parameter(ParameterSetName = "List")] public Hashtable MetadataFilter { get; set; } diff --git a/src/PSInfisicalAPI/Cmdlets/GetInfisicalTagCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/GetInfisicalTagCmdlet.cs index eefe56d..1cfd9d2 100644 --- a/src/PSInfisicalAPI/Cmdlets/GetInfisicalTagCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/GetInfisicalTagCmdlet.cs @@ -16,8 +16,6 @@ namespace PSInfisicalAPI.Cmdlets [Parameter(Mandatory = true)] public string ProjectId { get; set; } - [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } - protected override void ProcessRecord() { try diff --git a/src/PSInfisicalAPI/Cmdlets/SearchInfisicalCertificateCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/SearchInfisicalCertificateCmdlet.cs deleted file mode 100644 index 1bd04b5..0000000 --- a/src/PSInfisicalAPI/Cmdlets/SearchInfisicalCertificateCmdlet.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -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[] EnrollmentType { get; set; } - [Parameter] public string ExtendedKeyUsage { get; set; } - [Parameter] public string[] KeyAlgorithm { get; set; } - [Parameter] public string SignatureAlgorithm { get; set; } - [Parameter] public string[] Source { 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 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, - ApplicationIds = ApplicationId, - EnrollmentTypes = EnrollmentType, - ExtendedKeyUsage = ExtendedKeyUsage, - KeyAlgorithm = KeyAlgorithm, - SignatureAlgorithm = SignatureAlgorithm, - Source = Source, - NotAfterFrom = NotAfterFrom, - NotAfterTo = NotAfterTo, - NotBeforeFrom = NotBeforeFrom, - NotBeforeTo = NotBeforeTo, - SortBy = SortBy, - SortOrder = SortOrder, - Limit = Limit, - Offset = Offset - }; - } - } -} diff --git a/src/PSInfisicalAPI/Models/InfisicalCertificatePolicy.cs b/src/PSInfisicalAPI/Models/InfisicalCertificatePolicy.cs index 5708648..a8181a0 100644 --- a/src/PSInfisicalAPI/Models/InfisicalCertificatePolicy.cs +++ b/src/PSInfisicalAPI/Models/InfisicalCertificatePolicy.cs @@ -8,7 +8,7 @@ namespace PSInfisicalAPI.Models public string ProjectId { get; set; } public string Name { get; set; } public string Description { get; set; } - public InfisicalCertificatePolicySubject Subject { get; set; } + public InfisicalCertificatePolicySubject[] Subject { get; set; } public InfisicalCertificatePolicySan[] Sans { get; set; } public InfisicalCertificatePolicyUsages KeyUsages { get; set; } public InfisicalCertificatePolicyUsages ExtendedKeyUsages { get; set; } diff --git a/src/PSInfisicalAPI/Pki/InfisicalCertificateDtos.cs b/src/PSInfisicalAPI/Pki/InfisicalCertificateDtos.cs index 5996c44..44e8def 100644 --- a/src/PSInfisicalAPI/Pki/InfisicalCertificateDtos.cs +++ b/src/PSInfisicalAPI/Pki/InfisicalCertificateDtos.cs @@ -70,11 +70,13 @@ namespace PSInfisicalAPI.Pki [JsonProperty("limit", NullValueHandling = NullValueHandling.Ignore)] public int? Limit { get; set; } [JsonProperty("caIds", NullValueHandling = NullValueHandling.Ignore)] public string[] CaIds { get; set; } [JsonProperty("profileIds", NullValueHandling = NullValueHandling.Ignore)] public string[] ProfileIds { get; set; } + [JsonProperty("applicationId", NullValueHandling = NullValueHandling.Ignore)] public string ApplicationId { get; set; } [JsonProperty("applicationIds", NullValueHandling = NullValueHandling.Ignore)] public string[] ApplicationIds { get; set; } [JsonProperty("enrollmentTypes", NullValueHandling = NullValueHandling.Ignore)] public string[] EnrollmentTypes { get; set; } [JsonProperty("extendedKeyUsage", NullValueHandling = NullValueHandling.Ignore)] public string ExtendedKeyUsage { get; set; } [JsonProperty("keyAlgorithm", NullValueHandling = NullValueHandling.Ignore)] public string[] KeyAlgorithm { get; set; } [JsonProperty("signatureAlgorithm", NullValueHandling = NullValueHandling.Ignore)] public string SignatureAlgorithm { get; set; } + [JsonProperty("keySizes", NullValueHandling = NullValueHandling.Ignore)] public int[] KeySizes { get; set; } [JsonProperty("source", NullValueHandling = NullValueHandling.Ignore)] public string[] Source { get; set; } [JsonProperty("fromDate", NullValueHandling = NullValueHandling.Ignore)] public string FromDate { get; set; } [JsonProperty("toDate", NullValueHandling = NullValueHandling.Ignore)] public string ToDate { get; set; } @@ -82,11 +84,18 @@ namespace PSInfisicalAPI.Pki [JsonProperty("notAfterTo", NullValueHandling = NullValueHandling.Ignore)] public string NotAfterTo { get; set; } [JsonProperty("notBeforeFrom", NullValueHandling = NullValueHandling.Ignore)] public string NotBeforeFrom { get; set; } [JsonProperty("notBeforeTo", NullValueHandling = NullValueHandling.Ignore)] public string NotBeforeTo { get; set; } + [JsonProperty("metadata", NullValueHandling = NullValueHandling.Ignore)] public InfisicalCertificateSearchMetadataEntryDto[] Metadata { get; set; } [JsonProperty("sortBy", NullValueHandling = NullValueHandling.Ignore)] public string SortBy { get; set; } [JsonProperty("sortOrder", NullValueHandling = NullValueHandling.Ignore)] public string SortOrder { get; set; } [JsonProperty("forPkiSync", NullValueHandling = NullValueHandling.Ignore)] public bool? ForPkiSync { get; set; } } + internal sealed class InfisicalCertificateSearchMetadataEntryDto + { + [JsonProperty("key")] public string Key { get; set; } + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } + } + internal sealed class InfisicalCertificateBundleResponseDto { [JsonProperty("serialNumber")] public string SerialNumber { get; set; } diff --git a/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyDtos.cs b/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyDtos.cs index 485ea5a..3da73d5 100644 --- a/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyDtos.cs +++ b/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyDtos.cs @@ -10,7 +10,7 @@ namespace PSInfisicalAPI.Pki [JsonProperty("projectId")] public string ProjectId { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("description")] public string Description { get; set; } - [JsonProperty("subject")] public InfisicalCertificatePolicySubjectDto Subject { get; set; } + [JsonProperty("subject")] public JToken SubjectRaw { get; set; } [JsonProperty("sans")] public JToken SansRaw { get; set; } [JsonProperty("keyUsages")] public InfisicalCertificatePolicyUsagesDto KeyUsages { get; set; } [JsonProperty("extendedKeyUsages")] public InfisicalCertificatePolicyUsagesDto ExtendedKeyUsages { get; set; } diff --git a/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyMapper.cs b/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyMapper.cs index 69d3f74..8ba015a 100644 --- a/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyMapper.cs +++ b/src/PSInfisicalAPI/Pki/InfisicalCertificatePolicyMapper.cs @@ -21,7 +21,7 @@ namespace PSInfisicalAPI.Pki ProjectId = !string.IsNullOrEmpty(dto.ProjectId) ? dto.ProjectId : fallbackProjectId, Name = dto.Name, Description = dto.Description, - Subject = MapSubject(dto.Subject), + Subject = MapSubjects(dto.SubjectRaw), Sans = MapSans(dto.SansRaw), KeyUsages = MapUsages(dto.KeyUsages), ExtendedKeyUsages = MapUsages(dto.ExtendedKeyUsages), @@ -52,8 +52,32 @@ namespace PSInfisicalAPI.Pki return results.ToArray(); } - private static InfisicalCertificatePolicySubject MapSubject(InfisicalCertificatePolicySubjectDto dto) + private static InfisicalCertificatePolicySubject[] MapSubjects(JToken token) { + if (token == null || token.Type == JTokenType.Null) { return null; } + + List results = new List(); + if (token.Type == JTokenType.Array) + { + foreach (JToken child in (JArray)token) + { + InfisicalCertificatePolicySubject mapped = MapSubjectObject(child); + if (mapped != null) { results.Add(mapped); } + } + } + else if (token.Type == JTokenType.Object) + { + InfisicalCertificatePolicySubject mapped = MapSubjectObject(token); + if (mapped != null) { results.Add(mapped); } + } + + return results.Count > 0 ? results.ToArray() : null; + } + + private static InfisicalCertificatePolicySubject MapSubjectObject(JToken token) + { + if (token == null || token.Type != JTokenType.Object) { return null; } + InfisicalCertificatePolicySubjectDto dto = token.ToObject(); if (dto == null) { return null; } return new InfisicalCertificatePolicySubject { diff --git a/src/PSInfisicalAPI/Pki/InfisicalCertificateSearchQuery.cs b/src/PSInfisicalAPI/Pki/InfisicalCertificateSearchQuery.cs index f655a51..fb08d4b 100644 --- a/src/PSInfisicalAPI/Pki/InfisicalCertificateSearchQuery.cs +++ b/src/PSInfisicalAPI/Pki/InfisicalCertificateSearchQuery.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PSInfisicalAPI.Pki { @@ -13,11 +14,13 @@ namespace PSInfisicalAPI.Pki public int? Limit { get; set; } public string[] CaIds { get; set; } public string[] ProfileIds { get; set; } + public string ApplicationId { get; set; } public string[] ApplicationIds { get; set; } public string[] EnrollmentTypes { get; set; } public string ExtendedKeyUsage { get; set; } public string[] KeyAlgorithm { get; set; } public string SignatureAlgorithm { get; set; } + public int[] KeySizes { get; set; } public string[] Source { get; set; } public DateTimeOffset? FromDate { get; set; } public DateTimeOffset? ToDate { get; set; } @@ -25,6 +28,7 @@ namespace PSInfisicalAPI.Pki public DateTimeOffset? NotAfterTo { get; set; } public DateTimeOffset? NotBeforeFrom { get; set; } public DateTimeOffset? NotBeforeTo { get; set; } + public IDictionary Metadata { get; set; } public string SortBy { get; set; } public string SortOrder { get; set; } public bool? ForPkiSync { get; set; } diff --git a/src/PSInfisicalAPI/Pki/InfisicalPkiClient.cs b/src/PSInfisicalAPI/Pki/InfisicalPkiClient.cs index 2735cd6..657ea93 100644 --- a/src/PSInfisicalAPI/Pki/InfisicalPkiClient.cs +++ b/src/PSInfisicalAPI/Pki/InfisicalPkiClient.cs @@ -863,11 +863,13 @@ namespace PSInfisicalAPI.Pki Limit = query.Limit, CaIds = query.CaIds, ProfileIds = query.ProfileIds, + ApplicationId = query.ApplicationId, ApplicationIds = query.ApplicationIds, EnrollmentTypes = query.EnrollmentTypes, ExtendedKeyUsage = query.ExtendedKeyUsage, KeyAlgorithm = query.KeyAlgorithm, SignatureAlgorithm = query.SignatureAlgorithm, + KeySizes = query.KeySizes, Source = query.Source, FromDate = FormatTimestamp(query.FromDate), ToDate = FormatTimestamp(query.ToDate), @@ -875,12 +877,25 @@ namespace PSInfisicalAPI.Pki NotAfterTo = FormatTimestamp(query.NotAfterTo), NotBeforeFrom = FormatTimestamp(query.NotBeforeFrom), NotBeforeTo = FormatTimestamp(query.NotBeforeTo), + Metadata = BuildMetadataEntries(query.Metadata), SortBy = query.SortBy, SortOrder = query.SortOrder, ForPkiSync = query.ForPkiSync }; } + private static InfisicalCertificateSearchMetadataEntryDto[] BuildMetadataEntries(IDictionary source) + { + if (source == null || source.Count == 0) { return null; } + List entries = new List(source.Count); + foreach (KeyValuePair pair in source) + { + if (string.IsNullOrEmpty(pair.Key)) { continue; } + entries.Add(new InfisicalCertificateSearchMetadataEntryDto { Key = pair.Key, Value = pair.Value }); + } + return entries.Count == 0 ? null : entries.ToArray(); + } + private static string FormatTimestamp(DateTimeOffset? value) { if (!value.HasValue) { return null; }