[Quick Tip] When I wrote Japanese comments in the user data of a Japanese Windows EC2 instance, not a single line of the script was executed
This page has been translated by machine translation. View original
Hello, I'm Hayashi.
For a certain project, I was using user data to perform initial configuration on a Windows Server 2025 EC2 instance.
It was a PowerShell script with settings for timezone, firewall, and so on.
Thinking about future handoffs, I wrote the comments in Japanese — and that caused the user data to stop executing entirely. The logs didn't show the actual error content, so at first I had no idea what was causing it.
Conclusion First
The line immediately after a Japanese comment was getting absorbed into the comment, causing a syntax error.
Because EC2Launch v2 writes out the script and the Japanese-locale Windows PowerShell reads it as CP932, newlines can disappear at the end of lines. The safest approach is to not write Japanese comments in user data.
Environment
| Item | Details |
|---|---|
| OS | Windows Server 2025 Japanese Edition |
| EC2Launch | v2.5.2 |
| Windows PowerShell | 5.1.26100 |
| System Locale | Japanese (CP932) |
| User Data Specification | CloudFormation UserData |
| Script Line Endings | LF |
How to Investigate the Error
I launched an EC2 instance with the following user data. There is a try { immediately after two lines of Japanese comments.
<powershell>
Start-Transcript -Path C:\Windows\Temp\userdata.log -Append
# Allow ICMP (ping) inbound
# The inbound rule is disabled by default, so enable it
try {
Enable-NetFirewallRule -Name "FPS-ICMP4-ERQ-In" -ErrorAction Stop
} catch {
Write-Output "failed: $_"
}
Stop-Transcript
</powershell>
After launching, C:\Windows\Temp\userdata.log, which should have been created by Start-Transcript, was nowhere to be found.
Looking at the EC2Launch v2 log at C:\ProgramData\Amazon\EC2Launch\log\agent.log, I could see that the script had produced error output.
Info: Script file is created at: C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch2485221373\UserScript.ps1
Info: Error file is created at: C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch2485221373\err.tmp
Error: Script produced error output.
Info: Stage: postReadyUserData completed.
The error details were written to err.tmp, so I checked it.
At C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch2485221373\UserScript.ps1:5 char:1
+ } catch {
+ ~
The token '}' cannot be used as an expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
Even though try { was written, } catch { was being judged as having no matching try. Because it was a syntax error, apparently not a single line of the script was executed.
Workarounds
There are four workarounds available in user data.
Do Not Write Japanese in Comments
If comments contain only alphanumeric characters, this issue does not occur.
Use CRLF Line Endings
Because CR is added at the end of lines, newlines will no longer disappear. The line endings written in user data are preserved as-is in the file that EC2Launch v2 writes out.
If your template is saved with LF line endings, it will be passed along with LF. Either save the file with CRLF line endings in your editor, or if you are loading an external file in Terraform, replace the line endings when passing it.
user_data = replace(file("${path.module}/userdata.ps1"), "\n", "\r\n")
The comments will appear garbled, but since PowerShell does not execute comment lines, this does not affect the script's behavior.
Add a BOM at the Beginning of the Script
Because the BOM is preserved in the file that EC2Launch v2 writes out, PowerShell will read it as UTF-8. Only the content inside the tags is written out, so the BOM must be placed immediately after the <powershell> tag. However, this means embedding an invisible character in your template.
Place an ASCII-Only Line Between Japanese Comments and Executable Lines
By inserting a line like # ----, the newline that disappears becomes that line's newline, so the executable line is preserved. However, if that line is removed, the problem recurs.
I initially fixed it this way, but later when I cleaned up the comments, I deleted the separator line along with them, and it stopped working again.
Root Cause
The script written out by EC2Launch v2 does not have a BOM, the UTF-8 marker. Windows PowerShell 5.1 reads files without a BOM as CP932, so a script written in UTF-8 ends up being read as CP932.
Japanese characters in CP932 are 2 bytes per character, while in UTF-8 they are 3 bytes per character.
When reading 2 bytes at a time, the boundaries shift, and 1 byte may be left over at the end of a line. That 1 byte is read together with the following newline (0x0A) as a single character, causing the newline to disappear.
In this case, that's what happened on the second comment line.
The 8B from the trailing る (E3 82 8B) was left over and swallowed the newline.
00000080 81 AE E3 81 A7 E6 9C 89 E5 8A B9 E5 8C 96 E3 81 ®ã§æå¹åã
00000090 99 E3 82 8B 0A 74 72 79 20 7B 0A 20 20 20 20 45 ã.try {. E
When read as CP932, try { becomes a continuation of the comment line. A script that had 9 lines was now 8 lines.
Get-Content C:\...\UserScript.ps1 -Encoding Default
Start-Transcript -Path C:\Windows\Temp\userdata.log -Append
# ICMP・・ing・峨・蜿嶺ソ。險ア蜿ッ
# 蜿嶺ソ。隕丞援縺ッ譌「螳壹〒辟。蜉ケ縺ェ縺ョ縺ァ譛牙柑蛹悶☆繧・try {
Enable-NetFirewallRule -Name "FPS-ICMP4-ERQ-In" -ErrorAction Stop
} catch {
Write-Output "failed: $_"
}
Stop-Transcript
Which line is affected depends on the bytes at the end of the line, so changing the comment text changes the outcome. A script that was working can stop working just from editing a comment.
Summary
In user data for a Japanese-locale Windows EC2 instance, the line immediately after a Japanese comment can be absorbed into the comment, causing the entire script to fail to run. The cause is BOM-less UTF-8 being read as CP932, and this can be avoided by not writing Japanese in comments or by using CRLF line endings.
Even when user data fails to run, the error is not displayed anywhere. I also spent time looking only at the script contents at first, and it took a while before I noticed err.tmp. If you experience the same symptoms, try opening the path written in agent.log first.
I hope this article is useful to someone. Thank you for reading to the end!
References
