0

I am trying to configure a new RDS gateway server through Powershell (for automatic setup after EC2 creation). The issue I'm running into right now is setting up a default or otherwise CAP and RAP. Everything else seems to work just fine, and if I go through the server dialogs and point and click my way to doing the CAP/RAP wizard, it all works. Until I do so, those policies don't exist (not even a default).

The code I'm using, which I sourced from blog posts on technet about the subject, is this:

new-item -Force -Credential $AdminCredentials -path RDS:\GatewayServer\CAP -Name DomainAdmin-CAP -UserGroups “$AdminGroupName@$NetBiosDomainName" -AuthMethod 1
new-item -Force -Credential $AdminCredentials -path RDS:\GatewayServer\CAP -Name DomainUser-CAP -UserGroups “$UserGroupName@$NetBiosDomainName" -AuthMethod 1

new-item -Force -Credential $AdminCredentials -path RDS:\GatewayServer\RAP -Name DomainAdmin-RAP -UserGroups “$AdminGroupName@$NetBiosDomainName" -ComputerGroupType 2
new-item -Force -Credential $AdminCredentials -path RDS:\GatewayServer\RAP -Name DomainUser-RAP -UserGroups “$UserGroupName@$NetBiosdomainName" -ComputerGroupType 2

Again, everything else works and the system is 100% and useable once I RDP in to the server and set these up manually, so my only issue is this automation step. The error I'm getting when I run my script is this:

new-item : Access to the object at RDS:\GatewayServer\CAP\DomainAdmin-CAP is denied for the cmdlet New-Item.The supplied value is not valid, or you do not have sufficient permissions. At line:89 char:1 + new-item -Force -Credential $AdminCredentials -path RDS:\GatewayServe ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : PermissionDenied: (:) [New-Item], AccessViolationException + FullyQualifiedErrorId : PermissionDenied,Microsoft.PowerShell.Commands.NewItemCommand

Edit: Things I have tried based on suggestions and frustration:

I have made all " characters uniform after someone pointed out they were actually not the same thing on the front and rear of my -UserGroup variable strings - No error change.

I have tried $NetBiosDomainName as the simple one word NetBIOS version (DOMAIN) as well as the full domain (domain.company.com) - No error change.

I have tried changing the "$AdministratorsGroupName@$NetBiosDomainName" string out for $AdminGroup (= $AdministratorsGroupName + "@" + $NetBiosDomainName") to simplify the input to the -UserGroups parameter - No error change

I have run this script as both the domain admin and local administrator account - No error change

  • Silly question, are you running this as an admin ? Also, are you using the `Import-Module RemoteDesktopServices`? – jrider May 07 '18 at 20:54
  • Yes. No silly questions. I am logged in as either Domain Admin or Local admin, and launching Powershell ISE as Admin. Yes I am running the Import-Module RemoteDesktopServices line earlier in the script (installing the features and everything, as the scripts takes it from base windows 2016 to functional gateway) – Russell Anthony May 07 '18 at 21:09
  • 2
    I just verified the following works(on a freshly installed Remote Desktop Services role) : `New-Item -Path RDS:\GatewayServer\CAP -Name DomainAdmin-CAP -UserGroups "test@domain.local" -AuthMethod 1 `. Confirmed with `Get-ChildItem -Path RDS:\GatewayServer\CAP` Now, I did do this from my local PC using: `Enter-PSSession -ComputerName Server` . If this example still gives you the error, then I would look more into how this is being executed. – jrider May 07 '18 at 21:26
  • Use either PSSession or Invoke-Command to run it on the server remotely – Keith May 07 '18 at 21:54
  • I was running this script directly on the server itself, so local to where it should be creating the Items. – Russell Anthony May 07 '18 at 22:17
  • Not sure if it's a copy paste or you actually have different quotes `“` `"` around your `UserGroups` param. Powershell can deal with curly/smart quotes but it's best to avoid them. – henrycarteruk May 08 '18 at 09:04
  • That's a great catch James, thanks. I retyped my code in ISE which actually did have the 2 different types of quotes (TIL), so it's uniform now... however it did not change the error I am getting. – Russell Anthony May 10 '18 at 18:58
  • Based on the fact that you're using a NetBIOS name, I'm assuming that you're on a non-domain server. Have you verified that `$AdminGroupName` on `$NetBiosDomainName` actually exists? That was my problem. I had to actually create the local group. – Slogmeister Extraordinaire Mar 19 '21 at 13:14

1 Answers1

0

I was able to use the following script to configure a Remote Access Gateway on a non-domain Windows 2019/2016 server. This includes a CAP, a RAP, and a ManagedComputerGroup.

Install-WindowsFeature -Name "RDS-Gateway" -IncludeAllSubFeature -IncludeManagementTools > $null
Import-Module -Name RemoteDesktopServices

#=============User Modifiable=============#
$GroupName="SG_RemoteUsers@$env:COMPUTERNAME"
# No Restrictions
#$GroupName="Users@BUILTIN"
$ManagedComputers="RDG_RDCBComputers"
# Managed Computer Groups
$MCGComputers=@($env:COMPUTERNAME,"<target machines>")
$MCGs=@(@{Name="RDG_RDCBComputers";Desc="All RDCB Computers in the deployment";Computers=$MCGComputers})
# Connection Authorization Policies
$CAPs=@(@{Name="RDG_CAP_AllUsers";UserGroups=$GroupName;AuthMethod=1;Status=1})
# Resrouce Authorization Policies
$RAPs=@(@{Name="RDG_AllComputers";UserGroups=$GroupName;ComputerGroupType=2;ComputerGroup=$null})

# If you already have a certificate, skip this part.
<#region Certificate
$FilePath="C:\temp\export.cer"
$SelfSigned=New-SelfSignedCertificate -CertStoreLocation "Cert:\LocalMachine\My" -DnsName $env:COMPUTERNAME -FriendlyName $env:COMPUTERNAME -KeyAlgorithm "RSA" -HashAlgorithm "SHA256" -KeyDescription "RDG Key" -KeyLength 4096 -KeyUsage KeyEncipherment,DataEncipherment -KeyUsageProperty All
$CertPassword=ConvertTo-SecureString -String “password” -Force –AsPlainText
Export-PfxCertificate -Cert $SelfSigned.PSPath -FilePath $FilePath -Password $CertPassword > $null
Import-PfxCertificate -CertStoreLocation "Cert:\LocalMachine\Root" -FilePath $FilePath -Password $CertPassword > $null
Remove-Item -Path $FilePath
$Certificate=$SelfSigned
#endregion
#>
$Certificate=Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } | Sort-Object -Property NotAfter -Descending | Select-Object -Last 1

#=============Do not modify=============#
$CAPPath="RDS:\GatewayServer\CAP"
$RAPPath="RDS:\GatewayServer\RAP"
$MCGPath="RDS:\GatewayServer\GatewayManagedComputerGroups"

#=============Script=============#
# Add the certificate to RDS
Set-Item -Path "RDS:\GatewayServer\SSLCertificate\Thumbprint" -Value $Certificate.Thumbprint

try { Get-LocalGroup -Name $GroupName -ErrorAction Stop > $null }
catch { New-LocalGroup -Name $GroupName > $null }

try { Get-LocalGroupMember -Group $GroupName -Member "<user that should have access>" -ErrorAction Stop > $null }
catch { Add-LocalGroupMember -Group $GroupName -Member "<user that should have access>" > $null }

# Remove existing items (must be done in the order of CAP and/or RAP first, then GatewayManagedComputerGroups
$CAPs | ForEach-Object { if (Test-Path -Path "$CAPPath\$($_.Name)") { Remove-Item -Path "$CAPPath\$($_.Name)" -Recurse } }
$RAPs | ForEach-Object { if (Test-Path -Path "$RAPPath\$($_.Name)") { Remove-Item -Path "$RAPPath\$($_.Name)" -Recurse } }
$MCGs | ForEach-Object { if (Test-Path -Path "$MCGPath\$($_.Name)") { Remove-Item -Path "$MCGPath\$($_.Name)" -Recurse } }

$MCGs | ForEach-Object { New-Item -Path $MCGPath -Name $_.Name -Description $_.Desc -Computers $_.Computers > $null }
$CAPs | ForEach-Object { New-Item -Path $CAPPath -Name $_.Name -UserGroups $_.UserGroups -AuthMethod $_.AuthMethod -Status $_.Status > $null }
$RAPs | ForEach-Object { New-Item -Path $RAPPath -Name $_.Name -UserGroups $_.UserGroups -ComputerGroupType $_.ComputerGroupType > $null }

# Stop redirection of Serial Ports
$CAPs | ForEach-Object { Set-Item -Path "$CAPPath\$($_.Name)\DeviceRedirection\SerialPorts" -Value 0 }

Restart-Service -Name "TSGateway"

This script, which shares a significant portion of the previous, is what I used to configure the same on a server that is a member of an AD domain. It's not the only way to do it, but hopefully it will give you a head start.

There is a portion of this script that creates the necessary AD group.

The only part that's missing is that the certificate must be placed in the Trusted Root store on the PC from which you want to connect.

Install-WindowsFeature -Name "RDS-Gateway" -IncludeAllSubFeature -IncludeManagementTools > $null
Import-Module -Name RemoteDesktopServices
Add-Type -AssemblyName System.DirectoryServices.AccountManagement 

#=============User Modifiable=============#
$GroupName="SG_RemoteUsers"
$ManagedComputers="RDG_RDCBComputers"
# Managed Computer Groups
$MCGComputers=@($env:COMPUTERNAME,"<target machines>")
$MCGs=@(@{Name=$ManagedComputers;Desc="All RDCB Computers in the deployment";Computers=$MCGComputers})
# Connection Authorization Policies
$CAPs=@(@{Name="RDG_CAP_AllUsers";UserGroups="$GroupName@$env:USERDOMAIN";AuthMethod=1;Status=1})
# Resrouce Authorization Policies
$RAPs=@(@{Name="RDG_AllDomainComputers";UserGroups="$GroupName@$env:USERDOMAIN";ComputerGroupType=1;ComputerGroup="Domain Computers@$env:USERDOMAIN"},
        @{Name="RDG_RDConnectionBrokers";UserGroups="Domain Users@$env:USERDOMAIN";ComputerGroupType=0;ComputerGroup=$ManagedComputers})

# If you already have a certificate, skip this part.
<#region Certificate
$FilePath="C:\temp\export.cer"
$SelfSigned=New-SelfSignedCertificate -CertStoreLocation "Cert:\LocalMachine\My" -DnsName "$env:COMPUTERNAME.$env:USERDNSDOMAIN" -FriendlyName $env:COMPUTERNAME -KeyAlgorithm "RSA" -HashAlgorithm "SHA256" -KeyDescription "RDG Key" -KeyLength 4096 -KeyUsage KeyEncipherment,DataEncipherment -KeyUsageProperty All
$CertPassword=ConvertTo-SecureString -String “password” -Force –AsPlainText
Export-PfxCertificate -Cert $SelfSigned.PSPath -FilePath $FilePath -Password $CertPassword > $null
Import-PfxCertificate -CertStoreLocation "Cert:\LocalMachine\Root" -FilePath $FilePath -Password $CertPassword > $null
Remove-Item -Path $FilePath
$Certificate=$SelfSigned
#endregion
#>
$Certificate=Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } | Sort-Object -Property NotAfter -Descending | Select-Object -Last 1

#=============Do not modify=============#
$CAPPath="RDS:\GatewayServer\CAP"
$RAPPath="RDS:\GatewayServer\RAP"
$MCGPath="RDS:\GatewayServer\GatewayManagedComputerGroups"

#=============Script=============#
# Add the certificate to RDS
Set-Item -Path "RDS:\GatewayServer\SSLCertificate\Thumbprint" -Value $Certificate.Thumbprint

$ADGroup=[System.DirectoryServices.DirectorySearcher]::new("(&(objectCategory=Group)(samAccountName=$GroupName))").FindOne()
if ($ADGroup -ne $null) {
  $ADGroup=$ADGroup.GetDirectoryEntry()
  $Parent=[System.DirectoryServices.DirectoryEntry]::new($ADGroup.Parent)
  $Parent.Children.Remove($ADGroup)
  $Parent.CommitChanges()
  $Parent.Close()
}

$ADGroup=[System.DirectoryServices.AccountManagement.GroupPrincipal]::new([System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain),$GroupName)
$ADGroup.Description="Remote Gateway Users Group"
$ADGroup.GroupScope=[System.DirectoryServices.AccountManagement.GroupScope]::Global
$ADGroup.IsSecurityGroup=$true
$Member=[System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity([System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain),"Administrator")
$ADGroup.Members.Add($Member)
$Member=[System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity([System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain),"admin_jeberhardt")
$ADGroup.Members.Add($Member)
$ADGroup.DisplayName=$ADGroup.SamAccountName
$ADGroup.Save()
$OU=[System.DirectoryServices.DirectoryEntry]::new("LDAP://$($ADGroup.DistinguishedName)")
$NewOU=[System.DirectoryServices.DirectoryEntry]::new("LDAP://OU=<target OU>,DC=<domain name>,DC=com")
$OU.MoveTo($NewOU)
$OU.CommitChanges()
$OU.Close()
$NewOU.Close()

# Remove existing items (must be done in the order of CAP and/or RAP first, then GatewayManagedComputerGroups
$CAPs | ForEach-Object { if (Test-Path -Path "$CAPPath\$($_.Name)") { Write-Verbose "Removing $($_.Name)"; Remove-Item -Path "$CAPPath\$($_.Name)" -Recurse } }
$RAPs | ForEach-Object { if (Test-Path -Path "$RAPPath\$($_.Name)") { Write-Verbose "Removing $($_.Name)"; Remove-Item -Path "$RAPPath\$($_.Name)" -Recurse } }
$MCGs | ForEach-Object { if (Test-Path -Path "$MCGPath\$($_.Name)") { Write-Verbose "Removing $($_.Name)"; Remove-Item -Path "$MCGPath\$($_.Name)" -Recurse } }

$MCGs | ForEach-Object { Write-Verbose "Creating $($_.Name)"; New-Item -Path $MCGPath -Name $_.Name -Description $_.Desc -Computers $_.Computers > $null }
$CAPs | ForEach-Object { Write-Verbose "Creating $($_.Name)"; New-Item -Path $CAPPath -Name $_.Name -UserGroups $_.UserGroups -AuthMethod $_.AuthMethod -Status $_.Status > $null }
$RAPs | ForEach-Object { Write-Verbose "Creating $($_.Name)"; New-Item -Path $RAPPath -Name $_.Name -UserGroups $_.UserGroups -ComputerGroup $_.ComputerGroup -ComputerGroupType $_.ComputerGroupType > $null }

# Stop redirection of Serial Ports
$CAPs | ForEach-Object { Set-Item -Path "$CAPPath\$($_.Name)\DeviceRedirection\SerialPorts" -Value 0 }

Restart-Service -Name "TSGateway"