Post Request Script examples

I wrote a few Post Request scripts and thought I would share them here.

The first is for Emby Server. It’s a simple script that copies the latest renewed certificate to a designated location and restarts Emby Server. Emby Server is configured to reference the designated certificate.

Param($result)
$embyService=“Emby Server”
$embyCert="$env:SystemDrive\EmbyCert"
$pfx=$result.ManagedItem.CertificatePath
New-Item -Path $embyCert -ItemType “directory” -Force
Copy-Item -Path $pfx -Destination “$embyCert\embyCert.pfx” -Force
Restart-Service -Name $embyService -Force

The next is for Windows Admin Center. This script adds the first requested certificate via Netsh and then subsequent renewals are updated via Netsh.

param($result)
$WAC_Service=“Windows Admin Center”
$Thumbprint=$result.ManagedItem.CertificateThumbprintHash
$appId=’{00000000-0000-0000-0000-000000000000}’
$ipLocal=Resolve-DnsName hostname.fqdn | %{$_.IPAddress}
$ipPort=“443”
$result = netsh http show sslcert ipport="${ipLocal}:$ipPort"
if ($result -contains ‘The system cannot find the file specified.’) {
netsh http add sslcert ipport="${ipLocal}:$ipPort" certhash=$Thumbprint appid="$appId"
return
}
else {
netsh http update sslcert ipport="${ipLocal}:$ipPort" certhash=$Thumbprint appid="$appId"
}
Restart-Service -Name $WAC_Service -Force

Cheers.

1 Like

Thanks for sharing. Windows Admin Center really doesn’t want you to be able to set that cert easily does it!

Yep. It’s pretty crazy that MS didn’t make the process easier. I found this technique while trying to find a solution for my video management software. But the same technique works for WAC as well.

I modified a script that Tom Murphy wrote to set a certificate for remote desktop machines. So that you can use a commercially recognized cert to protect your RDP sessions. Anyways for those that are interested.

#Requires -Version 4.0
#Requires -Modules PKI

<#
.SYNOPSIS
   Replaces RDP certificate on local or remote computers

.DESCRIPTION
   This function replaces the certificate used by Remote Desktop Protocol on computers, including remote computers.

.EXAMPLE
   $SecurePass = ConvertTo-SecureString -String "P4$$w0rd9" -AsPlainText -Force
   Install-RDPCertificate -ComputerName RDSHServer1 -FilePath D:\WildcardCert.pfx -Password $SecurePass

   This example shows how to push a certificate located on the local machine to a remote computer.

.EXAMPLE
   $SecurePass = ConvertTo-SecureString -String "P4$$w0rd9" -AsPlainText -Force
   Install-RDPCertificate -ComputerName RDSHServer1,RDSHServer2,RDSHServer3 -FilePath D:\WildcardCert.pfx -Password $SecurePass

   This example shows how to push a certificated located on the local machine to multiple remote computers.

.EXAMPLE
   $SecurePass = ConvertTo-SecureString -String "P4$$w0rd9" -AsPlainText -Force
   Get-RDServer -Role RDS-RD-SERVER | Install-RDPCertificate -FilePath D:\WildcardCert.pfx -Password $SecurePass

   This example uses the Get-RDServer cmdlet to get a list of all RD Session Host servers in an RDS deployment, and then apply a certificate to them.

.NOTES
   Created by Tom Murphy 
   Last modified 4/15/2016
   http://blog.tmurphy.org
 
   Inspired by Ryan Mangan's RDS 2012 Session Host Certificate Configuration script. 
   https://gallery.technet.microsoft.com/RDS-2012-Session-Host-fbb54ff9 
 
.LINK 
   http://blog.tmurphy.org
#>
Param($result)
$pfx=$result.ManagedItem.CertificatePath
$SecurePass=ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
$CertPath="$env:SystemDrive\Certificate"
$ComputerList='comp1','comp2','comp3','comp4'
New-Item -Path $CertPath -ItemType "directory" -Force
$NewCert="$CertPath\Certificate.pfx"
$mypfx = Get-PfxData -FilePath $pfx
Export-PfxCertificate -PFXData $mypfx -FilePath $NewCert -Password $SecurePass -Force
function Install-RDPCertificate
{
    [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="Medium"
    )]
    
    Param
    (
        # One or more computers that the certificate should be installed to. Can accept pipeline input.
        [Parameter(Mandatory=$false, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0,
                   ParameterSetName='ParamSet1')]
        [ValidateNotNullOrEmpty()]
        [Alias("Computer")]
        [Alias("Server")]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        # Path to a certificate exported in PFX format. The exported certificate must be secured with a password.
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$false,
                   ValueFromRemainingArguments=$false,
                   Position=1,
                   ParameterSetName='ParamSet1')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
                if ($_ -like "*.pfx"){
                    $true
                } else {
                    Throw "Certificate must be in *.PFX format!"
                }})]
        [Alias("CertificatePath")]
        [Alias("PFX")]
        [string]$FilePath,

        # Password used to unlock the certificate PFX. Must be formatted as a SecureString.
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$false,
                   ValueFromRemainingArguments=$false,
                   Position=2,
                   ParameterSetName='ParamSet1')]
        [ValidateNotNullOrEmpty()]
        [System.Security.SecureString]$Password
    ) # end param block

    Begin
    {
        # Import modules
        Import-Module PKI -Verbose:$false

        # Check to ensure certificate exists at target path
        if (-not (Test-Path $FilePath)){
            # File does not exist
            throw "Certificate not found at target location $FilePath"
        } # end if

        # Get the thumbprint from the certificate
        try
        {
            $Thumbprint = (Get-PfxData -FilePath $FilePath -Password $Password).EndEntityCertificates.Thumbprint
            Write-Verbose "Certificate thumbprint: $Thumbprint"
        }
        catch [System.Exception]
        {
            # Cannot get thumbprint from certificate, password is likely invalid
            throw "Access denied to certificate - ensure the password is correct"
        } # end try/catch

        # Create array to hold output object
        $Output = @()
    } # end Begin block
    Process
    {
        foreach($Computer in $ComputerName){
            # Set -WhatIf information
            if($PSCmdlet.ShouldProcess("$Computer","Apply certificate '$(Split-Path -Path $FilePath -Leaf)' to RDP listener")){
                # Ensure target computer can be reached
                if (-not (Test-Connection $Computer -Count 1 -Quiet)){
                    # Computer cannot be pinged
                    Write-Warning "[$Computer] - Cannot ping target computer"
                    Continue
                } # end if

                # Create hashtable to hold output object properties and add default properties
                $hashtable = @{}
                $hashtable.ComputerName = $Computer

                # Get WMI object of Win32_TSGeneralSetting
                try
                {
                    $WMIObject = Get-WmiObject -Class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -Filter "TerminalName='RDP-tcp'" -ComputerName $Computer -Authentication 6
                    if ($WMIObject){
                        if ($WMIObject.SSLCertificateSHA1Hash -eq $Thumbprint){
                            # Thumbprint already matches, no need to continue
                            Write-Verbose "[$Computer] - The certificate thumbprint already matches the new certificate"
                            Continue
                        } # end if
                    } else {
                        # WMI query did not return any results
                        Write-Warning "[$Computer] - Could not query WMI class Win32_TSGeneralSetting"
                        Continue
                    } # end if
                }
                catch
                {
                    # Error connecting to WMI
                    Write-Warning "[$Computer] - Unable to connect to WMI`: $($Error[0])"
                    Continue
                } # end try/catch

                Write-Verbose "[$Computer] - Original thumbprint`: $($WMIObject.SSLCertificateSHA1Hash)"
                $hashtable.OriginalThumbprint = $WMIObject.SSLCertificateSHA1Hash

                # Get $env:SystemRoot path from remote computer and build remote path variables
                $RemoteSystemRoot = Invoke-Command -ComputerName $Computer -ScriptBlock {$env:SystemRoot.replace(":","$")}
                $RemoteFilePath = "\\" + $Computer + "\" + $RemoteSystemRoot + "\Temp"
                $RemoteCert = ($RemoteSystemRoot.replace("$",":")) + "\Temp\" + (Split-Path $FilePath -Leaf)
        
                # Push certificate to computer
                Write-Verbose "[$Computer] - Pushing certificate to $RemoteCert"
                Copy-Item -Path $FilePath -Destination $RemoteFilePath
        
                # Import certificate on remote machine
                Write-Verbose "[$Computer] - Importing certificate to LocalMachine store"
                try
                {
                    $SessionOptions = New-PSSessionOption -OperationTimeout 60000 -IdleTimeout 60000 -OpenTimeout 60000
                    Invoke-Command -ComputerName $Computer -ScriptBlock {param($FilePath,$Password) Import-PfxCertificate -FilePath $FilePath -Password $Password -CertStoreLocation Cert:\LocalMachine\My} -ArgumentList $RemoteCert,$Password -SessionOption $SessionOptions -ErrorAction Continue | Out-Null
                    Write-Verbose "[$Computer] - Import successful"
                }
                catch
                {
                    # Unable to import the certificate
                    Write-Warning "[$Computer] - Unable to import certificate into store`: $($Error[0])"
                    Continue
                } # end try/catch

                # Set the certificate and permissions
                Write-Verbose "[$Computer] - Applying the certificate to computer"
                try
                {
                    # Apply the certificate to WMI
                    $WMIObject.SSLCertificateSHA1Hash = $Thumbprint
                    $WMIObject.Put() | Out-Null
                    Write-Verbose "[$Computer] - Certificate applied successfully"
                
                    # Set the appropriate permissions to the private key so RDP may access it
                    $ScriptBlock = {
                        $FilePath = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys"
                        $File = Get-ChildItem $FilePath | Sort-Object LastWriteTime -Descending | Select-Object -First 1
                        # Specify account
                        $Account = "NT AUTHORITY\NETWORK SERVICE"
                        # Get current ACL on the private key
                        $ACL = Get-Acl -Path $File.FullName
                        # Set new rule
                        $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$Account", "Read", "Allow")
                        # Add rule to the ACL
                        $ACL.AddAccessRule($rule)
                        # Set new ACL to the private key
                        Set-Acl -Path $File.FullName -AclObject $ACL
                    } # end $ScriptBlock
                    Invoke-Command -ComputerName $Computer -ScriptBlock $ScriptBlock -ArgumentList $FilePath -SessionOption $SessionOptions
                    Write-Verbose "[$Computer] - Set private key permissions successfully"
                }
                catch
                {
                    # Unable to apply the certificate
                    Write-Warning "[$Computer] - Unable to apply certificate`: $($Error[0])"
                    Continue
                } # end try/catch
                Write-Verbose "[$Computer] - Certificate applied successfully"

                # Delete pfx certificate file from remote machine
                try
                {
                    Remove-Item -Path ($RemoteFilePath + '\' + (Split-Path $FilePath -Leaf)) -Force
                    Write-Verbose "[$Computer] - Deleted certificate file successfully"
                }
                catch
                {
                    Write-Warning "[$Computer] - Unable to delete PFX file from remote machine"
                } # end try/catch

                # Everything was successful, add properties to hashtable
                $hashtable.NewThumbprint = $Thumbprint

                # Create new object and add to object array
                $Object = New-Object -TypeName psobject -Property $hashtable
                $Output += $Object
            } # end $PSCmdlet.ShouldProcess
        } # end foreach
    } # end Process block
    End
    {
        # Write output object to the pipeline
        Write-Output $Output | Select-Object ComputerName, OriginalThumbprint, NewThumbprint
    } # end End block
} #end function
Install-RDPCertificate -ComputerName $ComputerList -FilePath $NewCert -Password $SecurePass
1 Like