|
11 | 11 | # 08/29/25 Fixed the add cert to store function to return the correct thumbprint |
12 | 12 | # Made changes to the IIS Binding logic, breaking it into manageable pieces to aid in debugging issues |
13 | 13 | # 09/16/25 Updated the Get CSP function to handle null values when reading hybrid certificates |
| 14 | +# 11/17/25 Fixed issue with SSL Flags not being applied correctly to IIS bindings (2.6.4) |
14 | 15 |
|
15 | 16 | # Set preferences globally at the script level |
16 | 17 | $DebugPreference = "Continue" |
@@ -388,74 +389,110 @@ function New-KFIISSiteBinding { |
388 | 389 | param ( |
389 | 390 | [Parameter(Mandatory = $true)] |
390 | 391 | [string]$SiteName, |
391 | | - |
392 | 392 | [string]$IPAddress = "*", |
393 | | - |
394 | 393 | [int]$Port = 443, |
395 | | - |
396 | 394 | [AllowEmptyString()] |
397 | 395 | [string]$Hostname = "", |
398 | | - |
399 | 396 | [ValidateSet("http", "https")] |
400 | 397 | [string]$Protocol = "https", |
401 | | - |
402 | 398 | [ValidateScript({ |
403 | 399 | if ($Protocol -eq 'https' -and [string]::IsNullOrEmpty($_)) { |
404 | 400 | throw "Thumbprint is required when Protocol is 'https'" |
405 | 401 | } |
406 | 402 | $true |
407 | 403 | })] |
408 | 404 | [string]$Thumbprint, |
409 | | - |
410 | 405 | [string]$StoreName = "My", |
411 | | - |
412 | 406 | [int]$SslFlags = 0 |
413 | 407 | ) |
414 | 408 |
|
415 | 409 | Write-Information "Entering PowerShell Script: New-KFIISSiteBinding" -InformationAction SilentlyContinue |
416 | | - Write-Verbose "Function: New-KFIISSiteBinding" |
417 | 410 | Write-Verbose "Parameters: $(($PSBoundParameters.GetEnumerator() | ForEach-Object { "$($_.Key): '$($_.Value)'" }) -join ', ')" |
418 | 411 |
|
419 | 412 | try { |
420 | | - # This function mimics IIS Manager behavior: |
421 | | - # - Replaces exact binding matches (same IP:Port:Hostname) |
422 | | - # - Allows multiple bindings with different hostnames (SNI) |
423 | | - # - Lets IIS handle true conflicts rather than pre-checking |
424 | | - |
425 | | - # Step 1: Verify site exists and get management approach |
| 413 | + # Step 1: Perform verifications and get management info |
| 414 | + # Check SslFlags |
| 415 | + if (-not (Test-ValidSslFlags -SslFlags $SslFlags)) { |
| 416 | + return New-ResultObject -Status Error 400 -Step "Validation" -ErrorMessage "Invalid SSL Flag bit configuration ($SslFlags)" |
| 417 | + } |
| 418 | + |
426 | 419 | $managementInfo = Get-IISManagementInfo -SiteName $SiteName |
427 | 420 | if (-not $managementInfo.Success) { |
428 | 421 | return $managementInfo.Result |
429 | 422 | } |
430 | 423 |
|
431 | | - # Step 2: Remove existing HTTPS bindings for this exact binding information |
432 | | - # This mimics IIS behavior: replace exact matches, allow different hostnames |
| 424 | + # Step 2: Remove existing HTTPS bindings for this binding info |
433 | 425 | $searchBindings = "${IPAddress}:${Port}:${Hostname}" |
434 | 426 | Write-Verbose "Removing existing HTTPS bindings for: $searchBindings" |
435 | | - |
| 427 | + |
436 | 428 | $removalResult = Remove-ExistingIISBinding -SiteName $SiteName -BindingInfo $searchBindings -UseIISDrive $managementInfo.UseIISDrive |
437 | 429 | if ($removalResult.Status -eq 'Error') { |
438 | 430 | return $removalResult |
439 | 431 | } |
440 | 432 |
|
441 | | - # Step 3: Add new binding with SSL certificate |
442 | | - Write-Verbose "Adding new binding with SSL certificate" |
443 | | - |
| 433 | + # Step 3: Determine SslFlags supported by Microsoft.Web.Administration |
| 434 | + if ($SslFlags -gt 3) { |
| 435 | + Write-Verbose "SslFlags value $SslFlags exceeds managed API range (0–3). Applying reduced flags for creation." |
| 436 | + $SslFlagsApplied = ($SslFlags -band 3) |
| 437 | + } else { |
| 438 | + $SslFlagsApplied = $SslFlags |
| 439 | + } |
| 440 | + |
| 441 | + # Step 4: Add the new binding with the reduced flag set |
| 442 | + Write-Verbose "Adding new binding with SSL certificate (SslFlagsApplied=$SslFlagsApplied)" |
| 443 | + |
444 | 444 | $addParams = @{ |
445 | | - SiteName = $SiteName |
446 | | - Protocol = $Protocol |
447 | | - IPAddress = $IPAddress |
448 | | - Port = $Port |
449 | | - Hostname = $Hostname |
450 | | - Thumbprint = $Thumbprint |
451 | | - StoreName = $StoreName |
452 | | - SslFlags = $SslFlags |
| 445 | + SiteName = $SiteName |
| 446 | + Protocol = $Protocol |
| 447 | + IPAddress = $IPAddress |
| 448 | + Port = $Port |
| 449 | + Hostname = $Hostname |
| 450 | + Thumbprint = $Thumbprint |
| 451 | + StoreName = $StoreName |
| 452 | + SslFlags = $SslFlagsApplied |
453 | 453 | UseIISDrive = $managementInfo.UseIISDrive |
454 | 454 | } |
455 | | - |
| 455 | + |
456 | 456 | $addResult = Add-IISBindingWithSSL @addParams |
457 | | - return $addResult |
458 | 457 |
|
| 458 | + if ($addResult.Status -eq 'Error') { |
| 459 | + return $addResult |
| 460 | + } |
| 461 | + |
| 462 | + # Step 5: If extended flags, update via appcmd.exe |
| 463 | + if ($SslFlags -gt 3) { |
| 464 | + Write-Verbose "Applying full SslFlags=$SslFlags via appcmd" |
| 465 | + |
| 466 | + $appcmd = Join-Path $env:windir "System32\inetsrv\appcmd.exe" |
| 467 | + |
| 468 | + # Escape any single quotes in hostname |
| 469 | + $safeHostname = $Hostname -replace "'", "''" |
| 470 | + $bindingInfo = "${IPAddress}:${Port}:${safeHostname}" |
| 471 | + |
| 472 | + # Quote site name only if it contains spaces |
| 473 | + if ($SiteName -match '\s') { |
| 474 | + $siteArg = "/site.name:`"$SiteName`"" |
| 475 | + } else { |
| 476 | + $siteArg = "/site.name:$SiteName" |
| 477 | + } |
| 478 | + |
| 479 | + # Build binding argument for appcmd |
| 480 | + $bindingArg = "/bindings.[protocol='https',bindingInformation='$bindingInfo'].sslFlags:$SslFlags" |
| 481 | + |
| 482 | + Write-Verbose "Running appcmd: $appcmd $siteArg $bindingArg" |
| 483 | + $appcmdOutput = & $appcmd set site $siteArg $bindingArg 2>&1 |
| 484 | + Write-Verbose "appcmd output: $appcmdOutput" |
| 485 | + |
| 486 | + #& $appcmd set site $siteArg $bindingArg | Out-Null |
| 487 | + |
| 488 | + if ($LASTEXITCODE -ne 0) { |
| 489 | + Write-Warning "appcmd failed to set extended SslFlags ($SslFlags) for binding $bindingInfo." |
| 490 | + } else { |
| 491 | + Write-Verbose "Successfully updated SslFlags to $SslFlags via appcmd." |
| 492 | + } |
| 493 | + } |
| 494 | + |
| 495 | + return $addResult |
459 | 496 | } |
460 | 497 | catch { |
461 | 498 | $errorMessage = "Unexpected error in New-KFIISSiteBinding: $($_.Exception.Message)" |
@@ -1464,6 +1501,15 @@ function Parse-DNSubject { |
1464 | 1501 | return $subjectString |
1465 | 1502 | } |
1466 | 1503 |
|
| 1504 | +function Test-ValidSslFlags { |
| 1505 | + param([int]$SslFlags) |
| 1506 | + |
| 1507 | + $validBits = 1,2,4,8,32,64,128 |
| 1508 | + $invalidBits = $SslFlags -bxor ($SslFlags -band ($validBits | Measure-Object -Sum).Sum) |
| 1509 | + |
| 1510 | + return ($invalidBits -eq 0) |
| 1511 | +} |
| 1512 | + |
1467 | 1513 | # Note: Removed Test-IISBindingConflict function - we now mimic IIS behavior |
1468 | 1514 | # IIS replaces exact matches and allows multiple hostnames (SNI) on same IP:Port |
1469 | 1515 | function Get-IISManagementInfo { |
|
0 commit comments