SqlSpnManager.psd1

@{
    ModuleVersion        = '1.4.1'
    GUID                 = 'b9e38d01-6c8a-4d2e-8a9a-3f9c5d8a2f1b'
    Author               = 'Keith Ramsey'
    CompanyName          = 'Keith Ramsey'
    Copyright            = '(c) Keith Ramsey. All rights reserved.'
    Description          = 'Getting SQL Server SPNs right — and keeping them right across Standalone, Always On, and Failover Cluster instances — is harder than it should be. SqlSpnManager takes the guesswork out: checks for duplicate SPNs forest-wide before touching anything, auto-resolves FCI cluster accounts, and handles cross-forest deployments. In shops where the DBA cannot write to AD directly, Export-SqlSpnRegistrationScript produces a clean setspn bundle the AD admin runs on their own schedule. Full audit log and Windows Event Log output on every operation.'
    PowerShellVersion    = '5.1'
    RootModule           = 'SqlSpnManager.psm1'
    RequiredModules      = @('ActiveDirectory')
    FunctionsToExport    = @(
        'Add-SqlSpn',
        'Assert-SqlAccountStandard',
        'Export-SqlSpnRegistrationScript',
        'Get-SqlSpnAccount',
        'Get-SqlSpnDiscoveryEngine',
        'Get-SqlSpnInfrastructure',
        'Invoke-SqlSpnExecutionEngine',
        'New-SqlSpnPlan',
        'Remove-SqlSpn',
        'Show-SqlSpnDiagnostic',
        'Start-SqlSpnConfiguration',
        'Start-SqlSpnManager',
        'Test-SqlSpnPlan'
    )
    CmdletsToExport      = @()
    VariablesToExport    = @()
    AliasesToExport      = @()
    HelpInfoURI          = ''  # TODO: set when module ships to a help-info host

    # Declarative file inventory of the module's runtime surface (informational
    # per Microsoft docs; the actual .nupkg filtering happens via
    # Tools\Publish-SqlSpnModule.ps1's staging directory).
    FileList             = @(
        'SqlSpnManager.psm1',
        'SqlSpnManager.psd1',
        'readme.md',
        'Public\Add-SqlSpn.ps1',
        'Public\Assert-SqlAccountStandard.ps1',
        'Public\Export-SqlSpnRegistrationScript.ps1',
        'Public\Get-SqlSpnAccount.ps1',
        'Public\Get-SqlSpnDiscoveryEngine.ps1',
        'Public\Get-SqlSpnInfrastructure.ps1',
        'Public\Invoke-SqlSpnExecutionEngine.ps1',
        'Public\New-SqlSpnPlan.ps1',
        'Public\Remove-SqlSpn.ps1',
        'Public\Show-SqlSpnDiagnostic.ps1',
        'Public\Start-SqlSpnConfiguration.ps1',
        'Public\Start-SqlSpnManager.ps1',
        'Public\Test-SqlSpnPlan.ps1',
        'Private\Get-SqlAccountPolicy.ps1',
        'Private\Get-SqlActualPort.ps1',
        'Private\Get-SqlRoleMetadata.ps1',
        'Private\Get-SqlSpnExecutionConfirmation.ps1',
        'Private\Get-SqlSpnScenarioChoice.ps1',
        'Private\Get-SqlSpnSourceChoice.ps1',
        'Private\Get-SqlSpnTargetName.ps1',
        'Private\Get-SqlSpnVisualAccountSelection.ps1',
        'Private\Invoke-SqlSpnNativeCall.ps1',
        'Private\Invoke-SqlSpnSetspnAction.ps1',
        'Private\Resolve-SqlPolicyFromContext.ps1',
        'Private\Resolve-SqlSpnFciCno.ps1',
        'Private\Resolve-SqlSpnLogPath.ps1',
        'Private\Resolve-SqlSpnStandardPool.ps1',
        'Private\Resolve-SqlSpnVirtualAccount.ps1',
        'Private\Test-SqlAdPermission.ps1',
        'Private\Write-SqlSpnEventLog.ps1',
        'Private\Write-SqlSpnLog.ps1'
    )

    PrivateData          = @{
        PSData = @{
            Tags         = @(
                'SQL', 'SPN', 'Kerberos', 'ActiveDirectory', 'AD',
                'FCI', 'AlwaysOn', 'AG',
                'Authentication', 'Audit', 'EventLog', 'SIEM',
                'DBA', 'Governance', 'ServicePrincipalName',
                'CrossForest', 'gMSA', 'ManagedServiceAccount',
                'Windows', 'PSEdition_Desktop', 'PSEdition_Core'
            )
            # ===== GR-003 / PSGallery publish TODO for Keith =====
            # License DECIDED 2026-05-21: MPL-2.0 (LICENSE file at repo root).
            # ProjectUri + LicenseUri SET. IconUri still needs a real asset URL.
            # See Docs/Goals/GR-003-publish-v1-to-psgallery.md for the full publish gate.
            ProjectUri   = 'https://sql-spn-manager.com'
            LicenseUri   = 'https://opensource.org/licenses/MPL-2.0'
            ExternalModuleDependencies = @('ActiveDirectory')
            # IconUri = 'https://<asset-host>/SqlSpnManager-icon.png' # 64x64 or 128x128 PNG
            # =====================================================
            ReleaseNotes = @'
v1.4.1:
- Cleaned up module description on PSGallery.

v1.4.0 (Phase 3 close - DR-309 + DR-311):
- Public surface narrowed to the lab-proven Engine core (DR-309):
  Role in {Engine, Agent} x Scenario in {Standalone, AlwaysOn, FCI}.
  SSAS, SSRS, PBIRS, Browser, MSDTC deferred as named, demand-sequenced,
  prove-before-expose post-v1 expansions (internal tables unchanged).
- Added Export-SqlSpnRegistrationScript (DR-311): renders a plan into a
  clean setspn command bundle for an AD admin to execute. Supports Cmd
  and PowerShell formats. Output carries provenance: module version,
  plan GUID, UTC stamp, target account sAMAccountName + DN. Closes the
  workflow for AD-segregated organisations (regulated environments,
  anywhere the DBA does not have AD write rights).
- DR-307 closed as documented v1 limitation (option c): English-locale
  assumption for setspn success detection; engineered fix deferred as a
  named post-v1 increment, reopens on real demand signal.
- DR-310 (Level 1 testing standard) implemented across the unit suite:
  tests run our own real functions and substitute ONLY the true external
  edge (setspn / AD cmdlets / OS APIs). Surfaced and removed a tautology
  test and a 30s remote-registry network hang.
- 213/213 Pester 5 tests; PSScriptAnalyzer gate clean; lab-validated
  Waves 1-3 on a real domain 2026-05-17.
'@

        }
    }
}