Windows EC2用户数据未执行



问题:

我们需要在Windows AWS EC2实例上使用Userdata执行Powershell脚本,以便我们可以加入和取消加入域的活动目录。EC2 Userdata日志显示实例卡在:

Ec2HandleUserData :  is currently executing. To end it kill the process with id:

我们已经尝试添加这里记录的代码行,但没有运气。有人能看出哪里做错了吗?注意,我们已经注释掉了日志记录,因为我们目前没有CloudWatch设置。我们使用的脚本如下,感谢您的帮助!

<powershell>
$file = $env:SystemRoot + "Temp" + (Get-Date).ToString("MM-dd-yy-hh-mm")
New-Item $file -ItemType file
# Script parameters
[string]$SecretAD = "prod/AD"
#class Logger {
#   #----------------------------------------------
#   [string] hidden  $cwlGroup
#   [string] hidden  $cwlStream
#   [string] hidden  $sequenceToken
#   #----------------------------------------------
#   # Log Initialization
#   #----------------------------------------------
#   Logger([string] $Action) {
#       $this.cwlGroup = "/ps/boot/configuration/"
#       $this.cwlStream = "{0}/{1}/{2}" -f $env:COMPUTERNAME, $Action,
#       (Get-Date -UFormat "%Y-%m-%d_%H.%M.%S")
#       $this.sequenceToken = ""
#       #------------------------------------------
#       if ( !(Get-CWLLogGroup -LogGroupNamePrefix $this.cwlGroup) ) {
#           New-CWLLogGroup -LogGroupName $this.cwlGroup
#           Write-CWLRetentionPolicy -LogGroupName $this.cwlGroup -RetentionInDays 3
#       }
#       if ( !(Get-CWLLogStream -LogGroupName $this.cwlGroup -LogStreamNamePrefix $this.cwlStream) ) {
#           New-CWLLogStream -LogGroupName $this.cwlGroup -LogStreamName $this.cwlStream
#       }
#   }
#   #----------------------------------------
#   [void] WriteLine([string] $msg) {
#       #$logEntry = New-Object -TypeName "Amazon.CloudWatchLogs.Model.InputLogEvent"
#       #-----------------------------------------------------------
#       #$logEntry.Message = $msg
#       #$logEntry.Timestamp = (Get-Date).ToUniversalTime()
#       if ("" -eq $this.sequenceToken) {
#           # First write into empty log...
#           $this.sequenceToken = Write-CWLLogEvent -LogGroupName $this.cwlGroup `
#               -LogStreamName $this.cwlStream `
#               -LogEvent #$logEntry
#       }
#       else {
#           # Subsequent write into the log...
#           $this.sequenceToken = Write-CWLLogEvent -LogGroupName $this.cwlGroup `
#               -LogStreamName $this.cwlStream `
#               -SequenceToken $this.sequenceToken `
#               -LogEvent #$logEntry
#       }
#   }
#}
#[Logger]#$log = [Logger]::new("UserData")
#$log.WriteLine("------------------------------")
#$log.WriteLine("Log Started - V4.0")
$RunUser = 'TrustedInstaller'
Write-Output "I set the run user"
#$log.WriteLine("PowerShell session user: $RunUser")
class SDManager {
#-------------------------------------------------------------------
#[Logger] hidden $SDLog
[string] hidden $GPScrShd_0_0 = "HKLM:SOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScriptsShutdown"
[string] hidden $GPMScrShd_0_0 = "HKLM:SOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScriptsShutdown"
#-------------------------------------------------------------------
SDManager([string]$RegFilePath, [string]$SecretName) {
#$this.SDLog = #$log
#----------------------------------------------------------------
[string] $SecretLine = '[string]$SecretAD    = "' + $SecretName + '"'
#--------------- Local Variables -------------
[string] $GPRootPath = "C:WindowsSystem32GroupPolicy"
[string] $GPMcnPath = "C:WindowsSystem32GroupPolicyMachine"
[string] $GPScrPath = "C:WindowsSystem32GroupPolicyMachineScripts"
[string] $GPSShdPath = "C:WindowsSystem32GroupPolicyMachineScriptsShutdown"
[string] $ScriptFile = [System.IO.Path]::Combine($GPSShdPath, "Shutdown-UnJoin.ps1")
#region Shutdown script (scheduled through Local Policy)
$ScriptBody =
@(
'param([string]$cntrl = "NotSet")',
$SecretLine,
'[string]$MachineName = $env:COMPUTERNAME',
'#class Logger {    ',
'#    #----------------------------------------------    ',
'#    [string] hidden  $cwlGroup    ',
'#    [string] hidden  $cwlStream    ',
'#    [string] hidden  $sequenceToken    ',
'#    #----------------------------------------------    ',
'#    # Log Initialization    ',
'#    #----------------------------------------------    ',
'#    Logger([string] $Action) {    ',
'#        $this.cwlGroup = "/ps/boot/configuration/"    ',
'#        $this.cwlStream = "{0}/{1}/{2}" -f $env:COMPUTERNAME, $Action,    ',
'#                                           (Get-Date -UFormat "%Y-%m-%d_%H.%M.%S")    ',
'#        $this.sequenceToken = ""    ',
'#        #------------------------------------------    ',
'#        if ( !(Get-CWLLogGroup -LogGroupNamePrefix $this.cwlGroup) ) {    ',
'#            New-CWLLogGroup -LogGroupName $this.cwlGroup    ',
'#            Write-CWLRetentionPolicy -LogGroupName $this.cwlGroup -RetentionInDays 3    ',
'#        }    ',
'#        if ( !(Get-CWLLogStream -LogGroupName $this.cwlGroup -LogStreamNamePrefix $this.cwlStream) ) {    ',
'#            New-CWLLogStream -LogGroupName $this.cwlGroup -LogStreamName $this.cwlStream    ',
'#        }    ',
'#    }    ',
'#    #----------------------------------------    ',
'#    [void] WriteLine([string] $msg) {    ',
'#        #$logEntry = New-Object -TypeName "Amazon.CloudWatchLogs.Model.InputLogEvent"    ',
'#        #-----------------------------------------------------------    ',
'#        #$logEntry.Message = $msg    ',
'#        #$logEntry.Timestamp = (Get-Date).ToUniversalTime()    ',
'#        if ("" -eq $this.sequenceToken) {    ',
'#            # First write into empty log...    ',
'#            $this.sequenceToken = Write-CWLLogEvent -LogGroupName $this.cwlGroup `',
'#                -LogStreamName $this.cwlStream `',
'#                -LogEvent #$logEntry    ',
'#        }    ',
'#        else {    ',
'#            # Subsequent write into the log...    ',
'#            $this.sequenceToken = Write-CWLLogEvent -LogGroupName $this.cwlGroup `',
'#                -LogStreamName $this.cwlStream `',
'#                -SequenceToken $this.sequenceToken `',
'#                -LogEvent #$logEntry    ',
'#        }    ',
'#    }    ',
'#}    ',
'#[Logger]#$log = [Logger]::new("UnJoin")',
'#$log.WriteLine("-----------------------------------------")',
'#$log.WriteLine("Log Started")',
'if ($cntrl -ne "run") ',
'    { ',
'    #$log.WriteLine("Script param <" + $cntrl + "> not set to <run> - script terminated") ',
'    return',
'    }',
'$compSys = Get-WmiObject -Class Win32_ComputerSystem',
'if ( -Not ($compSys.PartOfDomain))',
'    {',
'    #$log.WriteLine("Not member of a domain - terminating script")',
'    return',
'    }',
'$RSAT = (Get-WindowsFeature RSAT-AD-PowerShell)',
'if ( $RSAT -eq $null -or (-Not $RSAT.Installed) )',
'    {',
'    #$log.WriteLine("<RSAT-AD-PowerShell> feature not found - terminating script")',
'    return',
'    }',
'#$log.WriteLine("Removing machine <" +$MachineName + "> from Domain <" + $compSys.Domain + ">")',
'#$log.WriteLine("Reading Secret <" + $SecretAD + ">")',
#'Import-Module AWSPowerShell',
#'try { $SecretObj = (Get-SECSecretValue -SecretId $SecretAD) }',
#'catch ',
#'    { ',
#'    #$log.WriteLine("Could not load secret <" + $SecretAD + "> - terminating execution")',
#'    return ',
#'    }',
#'[PSCustomObject]$Secret = ($SecretObj.SecretString  | ConvertFrom-Json)',
'$password   = "<password>"',
'$username   = "<username>"',
'$credential = New-Object System.Management.Automation.PSCredential($username,$password)',
'import-module ActiveDirectory',
'$DCHostName = (Get-ADDomainController -Discover).HostName',
'#$log.WriteLine("Using Account <" + $username + ">")',
'#$log.WriteLine("Using Domain Controller <" + $DCHostName + ">")',
'Remove-Computer -WorkgroupName "WORKGROUP" -UnjoinDomainCredential $credential -Force -Confirm:$false ',
'Remove-ADComputer -Identity $MachineName -Credential $credential -Server "$DCHostName" -Confirm:$false ',
'#$log.WriteLine("Machine <" +$MachineName + "> removed from Domain <" + $compSys.Domain + ">")'
)
#$this.SDLog.WriteLine("Constracting artifacts required for domain UnJoin")
#----------------------------------------------------------------
Write-Output "I created SDManager class"
try {
if (!(Test-Path -Path $GPRootPath -pathType container))
{ New-Item -ItemType directory -Path $GPRootPath }
if (!(Test-Path -Path $GPMcnPath -pathType container))
{ New-Item -ItemType directory -Path $GPMcnPath }
if (!(Test-Path -Path $GPScrPath -pathType container))
{ New-Item -ItemType directory -Path $GPScrPath }
if (!(Test-Path -Path $GPSShdPath -pathType container))
{ New-Item -ItemType directory -Path $GPSShdPath }
}
catch {
#$this.SDLog.WriteLine("Failure creating UnJoin script directory!" )
#$this.SDLog.WriteLine($_)
Write-Output  "hello"
}
#----------------------------------------
try {
Set-Content $ScriptFile -Value $ScriptBody
}
catch {
#$this.SDLog.WriteLine("Failure saving UnJoin script!" )
#$this.SDLog.WriteLine($_)
Write-Output  "hello"
}
#----------------------------------------

# UPDATE WINDOWS REGISTRY AND CREATE A SHUTDOWN TASK        

$RegistryScript =
@(
'Windows Registry Editor Version 5.00',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScripts]',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScriptsShutdown]',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScriptsShutdown]',
'"GPO-ID"="LocalGPO"',
'"SOM-ID"="Local"',
'"FileSysPath"="C:\Windows\System32\GroupPolicy\Machine"',
'"DisplayName"="Local Group Policy"',
'"GPOName"="Local Group Policy"',
'"PSScriptOrder"=dword:00000001',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScriptsShutdown]',
'"Script"="Shutdown-UnJoin.ps1"',
'"Parameters"=""',
'"IsPowershell"=dword:00000001',
'"ExecTime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyScriptsStartup]',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScripts]',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScriptsShutdown]',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScriptsShutdown]',
'"GPO-ID"="LocalGPO"',
'"SOM-ID"="Local"',
'"FileSysPath"="C:\Windows\System32\GroupPolicy\Machine"',
'"DisplayName"="Local Group Policy"',
'"GPOName"="Local Group Policy"',
'"PSScriptOrder"=dword:00000001',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScriptsShutdown]',
'"Script"="Shutdown-UnJoin.ps1"',
'"Parameters"=""',
'"ExecTime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00',
'[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionGroup PolicyStateMachineScriptsStartup]'
)
Write-Output "I created the registry script."
try {
[string] $RegistryFile = [System.IO.Path]::Combine($RegFilePath, "OnShutdown.reg")
Set-Content $RegistryFile -Value $RegistryScript
&regedit.exe /S "$RegistryFile"
}
catch {
#$this.SDLog.WriteLine("Failure creating policy entry in Registry!" )
#$this.SDLog.WriteLine($_)
Write-Output "hello"
}
}
#DISABLE UNJOIN AND ENABLE JOIN FOR THE FIRST RUN

#----------------------------------------
[void] DisableUnJoin() {
try {
Set-ItemProperty -Path $this.GPScrShd_0_0  -Name "Parameters" -Value "ignore"
Set-ItemProperty -Path $this.GPMScrShd_0_0 -Name "Parameters" -Value "ignore"
&gpupdate /Target:computer /Wait:0
}
catch {
#$this.SDLog.WriteLine("Failure in <DisableUnjoin> function!" )
#$this.SDLog.WriteLine($_)
Write-Output  "hello"
}
}
#----------------------------------------
[void] EnableUnJoin() {
try {
Set-ItemProperty -Path $this.GPScrShd_0_0  -Name "Parameters" -Value "run"
Set-ItemProperty -Path $this.GPMScrShd_0_0 -Name "Parameters" -Value "run"
&gpupdate /Target:computer /Wait:0
}
catch {
#$this.SDLog.WriteLine("Failure in <EnableUnjoin> function!" )
#$this.SDLog.WriteLine($_)
Write-Output "hello"
}
}
}
Write-Output "I created the the join and unjoin functions"
# GET SECRETS
#[SDManager]$sdm = [SDManager]::new(#$log, "C:ProgramDataAmazonEC2-WindowsLaunchScripts", $SecretAD)
##$log.WriteLine("Loading Secret <" + $SecretAD + ">")
#Import-Module AWSPowerShell
#try { $SecretObj = (Get-SECSecretValue -SecretId $SecretAD) }
#catch {
#   #$log.WriteLine("Could not load secret <" + $SecretAD + "> - terminating execution")
#   return
#}
#[PSCustomObject]$Secret = ($SecretObj.SecretString  | ConvertFrom-Json)
##$log.WriteLine("Domain (from Secret): <" + $domain + ">")

# Verify domain membership
#IF ALREADY MEMBER OF DOMAIN 
$compSys = Get-WmiObject -Class Win32_ComputerSystem
#------------------------------------------------------------------------------
if ( ($compSys.PartOfDomain) -and ($compSys.Domain -eq $domain)) {
#$log.WriteLine("Already member of: <" + $compSys.Domain + "> - Verifying RSAT Status")

#CHECK IF RSTAT IS INSTALLED

$RSAT = (Get-WindowsFeature RSAT-AD-PowerShell)
if ($null -eq $RSAT) {
#$log.WriteLine("<RSAT-AD-PowerShell> feature not found - terminating script")
return
}

#ENABLE ON SHUT DOWN & INSTALL RSTAT

#$log.WriteLine("Enable OnShutdown task to un-join Domain")
$sdm.EnableUnJoin()
if ( (-Not $RSAT.Installed) -and ($RSAT.InstallState -eq "Available") ) {
#$log.WriteLine("Installing <RSAT-AD-PowerShell> feature")
Install-WindowsFeature RSAT-AD-PowerShell
}
#$log.WriteLine("Terminating script - ")
return
}
# IF NOT MEMBER OF DOMAIN THEN JOIN AND RESTART
# Performing Domain Join
#$log.WriteLine("Domain Join required")
#$log.WriteLine("Disable OnShutdown task to avoid reboot loop")
$sdm.DisableUnJoin()
$password = "<password>"
$username = "<username>"
$domain = "<domain>"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
#$log.WriteLine("Attempting to join domain <" + $domain + ">")
Add-Computer -DomainName $domain -Credential $credential -Restart -Force
#$log.WriteLine("Requesting restart...")
Write-Output "I joined or unjoined the domain friends."
#------------------------------------------------------------------------------
</powershell>
<persist>true</persist>

你找到答案了吗?我相信你的内联脚本太长,无法在userdata中执行。您可能会在这里遇到这个问题:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-add-user-data.html

当我遇到这种情况时,我发现最好将脚本上传到S3,允许EC2实例RO通过EC2实例配置文件访问S3桶,然后从桶中拉出并在userdata中运行脚本。

HTH !

最新更新