From ab38c4246744aad303447d2da464680545883755 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 16 Aug 2019 11:16:53 -0700 Subject: [PATCH 01/25] Provides function to retry net connection tests, returning valid/stale servers --- psmodules/P3Utils/P3Utils.psm1 | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index beececaf..2e968d21 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -78,3 +78,56 @@ function global:Invoke-RetryCommand { } End {} } + +function global:Test-RetryNetConnection { + Param( + [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] + [string[]] + $ComputerName, + + [Parameter(Mandatory=$false)] + [string] + $CheckExpression = '$? -and $Return.Result.TcpTestSucceeded', + + [Parameter(Mandatory=$false)] + [int] + $Tries = 5, + + [Parameter(Mandatory=$false)] + [int] + $InitialDelay = 2, # in seconds + + [Parameter(Mandatory=$false)] + [int] + $MaxDelay = 32 # in seconds + ) + BEGIN { + $ValidComputers = @() + $StaleComputers = @() + } + PROCESS { + ForEach ($computer in $ComputerName) + { + Write-Verbose ("Testing connectivity to server: {0}" -f $computer) + try + { + $null = Invoke-RetryCommand -Command Test-NetConnection -ArgList @{ComputerName=$computer; CommonTCPPort="RDP"} -CheckExpression $CheckExpression -Tries $Tries + Write-Verbose ("Successfully connected to server: {0}" -f $computer) + Write-Output @{ ValidComputers = $computer } + $ValidComputers += $computer + } + catch + { + Write-Verbose ("Server is not available, marked as stale: {0}" -f $computer) + Write-Output @{ StaleComputers = $computer } + $StaleComputers += $computer + } + } + } + END { + Write-Verbose "Valid Computers:" + $ValidComputers | ForEach-Object { Write-Verbose "* $_" } + Write-Verbose "Stale Computers:" + $StaleComputers | ForEach-Object { Write-Verbose "* $_" } + } +} From 3d7b19d3d4271c2f575c2d687b7719ae136728ef Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 16 Aug 2019 14:52:00 -0700 Subject: [PATCH 02/25] Provides function to clear stale session hosts from connection broker --- psmodules/P3RemoteAccess/P3RemoteAccess.psd1 | 4 ++- psmodules/P3RemoteAccess/P3RemoteAccess.psm1 | 27 +++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 b/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 index 7a97a7f2..f900aa46 100644 --- a/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 +++ b/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 @@ -47,7 +47,9 @@ Copyright = '(c) 2018 Maintainers of plus3it/cfn. All rights reserved.' # ProcessorArchitecture = '' # Modules that must be imported into the global environment prior to importing this module -# RequiredModules = @() +RequiredModules = @( + "RemoteDesktop" +) # Assemblies that must be loaded prior to importing this module # RequiredAssemblies = @() diff --git a/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 b/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 index aa897fa2..a7a78736 100644 --- a/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 +++ b/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 @@ -4,7 +4,6 @@ function global:Update-RDMS { Process{ Write-Debug "Starting Update-RDMS" Write-Debug "Import RDS cmdlets" - Import-Module RemoteDesktop $ConnectionBrokers = Get-RDServer | Where-Object {$_.Roles -contains "RDS-CONNECTION-BROKER"} $ServerManagerXML = "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\ServerManager\Serverlist.xml" Write-Debug "Find active Connection Broker" @@ -59,3 +58,29 @@ function global:Update-RDMS { } End{} } + +function global:Clear-RDSessionHost { + Param( + [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] + [Microsoft.RemoteDesktopServices.Management.RDServer[]] + $SessionHost, + + [Parameter(Mandatory=$false)] + [string] + $ConnectionBroker = [System.Net.DNS]::GetHostByName('').HostName + ) + BEGIN { + $Role = "RDS-RD-SERVER" + } + PROCESS { + ForEach ($instance in $SessionHost) + { + Write-Verbose "Removing RD Session Host, $($instance.SessionHost), from the collection, ${CollectionName}..." + Remove-RDSessionHost -SessionHost $instance.SessionHost -ConnectionBroker $ConnectionBroker -Force + + Write-Verbose "Removing ${Role} role from $($instance.SessionHost)..." + Remove-RDServer -Role $Role -Server $instance.SessionHost -ConnectionBroker $ConnectionBroker -Force + } + } + END {} +} From ac8d96c452d22c8ac3530168c176116b1ec0c15d Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Mon, 19 Aug 2019 07:06:55 -0700 Subject: [PATCH 03/25] Provides function to edit rule identities in a filesystem acl --- psmodules/P3Utils/P3Utils.psm1 | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index 2e968d21..734eb284 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -131,3 +131,85 @@ function global:Test-RetryNetConnection { $StaleComputers | ForEach-Object { Write-Verbose "* $_" } } } + +function global:Edit-AclIdentityReference { + Param( + [Parameter(Mandatory=$true)] + [System.Security.AccessControl.DirectorySecurity] + $Acl, + + [Parameter(Mandatory=$false)] + [string[]] + $IdentityReference, + + [Parameter(Mandatory=$false)] + [string] + $IdentityFilter = "(?i).*\\.*[$]$", + + [Parameter(Mandatory=$false)] + [string] + $FileSystemRights = "FullControl", + + [Parameter(Mandatory=$false)] + [string] + $InheritanceFlags = "ContainerInherit, ObjectInherit", + + [Parameter(Mandatory=$false)] + [string] + $PropagationFlags = "None", + + [Parameter(Mandatory=$false)] + [string] + $AccessControlType = "Allow" + ) + BEGIN { + $AclIdentities = @($Acl.Access.IdentityReference.Value) | Where-Object { $_ -match $IdentityFilter } + + # Test if ACL contains only matching identity references + $DiffIdentities = Compare-Object $IdentityReference $AclIdentities + + # Skip further processing if there are no differences + if (-not $DiffIdentities) + { + Write-Verbose "ACL contains only matching identities, no changes needed..." + return + } + + # Identity in ACL but not in $IdentityReference; need to remove + $RemoveIdentities = $DiffIdentities | Where-Object { $_.SideIndicator -eq "=>" } | ForEach-Object { $_.InputObject } + + # Identity in $IdentityReference but not in ACL; need to add + $AddIdentities = $DiffIdentities | Where-Object { $_.SideIndicator -eq "<=" } | ForEach-Object { $_.InputObject } + + # Remove rules for identity references not present in $IdentityReference + foreach ($Rule in $Acl.Access) + { + $Identity = $Rule.IdentityReference.Value + + if ($Identity -in $RemoveIdentities) + { + Write-Verbose "Identity is NOT VALID, removing rule:" + Write-Verbose "* Rule Identity: $Identity" + $Acl.RemoveAccessRule($Rule) + } + } + + # Add rules for identity references in $IdentityReference that are missing from the ACL + foreach ($Identity in $AddIdentities) + { + Write-Verbose "Adding missing access rule to ACL:" + Write-Verbose "* Rule Identity: $Identity" + $Acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule( + $Identity, + $FileSystemRights, + $InheritanceFlags, + $PropagationFlags, + $AccessControlType + ))) + } + + # Output the new ACL + Write-Verbose ($Acl.Access | Out-String) + Write-Output $Acl + } +} From f316999c85f75b0b55e9d882aa25fec7a337ecdc Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Mon, 19 Aug 2019 15:35:10 -0700 Subject: [PATCH 04/25] Provides script to cleanup session hosts from connection broker --- scripts/cleanup-rdcb.ps1 | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/cleanup-rdcb.ps1 diff --git a/scripts/cleanup-rdcb.ps1 b/scripts/cleanup-rdcb.ps1 new file mode 100644 index 00000000..72c96fa1 --- /dev/null +++ b/scripts/cleanup-rdcb.ps1 @@ -0,0 +1,37 @@ +[CmdLetBinding()] + +#Requires -Modules RemoteDesktop, P3RemoteAccess, P3Utils +#Requires -RunAsAdministrator + +Param( + [Parameter(Mandatory=$true)] + [String] + $UpdPath, + + [Parameter(Mandatory=$false)] + [String] + $ConnectionBroker = [System.Net.DNS]::GetHostByName('').HostName, + + [Parameter(Mandatory=$false)] + [String] + $CollectionName = "RDS Collection" +) +$SessionHosts = Get-RDSessionHost -CollectionName $CollectionName -ConnectionBroker $ConnectionBroker -ErrorAction Stop +$TestedSessionHosts = Test-RetryNetConnection -ComputerName $SessionHosts.SessionHost + +if ($TestedSessionHosts.StaleComputers) { + Clear-RDSessionHost -SessionHost ($SessionHosts | Where-Object { $_.SessionHost -in $TestedSessionHosts.StaleComputers}) -ConnectionBroker $ConnectionBroker +} + +$Acl = Get-Acl $UpdPath -ErrorAction Stop + +$IdentityReferences = @() +if ($TestedSessionHosts.ValidComputers) { + $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetBiosName}\{0}$" -f $_.Split(".")[0] } +} + +$ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences + +if ($ValidAcl) { + Invoke-RetryCommand -Command Set-Acl -ArgList @{Path=$UpdPath; AclObject=$ValidAcl} -CheckExpression '$?' +} From 172fb021b2c9dedf25260f0b8a90a0ee4a887ac7 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Wed, 21 Aug 2019 08:24:27 -0700 Subject: [PATCH 05/25] Provides utils function to retrieve a file from a URI --- psmodules/P3Utils/P3Utils.psm1 | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index 734eb284..761faf0e 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -213,3 +213,72 @@ function global:Edit-AclIdentityReference { Write-Output $Acl } } + +function global:Get-File { + Param ( + [Parameter(Mandatory=$true)] + [System.URI] + $Source, + + [Parameter(Mandatory=$true)] + [System.IO.FileInfo] + $Destination, + + [Parameter(Mandatory=$false)] + [ValidateSet("Ssl3","SystemDefault","Tls","Tls11","Tls12")] + [String] + $SecurityProtocol = "Tls12", + + [Parameter(Mandatory=$false)] + [Switch] + $MakeDir, + + [Parameter(Mandatory=$false)] + [Switch] + $OverWrite + ) + try { + $ResolvedDestination = [System.IO.FileInfo]$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Destination) + $TempFile = New-TemporaryFile + + Write-Verbose "Retrieving file:" + Write-Verbose "* Source: ${Source}" + Write-Verbose "* Destination: ${ResolvedDestination}" + Write-Verbose "* Temporary Destination: ${TempFile}" + + try + { + Write-Verbose "Attempting to retrieve file using .NET method..." + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::$SecurityProtocol + (New-Object Net.WebClient).DownloadFile("$Source","$TempFile") + } + catch + { + try + { + Write-Verbose $PSItem.ToString() + Write-Verbose ".NET method failed, attempting BITS transfer method..." + Start-BitsTransfer -Source $Source -Destination $TempFile -ErrorAction Stop + } + catch + { + Write-Verbose $PSItem.ToString() + $PSCmdlet.ThrowTerminatingError($PSItem) + } + } + + If (-not $ResolvedDestination.Directory.Exists -and $MakeDir) { + $null = New-Item -Path $ResolvedDestination.Directory -ItemType Directory + } + + Move-Item $TempFile $ResolvedDestination -Force:$OverWrite -ErrorAction Stop + Write-Output (Get-ChildItem $ResolvedDestination) + } + finally + { + if (Test-Path $TempFile) + { + Remove-Item -Path $TempFile -Force + } + } +} From 881e41a8d16287595b0cb9e5d707c7b58c4c01ef Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Wed, 21 Aug 2019 12:33:01 -0700 Subject: [PATCH 06/25] Ensures files are downloaded/updated during stack updates --- ...cb_fileserver_standalone.template.cfn.yaml | 114 ++++++++++++++++-- 1 file changed, 101 insertions(+), 13 deletions(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index ccf930c1..aba67c96 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -392,22 +392,118 @@ Resources: 'AWS::CloudFormation::Init': cfnsetup: commands: - a-set-execution-policy: + 00-get-p3utils-psd1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psd1 + -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 01-get-p3utils-psm1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psm1 + -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 02-get-p3remoteaccess-psd1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 + -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psd1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 03-get-p3remoteaccess-psm1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 + -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psm1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 04-get-configure-ebsbackups-ps1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-ebsbackups.ps1 + -Destination 'c:\cfn\scripts\configure-ebsbackups.ps1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 05-get-snap-by-group-ebsbackups-ps1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapByCgroup.ps1 + -Destination 'c:\cfn\scripts\snap-by-group.ps1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 06-get-snap-maintenance-ps1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapMaint.ps1 + -Destination 'c:\cfn\scripts\snap-maintenance.ps1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 07-get-unzip-archive-ps1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/unzip-archive.ps1 + -Destination 'c:\cfn\scripts\unzip-archive.ps1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 50-set-execution-policy: command: powershell.exe -command Set-ExecutionPolicy RemoteSigned -Force waitAfterCompletion: '0' - b-online-disks: + 51-online-disks: command: powershell.exe "foreach ($disk in (Get-CimInstance -ClassName Win32_DiskDrive)) { Set-Disk -Number $disk.Index -IsOffline $false }" ignoreErrors: 'true' waitAfterCompletion: '0' - c-initialize-disks: + 52-initialize-disks: command: powershell.exe C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1 ignoreErrors: 'true' waitAfterCompletion: '0' - d-extend-disks: + 53-extend-disks: command: 'powershell.exe c:\cfn\scripts\extend-volumes.ps1 -verbose' ignoreErrors: 'true' waitAfterCompletion: '0' - e-unzip-pstools: + 54-unzip-pstools: command: powershell.exe c:\cfn\scripts\unzip-archive.ps1 c:\cfn\files\pstools.zip c:\cfn\files\pstools ignoreErrors: 'true' waitAfterCompletion: '0' @@ -431,8 +527,6 @@ Resources: - InitUpdate: !Sub - ${Command} --stack ${AWS::StackName} --region ${AWS::Region} - Command: !FindInMap [CfnUtilsMap, Init, Update] - 'c:\cfn\scripts\configure-ebsbackups.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-ebsbackups.ps1 'c:\cfn\scripts\configure-fileshares.ps1': source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-fileshares.ps1 'c:\cfn\scripts\configure-rdcb.ps1': @@ -453,12 +547,6 @@ Resources: Write-Verbose "No change to disk $($disk.Number) partition 1" } } - 'c:\cfn\scripts\snap-by-group.ps1': - source: https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapByCgroup.ps1 - 'c:\cfn\scripts\snap-maintenance.ps1': - source: https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapMaint.ps1 - 'c:\cfn\scripts\unzip-archive.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/unzip-archive.ps1 services: windows: cfn-hup: From 6b15d9dd6cf832756a4acfa53b85f7ffda99f8bb Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Wed, 21 Aug 2019 13:21:17 -0700 Subject: [PATCH 07/25] Provides utils function the create repeating scheduled tasks --- psmodules/P3Utils/P3Utils.psm1 | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index 761faf0e..cd0c11df 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -282,3 +282,70 @@ function global:Get-File { } } } + +function global:New-RepeatingTask { + Param( + [Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [String] + $Name, + + [Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [String[]] + $Arguments, + + [Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [String] + $User, + + [Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [SecureString] + $SecurePassword, + + [Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [String] + $Command = "powershell.exe", + + [Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [DateTime] + $StartTime = (Get-Date).Date, + + [Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [TimeSpan] + $RepetitionInterval = (New-TimeSpan -Hours 1), + + [Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [TimeSpan] + $RandomDelay = (New-TimeSpan -Minutes 10), + + [Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipeLineByPropertyName=$false)] + [Switch] + $Force + ) + if (Get-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue) + { + if ($Force) + { + UnRegister-ScheduledTask -TaskName $Name -Confirm:$false + Write-Verbose "Force-unregistered existing job, ${Name}" + } + else + { + throw "Task already exists, ${Name}. Use '-Force' to delete it" + } + } + + $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $User, $SecurePassword + $Password = $Credentials.GetNetworkCredential().Password + $Action = New-ScheduledTaskAction -Execute $Command -Argument "$Arguments" + $Trigger = New-JobTrigger -Once -At $StartTime -RepeatIndefinitely -RepetitionInterval $RepetitionInterval -RandomDelay $RandomDelay + $Settings = New-ScheduledTaskSettingsSet -MultipleInstances Parallel + Register-ScheduledTask -TaskName $Name -Action $Action -Trigger $Trigger -User $User -Password $Password -RunLevel Highest -Settings $Settings + Write-Verbose "Created scheduled job, ${Name}" + + if ($StartTime.CompareTo((Get-Date)) -le 0) + { + # Start time is now or in the past, trigger job immediately + Start-ScheduledTask -TaskName $Name + Write-Verbose "Triggered job, ${Name}" + } +} From 5d4e63d90646e718708bcc21d5450f5c043daaf3 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Wed, 21 Aug 2019 14:59:44 -0700 Subject: [PATCH 08/25] Creates repeating task to cleanup rdcp session hosts and acls --- ...cb_fileserver_standalone.template.cfn.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index aba67c96..f82f797a 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -488,6 +488,18 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + 08-get-cleanup-rdcb-ps1: + command: !Sub + - >- + ${PowershellCommand} -Command " + Get-File + -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/cleanup-rdcb.ps1 + -Destination 'c:\cfn\scripts\cleanup-rdcb.ps1' + -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] 50-set-execution-policy: command: powershell.exe -command Set-ExecutionPolicy RemoteSigned -Force waitAfterCompletion: '0' @@ -634,6 +646,31 @@ Resources: - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] waitAfterCompletion: '0' + configure-rdcb-cleanup: + commands: + 20-configure-rdcb: + command: !Sub + - >- + ${PowershellCommand} -Command "${PsExecCommand} + -u \"${DomainNetbiosName}\$((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}' }).Value).Username)\" + -p \"$((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}'}).Value).Password)\" + ${PowershellCommand} -Command + \"New-RepeatingTask + -Name 'RDCB Cleanup' + -Command 'powershell.exe' + -Arguments 'C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$' + -User (Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}' }).Value).Username + -SecurePassword ((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}'}).Value).Password ^| ConvertTo-SecureString -AsPlainText -Force) + -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) + -RepetitionInterval (New-TimeSpan -Hours 24)) + \" + -Verbose -ErrorAction Stop" || ${SignalFailure} + - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] + PsExecCommand: !FindInMap [ShellCommandMap, psexec, command] + SignalFailure: !Sub + - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) + - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' configure-rdcb: commands: 20-configure-rdcb: From ac5aa1ef3e6a4f5f9b5b41c196367b956cabb21e Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 06:47:15 -0700 Subject: [PATCH 09/25] Exposes parameter to source scripts from forks/branches --- ...uac_autoscale_public_alb.template.cfn.yaml | 7 ++++- ...cb_fileserver_standalone.template.cfn.yaml | 27 +++++++++++-------- ...rdgw_autoscale_public_lb.template.cfn.yaml | 11 +++++--- ...sh_autoscale_internal_lb.template.cfn.yaml | 13 ++++++--- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/templates/ra_guac_autoscale_public_alb.template.cfn.yaml b/templates/ra_guac_autoscale_public_alb.template.cfn.yaml index e545e166..2ca274f2 100644 --- a/templates/ra_guac_autoscale_public_alb.template.cfn.yaml +++ b/templates/ra_guac_autoscale_public_alb.template.cfn.yaml @@ -180,6 +180,11 @@ Parameters: PublicSubnetIDs: Description: A list of Public subnet IDs to attach to the Application Load Balancer Type: 'List' + RepoBranchPrefixUrl: + Description: URL prefix where the repo scripts can be retrieved + Default: https://raw.githubusercontent.com/plus3it/cfn/master + Type: String + AllowedPattern: '^https:/.*' ScaleDownDesiredCapacity: Default: '1' Description: (Optional) Desired number of instances during the Scale Down Scheduled Action; ignored if ScaleDownSchedule is unset @@ -563,7 +568,7 @@ Resources: group: root mode: '000700' owner: root - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/make-guac.sh + source: !Sub ${RepoBranchPrefixUrl}/scripts/make-guac.sh services: sysvinit: cfn-hup: diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index f82f797a..9897704f 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -193,6 +193,11 @@ Parameters: AllowedPattern: '^$|.*[@].*' Description: (Optional) Email address to subscribe to notifications and alarms Type: String + RepoBranchPrefixUrl: + Description: URL prefix where the repo scripts can be retrieved + Default: https://raw.githubusercontent.com/plus3it/cfn/master + Type: String + AllowedPattern: '^https:/.*' SnapshotFrequency: Description: '(Optional) Specify an interval in minutes to configure snapshots of the EBS fileshare volume. Set an empty value "" to skip configuring snapshots. Default interval is 60 minutes.' Default: '60' @@ -397,7 +402,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psd1 + -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -409,7 +414,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psm1 + -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -421,7 +426,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 + -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psd1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -433,7 +438,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 + -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psm1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -445,7 +450,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-ebsbackups.ps1 + -Source ${RepoBranchPrefixUrl}/scripts/configure-ebsbackups.ps1 -Destination 'c:\cfn\scripts\configure-ebsbackups.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -481,7 +486,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/unzip-archive.ps1 + -Source ${RepoBranchPrefixUrl}/scripts/unzip-archive.ps1 -Destination 'c:\cfn\scripts\unzip-archive.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -493,7 +498,7 @@ Resources: - >- ${PowershellCommand} -Command " Get-File - -Source https://raw.githubusercontent.com/plus3it/cfn/master/scripts/cleanup-rdcb.ps1 + -Source ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 -Destination 'c:\cfn\scripts\cleanup-rdcb.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] @@ -540,9 +545,9 @@ Resources: - ${Command} --stack ${AWS::StackName} --region ${AWS::Region} - Command: !FindInMap [CfnUtilsMap, Init, Update] 'c:\cfn\scripts\configure-fileshares.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-fileshares.ps1 + source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-fileshares.ps1 'c:\cfn\scripts\configure-rdcb.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-rdcb.ps1 + source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-rdcb.ps1 'c:\cfn\scripts\extend-volumes.ps1': content: | [CmdLetBinding()] @@ -822,9 +827,9 @@ Resources: ps-modules: files: 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psd1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psm1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 reboot: commands: 10-reboot: diff --git a/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml b/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml index 8654ba4d..9bd837a7 100644 --- a/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml +++ b/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml @@ -210,6 +210,11 @@ Parameters: Description: Domain group of users authorized to use the RDGW MinLength: '1' Type: String + RepoBranchPrefixUrl: + Description: URL prefix where the repo scripts can be retrieved + Default: https://raw.githubusercontent.com/plus3it/cfn/master + Type: String + AllowedPattern: '^https:/.*' ScaleDownDesiredCapacity: Default: '1' Description: (Optional) Desired number of instances during the Scale Down Scheduled Action; ignored if ScaleDownSchedule is unset @@ -540,9 +545,9 @@ Resources: ps-modules: files: 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psd1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psm1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 setup: files: 'c:\cfn\cfn-hup.conf': @@ -561,7 +566,7 @@ Resources: - ${Command} --stack ${AWS::StackName} --region ${AWS::Region} - Command: !FindInMap [CfnUtilsMap, Init, Update] 'c:\cfn\scripts\configure-rdgw.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-rdgw.ps1 + source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-rdgw.ps1 services: windows: cfn-hup: diff --git a/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml b/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml index 7e12d960..05af28aa 100644 --- a/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml +++ b/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml @@ -241,6 +241,11 @@ Parameters: Default: 'https://s3.amazonaws.com' Description: S3 endpoint URL hosting the bucket where the RDP certificate private key is stored Type: String + RepoBranchPrefixUrl: + Description: URL prefix where the repo scripts can be retrieved + Default: https://raw.githubusercontent.com/plus3it/cfn/master + Type: String + AllowedPattern: '^https:/.*' ScaleDownDesiredCapacity: Default: '1' Description: (Optional) Desired number of instances during the Scale Down Scheduled Action; ignored if ScaleDownSchedule is unset @@ -617,9 +622,9 @@ Resources: ps-modules: files: 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psd1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/psmodules/P3Utils/P3Utils.psm1 + source: !Sub ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 setup: commands: a-unzip-pstools: @@ -652,9 +657,9 @@ Resources: - ${Command} --stack ${AWS::StackName} --region ${AWS::Region} - Command: !FindInMap [CfnUtilsMap, Init, Update] 'c:\cfn\scripts\configure-rdsh.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/configure-rdsh.ps1 + source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-rdsh.ps1 'c:\cfn\scripts\unzip-archive.ps1': - source: https://raw.githubusercontent.com/plus3it/cfn/master/scripts/unzip-archive.ps1 + source: !Sub ${RepoBranchPrefixUrl}/scripts/unzip-archive.ps1 services: windows: cfn-hup: From 42c900959aca2b8771f7dae33c0b1e87cefa907c Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 07:07:16 -0700 Subject: [PATCH 10/25] Imports module so function can be used --- psmodules/P3Utils/P3Utils.psm1 | 1 + ...cb_fileserver_standalone.template.cfn.yaml | 45 +++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index cd0c11df..f384cbb4 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -272,6 +272,7 @@ function global:Get-File { } Move-Item $TempFile $ResolvedDestination -Force:$OverWrite -ErrorAction Stop + Write-Verbose "Retrieved file successfully!" Write-Output (Get-ChildItem $ResolvedDestination) } finally diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 9897704f..07106345 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -400,8 +400,8 @@ Resources: 00-get-p3utils-psd1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -409,11 +409,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 01-get-p3utils-psm1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -421,11 +422,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 02-get-p3remoteaccess-psd1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psd1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -433,11 +435,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 03-get-p3remoteaccess-psm1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psm1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -445,11 +448,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 04-get-configure-ebsbackups-ps1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/scripts/configure-ebsbackups.ps1 -Destination 'c:\cfn\scripts\configure-ebsbackups.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -457,11 +461,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 05-get-snap-by-group-ebsbackups-ps1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapByCgroup.ps1 -Destination 'c:\cfn\scripts\snap-by-group.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -469,11 +474,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 06-get-snap-maintenance-ps1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapMaint.ps1 -Destination 'c:\cfn\scripts\snap-maintenance.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -481,11 +487,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 07-get-unzip-archive-ps1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/scripts/unzip-archive.ps1 -Destination 'c:\cfn\scripts\unzip-archive.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -493,11 +500,12 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 08-get-cleanup-rdcb-ps1: command: !Sub - >- - ${PowershellCommand} -Command " - Get-File + ${PowershellCommand} -Command "Import-Module P3Utils; + $null = Get-File -Source ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 -Destination 'c:\cfn\scripts\cleanup-rdcb.ps1' -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} @@ -505,6 +513,7 @@ Resources: SignalFailure: !Sub - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] + waitAfterCompletion: '0' 50-set-execution-policy: command: powershell.exe -command Set-ExecutionPolicy RemoteSigned -Force waitAfterCompletion: '0' From a8071daff229a326f15381357fb28f2b475afe63 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 07:26:15 -0700 Subject: [PATCH 11/25] Reverts back to using `files` capability of cfn-init Turns out the "error" noticed in the log that inspired the change to use Get-File *did not* actually prevent cfn-init from updating the target file. --- ...cb_fileserver_standalone.template.cfn.yaml | 128 ++---------------- 1 file changed, 11 insertions(+), 117 deletions(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 07106345..514474dd 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -397,123 +397,6 @@ Resources: 'AWS::CloudFormation::Init': cfnsetup: commands: - 00-get-p3utils-psd1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psd1 - -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psd1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 01-get-p3utils-psm1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/psmodules/P3Utils/P3Utils.psm1 - -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3Utils\P3Utils.psm1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 02-get-p3remoteaccess-psd1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psd1 - -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psd1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 03-get-p3remoteaccess-psm1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/psmodules/P3RemoteAccess/P3RemoteAccess.psm1 - -Destination 'C:\Program Files\WindowsPowerShell\Modules\P3RemoteAccess\P3RemoteAccess.psm1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 04-get-configure-ebsbackups-ps1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/scripts/configure-ebsbackups.ps1 - -Destination 'c:\cfn\scripts\configure-ebsbackups.ps1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 05-get-snap-by-group-ebsbackups-ps1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapByCgroup.ps1 - -Destination 'c:\cfn\scripts\snap-by-group.ps1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 06-get-snap-maintenance-ps1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapMaint.ps1 - -Destination 'c:\cfn\scripts\snap-maintenance.ps1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 07-get-unzip-archive-ps1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/scripts/unzip-archive.ps1 - -Destination 'c:\cfn\scripts\unzip-archive.ps1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' - 08-get-cleanup-rdcb-ps1: - command: !Sub - - >- - ${PowershellCommand} -Command "Import-Module P3Utils; - $null = Get-File - -Source ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 - -Destination 'c:\cfn\scripts\cleanup-rdcb.ps1' - -MakeDir -OverWrite -Verbose -ErrorAction Stop" || ${SignalFailure} - - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] - SignalFailure: !Sub - - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - - Command: !FindInMap [CfnUtilsMap, Signal, Failure] - waitAfterCompletion: '0' 50-set-execution-policy: command: powershell.exe -command Set-ExecutionPolicy RemoteSigned -Force waitAfterCompletion: '0' @@ -553,10 +436,18 @@ Resources: - InitUpdate: !Sub - ${Command} --stack ${AWS::StackName} --region ${AWS::Region} - Command: !FindInMap [CfnUtilsMap, Init, Update] + 'c:\cfn\scripts\unzip-archive.ps1': + source: !Sub ${RepoBranchPrefixUrl}/scripts/unzip-archive.ps1 + 'c:\cfn\scripts\configure-ebsbackups.ps1': + source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-ebsbackups.ps1 'c:\cfn\scripts\configure-fileshares.ps1': source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-fileshares.ps1 'c:\cfn\scripts\configure-rdcb.ps1': source: !Sub ${RepoBranchPrefixUrl}/scripts/configure-rdcb.ps1 + 'c:\cfn\scripts\snap-by-group.ps1': + source: https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapByCgroup.ps1 + 'c:\cfn\scripts\snap-maintenance.ps1': + source: https://raw.githubusercontent.com/plus3it/WinEBSbackups/master/SnapMaint.ps1 'c:\cfn\scripts\extend-volumes.ps1': content: | [CmdLetBinding()] @@ -685,6 +576,9 @@ Resources: - (${Command} --stack ${AWS::StackName} --region ${AWS::Region} && exit /b 1) - Command: !FindInMap [CfnUtilsMap, Signal, Failure] waitAfterCompletion: '0' + files: + 'c:\cfn\scripts\cleanup-rdcb.ps1': + source: !Sub ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 configure-rdcb: commands: 20-configure-rdcb: From 4e000ee44c1c91e3d1c4106991b063b5011d7fa9 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 07:28:52 -0700 Subject: [PATCH 12/25] Adds rdcb cleanup to the configsets --- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 514474dd..f6616487 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -487,11 +487,13 @@ Resources: - !Ref "AWS::NoValue" - configure-admins - configure-rdcb + - configure-rdcb-cleanup - reboot - finalize update: - ps-modules - cfnsetup + - configure-rdcb-cleanup - finalize configure-admins: commands: @@ -553,7 +555,7 @@ Resources: waitAfterCompletion: '0' configure-rdcb-cleanup: commands: - 20-configure-rdcb: + 20-rdcb-cleanup: command: !Sub - >- ${PowershellCommand} -Command "${PsExecCommand} From 095a6badab6afa9da3822c1c5ded8a82500e96dc Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 07:54:06 -0700 Subject: [PATCH 13/25] Uses inline file to invoke scheduled task Avoids psexec error "Argument to long" --- ...cb_fileserver_standalone.template.cfn.yaml | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index f6616487..94827904 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -561,16 +561,7 @@ Resources: ${PowershellCommand} -Command "${PsExecCommand} -u \"${DomainNetbiosName}\$((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}' }).Value).Username)\" -p \"$((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}'}).Value).Password)\" - ${PowershellCommand} -Command - \"New-RepeatingTask - -Name 'RDCB Cleanup' - -Command 'powershell.exe' - -Arguments 'C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$' - -User (Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}' }).Value).Username - -SecurePassword ((Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters ^| ? {$_.Name -eq '${SsmRdcbCredential}'}).Value).Password ^| ConvertTo-SecureString -AsPlainText -Force) - -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) - -RepetitionInterval (New-TimeSpan -Hours 24)) - \" + ${PowershellCommand} c:\cfn\scripts\cleanup-rdcb-schedule.ps1 -Verbose -ErrorAction Stop" || ${SignalFailure} - PowershellCommand: !FindInMap [ShellCommandMap, powershell, command] PsExecCommand: !FindInMap [ShellCommandMap, psexec, command] @@ -581,6 +572,21 @@ Resources: files: 'c:\cfn\scripts\cleanup-rdcb.ps1': source: !Sub ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 + files: + 'c:\cfn\scripts\cleanup-rdcb-schedule.ps1': + content: !Sub | + [CmdLetBinding()] + Param() + Import-Module P3Utils + $Credential = Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters | ? {$_.Name -eq '${SsmRdcbCredential}' }).Value + New-RepeatingTask ` + -Name 'RDCB Cleanup' ` + -Command 'powershell.exe' ` + -Arguments 'C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$' ` + -User $Credential.Username ` + -SecurePassword ($Credential.Password | ConvertTo-SecureString -AsPlainText -Force) ` + -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) ` + -RepetitionInterval (New-TimeSpan -Hours 24) configure-rdcb: commands: 20-configure-rdcb: From ccc51dec14be306ccc910b711883f92465baf5c4 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 08:41:53 -0700 Subject: [PATCH 14/25] Captures log file of rdcb cleanup task --- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 94827904..df423aef 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -572,7 +572,6 @@ Resources: files: 'c:\cfn\scripts\cleanup-rdcb.ps1': source: !Sub ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 - files: 'c:\cfn\scripts\cleanup-rdcb-schedule.ps1': content: !Sub | [CmdLetBinding()] @@ -581,12 +580,13 @@ Resources: $Credential = Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters | ? {$_.Name -eq '${SsmRdcbCredential}' }).Value New-RepeatingTask ` -Name 'RDCB Cleanup' ` - -Command 'powershell.exe' ` - -Arguments 'C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$' ` + -Command 'cmd' ` + -Arguments '/c powershell.exe C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$ -Verbose -ErrorAction Stop >> c:\cfn\log\cleanup-rdcb.log 2>&1' ` -User $Credential.Username ` -SecurePassword ($Credential.Password | ConvertTo-SecureString -AsPlainText -Force) ` -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) ` - -RepetitionInterval (New-TimeSpan -Hours 24) + -RepetitionInterval (New-TimeSpan -Hours 24) ` + -Force configure-rdcb: commands: 20-configure-rdcb: From 6e8e63b62c961c5754a0904f6aed18ce105d8518 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 11:10:44 -0700 Subject: [PATCH 15/25] Avoids leaking results into the output stream --- psmodules/P3Utils/P3Utils.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psmodules/P3Utils/P3Utils.psm1 b/psmodules/P3Utils/P3Utils.psm1 index f384cbb4..0a928814 100644 --- a/psmodules/P3Utils/P3Utils.psm1 +++ b/psmodules/P3Utils/P3Utils.psm1 @@ -190,7 +190,7 @@ function global:Edit-AclIdentityReference { { Write-Verbose "Identity is NOT VALID, removing rule:" Write-Verbose "* Rule Identity: $Identity" - $Acl.RemoveAccessRule($Rule) + $null = $Acl.RemoveAccessRule($Rule) } } @@ -199,7 +199,7 @@ function global:Edit-AclIdentityReference { { Write-Verbose "Adding missing access rule to ACL:" Write-Verbose "* Rule Identity: $Identity" - $Acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule( + $null = $Acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule( $Identity, $FileSystemRights, $InheritanceFlags, From 1d7838f3b46ba3a4441713bbb61d5cadda71704e Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 11:11:12 -0700 Subject: [PATCH 16/25] Ensures verbose preference is passed through rdcb cleanup script --- scripts/cleanup-rdcb.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/cleanup-rdcb.ps1 b/scripts/cleanup-rdcb.ps1 index 72c96fa1..f68e5e9c 100644 --- a/scripts/cleanup-rdcb.ps1 +++ b/scripts/cleanup-rdcb.ps1 @@ -17,10 +17,10 @@ Param( $CollectionName = "RDS Collection" ) $SessionHosts = Get-RDSessionHost -CollectionName $CollectionName -ConnectionBroker $ConnectionBroker -ErrorAction Stop -$TestedSessionHosts = Test-RetryNetConnection -ComputerName $SessionHosts.SessionHost +$TestedSessionHosts = Test-RetryNetConnection -ComputerName $SessionHosts.SessionHost -Verbose:$VerbosePreference if ($TestedSessionHosts.StaleComputers) { - Clear-RDSessionHost -SessionHost ($SessionHosts | Where-Object { $_.SessionHost -in $TestedSessionHosts.StaleComputers}) -ConnectionBroker $ConnectionBroker + Clear-RDSessionHost -SessionHost ($SessionHosts | Where-Object { $_.SessionHost -in $TestedSessionHosts.StaleComputers}) -ConnectionBroker $ConnectionBroker -Verbose:$VerbosePreference } $Acl = Get-Acl $UpdPath -ErrorAction Stop @@ -30,8 +30,8 @@ if ($TestedSessionHosts.ValidComputers) { $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetBiosName}\{0}$" -f $_.Split(".")[0] } } -$ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences +$ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences -Verbose:$VerbosePreference if ($ValidAcl) { - Invoke-RetryCommand -Command Set-Acl -ArgList @{Path=$UpdPath; AclObject=$ValidAcl} -CheckExpression '$?' + Invoke-RetryCommand -Command Set-Acl -ArgList @{Path=$UpdPath; AclObject=$ValidAcl} -CheckExpression '$?' -Verbose:$VerbosePreference } From dea619281ea5e579e079278b902d677ec613f522 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 22 Aug 2019 11:52:09 -0700 Subject: [PATCH 17/25] Adds missing DomainNetbiosName parameter to cleanup function --- scripts/cleanup-rdcb.ps1 | 6 +++++- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/cleanup-rdcb.ps1 b/scripts/cleanup-rdcb.ps1 index f68e5e9c..e6e29d39 100644 --- a/scripts/cleanup-rdcb.ps1 +++ b/scripts/cleanup-rdcb.ps1 @@ -8,6 +8,10 @@ Param( [String] $UpdPath, + [Parameter(Mandatory=$true)] + [String] + $DomainNetbiosName, + [Parameter(Mandatory=$false)] [String] $ConnectionBroker = [System.Net.DNS]::GetHostByName('').HostName, @@ -27,7 +31,7 @@ $Acl = Get-Acl $UpdPath -ErrorAction Stop $IdentityReferences = @() if ($TestedSessionHosts.ValidComputers) { - $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetBiosName}\{0}$" -f $_.Split(".")[0] } + $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetbiosName}\{0}$" -f $_.Split(".")[0] } } $ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences -Verbose:$VerbosePreference diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index df423aef..aeeace34 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -581,7 +581,7 @@ Resources: New-RepeatingTask ` -Name 'RDCB Cleanup' ` -Command 'cmd' ` - -Arguments '/c powershell.exe C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$ -Verbose -ErrorAction Stop >> c:\cfn\log\cleanup-rdcb.log 2>&1' ` + -Arguments '/c powershell.exe C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$ -DomainNetbiosName ${DomainNetbiosName} -Verbose -ErrorAction Stop >> c:\cfn\log\cleanup-rdcb.log 2>&1' ` -User $Credential.Username ` -SecurePassword ($Credential.Password | ConvertTo-SecureString -AsPlainText -Force) ` -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) ` From 379a33e71f091dc348c37e45dd6b397faf9b764a Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 23 Aug 2019 13:07:54 -0700 Subject: [PATCH 18/25] Uses a wrapper to run cleanup script and log start/end time --- scripts/logit.cmd | 29 +++++++++++++++++++ ...cb_fileserver_standalone.template.cfn.yaml | 6 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 scripts/logit.cmd diff --git a/scripts/logit.cmd b/scripts/logit.cmd new file mode 100644 index 00000000..75c9ce43 --- /dev/null +++ b/scripts/logit.cmd @@ -0,0 +1,29 @@ +@ECHO OFF +SETLOCAL + +SET logsep=------------------------------------------ +SET cmd=%* + +ECHO %logsep% +ECHO Start time: %date% %time% +ECHO Running command: %cmd% +ECHO. + +%cmd% + +SET err=%ERRORLEVEL% + +ECHO. + +IF %err% equ 0 GOTO success +:error +ECHO Command exited with non-zero return code: %err% +GOTO exit + +:success +ECHO Command succeeded^! + +:exit +ECHO End time: %date% %time% +ECHO %logsep% +EXIT /B %err% diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index aeeace34..36a913ce 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -572,6 +572,8 @@ Resources: files: 'c:\cfn\scripts\cleanup-rdcb.ps1': source: !Sub ${RepoBranchPrefixUrl}/scripts/cleanup-rdcb.ps1 + 'c:\cfn\scripts\logit.cmd': + source: !Sub ${RepoBranchPrefixUrl}/scripts/logit.cmd 'c:\cfn\scripts\cleanup-rdcb-schedule.ps1': content: !Sub | [CmdLetBinding()] @@ -580,8 +582,8 @@ Resources: $Credential = Invoke-Expression ((Get-SSMParameterValue -Name '${SsmRdcbCredential}' -WithDecryption $true).Parameters | ? {$_.Name -eq '${SsmRdcbCredential}' }).Value New-RepeatingTask ` -Name 'RDCB Cleanup' ` - -Command 'cmd' ` - -Arguments '/c powershell.exe C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$ -DomainNetbiosName ${DomainNetbiosName} -Verbose -ErrorAction Stop >> c:\cfn\log\cleanup-rdcb.log 2>&1' ` + -Command 'c:\cfn\scripts\logit.cmd' ` + -Arguments 'powershell.exe C:\cfn\scripts\cleanup-rdcb.ps1 -UpdPath D:\Shares\Profiles$ -DomainNetbiosName ${DomainNetbiosName} -Verbose -ErrorAction Stop >> c:\cfn\log\cleanup-rdcb.log 2>&1' ` -User $Credential.Username ` -SecurePassword ($Credential.Password | ConvertTo-SecureString -AsPlainText -Force) ` -StartTime (Get-Date -Hour 20 -Minute 0 -Second 0).AddDays(1) ` From 739aa84146ccc10358ece9f6067a805ca584aacb Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 23 Aug 2019 13:15:59 -0700 Subject: [PATCH 19/25] Forwards rdcb cleanup log to cloudwatch --- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 36a913ce..323dc0a7 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -667,6 +667,12 @@ Resources: "log_group_name": "${local_InstanceLogGroup}", "log_stream_name": "{instance_id}//c/cfn/log/cfn-init-cmd.log", "timestamp_format": "%H:%M:%S %y %b %-d" + }, + { + "file_path": "c:\\cfn\\log\\cleanup-rdcb.log", + "log_group_name": "${local_InstanceLogGroup}", + "log_stream_name": "{instance_id}//c/cfn/log/cleanup-rdcb.log", + "timestamp_format": "%H:%M:%S %y %b %-d" } ] }, From f5b199f048d945c6413fd3e4aee994e7b1433bbc Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 23 Aug 2019 13:42:01 -0700 Subject: [PATCH 20/25] Updates cloudwatch agent during stack update --- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 323dc0a7..40e052dc 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -492,6 +492,7 @@ Resources: - finalize update: - ps-modules + - install-cloudwatch-agent - cfnsetup - configure-rdcb-cleanup - finalize @@ -720,6 +721,13 @@ Resources: } } - local_InstanceLogGroup: !If [InstallCloudWatchAgent, !Ref InstanceLogGroup, !Ref 'AWS::NoValue'] + services: + windows: + AmazonCloudWatchAgent: + enabled: 'true' + ensureRunning: 'true' + files: + - 'c:\cfn\scripts\AmazonCloudWatchAgent\aws-cloudwatch-agent-config.json' install-roles: commands: 10-install-roles: From 707236ad637940648b80ccfd03f8c4290ae6d43d Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 23 Aug 2019 14:13:42 -0700 Subject: [PATCH 21/25] Uses cfn-init packages feature to install cloudwatch-agent --- ...cb_fileserver_standalone.template.cfn.yaml | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 40e052dc..68d1135d 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -109,9 +109,9 @@ Parameters: Description: Search pattern to match against an AMI Name Type: String CloudWatchAgentUrl: - AllowedPattern: '^$|^s3://.*\.msi$' + AllowedPattern: '^$|^https://.*\.msi$' Default: '' - Description: '(Optional) S3 URL to CloudWatch Agent MSI. Example: s3://amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi' + Description: '(Optional) S3 URL to CloudWatch Agent MSI. Example: https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi' Type: String DataVolumeSize: Default: '5' @@ -270,10 +270,6 @@ Resources: Effect: Allow Resource: '*' Sid: AllowRestrictedSnapshotActions - - Action: - - 's3:GetObject' - Effect: Allow - Resource: 'arn:aws:s3:::amazoncloudwatch-agent/*' - Action: - 'ec2:CreateSnapshot' - 'ec2:DeleteSnapshot' @@ -618,20 +614,14 @@ Resources: waitAfterCompletion: '0' install-cloudwatch-agent: commands: - 10-install-cloudwatch-agent: + 10-configure-cloudwatch-agent: command: !Sub - >- ${PowershellCommand} -Command " Invoke-Command -ScriptBlock { $ErrorActionPreference = 'Stop'; Import-Module P3Utils; - $CloudWatchAgentUri = [System.Uri]'${CloudWatchAgentUrl}'; - $CloudWatchAgentScriptDir = 'c:\cfn\scripts\AmazonCloudWatchAgent'; - $CloudWatchAgentInstaller = Join-Path $CloudWatchAgentScriptDir $CloudWatchAgentUri.Segments[($CloudWatchAgentUri.Segments.Length-1)]; - $Null = New-Item $CloudWatchAgentScriptDir -Type Directory -Force; - Read-S3Object -BucketName $CloudWatchAgentUri.Host -Key ($CloudWatchAgentUri.Segments[1..($CloudWatchAgentUri.Segments.Length-1)] -Join '') -File $CloudWatchAgentInstaller -Region ${AWS::Region}; - $CloudWatchAgentConfig = $CloudWatchAgentScriptDir + '\aws-cloudwatch-agent-config.json'; - Invoke-RetryCommand -Command Start-Process -ArgList @{ FilePath='msiexec.exe'; ArgumentList = @('/i', $CloudWatchAgentInstaller, '/qn'); NoNewWindow = $true; PassThru = $true; Wait = $true } -CheckExpression '$Return.Result.ExitCode -eq 0' -InitialDelay 17 -MaxDelay 59 -Verbose; + $CloudWatchAgentConfig = 'c:\cfn\files\aws-cloudwatch-agent-config.json'; $CloudWatchAgentCtl = \"${!Env:ProgramFiles}\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1\"; & $CloudWatchAgentCtl -Action cond-restart; & $CloudWatchAgentCtl -a fetch-config -m ec2 -c file:$CloudWatchAgentConfig -s; @@ -643,7 +633,7 @@ Resources: - Command: !FindInMap [CfnUtilsMap, Signal, Failure] waitAfterCompletion: '0' files: - 'c:\cfn\scripts\AmazonCloudWatchAgent\aws-cloudwatch-agent-config.json': + 'c:\cfn\files\aws-cloudwatch-agent-config.json': content: !Sub - |- { @@ -721,13 +711,16 @@ Resources: } } - local_InstanceLogGroup: !If [InstallCloudWatchAgent, !Ref InstanceLogGroup, !Ref 'AWS::NoValue'] + packages: + msi: + cloudwatch-agent: !Ref CloudWatchAgentUrl services: windows: AmazonCloudWatchAgent: enabled: 'true' ensureRunning: 'true' files: - - 'c:\cfn\scripts\AmazonCloudWatchAgent\aws-cloudwatch-agent-config.json' + - 'c:\cfn\files\aws-cloudwatch-agent-config.json' install-roles: commands: 10-install-roles: From 337c1eb94ddd740cfe9d3ef59e99e1fad4e7ca32 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Mon, 26 Aug 2019 14:48:54 -0400 Subject: [PATCH 22/25] Uses lock to avoid collisions in rdcb cleanup tasks --- scripts/cleanup-rdcb.ps1 | 54 +++++++++++++++++++++++++++++--------- scripts/configure-rdsh.ps1 | 2 +- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/scripts/cleanup-rdcb.ps1 b/scripts/cleanup-rdcb.ps1 index e6e29d39..6a95e247 100644 --- a/scripts/cleanup-rdcb.ps1 +++ b/scripts/cleanup-rdcb.ps1 @@ -20,22 +20,52 @@ Param( [String] $CollectionName = "RDS Collection" ) -$SessionHosts = Get-RDSessionHost -CollectionName $CollectionName -ConnectionBroker $ConnectionBroker -ErrorAction Stop -$TestedSessionHosts = Test-RetryNetConnection -ComputerName $SessionHosts.SessionHost -Verbose:$VerbosePreference -if ($TestedSessionHosts.StaleComputers) { - Clear-RDSessionHost -SessionHost ($SessionHosts | Where-Object { $_.SessionHost -in $TestedSessionHosts.StaleComputers}) -ConnectionBroker $ConnectionBroker -Verbose:$VerbosePreference +# Create a lock before doing work on the connection broker (a shared resource) +$LockFile = "${UpdPath}\cleanup-rdcb-${ConnectionBroker}.lock".ToLower() +$Lock = $false + +# Get an exclusive lock on the lock file +Write-Verbose "Attempting to create exclusive lock on ${LockFile}" +while (-not $Lock) { + try { + $Lock = [System.IO.File]::Open($LockFile, [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) + Write-Verbose "Established lock!" + } + catch { + # Sleep for 3 to 20 seconds - randomized to keep from hammering + $Sleep = Get-Random -Minimum 3 -Maximum 20 + Write-Verbose "Detected existing lock, retrying in $Sleep seconds" + $Sleep | Start-Sleep + } } -$Acl = Get-Acl $UpdPath -ErrorAction Stop +try { -$IdentityReferences = @() -if ($TestedSessionHosts.ValidComputers) { - $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetbiosName}\{0}$" -f $_.Split(".")[0] } -} + $SessionHosts = Get-RDSessionHost -CollectionName $CollectionName -ConnectionBroker $ConnectionBroker -ErrorAction Stop + $TestedSessionHosts = Test-RetryNetConnection -ComputerName $SessionHosts.SessionHost -Verbose:$VerbosePreference + + if ($TestedSessionHosts.StaleComputers) { + Clear-RDSessionHost -SessionHost ($SessionHosts | Where-Object { $_.SessionHost -in $TestedSessionHosts.StaleComputers}) -ConnectionBroker $ConnectionBroker -Verbose:$VerbosePreference + } + + $Acl = Get-Acl $UpdPath -ErrorAction Stop + + $IdentityReferences = @() + if ($TestedSessionHosts.ValidComputers) { + $IdentityReferences = $TestedSessionHosts.ValidComputers | ForEach-Object { "${DomainNetbiosName}\{0}$" -f $_.Split(".")[0] } + } -$ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences -Verbose:$VerbosePreference + $ValidAcl = Edit-AclIdentityReference -Acl $Acl -IdentityReference $IdentityReferences -Verbose:$VerbosePreference -if ($ValidAcl) { - Invoke-RetryCommand -Command Set-Acl -ArgList @{Path=$UpdPath; AclObject=$ValidAcl} -CheckExpression '$?' -Verbose:$VerbosePreference + if ($ValidAcl) { + Invoke-RetryCommand -Command Set-Acl -ArgList @{Path=$UpdPath; AclObject=$ValidAcl} -CheckExpression '$?' -Verbose:$VerbosePreference + } +} catch { + Write-Verbose $PSItem.ToString() + $PSCmdlet.ThrowTerminatingError($PSitem) +} finally { + # Release the lock on the shared resource + $Lock.Close() + Write-Verbose "Released lock on ${LockFile}" } diff --git a/scripts/configure-rdsh.ps1 b/scripts/configure-rdsh.ps1 index bbad3631..4f1615b0 100644 --- a/scripts/configure-rdsh.ps1 +++ b/scripts/configure-rdsh.ps1 @@ -129,7 +129,7 @@ $RequiredRoles = @( ) # Create a lock before doing work on the connection broker (a shared resource) -$LockFile = "${UpdPath}\configure-rdsh.lock" +$LockFile = "${UpdPath}\cleanup-rdcb-${ConnectionBroker}.lock".ToLower() $Lock = $false # Get an exclusive lock on the lock file From 439a993faaa2cde7793707a0a89ec997f3195ccc Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Mon, 26 Aug 2019 15:28:32 -0400 Subject: [PATCH 23/25] Adds param to force-toggle cfn-init updates --- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 68d1135d..33095ec3 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -156,6 +156,13 @@ Parameters: ExtraSecurityGroupIds: Description: List of extra Security Group IDs to attach to the RDCB EC2 instance Type: 'List' + ForceCfnInitUpdate: + AllowedValues: + - A + - B + Default: A + Description: Toggles a cfn-init metadata update even if nothing else changes + Type: String InstanceType: AllowedValues: - t2.micro @@ -762,6 +769,7 @@ Resources: waitAfterCompletion: forever CfnUpdateTriggers: EbsVolumeSize: !Ref DataVolumeSize + ForceCfnInitUpdate: !Ref ForceCfnInitUpdate Properties: BlockDeviceMappings: - DeviceName: /dev/sda1 From 928c5f38f00445960e19d0d82eef6d992ea08740 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Mon, 26 Aug 2019 16:00:41 -0400 Subject: [PATCH 24/25] Removes session host cleanup from rdsh configure script --- scripts/configure-rdsh.ps1 | 134 +++---------------------------------- 1 file changed, 11 insertions(+), 123 deletions(-) diff --git a/scripts/configure-rdsh.ps1 b/scripts/configure-rdsh.ps1 index 4f1615b0..430f9edb 100644 --- a/scripts/configure-rdsh.ps1 +++ b/scripts/configure-rdsh.ps1 @@ -152,68 +152,19 @@ while (-not $Lock) try { $RDServers = Get-RDServer -ConnectionBroker $ConnectionBroker -ErrorAction SilentlyContinue - $ValidRDServers = @() - $StaleRDServers = @() if (-not $RDServers) { # Create RD Session Deployment New-RDSessionDeployment -ConnectionBroker $ConnectionBroker -SessionHost $SystemName -ErrorAction Stop Write-Verbose "Created the RD Session Deployment!" } - else - { - Write-Verbose "RD Session Deployment already exists; evaluating RDServers:" - $RDServers.Server | % { Write-Verbose " $_" } - - # Cleanup non-responsive RD Servers - ForEach ($RDServer in $RDServers) - { - Write-Verbose ("Testing connectivity to host: {0}" -f $RDServer.Server) - try - { - $null = Invoke-RetryCommand -Command Test-NetConnection -ArgList @{ComputerName=$RDServer.Server; CommonTCPPort="RDP"} -CheckExpression '$? -and $Return.Result.TcpTestSucceeded' -Tries 7 - $ValidRDServers += $RDServer.Server - Write-Verbose "Successfully connected to host, $($RDServer.Server), keeping this RD Server" - } - catch - { - $StaleRDServers += $RDServer.Server - Write-Verbose ("RDServer is not available, marked as stale: {0}" -f $RDServer.Server) - if ($RDServer.Server -in (Get-RDSessionHost -CollectionName $CollectionName -ConnectionBroker $ConnectionBroker -ErrorAction SilentlyContinue).SessionHost) - { - Write-Verbose "Removing RD Session Host, $($RDServer.Server), from the collection..." - Remove-RDSessionHost -SessionHost $RDServer.Server -ConnectionBroker $ConnectionBroker -Force - } - - $Role = "RDS-RD-SERVER" - if ($Role -in @(Get-RDServer -ConnectionBroker $ConnectionBroker | Where { $_.Server -eq $RDServer.Server }).Roles) - { - Write-Verbose "Removing ${Role} role from $($RDServer.Server)..." - Remove-RDServer -Role $Role -Server $RDServer.Server -ConnectionBroker $ConnectionBroker -Force - } - } - } - } - - if ($ValidRDServers) - { - Write-Verbose "Marked VALID RDServers:" - $ValidRDServers | % { Write-Verbose " $_" } - } - - if ($StaleRDServers) - { - Write-Verbose "Marked STALE RDServers:" - $StaleRDServers | % { Write-Verbose " $_" } - } - $CurrentRoles = @(Get-RDServer -ConnectionBroker $ConnectionBroker | Where { $_.Server -eq $SystemName }) + $CurrentRoles = @(Get-RDServer -ConnectionBroker $ConnectionBroker | Where-Object { $_.Server -eq $SystemName }) foreach ($Role in $RequiredRoles) { if (-not ($Role -in $CurrentRoles.Roles)) { Invoke-RetryCommand -Command Add-RDServer -ArgList @{Server=$SystemName; Role=$Role; ConnectionBroker=$ConnectionBroker} - $ValidRDServers += $SystemName.ToUpper() Write-Verbose "Configured system with role, ${Role}" } } @@ -234,8 +185,8 @@ try { Invoke-RetryCommand -Command Add-RDSessionHost -ArgList @{CollectionName=$CollectionName; SessionHost=$SystemName; ConnectionBroker=$ConnectionBroker} -CheckExpression '$?' Write-Verbose "Added system to RD Session Collection" - Write-Verbose " SessionHost=${SystemName}" - Write-Verbose " CollectionName=${CollectionName}" + Write-Verbose "* SessionHost=${SystemName}" + Write-Verbose "* CollectionName=${CollectionName}" } # Disable new sessions until reboot @@ -247,78 +198,15 @@ try Write-Verbose "Current ACL on ${UpdPath}:" Write-Verbose ($UpdAcl.Access | Out-String) - # Get a list of server names from the computer objects in the ACL - $UpdAclServers = @($UpdAcl.Access.IdentityReference.Value | % { - if ($_ -match "(?i)^${DomainNetBiosName}\\(.*)[$]$") - { - [System.Net.DNS]::GetHostEntry($Matches[1]).HostName.ToUpper() - } - }) - - Write-Verbose "Current servers in ACL:" - $UpdAclServers | % { Write-Verbose " $_" } - - # Update the ACL only if the current ACL contains invalid/stale RD Servers - # Note: The Connection Broker *is* a valid RD Server, but should not be in - # the ACL, so we remove it from the list to compare - $ExpectedAclServers = @($ValidRDServers | ? { $_ -ne $ConnectionBroker.ToUpper() }) - Write-Verbose "Expected servers in ACL:" - $ExpectedAclServers | % { Write-Verbose " $_" } - - if (Compare-Object $UpdAclServers $ExpectedAclServers) + # Ensure this host is in the UPD share ACL + $Identities = ($UpdAcl.Access | Select-Object IdentityReference).IdentityReference.Value + $Identity = "${DomainNetBiosName}\$((Get-WmiObject Win32_ComputerSystem).Name)$" + if (-not ($Identity -in $Identities)) { - Write-Verbose "Evaluating ACLs on User Profile Share: $UpdPath" - foreach ($Rule in $UpdAcl.Access) - { - # Test if the rule is a computer object - if ($Rule.IdentityReference.Value -match "(?i)^${DomainNetBiosName}\\(.*)[$]$") - { - # Check previously marked servers - $Server = [System.Net.DNS]::GetHostEntry("$($Matches[1])").HostName - if ($Server -in $ValidRDServers) - { - Write-Verbose "Host previously marked VALID, keeping rule" - Write-Verbose " Host: $Server" - Write-Verbose (" Rule Identity: {0}" -f $Rule.IdentityReference.Value) - } - elseif ($Server -in $StaleRDServers) - { - $UpdAcl.RemoveAccessRule($Rule) - Write-Verbose "Host previously marked STALE, removed rule:" - Write-Verbose " Host: $Server" - Write-Verbose (" Rule Identity: {0}" -f $Rule.IdentityReference.Value) - } - else - { - # Host is in ACL, but was not an RD Server; test connectivity and remove the rule if the host is not responding - try - { - $null = Invoke-RetryCommand -Command Test-NetConnection -ArgList @{ComputerName=$Server; CommonTCPPort="RDP"} -CheckExpression '$? -and $Return.Result.TcpTestSucceeded' -Tries 1 - Write-Verbose "Successfully connected to host, keeping this access rule" - Write-Verbose " Host: $Server" - Write-Verbose (" Rule Identity: {0}" -f $Rule.IdentityReference.Value) - } - catch - { - $UpdAcl.RemoveAccessRule($Rule) - Write-Verbose "Host is non-responsive, removed rule:" - Write-Verbose " Host: $Server" - Write-Verbose (" Rule Identity: {0}" -f $Rule.IdentityReference.Value) - } - } - } - } - - # Ensure this host is in the UPD share ACL - $Identities = ($UpdAcl.Access | Select IdentityReference).IdentityReference.Value - $Identity = "${DomainNetBiosName}\$((Get-WmiObject Win32_ComputerSystem).Name)$" - if (-not ($Identity -in $Identities)) - { - Write-Verbose "Adding missing access rule for this host to UPD share." - Write-Verbose " Rule Identity: $Identity" - $Rule = New-Object System.Security.AccessControl.FileSystemAccessRule("${Identity}", "FullControl", "ContainerInherit, ObjectInherit", "None", "Allow") - $updAcl.AddAccessRule($Rule) - } + Write-Verbose "Adding missing access rule for this host to UPD share." + Write-Verbose "* Rule Identity: $Identity" + $Rule = New-Object System.Security.AccessControl.FileSystemAccessRule("${Identity}", "FullControl", "ContainerInherit, ObjectInherit", "None", "Allow") + $updAcl.AddAccessRule($Rule) # Write the new ACL Write-Verbose "Setting updated ACL on ${UpdPath}:" From dfffbec1f0d39cbb0d76a62725e15951bf057618 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Fri, 30 Aug 2019 17:06:41 -0700 Subject: [PATCH 25/25] Bumps version to 0.4.0 --- .bumpversion.cfg | 2 +- templates/db_mssql_alwayson.template.cfn.json | 2 +- templates/db_rds_mysql_audit_plugin.element.template.cfn.json | 2 +- templates/ds_ad_primary_dc.element.template.cfn.json | 2 +- templates/ds_ad_private_hosted_zone.element.template.cfn.json | 2 +- templates/ds_ad_replica_dc.element.template.cfn.json | 2 +- templates/ds_ad_security_groups.element.template.cfn.json | 2 +- templates/ds_dhcp_options.element.template.cfn.json | 2 +- templates/ds_singleaz_ad.compound.template.cfn.json | 2 +- templates/es_service_domain.element.template.cfn.json | 2 +- templates/nw_create_peer_role.element.template.cfn.json | 2 +- .../nw_dualaz_multitier_nat_with_eni.compound.template.cfn.json | 2 +- .../nw_dualaz_multitier_natgateway.compound.template.cfn.json | 2 +- templates/nw_nat_gateway.element.template.cfn.json | 2 +- templates/nw_nat_with_eni.element.template.cfn.json | 2 +- templates/nw_peered_sg.element.template.cfn.json | 2 +- templates/nw_private_subnet.element.template.cfn.json | 2 +- templates/nw_public_subnet.element.template.cfn.json | 2 +- templates/nw_r53_peered_domain.element.template.cfn.json | 2 +- ...w_singleaz_multitier_nat_with_eni.compound.template.cfn.json | 2 +- .../nw_singleaz_multitier_natgateway.compound.template.cfn.json | 2 +- ...w_tripleaz_multitier_nat_with_eni.compound.template.cfn.json | 2 +- .../nw_tripleaz_multitier_natgateway.compound.template.cfn.json | 2 +- templates/nw_vpc_peering_connection.element.template.cfn.json | 2 +- templates/nw_vpc_with_igw.element.template.cfn.json | 2 +- templates/ra_guac_autoscale_public_alb.template.cfn.yaml | 2 +- templates/ra_rdcb_fileserver_ha.template.cfn.json | 2 +- templates/ra_rdcb_fileserver_standalone.template.cfn.yaml | 2 +- templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml | 2 +- templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6f1ec36b..60c7dff3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.3.6 +current_version = 0.4.0 commit = True message = Bumps version to {new_version} tag = False diff --git a/templates/db_mssql_alwayson.template.cfn.json b/templates/db_mssql_alwayson.template.cfn.json index b2a809f7..e955f56a 100644 --- a/templates/db_mssql_alwayson.template.cfn.json +++ b/templates/db_mssql_alwayson.template.cfn.json @@ -298,7 +298,7 @@ } } }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "MssqlNode1InstanceId": { diff --git a/templates/db_rds_mysql_audit_plugin.element.template.cfn.json b/templates/db_rds_mysql_audit_plugin.element.template.cfn.json index 9f79e55b..29430e67 100644 --- a/templates/db_rds_mysql_audit_plugin.element.template.cfn.json +++ b/templates/db_rds_mysql_audit_plugin.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This template deploys a MySQL RDS instance", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "JDBCConnectionString": { diff --git a/templates/ds_ad_primary_dc.element.template.cfn.json b/templates/ds_ad_primary_dc.element.template.cfn.json index 117c1c88..f3f17e1d 100644 --- a/templates/ds_ad_primary_dc.element.template.cfn.json +++ b/templates/ds_ad_primary_dc.element.template.cfn.json @@ -56,7 +56,7 @@ } }, "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "DomainAdmin": { diff --git a/templates/ds_ad_private_hosted_zone.element.template.cfn.json b/templates/ds_ad_private_hosted_zone.element.template.cfn.json index 144555b1..2507d2a9 100644 --- a/templates/ds_ad_private_hosted_zone.element.template.cfn.json +++ b/templates/ds_ad_private_hosted_zone.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a Route53 private hosted zone, to resolve the domain to the AD Domain Controllers via DHCP.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "HostedZoneId": { diff --git a/templates/ds_ad_replica_dc.element.template.cfn.json b/templates/ds_ad_replica_dc.element.template.cfn.json index 377c4243..818f2058 100644 --- a/templates/ds_ad_replica_dc.element.template.cfn.json +++ b/templates/ds_ad_replica_dc.element.template.cfn.json @@ -56,7 +56,7 @@ } }, "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "DomainControllerID": { diff --git a/templates/ds_ad_security_groups.element.template.cfn.json b/templates/ds_ad_security_groups.element.template.cfn.json index 680f6ac4..27546a03 100644 --- a/templates/ds_ad_security_groups.element.template.cfn.json +++ b/templates/ds_ad_security_groups.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates 2 security groups for an Active Directory domain -- one for Domain Controllers and one for Domain Members.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "DomainControllerSGID": { diff --git a/templates/ds_dhcp_options.element.template.cfn.json b/templates/ds_dhcp_options.element.template.cfn.json index ce3db368..2c29c7ff 100644 --- a/templates/ds_dhcp_options.element.template.cfn.json +++ b/templates/ds_dhcp_options.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates an Active Directory domain with a single domain controller. The default Domain Administrator password will be the one retrieved from the instance.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Parameters": { "DomainControllerIPs": { diff --git a/templates/ds_singleaz_ad.compound.template.cfn.json b/templates/ds_singleaz_ad.compound.template.cfn.json index bf3f195b..0c080a1e 100644 --- a/templates/ds_singleaz_ad.compound.template.cfn.json +++ b/templates/ds_singleaz_ad.compound.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This template creates an Active Directory infrastructure in a Single AZ.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "DomainAdmin": { diff --git a/templates/es_service_domain.element.template.cfn.json b/templates/es_service_domain.element.template.cfn.json index be8805ea..d783e072 100644 --- a/templates/es_service_domain.element.template.cfn.json +++ b/templates/es_service_domain.element.template.cfn.json @@ -39,7 +39,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "DedicatedMasterCount": { diff --git a/templates/nw_create_peer_role.element.template.cfn.json b/templates/nw_create_peer_role.element.template.cfn.json index 2c096812..52d74187 100644 --- a/templates/nw_create_peer_role.element.template.cfn.json +++ b/templates/nw_create_peer_role.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This template creates an assumable role for cross account VPC peering.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "RoleARN": { diff --git a/templates/nw_dualaz_multitier_nat_with_eni.compound.template.cfn.json b/templates/nw_dualaz_multitier_nat_with_eni.compound.template.cfn.json index deafe531..5ef9b39b 100644 --- a/templates/nw_dualaz_multitier_nat_with_eni.compound.template.cfn.json +++ b/templates/nw_dualaz_multitier_nat_with_eni.compound.template.cfn.json @@ -104,7 +104,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_dualaz_multitier_natgateway.compound.template.cfn.json b/templates/nw_dualaz_multitier_natgateway.compound.template.cfn.json index dd20ad85..245845a9 100644 --- a/templates/nw_dualaz_multitier_natgateway.compound.template.cfn.json +++ b/templates/nw_dualaz_multitier_natgateway.compound.template.cfn.json @@ -94,7 +94,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_nat_gateway.element.template.cfn.json b/templates/nw_nat_gateway.element.template.cfn.json index 802b0aed..f45996d9 100644 --- a/templates/nw_nat_gateway.element.template.cfn.json +++ b/templates/nw_nat_gateway.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a NAT Gateway with an Elastic IP, Private route table with route to the NAT Gateway.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "NATGatewayElasticIP": { diff --git a/templates/nw_nat_with_eni.element.template.cfn.json b/templates/nw_nat_with_eni.element.template.cfn.json index d62293f4..28c61f0a 100644 --- a/templates/nw_nat_with_eni.element.template.cfn.json +++ b/templates/nw_nat_with_eni.element.template.cfn.json @@ -56,7 +56,7 @@ } }, "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "NATElasticNetworkInterfaceId": { diff --git a/templates/nw_peered_sg.element.template.cfn.json b/templates/nw_peered_sg.element.template.cfn.json index c4b020f6..b9848242 100644 --- a/templates/nw_peered_sg.element.template.cfn.json +++ b/templates/nw_peered_sg.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a Security Group to allow remote access from instances in the specified security group within the peered account.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "VpcPeerSecurityGroupId": { diff --git a/templates/nw_private_subnet.element.template.cfn.json b/templates/nw_private_subnet.element.template.cfn.json index 89af119f..394436f2 100644 --- a/templates/nw_private_subnet.element.template.cfn.json +++ b/templates/nw_private_subnet.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a Private Subnet and associates it with a given Route Table.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "AvailabilityZoneName": { diff --git a/templates/nw_public_subnet.element.template.cfn.json b/templates/nw_public_subnet.element.template.cfn.json index 4dbfc2a6..258f09eb 100644 --- a/templates/nw_public_subnet.element.template.cfn.json +++ b/templates/nw_public_subnet.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a Public Subnet and associates it with a given Route Table.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "AvailabilityZoneName": { diff --git a/templates/nw_r53_peered_domain.element.template.cfn.json b/templates/nw_r53_peered_domain.element.template.cfn.json index 05a5b4f9..beca31fa 100644 --- a/templates/nw_r53_peered_domain.element.template.cfn.json +++ b/templates/nw_r53_peered_domain.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a Route53 Private Hosted Zone and the associated resource records for a peered domain.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "PrivateHostedZoneId": { diff --git a/templates/nw_singleaz_multitier_nat_with_eni.compound.template.cfn.json b/templates/nw_singleaz_multitier_nat_with_eni.compound.template.cfn.json index 4b3f3ec1..c45403b1 100644 --- a/templates/nw_singleaz_multitier_nat_with_eni.compound.template.cfn.json +++ b/templates/nw_singleaz_multitier_nat_with_eni.compound.template.cfn.json @@ -101,7 +101,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_singleaz_multitier_natgateway.compound.template.cfn.json b/templates/nw_singleaz_multitier_natgateway.compound.template.cfn.json index eec80d18..f8412973 100644 --- a/templates/nw_singleaz_multitier_natgateway.compound.template.cfn.json +++ b/templates/nw_singleaz_multitier_natgateway.compound.template.cfn.json @@ -92,7 +92,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_tripleaz_multitier_nat_with_eni.compound.template.cfn.json b/templates/nw_tripleaz_multitier_nat_with_eni.compound.template.cfn.json index 67e8ecfe..1580b853 100644 --- a/templates/nw_tripleaz_multitier_nat_with_eni.compound.template.cfn.json +++ b/templates/nw_tripleaz_multitier_nat_with_eni.compound.template.cfn.json @@ -108,7 +108,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_tripleaz_multitier_natgateway.compound.template.cfn.json b/templates/nw_tripleaz_multitier_natgateway.compound.template.cfn.json index 9925493b..f0cf883d 100644 --- a/templates/nw_tripleaz_multitier_natgateway.compound.template.cfn.json +++ b/templates/nw_tripleaz_multitier_natgateway.compound.template.cfn.json @@ -96,7 +96,7 @@ } ] }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/nw_vpc_peering_connection.element.template.cfn.json b/templates/nw_vpc_peering_connection.element.template.cfn.json index a0e3ecda..bc0b53d6 100644 --- a/templates/nw_vpc_peering_connection.element.template.cfn.json +++ b/templates/nw_vpc_peering_connection.element.template.cfn.json @@ -52,7 +52,7 @@ }, "Description": "This element creates a VPC peering connection and adds the necessary route to specified route tables.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "VpcPeeringConnection": { diff --git a/templates/nw_vpc_with_igw.element.template.cfn.json b/templates/nw_vpc_with_igw.element.template.cfn.json index 1f1fa996..8e6ec30e 100644 --- a/templates/nw_vpc_with_igw.element.template.cfn.json +++ b/templates/nw_vpc_with_igw.element.template.cfn.json @@ -2,7 +2,7 @@ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This element creates a VPC network with an Internet Gateway.", "Metadata": { - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "InternetGatewayId": { diff --git a/templates/ra_guac_autoscale_public_alb.template.cfn.yaml b/templates/ra_guac_autoscale_public_alb.template.cfn.yaml index 2ca274f2..79d5ca1b 100644 --- a/templates/ra_guac_autoscale_public_alb.template.cfn.yaml +++ b/templates/ra_guac_autoscale_public_alb.template.cfn.yaml @@ -58,7 +58,7 @@ Mappings: Parameters: Location: 's3://app-chemistry/snippets/instance_type_map.snippet.cfn.yaml' Metadata: - Version: 0.3.6 + Version: 0.4.0 cfn-lint: config: ignore_checks: diff --git a/templates/ra_rdcb_fileserver_ha.template.cfn.json b/templates/ra_rdcb_fileserver_ha.template.cfn.json index 17ba4177..1305412f 100644 --- a/templates/ra_rdcb_fileserver_ha.template.cfn.json +++ b/templates/ra_rdcb_fileserver_ha.template.cfn.json @@ -207,7 +207,7 @@ } } }, - "Version": "0.3.6" + "Version": "0.4.0" }, "Outputs": { "RdcbEc2InstanceId": { diff --git a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml index 33095ec3..d4e7b5a5 100644 --- a/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml +++ b/templates/ra_rdcb_fileserver_standalone.template.cfn.yaml @@ -82,7 +82,7 @@ Metadata: ParameterLabels: AmiNameSearchString: default: AMI Name Search Pattern - Version: 0.3.6 + Version: 0.4.0 cfn-lint: config: ignore_checks: diff --git a/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml b/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml index 9bd837a7..f3085247 100644 --- a/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml +++ b/templates/ra_rdgw_autoscale_public_lb.template.cfn.yaml @@ -90,7 +90,7 @@ Metadata: default: AMI Name Search Pattern ScaleDownDesiredCapacity: default: Scale Down Desired Capacity - Version: 0.3.6 + Version: 0.4.0 cfn-lint: config: ignore_checks: diff --git a/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml b/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml index 05af28aa..f47211a4 100644 --- a/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml +++ b/templates/ra_rdsh_autoscale_internal_lb.template.cfn.yaml @@ -89,7 +89,7 @@ Metadata: default: AMI Name Search Pattern ScaleDownDesiredCapacity: default: Scale Down Desired Capacity - Version: 0.3.6 + Version: 0.4.0 cfn-lint: config: ignore_checks: