how to enable WinRM securely in PowerShell?

Article 2: Enabling WinRM over HTTPS Using PowerShell

This article will provide you with a PowerShell script to automate the process of enabling WinRM over HTTPS on multiple servers, configuring certificate auto-enrollment, creating a specific certificate template, and setting up the HTTPS listener.

PowerShell Script for Enabling WinRM over HTTPS

Save the following script as Configure-WinRM-HTTPS.ps1 and run it with administrative privileges on the server.

# Define variables
$domain = (Get-WmiObject Win32_ComputerSystem).Domain
$gpoName = "Enable WinRM with HTTPS and Auto-Enrollment"
$certificateTemplateName = "WinRM HTTPS"
$certRenewalPeriodHours = 1 # Certificate renewal period in hours
$additionalOU = "Servers"  # Additional OU or attribute to be included in the certificate subject

# Function to create a new GPO and edit settings
function Configure-GPO {
    # Import the GroupPolicy module
    Import-Module GroupPolicy

    # Create a new GPO
    Write-Output "Creating GPO: $gpoName"
    New-GPO -Name $gpoName

    # Link GPO to the domain root
    Write-Output "Linking GPO to domain root"
    New-GPLink -Name $gpoName -Target "DC=$($domain -replace '\.', ',DC=')"

    # Configure Auto-Enrollment for Certificates
    Write-Output "Configuring Auto-Enrollment for Certificates"
    Set-GPRegistryValue -Name $gpoName -Key "HKLM\Software\Policies\Microsoft\Cryptography\AutoEnrollment" -ValueName "AEPolicy" -Type DWORD -Value 1

    # Configure Allow Remote Management through WinRM
    Write-Output "Configuring WinRM Settings"
    Set-GPRegistryValue -Name $gpoName -Key "HKLM\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service" -ValueName "AllowAutoConfig" -Type DWORD -Value 1
    Set-GPRegistryValue -Name $gpoName -Key "HKLM\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service" -ValueName "IPv4Filter" -Type String -Value "*"

    # Enable WinRM Service
    Write-Output "Configuring WinRM Service to start automatically"
    Set-GPRegistryValue -Name $gpoName -Key "HKLM\SYSTEM\CurrentControlSet\Services\WinRM" -ValueName "Start" -Type DWORD -Value 2

    # Configure firewall rules for WinRM
    Write-Output "Configuring Firewall Rules for WinRM"
    Invoke-Expression "netsh advfirewall firewall add rule name='WinRM HTTPS' dir=in action=allow protocol=TCP localport=5986"
    Invoke-Expression "netsh advfirewall firewall add rule name='WinRM HTTP' dir=in action=allow protocol=TCP localport=5985"
}

# Function to create and publish a certificate template
function Configure-CertificateTemplate {
    # Import Certificate Authority module
    Import-Module PKI

    # Duplicate the Web Server template
    Write-Output "Creating new Certificate Template for WinRM"
    $webServerTemplate = Get-CATemplate | Where-Object {$_.DisplayName -eq 'Web Server'}
    $newTemplate = $webServerTemplate.Duplicate()
    $newTemplate.DisplayName = $certificateTemplateName

    # Configure the template for dynamic subject with hostname and additional criteria
    $newTemplate.SubjectNameFlags = 'Machine Name'
    $newTemplate.ValidityPeriod =

 'Hours'
    $newTemplate.ValidityPeriodUnits = $certRenewalPeriodHours
    $newTemplate.Purpose = @('Server Authentication')

    # Set template for automatic enrollment
    Write-Output "Publishing Certificate Template for Auto-Enrollment"
    $newTemplate.EnrollmentFlags = 'IncludeSymmetricAlgorithms'
    Add-CATemplate -Template $newTemplate
}

# Function to create WinRM HTTPS listener using a specific certificate
function Configure-WinRMHTTPSListener {
    Write-Output "Creating Scheduled Task to configure WinRM HTTPS Listener"

    # Retrieve the certificate thumbprint for the specific template name
    $certThumbprint = (Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.NotAfter -gt (Get-Date) } | ForEach-Object { 
        $templateName = ($_.Extensions | Where-Object { $_.Oid.Value -eq "1.3.6.1.4.1.311.21.7" }).Format($false); 
        if ($templateName -like "*WinRM*") { 
            [PSCustomObject]@{ Subject = $_.Subject; TemplateName = $templateName } 
        } 
    }).Thumbprint

    if (-not $certThumbprint) {
        Write-Output "No valid certificate found for template: $certificateTemplateName"
        return
    }

    # Create a scheduled task to configure the WinRM HTTPS listener
    $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-Command `"New-Item -Path WSMan:\Localhost\Listener -Transport HTTPS -Address * -CertificateThumbprint $certThumbprint`""
    $trigger = New-ScheduledTaskTrigger -AtStartup
    Register-ScheduledTask -Action $action -Trigger $trigger -TaskName 'Configure WinRM HTTPS Listener' -Description 'Configure WinRM HTTPS Listener for secure remote management' -RunLevel Highest -User 'SYSTEM'
}

# Function to set up scheduled task for certificate renewal
function Configure-CertRenewalTask {
    Write-Output "Creating Scheduled Task for frequent certificate renewal check"

    # Create a scheduled task action to trigger certificate renewal
    $renewalAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-Command "gpupdate /force"'
    # Set a trigger to run the task every hour
    $renewalTrigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Hours $certRenewalPeriodHours) -RepetitionDuration ([TimeSpan]::MaxValue)

    Register-ScheduledTask -Action $renewalAction -Trigger $renewalTrigger -TaskName 'CertRenewal' -Description 'Certificate auto-renewal every hour' -RunLevel Highest -User 'SYSTEM'
}

# Main script execution
Write-Output "Starting the configuration process..."
Configure-GPO
Configure-CertificateTemplate
Configure-WinRMHTTPSListener
Configure-CertRenewalTask
Write-Output "Configuration completed successfully!"

How to Use the PowerShell Script

  1. Run PowerShell as Administrator: Open PowerShell with elevated privileges.
  2. Save the Script: Save the script as Configure-WinRM-HTTPS.ps1.
  3. Execute the Script:

powershell .\Configure-WinRM-HTTPS.ps1

Table of Contents