Skip to content

81018 adding jea support#185

Open
rcpokorny wants to merge 48 commits into
release-4.0from
81018-Adding_JEA_Support
Open

81018 adding jea support#185
rcpokorny wants to merge 48 commits into
release-4.0from
81018-Adding_JEA_Support

Conversation

@rcpokorny

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings May 11, 2026 22:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces JEA (Just Enough Administration) support for WinRM-based remote execution by refactoring the extension’s PowerShell surface into installable modules/role capabilities, wiring a new JEAEndpointName job property through the orchestrator, and updating tests/docs to cover the new behavior.

Changes:

  • Add JEAEndpointName support end-to-end (job properties → PSHelper session creation → integration/unit tests).
  • Replace monolithic WinCertScripts.ps1 script injection with modular PowerShell (Keyfactor.WinCert.Common/IIS/SQL) plus JEA .psrc role capability files and a .pssc session configuration template.
  • Update documentation (README + docsource) and integration tests to reflect JEA setup and connection selection.

Reviewed changes

Copilot reviewed 67 out of 68 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
WindowsCertStore.UnitTests/WindowsCertStore.UnitTests.csproj Adds Moq/Newtonsoft.Json; sets xUnit VS runner PrivateAssets metadata.
WindowsCertStore.UnitTests/PSHelperUnitTests.cs Updates script folder name lookup from PowerShellScripts to PowerShell.
WindowsCertStore.UnitTests/PSHelperConfigTests.cs Adds unit tests for PSHelper constructors, script directory discovery, and LocalMachine+JEA guard behavior.
WindowsCertStore.UnitTests/JobPropertiesTests.cs Adds unit tests validating JobProperties defaulting + legacy field tolerance.
WindowsCertStore.IntegrationTests/WinSQLIntegrationTests.cs Adds Integration trait; passes JEAEndpointName; uses SQL-only connection data source.
WindowsCertStore.IntegrationTests/WinIISIntegrationTests.cs Adds Integration trait; passes JEAEndpointName; uses IIS-only connection data source.
WindowsCertStore.IntegrationTests/WinCertIntegrationTests.cs New WinCert E2E integration tests (Add/Inventory/Remove and renewal flow) with JEA support.
WindowsCertStore.IntegrationTests/servers.json Expands server definitions with StoreType + JEA endpoint name.
WindowsCertStore.IntegrationTests/Factories/ConnectionFactory.cs Refactors connection loading, adds store-type filtering and env/appsettings credential sourcing.
WindowsCertStore.IntegrationTests/ClientConnection.cs Adds StoreType and JEAEndpointName to connection model.
README.md Adds detailed JEA documentation and updates WinRM port references (5985/5986).
docsource/content.md Adds detailed JEA documentation for generated docs; notes module install requirements for JEA.
IISU/WindowsCertStore.csproj Updates packaging to include new PowerShell\ module tree + .pssc and legacy scripts.
IISU/RemoteSettings.cs Adds JEAEndpointName to remote settings model.
IISU/PSHelper.cs Adds JEA endpoint support (WinRM ConfigurationName), blocks LocalMachine+JEA, changes script loading strategy, improves Information stream handling.
IISU/Properties/AssemblyInfo.cs Exposes internals to unit/integration test assemblies.
IISU/PowerShellScripts/WinCertScripts.ps1 Removes legacy monolithic script.
IISU/PowerShell/WinADFSScripts.ps1 Adjusts logging to use Information stream “[VERBOSE] …” convention.
IISU/PowerShell/Keyfactor.WinCert.SQL/RoleCapabilities/Keyfactor.WinCert.SQL.psrc New SQL JEA role capability definition.
IISU/PowerShell/Keyfactor.WinCert.SQL/Public/Remove-KeyfactorSQLCertificate.ps1 New SQL unbind function.
IISU/PowerShell/Keyfactor.WinCert.SQL/Public/New-KeyfactorSQLBinding.ps1 New SQL bind function wrapper.
IISU/PowerShell/Keyfactor.WinCert.SQL/Public/Get-KeyfactorSQLInventory.ps1 New SQL inventory function.
IISU/PowerShell/Keyfactor.WinCert.SQL/Private/Set-KeyfactorSQLCertificateBinding.ps1 New SQL bind implementation (registry + ACL + optional restart).
IISU/PowerShell/Keyfactor.WinCert.SQL/Private/Get-KeyfactorSQLServiceUser.ps1 New helper to read SQL service user.
IISU/PowerShell/Keyfactor.WinCert.SQL/Private/Get-KeyfactorSQLServiceName.ps1 New helper to compute SQL service name.
IISU/PowerShell/Keyfactor.WinCert.SQL/Keyfactor.WinCert.SQL.psm1 New SQL module entry point with explicit dot-sourcing + exports.
IISU/PowerShell/Keyfactor.WinCert.IIS/RoleCapabilities/Keyfactor.WinCert.IIS.psrc New IIS JEA role capability definition.
IISU/PowerShell/Keyfactor.WinCert.IIS/Public/Remove-KeyfactorIISSiteBinding.ps1 New IIS binding removal function with IIS drive autodetect.
IISU/PowerShell/Keyfactor.WinCert.IIS/Public/Remove-KeyfactorIISCertificateIfUnused.ps1 New IIS certificate cleanup helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Public/New-KeyfactorIISSiteBinding.ps1 New IIS binding creation with SSL flags handling and appcmd fallback.
IISU/PowerShell/Keyfactor.WinCert.IIS/Public/Get-KeyfactorIISBoundCertificates.ps1 New IIS inventory function.
IISU/PowerShell/Keyfactor.WinCert.IIS/Private/Test-ValidSslFlags.ps1 New SSL flag validation helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Private/Test-IISDrive.ps1 New IIS:\ drive availability helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Private/Get-ValidSslFlagsForSystem.ps1 New OS-build-based SSL flag support helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Private/Get-IISManagementInfo.ps1 New IIS management mode detection helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Private/Add-IISBindingWithSSL.ps1 New IIS binding add + SSL attach helper.
IISU/PowerShell/Keyfactor.WinCert.IIS/Keyfactor.WinCert.IIS.psm1 New IIS module entry point with explicit dot-sourcing + exports.
IISU/PowerShell/Keyfactor.WinCert.Common/RoleCapabilities/Keyfactor.WinCert.Common.psrc New common JEA role capability definition.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/Remove-KeyfactorCertificate.ps1 New common remove-from-store implementation.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/New-KeyfactorResult.ps1 New common structured result helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/New-KeyfactorODKGEnrollment.ps1 New ODKG CSR generation function.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/Import-KeyfactorSignedCertificate.ps1 New signed cert import helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/Get-KeyfactorCertificates.ps1 New common inventory function.
IISU/PowerShell/Keyfactor.WinCert.Common/Public/Add-KeyfactorCertificate.ps1 New common add-to-store implementation.
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Validate-CryptoProvider.ps1 New provider validation helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Test-CryptoServiceProvider.ps1 New provider existence helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Get-CryptoProviders.ps1 New CSP discovery helper using certutil.
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Get-CertificateSAN.ps1 New SAN extraction helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Get-CertificateCSP.ps1 New CSP/KSP detection helper (CAPI + CNG).
IISU/PowerShell/Keyfactor.WinCert.Common/Private/Convert-DNSSubject.ps1 New DN subject parsing helper.
IISU/PowerShell/Keyfactor.WinCert.Common/Keyfactor.WinCert.Common.psm1 New Common module entry point with explicit dot-sourcing + exports.
IISU/PowerShell/Build/KeyfactorWinCert.pssc New JEA session configuration template (RestrictedRemoteServer + transcripts + role mapping).
IISU/Models/JobProperties.cs Adds JEAEndpointName job property.
IISU/ImplementedStoreTypes/WinSQL/WinSqlBinding.cs Switches to new SQL module function names.
IISU/ImplementedStoreTypes/WinSQL/Management.cs Wires JEAEndpointName; switches to new module function names.
IISU/ImplementedStoreTypes/WinSQL/Inventory.cs Wires JEAEndpointName; switches to new inventory function name and signature.
IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs Switches to new IIS module function names; updates unbind parameter shape and result parsing.
IISU/ImplementedStoreTypes/WinIIS/Management.cs Wires JEAEndpointName; switches to new module function names.
IISU/ImplementedStoreTypes/WinIIS/Inventory.cs Wires JEAEndpointName; switches to new IIS inventory function name.
IISU/ImplementedStoreTypes/WinADFS/Inventory.cs Removes SAN field propagation for ADFS inventory parameters.
IISU/ImplementedStoreTypes/Win/WinInventory.cs Marks unused class obsolete.
IISU/ImplementedStoreTypes/Win/WinCertCertificateInfo.cs Removes SAN field from WinCert cert info model.
IISU/ImplementedStoreTypes/Win/Management.cs Wires JEAEndpointName; switches to new module function names.
IISU/ImplementedStoreTypes/Win/Inventory.cs Wires JEAEndpointName; switches to new inventory function name; removes SAN parameter propagation.
IISU/ClientPSCertStoreReEnrollment.cs Wires JEAEndpointName; switches to new ODKG/import function names; updates log strings.
CHANGELOG.md Adds 4.0.0 entry documenting SAN removal and JEA support.
.vscode/launch.json Adds VS Code launch configuration for PowerShell.
.gitignore Ignores local.runsettings to avoid committing local credentials.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +22 to +29
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.Build();

// 3. Retrieve connection details from configuration
var vault = new VaultHelper(config);
return (vault.GetSecret("Username"), vault.GetSecret("Password"));
}
Comment thread IISU/PSHelper.cs
Comment on lines +292 to +311
// Pre-flight: verify Keyfactor modules are installed on the JEA endpoint.
PS.AddCommand("Invoke-Command")
.AddParameter("Session", _PSSession)
.AddParameter("ScriptBlock", ScriptBlock.Create("[bool](Get-Command 'New-KeyfactorResult' -ErrorAction SilentlyContinue)"));
var preFlightResults = PS.Invoke();
PS.Commands.Clear();

bool modulesInstalled = preFlightResults != null &&
preFlightResults.Count > 0 &&
preFlightResults[0]?.BaseObject is bool preFlightBool &&
preFlightBool;

if (!modulesInstalled)
{
throw new Exception(
$"JEA endpoint '{jeaEndpoint}' is reachable but Keyfactor modules are not installed. " +
"Install Keyfactor.WinCert.Common (and any required store-type modules) under " +
"'C:\\Program Files\\WindowsPowerShell\\Modules\\' on the target machine, " +
"re-register the JEA session configuration, and restart WinRM.");
}

try {
Write-Information "Entering PowerShell Script Add-KeyfactorCertificateToStore"
Write-Information "[VERBOSE] Add-KeyfactorCertificateToStore - Received: StoreName: '$StoreName', CryptoServiceProvider: '$CryptoServiceProvider', Base64Cert: '$Base64Cert'"
Comment on lines +77 to +78
Write-Information "[VERBOSE] Running certutil with arguments: $argLine"

Comment on lines +10 to +15
if ($serviceUser) {
return $serviceUser
} else {
Write-Error "SQL Server instance '$SQLInstanceName' not found or no service user associated."
return $null
}
Comment thread CHANGELOG.md
@@ -1,3 +1,7 @@
4.0.0
* As of this version of the extension, SANs will be handled through the ODKG Enrollment page in Command and will no longer use the SAN Entry Parameter. This version, we are removing all support for the SAN Entry Parameter. If you are still using the SAN Entry Parameter, you will need to remove it from your store types and re-run inventory to remove it from your database.
* Adding JEA Support for local PowerShell execution. This will allow for more secure execution of the extension when running in a local PowerShell Runspace. To utilize this feature, you will need to create a JEA endpoint on the target server and specify the endpoint name as a new parameter in the specific Cert Store definition. Refer to the README for more details.
Comment on lines +28 to +34
Write-Information "[VERBOSE] Instance: $instance"
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

Comment on lines 286 to 301
_results = _psHelper.ExecutePowerShell("Add-KFCertificateToStore", parameters);
_results = _psHelper.ExecutePowerShell("Add-KeyfactorCertificate", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KFCertificateToStore)");

Comment on lines +269 to +285
_results = _psHelper.ExecutePowerShell("Add-KFCertificateToStore", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KFCertificateToStore)");
_results = _psHelper.ExecutePowerShell("Add-KeyfactorCertificate", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KeyfactorCertificate)");
Comment on lines 149 to 164
_logger.LogTrace("Returned from executing PS function (Add-KFCertificateToStore)");
_results = _psHelper.ExecutePowerShell("Add-KeyfactorCertificate", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KeyfactorCertificate)");

Copilot AI review requested due to automatic review settings May 12, 2026 16:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 145 changed files in this pull request and generated 11 comments.

Comment on lines +4 to +8
[string]$StorePath,

[parameter(ParameterSetName = $false)]
[switch]$IsAlias
)
Comment on lines +31 to +33
Set-Location -Path "Cert:\LocalMachine\$StoreName"

$importResult = Import-Certificate -FilePath $cerFilename
Comment on lines +28 to +36
Write-Information "[VERBOSE] Instance: $instance"
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Write-Information "Renewal thumbprint matches for instance: $fullInstance"
Comment on lines +35 to +46
if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Write-Information "Renewal thumbprint matches for instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
} elseif (-not $RenewalThumbprint) {
Write-Information "No renewal thumbprint provided. Binding certificate to instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
}

if (-not $result) {
Write-Error "Failed to bind certificate for instance: $instance"
$bindingSuccess = $false
}
Comment on lines +11 to +15
return $serviceUser
} else {
Write-Error "SQL Server instance '$SQLInstanceName' not found or no service user associated."
return $null
}
Comment on lines +41 to +44
var (username, password) = GetCredentials();
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
yield break;

Comment on lines +299 to 301
_results = _psHelper.ExecutePowerShell("Add-KeyfactorCertificate", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KFCertificateToStore)");

Comment on lines 164 to 168
case "Skipped":
psResult = OrchestratorJobStatusJobResult.Failure;
failureMessage = ($"PowerShell function New-KFIISSiteBinding failed on step: {step} - message:\n {errorMessage}");
failureMessage = ($"PowerShell function New-KeyfactorIISSiteBinding failed on step: {step} - message:\n {errorMessage}");
_logger.LogDebug(failureMessage);
break;
Comment on lines +4 to 6
Write-Host "Creating store type: WinCert"
kfutil store-types create WinCert

Comment on lines +1 to +8
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e

if ! command -v kfutil &> /dev/null; then
echo "kfutil could not be found. Please install kfutil"
echo "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
fi
echo "Creating store type: WinCert"
kfutil store-types create WinCert
Copilot AI review requested due to automatic review settings May 12, 2026 16:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 145 changed files in this pull request and generated 12 comments.

Comment on lines +8 to +14
$serviceUser = (Get-CimInstance -ClassName Win32_Service -Filter "Name='$SQLServiceName'").StartName

if ($serviceUser) {
return $serviceUser
} else {
Write-Error "SQL Server instance '$SQLInstanceName' not found or no service user associated."
return $null
Comment on lines +29 to +35
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Comment on lines +24 to +26
Write-Information "Entering PowerShell Script: New-KFIISSiteBinding" -InformationAction SilentlyContinue
Write-Information "[VERBOSE] Parameters: $(($PSBoundParameters.GetEnumerator() | ForEach-Object { "$($_.Key): '$($_.Value)'" }) -join ', ')"

Comment on lines +113 to +117
catch {
$errorMessage = "Unexpected error in New-KFIISSiteBinding: $($_.Exception.Message)"
Write-Error $errorMessage
return New-KeyfactorResult -Status Error -Code 999 -Step UnexpectedError -ErrorMessage $errorMessage
}
Comment on lines +12 to +16
if ($build -ge 20348) {
# Windows Server 2022+ (IIS 10.0.20348+)
Write-Information "[VERBOSE] Detected Windows Server 2022 or later (Build: $build)"
return @(1, 4, 8, 16, 32, 64) # Include unknowns for testing
}
Comment on lines +5 to +8

[parameter(ParameterSetName = $false)]
[switch]$IsAlias
)
Comment on lines +31 to +33
Set-Location -Path "Cert:\LocalMachine\$StoreName"

$importResult = Import-Certificate -FilePath $cerFilename
Comment on lines +2 to +6
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "{SQL-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "" },
{ "Machine": "{SQL-JEA-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
Comment on lines +1 to +8
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e

if ! command -v kfutil &> /dev/null; then
echo "kfutil could not be found. Please install kfutil"
echo "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
fi
echo "Creating store type: WinCert"
kfutil store-types create WinCert
Comment on lines +1 to +8
# Store Type creation script using kfutil
# Generated by Doctool

# Uncomment if kfutil is not in your PATH
# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe'
Write-Host "Creating store type: WinCert"
kfutil store-types create WinCert

if ($null -eq (Get-Command "kfutil" -ErrorAction SilentlyContinue)) {
Write-Host "kfutil could not be found. Please install kfutil"
Write-Host "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
}
Write-Host "Creating store type: IISU"
kfutil store-types create IISU
Copilot AI review requested due to automatic review settings May 15, 2026 23:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 77 out of 157 changed files in this pull request and generated 13 comments.

Comment on lines +31 to +33
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

_results = _psHelper.ExecutePowerShell("Add-KFCertificateToStore", parameters);
_results = _psHelper.ExecutePowerShell("Add-KeyfactorCertificate", parameters);
_logger.LogTrace("Returned from executing PS function (Add-KFCertificateToStore)");
# Generate INF file content for the CSR
$infContent = @"
[Version]
Signature=`"$`Windows NT$`"
Comment on lines +2 to +7
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "{SQL-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "" },
{ "Machine": "{SQL-JEA-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "keyfactor.wincert" }
Comment on lines +82 to +96
//Assert.Equal(legacySan, result);

// Assert
if (legacySan == null)
{
Assert.Equal(string.Empty, result);
}
else if (legacySan == string.Empty)
{
Assert.Equal(string.Empty, result);
}
else
{
Assert.Equal(legacySan, result);
}
Comment on lines +35 to +46
if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Write-Information "Renewal thumbprint matches for instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
} elseif (-not $RenewalThumbprint) {
Write-Information "No renewal thumbprint provided. Binding certificate to instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
}

if (-not $result) {
Write-Error "Failed to bind certificate for instance: $instance"
$bindingSuccess = $false
}
if ($serviceUser) {
return $serviceUser
} else {
Write-Error "SQL Server instance '$SQLInstanceName' not found or no service user associated."
Comment on lines +6 to +7
[parameter(ParameterSetName = $false)]
[switch]$IsAlias
Comment on lines +37 to +48
# Close the store
$store.Close()
} catch {
# Log and rethrow the exception
Write-Error "An error occurred: $_"
throw $_
} finally {
# Ensure the store is closed
if ($store) {
$store.Close()
}
}
_logger.LogTrace(LogHandler.FlattenException(ex));

var failureMessage = $"Management job {config.OperationType} failed for Site '{config.CertificateStoreDetails.StorePath}' on server '{config.CertificateStoreDetails.ClientMachine}' with error: '{LogHandler.FlattenException(ex)}'";
var failureMessage = $"Management job {config.OperationType} failed for Site '{config.CertificateStoreDetails.StorePath}' on server '{config.CertificateStoreDetails.ClientMachine}' with error: '{ex.Message}'";
Copilot AI review requested due to automatic review settings June 18, 2026 15:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 77 out of 157 changed files in this pull request and generated 12 comments.

Comment on lines +6 to +7
[parameter(ParameterSetName = $false)]
[switch]$IsAlias
Comment on lines +30 to +33
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Comment thread IISU/PowerShell/Keyfactor.WinCert.SQL/Private/Get-KeyfactorSQLServiceUser.ps1 Outdated
if ($build -ge 20348) {
# Windows Server 2022+ (IIS 10.0.20348+)
Write-Information "[VERBOSE] Detected Windows Server 2022 or later (Build: $build)"
return @(1, 4, 8, 16, 32, 64) # Include unknowns for testing
Comment on lines +6 to +7
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "keyfactor.wincert" }
Comment on lines +1 to +5
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e
Comment on lines +1 to +5
# Store Type creation script using kfutil
# Generated by Doctool

# Uncomment if kfutil is not in your PATH
# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe'
Write-Host "Creating store type: WinCert"
kfutil store-types create WinCert
Comment on lines 81 to +96
// Assert
Assert.Equal("dns=legacy.example.com&dns=old.example.com", result);
//Assert.Equal(legacySan, result);

// Assert
if (legacySan == null)
{
Assert.Equal(string.Empty, result);
}
else if (legacySan == string.Empty)
{
Assert.Equal(string.Empty, result);
}
else
{
Assert.Equal(legacySan, result);
}
Comment on lines +210 to 211
var failureMessage = $"Management job {config.OperationType} failed for Site '{config.CertificateStoreDetails.StorePath}' on server '{config.CertificateStoreDetails.ClientMachine}' with error: '{ex.Message}'";
_logger.LogWarning(failureMessage);
Copilot AI review requested due to automatic review settings June 26, 2026 18:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 78 out of 158 changed files in this pull request and generated 8 comments.

Comment on lines +28 to +46
Write-Information "[VERBOSE] Instance: $instance"
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Write-Information "Renewal thumbprint matches for instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
} elseif (-not $RenewalThumbprint) {
Write-Information "No renewal thumbprint provided. Binding certificate to instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
}

if (-not $result) {
Write-Error "Failed to bind certificate for instance: $instance"
$bindingSuccess = $false
}
Comment on lines +3 to +8
[string]$Thumbprint,
[string]$StorePath,

[parameter(ParameterSetName = $false)]
[switch]$IsAlias
)
Comment on lines +29 to +34
# Step 4: Import the certificate into the specified store
Write-Verbose "Importing the certificate to the store: Cert:\LocalMachine\$StoreName"
Set-Location -Path "Cert:\LocalMachine\$StoreName"

$importResult = Import-Certificate -FilePath $cerFilename
if ($importResult) {
Comment on lines +1 to +5
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e
Comment on lines +1 to +5
# Store Type creation script using kfutil
# Generated by Doctool

# Uncomment if kfutil is not in your PATH
# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe'
Write-Host "Creating store type: WinCert"
kfutil store-types create WinCert
Comment on lines +2 to +6
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "{SQL-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "" },
{ "Machine": "{SQL-JEA-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
Comment on lines 81 to +86
// Assert
Assert.Equal("dns=legacy.example.com&dns=old.example.com", result);
//Assert.Equal(legacySan, result);

// Assert
if (legacySan == null)
{
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 26, 2026 18:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 78 out of 158 changed files in this pull request and generated 8 comments.

Comment on lines +28 to +33
Write-Information "[VERBOSE] Instance: $instance"
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
if ($build -ge 20348) {
# Windows Server 2022+ (IIS 10.0.20348+)
Write-Information "[VERBOSE] Detected Windows Server 2022 or later (Build: $build)"
return @(1, 4, 8, 16, 32, 64) # Include unknowns for testing
Comment on lines +6 to +7
[parameter(ParameterSetName = $false)]
[switch]$IsAlias
Comment on lines +29 to +33
# Step 4: Import the certificate into the specified store
Write-Verbose "Importing the certificate to the store: Cert:\LocalMachine\$StoreName"
Set-Location -Path "Cert:\LocalMachine\$StoreName"

$importResult = Import-Certificate -FilePath $cerFilename
)

try {
Validate-CryptoProvider -ProviderName $CSPName -Verbose:$false
Comment on lines +82 to +96
//Assert.Equal(legacySan, result);

// Assert
if (legacySan == null)
{
Assert.Equal(string.Empty, result);
}
else if (legacySan == string.Empty)
{
Assert.Equal(string.Empty, result);
}
else
{
Assert.Equal(legacySan, result);
}
Comment on lines +41 to +43
var (username, password) = GetCredentials();
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
yield break;
Copilot Bot review requested due to automatic review settings July 6, 2026 20:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 81 out of 161 changed files in this pull request and generated 13 comments.

Comment on lines +1 to +3
using Keyfactor.Extensions.Orchestrator.WindowsCertStore;

namespace WindowsCertStore.UnitTests
Comment on lines +1 to +5
using Keyfactor.Extensions.Orchestrator.WindowsCertStore;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace WindowsCertStore.UnitTests
Comment on lines 81 to +84
// Assert
Assert.Equal("dns=legacy.example.com&dns=old.example.com", result);
//Assert.Equal(legacySan, result);

// Assert
Comment on lines +5 to +8

[parameter(ParameterSetName = $false)]
[switch]$IsAlias
)
Comment on lines +25 to +33
if ($cert) {
# Remove the certificate from the store
Write-Information "Attempting to remove certificate from store '$StorePath' with the thumbprint: $Thumbprint"
$store.Remove($cert)
Write-Information "Certificate removed successfully from store '$StorePath'"

# Mark success
$isSuccessful = $true
} else {
Comment on lines +1 to 6
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e

Comment on lines +1 to 3
# Store Type creation script using kfutil
# Generated by Doctool

Comment on lines +2 to +7
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "{SQL-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "" },
{ "Machine": "{SQL-JEA-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "keyfactor.wincert" }
Comment on lines +29 to +34
# Step 4: Import the certificate into the specified store
Write-Verbose "Importing the certificate to the store: Cert:\LocalMachine\$StoreName"
Set-Location -Path "Cert:\LocalMachine\$StoreName"

$importResult = Import-Certificate -FilePath $cerFilename
if ($importResult) {
Comment on lines +51 to +56
# Path to temporary INF file
$infFile = [System.IO.Path]::GetTempFileName() + ".inf"
$csrOutputFile = [System.IO.Path]::GetTempFileName() + ".csr"

Set-Content -Path $infFile -Value $infContent
Write-Information "Generated INF file at: $infFile"
Copilot Bot review requested due to automatic review settings July 6, 2026 20:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 81 out of 161 changed files in this pull request and generated 11 comments.

Comment on lines 1 to 7
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

Comment on lines +41 to +43
var (username, password) = GetCredentials();
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
yield break;
Comment on lines +2 to +7
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinIIS", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "{SQL-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "" },
{ "Machine": "{SQL-JEA-Server-IP-or-Hostname}", "StoreType": "WinSQL", "JEAEndpointName": "keyfactor.wincert" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "" },
{ "Machine": "192.168.230.139", "StoreType": "WinCert", "JEAEndpointName": "keyfactor.wincert" }
Comment on lines +28 to +46
Write-Information "[VERBOSE] Instance: $instance"
Write-Information "[VERBOSE] Full Instance: $fullInstance"
Write-Information "[VERBOSE] Registry Location: $regLocation"
Write-Information "[VERBOSE] Current Thumbprint: $currentThumbprint"

$currentThumbprint = Get-ItemPropertyValue -Path $regLocation -Name "Certificate" -ErrorAction SilentlyContinue

if ($RenewalThumbprint -and $RenewalThumbprint -contains $currentThumbprint) {
Write-Information "Renewal thumbprint matches for instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
} elseif (-not $RenewalThumbprint) {
Write-Information "No renewal thumbprint provided. Binding certificate to instance: $fullInstance"
$result = Set-KeyfactorSQLCertificateBinding -InstanceName $instance -NewThumbprint $NewThumbprint -RestartService:$RestartService
}

if (-not $result) {
Write-Error "Failed to bind certificate for instance: $instance"
$bindingSuccess = $false
}
Comment on lines +48 to +51
$sqlSettingsDict = @{
InstanceName = $instanceNames
ProviderName = $cert.PrivateKey.CspKeyContainerInfo.ProviderName
}
Comment on lines +12 to +16
if ($build -ge 20348) {
# Windows Server 2022+ (IIS 10.0.20348+)
Write-Information "[VERBOSE] Detected Windows Server 2022 or later (Build: $build)"
return @(1, 4, 8, 16, 32, 64) # Include unknowns for testing
}
Comment on lines +1 to 6
# Store Type creation script using kfutil
# Generated by Doctool

# Uncomment if kfutil is not in your PATH
# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe'
Write-Host "Creating store type: WinCert"
kfutil store-types create WinCert

Comment on lines +1 to 9
#!/bin/bash
# Store Type creation script using kfutil
# Generated by Doctool

# Creates all 4 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.
set -e

if ! command -v kfutil &> /dev/null; then
echo "kfutil could not be found. Please install kfutil"
echo "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
fi
echo "Creating store type: WinCert"
kfutil store-types create WinCert

[InlineData("dns=legacy.example.com&dns=old.example.com")]
[InlineData("")]
[InlineData(null)]
public void ResolveSanString_UsesLegacySAN_WhenConfigSANsMissing(string legacySan)
Comment on lines 81 to +96
// Assert
Assert.Equal("dns=legacy.example.com&dns=old.example.com", result);
//Assert.Equal(legacySan, result);

// Assert
if (legacySan == null)
{
Assert.Equal(string.Empty, result);
}
else if (legacySan == string.Empty)
{
Assert.Equal(string.Empty, result);
}
else
{
Assert.Equal(legacySan, result);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants