Powershell - Find instances without a tag associated - amazon-web-services

I have spent a long time on this getting nowhere and cannot find an answer on the web.
I am looking for a PowerShell script that will return EC2 Instances without tag called 'backup' associated with it.
Each Backup tag has a value but right now I am just looking for instances which do not have the tag. Any help would be greatly appreciated.
Thanks

This returns the EC2 Instance objects without a tag named Backup in a specific region:
Import-Module AWSPowershell
$instances = (Get-EC2Instance -Region $region -Credential $cred).Instances
$EC2Tags = Get-EC2Tag -Region $region -Credential $cred |
Where {$_.Key -eq 'Backup' -and $_.ResourceType -EQ 'Instance'}
$instances | Where {$_.InstanceID -NotIn $EC2Tags.ResourceID}

Related

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

Rename ec2 hostname using userdata does not work

I am trying to rename the hostname to a specific one - TEAM-CNTNR using the user-data script but after the EC2 instance comes up online and I connect to it (via Session Manager), the hostname is the random one that EC2 service gives the instance such as EC2AMAZ-VHAGRNV.
This is my user-data script, am I missing something? This is my user-data script:
<powershell>
Import-Module ECSTools
[Environment]::SetEnvironmentVariable("ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE", $TRUE, "Machine")
Initialize-ECSAgent -Cluster "${cluster_name}" -EnableTaskIAMRole -LoggingDrivers '["json-file","awslogs"]' -EnableTaskENI
# rename the instance hostname so that it works with the gMSA account
Rename-Computer -NewName "TEAM-CNTNR" -Force
## instance-domain-join code here. Omitted for brevity
# Perform the domain join
Add-Computer -DomainName "$domain_name.$domain_tld" -OUPath "OU=Computers,OU=enrcloud,DC=enr,DC=cloud" -ComputerName "$hostname" -Credential $credential -Passthru -Verbose -Restart
</powershell>
<runAsLocalSystem>true</runAsLocalSystem>
It was revealed to me that there is a NewName parameter that can be used that is part of the Add-Computer command that would:
join the machine to the new domain
and change its name at the same time
Add-Computer ... -NewName "MyComputer" ...
Reference: Microsoft site

Download Last 24 hour files from s3 using Powershell

I have an s3 bucket with different filenames. I need to download specific files (filenames that starts with impression) that are created or modified in last 24 hours from s3 bucket to local folder using powershell?
$items = Get-S3Object -BucketName $sourceBucket -ProfileName $profile -Region 'us-east-1' | Sort-Object LastModified -Descending | Select-Object -First 1 | select Key Write-Host "$($items.Length) objects to copy" $index = 1 $items | % { Write-Host "$index/$($items.Length): $($_.Key)" $fileName = $Folder + ".\$($_.Key.Replace('/','\'))" Write-Host "$fileName" Read-S3Object -BucketName $sourceBucket -Key $_.Key -File $fileName -ProfileName $profile -Region 'us-east-1' > $null $index += 1 }
A workaround might be to turn on access log, and since the access log will contain timestamp, you can get all access logs in the past 24 hours, de-duplicate repeated S3 objects, then download them all.
You can enable S3 access log in the bucket settings, the logs will be stored in another bucket.
If you end up writing a script for this, just bear in mind downloading the S3 objects will essentially create new access logs, making the operation irreversible.
If you want something fancy perhaps you can even query the logs and perhaps deduplicate using AWS Athena.

Scheduling a Powershell script to run weekly in AWS

So, I've got the following powershell script to find inactive AD users and disable their accounts, creating a log file containing a list of what accounts have been disabled:
Import-Module ActiveDirectory
# Set the number of days since last logon
$DaysInactive = 60
$InactiveDate = (Get-Date).Adddays(-($DaysInactive))
# Get AD Users that haven't logged on in xx days
$Users = Get-ADUser -Filter { LastLogonDate -lt $InactiveDate -and Enabled -eq $true } -
Properties LastLogonDate | Select-Object #{ Name="Username"; Expression=.
{$_.SamAccountName} }, Name, LastLogonDate, DistinguishedName
# Export results to CSV
$Users | Export-Csv C:\Temp\InactiveUsers.csv -NoTypeInformation
# Disable Inactive Users
ForEach ($Item in $Users){
$DistName = $Item.DistinguishedName
Disable-ADAccount -Identity $DistName
Get-ADUser -Filter { DistinguishedName -eq $DistName } | Select-Object #{ Name="Username"; Expression={$_.SamAccountName} }, Name, Enabled
}
The script works and is doing everything it should. What I am trying to figure out is how to automate this in an AWS environment.
I'm guessing I need to use a Lambda function in AWS to trigger this script to run on a schedule but don't know where to start.
Any help greatly appreciated.
I recomment to create a Lambda function with dotnet environment: https://docs.aws.amazon.com/lambda/latest/dg/lambda-powershell.html
Use a CloudWatch Event on a Scheduled basis to trigger the function:
https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/RunLambdaSchedule.html
An alternative, if you like to to have a more pipeline style execution you could use CodePipeline and CodeBuild to run the script. Use again CloudWatch to trigger the CodePipeline on a scheduled basis!

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>