Unable to register targets on AWS Target group - amazon-web-services

I am trying to setup an automated DNS deployment using powershell. I have written a powershell script that creates TargetGroup, registers instances to the TG, creates an ALB and adds a listener to it. Once, that is done, it creates R53 RecordSet and creates an A record to the ALB DNS.
I am having issues in having the instances registered to the TargetGroup.
This is my code snippet to that section:
$searchFor1 =#( #{name = 'tag:Name'; values = $target1})
$searchFor2 =#( #{name = 'tag:Name'; values = $target2})
$id1 = (Get-EC2Instance -Filter $searchFor1).Instances | select InstanceId
$id2 = (Get-EC2Instance -Filter $searchFor2).Instances | select InstanceId
# Create Target Group
$tg = New-ELB2TargetGroup -TargetType "instance" -HealthyThresholdCount 4 -Name $custname -Port $siteport -Protocol "HTTP" -UnhealthyThresholdCount 4 -VpcId $vpcid
Start-Sleep -s 120
$addid1 = New-Object Amazon.ElasticLoadBalancingV2.Model.TargetDescription
$addid2 = New-Object Amazon.ElasticLoadBalancingV2.Model.TargetDescription
$addid1.Id = $id1.InstanceId
$addid2.Id = $id2.InstanceId
$addid1.Port = $siteport
$addid2.Port = $siteport
$tgarn = (Get-ELB2TargetGroup -Name $custname).TargetGroupArn
Register-ELB2Target -TargetGroupArn $tgarn -Target #($addid1)
Register-ELB2Target -TargetGroupArn $tgarn -Target #($addid2)
It throws below error:
Register-ELB2Target : An instance ID must be specified
At C:\scripts\Distinct-DNS-Deployment.ps1:107 char:1
+ Register-ELB2Target -TargetGroupArn $tgarn -Target #($addid1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Amazon.PowerShe...LB2TargetCmdlet:RegisterELB2TargetCmdlet) [Register
-ELB2Target], InvalidOperationException
+ FullyQualifiedErrorId : Amazon.ElasticLoadBalancingV2.AmazonElasticLoadBalancingV2Exception,Amazon.PowerShell.Cm
dlets.ELB2.RegisterELB2TargetCmdlet
I have checked a similar post here. And the corresponding posts, so far nothing helped. I am wondering if anyone can guide me what am I doing wrong?
I have tried to run each line one by one and that happens to register the instance to the TargetGroup, just the script fails.
Instances are t2.micro and they are in running state.

As per the https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/ElasticLoadBalancingV2/TTargetDescription.html -
the Amazon.ElasticLoadBalancingV2.Model.TargetDescription is about 'Information about a target' -
which means, you should be assigning a single instance id Also, if you take a close look at the properties:
AvailabilityZone System.String
Id System.String
Port System.Int32
The result of your instance search may or may not be single output - you should keep them in loop to create each target via TargetDescription
$Instances = (Get-EC2Instance -Filter #{Name="tag:auto-delete";Value="no"}).instances |select instanceid
$theVpc = get-ec2vpc -VpcId vpc-4565e5c4
$name = "new-tg"
$port = "80"
$protocol = "HTTP"
$tg = New-ELB2TargetGroup -TargetType "instance" -HealthyThresholdCount 4 -Name $name -Port $port -Protocol "HTTP" -UnhealthyThresholdCount 4 -VpcId $theVpc.VpcId
$tgarn = (Get-ELB2TargetGroup -Name $name).TargetGroupArn
If($instances -ne $null){
foreach ($instance in $instances ){
$addid1 = New-Object Amazon.ElasticLoadBalancingV2.Model.TargetDescription
$addid1.Id = $Instance.instanceid
$addid1.Port = $port
Register-ELB2Target -TargetGroupArn $tgarn -Target #($addid1)
Remove-Variable addid1
}
}
else {
echo "There were no instances with the matching filter"
}

Related

powercli site recovery manager: determine which protection group an unprotected VM will be in. SRM uses array based replication

I use automation to deply VM's to various vcenter clusters.
I then confgiure SRM network mapping to create a network map between the cluster that the VM is in and the cluster which is used for DR purposes, in the protection group for those two clusters.
SRM is set up for array based replication, so as long as the VM is placed on replicated storage in the right cluster it will appear in SRM under the protection group, if a network mapping is in place then the VM will be auto protected by SRM or via my SRM config script.
I currently have the primary cluster, DR cluster and protection group hard coded, but would like to determine the protection group a VM is in and the name of the two clusters which the protection group is set up for, that way any changes to cluster configuration is automatically picked up and doesn't require manual changes to the SRM config script.
I've looked in the SRM API docs but it's not something I have worked out yet!
I have solved the issue:
$credential = Get-Credential
$server_name = "test-server"
Connect-VIServer -Server $primaryDC -Credential $credential
$srmConnection = Connect-SrmServer -Credential $credential -RemoteCredential $credential
Connect-VIServer -Server $secondaryDC -Credential $credential
$srmApi = $srmConnection.ExtensionData
$protectionGroups = $srmApi.Protection.ListProtectionGroups()
foreach ($protectionGroup in $protectionGroups){
$associatedVms = $protectionGroup.ListProtectedDatastores() | Get-VIObjectByVIView | Get-VM | Where-Object {($_.name -eq $server_name) -and($_.ExtensionData.Config.ManagedBy.ExtensionKey -ne 'com.vmware.vcDr' )}
foreach ($vm in $associatedVms) {
if ($vm.Name -eq $server_name) {
$protection_group_name = $protectionGroup.GetInfo().Name
$primary_cluster = get-vm -name $server_name | get-cluster
$primary_cluster_res_group = $primary_cluster.ExtensionData.ResourcePool
$srm_resource_groups = $srmApi.inventoryMapping.getResourcePoolMappings()
foreach ($resource_group in $srm_resource_groups){
if ($resource_group.PrimaryObject -eq $primary_cluster_res_group){
$secondary_res_group = $resource_group.SecondaryObject
}
}
}
}
}
$secondary_cluster = Get-Cluster | Where-Object {$_.ExtensionData.ResourcePool -eq $secondary_res_group}
Write-Host "VM: $vm - Protection Group: $protection_group_name - Primary cluster: $primary_cluster - Secondary cluster: $secondary_cluster - Primary ResGrp: $primary_cluster_res_group - Secondary ResGrp: $secondary_res_group"

infinite loop for checking aws instance status in ec2 targetgroup while draining

I am trying to capture the status of an ec2 instance which is part of a target group. I try to de-register the instance and then inside a do until look I constantly check for the status of the instance when it migrates from draining to unused and then exit out of the loop at that point. I am unable to figure out why it is getting into an infinite loop even though I constantly check for the status. Here is the power-shell snippet I am using
$instance_id = "i-ec2ID"
$targetGroupArn = "arn:aws:elasticloadbalancing:region:accountID:targetgroup/tg-name/guid12345"
aws elbv2 deregister-targets --target-group-arn $targetGroupArn --targets Id=$instance_id
Do {
$instance_status = aws elbv2 describe-target-health --target-group-arn $targetGroupArn --query "TargetHealthDescriptions[].{Id:Target.Id,Health:TargetHealth.State}" --output text|Select-String -Pattern $instance_id
$a = $instance_status.ToString()
$instance_state = $a.Substring(0, $a.Length - 20)
echo "Instance is still: "$instance_state
Start-Sleep -s 10
}
Until ($instance_state -match "unused")
Any suggestion on how to overcome this issue or any better suggestion to achieve what I am trying to do is welcome
I figured out the issue and was able to resolve it by putting an if-else block inside the do until loop which will basically evaluate the status if it is null and exit out of the loop gracefully
Do {
$instance_status = aws elbv2 describe-target-health --target-group-arn $targetGroupArn --query "TargetHealthDescriptions[].{Id:Target.Id,Health:TargetHealth.State}" --output text|Select-String -Pattern $instance_id
if($instance_status -eq $null) {
$instance_state = $null
}
else{
$a = $instance_status.ToString()
$instance_state = $a.Substring(0, $a.Length - 20)
echo "Instance is still: "$instance_state
Start-Sleep -s 10
}
}
Until ($instance_state -eq $null)
Hopefully this helps someone

Using Powershell to Report AWS Security Groups

I am new to powershell and the AWS CLI and have look and looked for someone else who has posted this...
What I'm trying to do is get the code right to create a report of each AWS Security Group that shows the inbound rules.
Something like this I would image the output would be.
SecurityGroupName GroupID, Type, Protcol, PortRange, Source, Description
SSH & HTTP gs-1111 SSH TCP 22 0.0.0.0/0 Inbound SSH & HTTP
SSH & HTTP gs-1111 HTTP TCP 80 1.2.34 Inbound SSH & HTTP
HTTPS gs-2222 HTTPS TCP 443 0.0.0.0/0
'
But I can't figure it out.
I can use $GroupID=Get-EC2SecurityGroup -Region us-east-1 |Select-Object -ExpandProperty GroupID
ForEach ($item in $GroupID) {
(Get-EC2SecurityGroup -Region us-east-1 -GroupId $item).IpPermissions | Select-Object IPProtocol,IpRange, FromPort,ToPort}
to get the basic rule but can't seem to combine all the properties you need. This is where my lack of powershell really hurts. Any help would be great!
First, you need to create a new Powershell array that will hold all the objects.
Later, run over all the security groups in the specific region and add relevant data to the hash-table object.
Then, just add the object to the array we created earlier.
Code snippet:
$region = 'YOUR_REGION'
$allSG = #()
Get-EC2SecurityGroup -Region $region | % {
$obj = #{
Description = $_.IpPermission.Ipv4Ranges.Description
GroupId = $_.GroupId
SecurityGroupName = $_.GroupName
Source = $_.IpPermission.Ipv4Ranges.CidrIp
FromPort = $_.IpPermission.FromPort
ToPort = $_.IpPermission.ToPort
Protocol = $_.IpPermission.IpProtocol
}
$object = new-object psobject -Property $obj
$allSG += $object
}
Output:
Insights:
Some Descriptions might be missing.
The From/To Port represent the Type (e.g - 80 = HTTP, 443 = HTTPS)
More about Get-EC2SecurityGroup.

EC2 User data - Disable it after all conditions are met in user data

I'm trying to rename hostname and add to AD of a spot instance. It is a simple powershell script. I've read the docs that by default user data will be disable after it gets executed once and if <persist>true</persist> is used it will not be disabled.
I think I saw somewhere this(enabling to be run at each startup) is done via taskscheduler but can't find the link.
Can someone point me to the task scheduler job or the way to manually disable the userdata once my if conditions are met.
<powershell>
Set-ExecutionPolicy unrestricted -Force
$instanceName = "test-name5"
$username = "domain\username"
$password = "password" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential($username, $password)
Start-Sleep -s 5
$hostname = hostname
$domain = (Get-WmiObject win32_computersystem).Domain
if (!($hostname -eq $instanceName)){
Rename-Computer -NewName $instanceName -restart -force
}Elseif (!($domain -eq 'my.domain.local')){
Start-Sleep -s 5
Add-Computer -DomainName my.domain.local -OUPath "OU=Windows,OU=QAServers,OU=Servers,DC=my,DC=domain,DC=local" -Credential $cred -Force -Restart -erroraction 'stop'
}Else {
####code to disable the running of userdata once above conditions
are met####
}
</powershell>
<persist>true</persist>
It's worth reading the ec2config-service documentation, as the setting you want is referenced in there.
You want the Ec2HandleUserData setting, which is configured in the Config.xml.
Powershell can easily update this setting:
$path = 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml'
$xml = [xml](Get-Content $path)
$state = $xml.Ec2ConfigurationSettings.Plugins.Plugin | where {$_.Name -eq 'Ec2HandleUserData'}
$state.State = 'Disabled'
$xml.Save($path)
I use this code when creating custom AMI's to re-enable userdata handling ($state.State = 'Enabled').
EDIT: The above is for ec2config not ec2launch which is what the OP is using. I'd missed this originally.
I this case I think you need to change the way your script runs, rather than use <persist> and then try to disable its functionality, I would remove the persist tag and call InitializeInstance.ps1 –Schedule (documentation link) in your if for the conditions you want the userdata to re-run:
if ($hostname -ne $instanceName) {
& C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeInstance.ps1 -Schedule
Rename-Computer -NewName $instanceName -Restart -Force
}
elseif ($domain -ne 'my.domain.local') {
& C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeInstance.ps1 -Schedule
Add-Computer -DomainName aws.macmillan.local -OUPath "OU=Windows,OU=QAServers,OU=Servers,DC=my,DC=domain,DC=local" -Credential $cred -Force -Restart -ErrorAction 'stop'
}
As I said in the comments of the previous answer, I had 3 options and since I found the aws scheduled task I went with the last option. Answering my own question since it'll be easy to spot the code.
<powershell>
Set-ExecutionPolicy unrestricted -Force
#Enter instance hostname here
$instanceName = "test-name8"
$username = "domain\username"
#Using ssm parameter store to avoid having the password in plaintext
$password = (Get-SSMParameterValue -Name AD-Password -WithDecryption $True -Region us-east-1).Parameters[0].Value | ConvertTo-SecureString -asPlainText -Force
Start-Sleep -s 3
$cred = New-Object -typename System.Management.Automation.PSCredential($username, $password)
Start-Sleep -s 5
$hostname = hostname
$domain = (Get-WmiObject win32_computersystem).Domain
if ($hostname -ne $instanceName){
Rename-Computer -NewName $instanceName -restart -force
}Elseif ($domain -ne 'my.domain.local'){
Start-Sleep -s 5
Add-Computer -DomainName my.domain.local -OUPath "OU=Windows,OU=QAServers,OU=Servers,DC=my,DC=domain,DC=local" -Credential $cred -Force -Restart -erroraction 'stop'
}Else {
Disable-ScheduledTask -TaskName "Amazon Ec2 Launch - Userdata Execution"
Unregister-ScheduledTask -TaskName "Amazon Ec2 Launch - Userdata Execution"
}
</powershell>
<persist>true</persist>
note: a role that has ssm policies must be attached while launching the server for this ssm parameter command to work.
I was solving similar issue and I had to change Windows Server 2016 hostname and enroll it to Elastic Server Fleet. Also I could not allow instance to be rebooted. I used this code to solve this.
NB. I understand that it is not direct way of doing this and has numerous drawbacks, but in my circumstances goal was achieved without negative impact.
<powershell>
$ComputerName = "MyPCRandomName"
Set-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" -name "Hostname" -value $ComputerName
elastic-agent enroll --enrollment-token 123 --url=321
</powershell>

Why Am I Seeing These Errors in My SSRS Powershell Script in One Environment but Not Another?

I have a Powershell Script I'm working on for post-migration SSRS report administration tasks.
In this particular scenario we have a DEV environment (where I've been primarily testing) which hosts a single instance of SSRS, and a Prod environment which is a scaled out deployment across 4 nodes.
I'm new to Powershell (just discovered it 2 days ago...) and the script I have is pretty simple:
Clear-Host 
$Username = "domain\myUsername"
$Password = "myPassword"
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($Username,(ConvertTo-SecureString -String $Password -AsPlainText -Force))
# Dev Connection String
$webServiceUrl = 'http://DEVwebServer.domain.com/reportserver/reportservice2010.asmx?WSDL'
# Prod Connection String
# $webServiceUrl = 'http://PRODwebServerNode1.domain.com/reportserver/reportservice2010.asmx?WSDL'
$rs = New-WebServiceProxy -Uri $webServiceUrl -Credential $Cred
 
$reports = $rs.ListChildren("/Some Folder Under Root", $true) | Where-Object { $_.TypeName -eq "Report" }
$type = $ssrsProxy.GetType().Namespace;
$schedDefType = "{0}.ScheduleDefinition" -f $type;
$schedDef = New-Object ($schedDefType)
$warning = #();
foreach ($report in $reports) {
$sched = $rs.GetExecutionOptions($report.Path, [ref]$schedDef);
$snapShotExists = $rs.ListItemHistory($report.Path);
if($sched -eq "Snapshot") {
Write-Host "Following report is configured to run from Snapshot:" -ForegroundColor Yellow
Write-Host ("Report Name: {0}`nReport Path: {1}`nExecution Type: {2}`n" -f $report.Name, $report.Path, $sched)
if ($snapShotExists) {
Write-Host "Does Snapshot Exist..?`n" -ForegroundColor Yellow
Write-Host "Yes!`tNumber of Snapshots: " $snapShotExists.Count -ForegroundColor Green
$snapShotExists.CreationDate
Write-Host "`n------------------------------------------------------------"
}
elseif (!$snapShotExists) {
Write-Host "Does Snapshot Exist..?`n" -ForegroundColor Yellow
Write-Host ("No!`n") -ForegroundColor Red
Write-Host "Creating Snapshot.......`n" -ForegroundColor Yellow
$rs.CreateItemHistorySnapshot($report.Path, [ref]$warning);
Write-Host "Snapshot Created!`n" -ForegroundColor Green
$snapShotExists.CreationDate
Write-Host "`n------------------------------------------------------------"
}
}
}
The purpose of the script is simply to recursively iterate over all of the reports for the given folder in the $reports variable, check to see if the execution type is set to "Snapshot", if it is check to see if a "History Snapshot" exists, and if one does not exist, create one.
When I run this in Dev it works just fine, but when I run in PROD I get the following error repeated for each $report in my foreach loop:
Any ideas on why this would work in one and not the other and how to overcome this error?
I was able to get this working on the Prod instance by making some adjustments using this answer as a guide:
By updating my call to New-WebServiceProxy to add a Class and Namespace flag, I was able to update the script in the following ways:
...
# Add Class and Namespace flags to New-WebServiceProxy call
$rs = New-WebServiceProxy -Class 'RS' -Namespace 'RS' -Uri $webServiceUrl -Credential $Cred
 
$reports = $rs.ListChildren("/Business and Technology Solutions", $true) | Where-Object { $_.TypeName -eq "Report" }
# Declare new "ScheduleDefintion object using the Class declared in the New-WebServiceProxy call
$schedDef = New-Object RS.ScheduleDefinition
$warning = #();
foreach ($report in $reports) {
# Referencing the "Item" property from the ScheduleDefinition
$execType = $rs.GetExecutionOptions($report.Path, [ref]$schedDef.Item)
...
I don't think the adding of the Class and Namespace flags on the New-WebServiceProxy call was exactly what did it, as I think it's just a cleaner way to ensure you're getting the proper Namespace from the WebService. Maybe just a little sugar.
I think the key change was making sure to the "Item" property from the schedule definition object, although I'm not sure why it was working in Dev without doing so...