EC2 Windows User Data: Powershell does not run as expected - windows

I am trying to bootstrap EC2 Windows instances via Powershell commands inside user data. The steps I am trying to execute via user data are:
Install chocolatey
Use chocolatey to install Python
Use chocolatey to install AWS CLI
Use AWS CLI to download a Powershell script from S3
Run that Powershell script
The user data is pretty straightforward:
<powershell>
Set-ExecutionPolicy Bypass -Force;
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'));
choco install python3 -y;
choco install awscli -y
refreshenv
$BootstrapScript = (Join-Path $env:TEMP "NewBootstrap.ps1")
& aws s3api get-object --bucket my-bucket-name --key bootstrap/WindowsBootstrap.ps1 "$BootstrapScript"
iex "$BootstrapScript"
</powershell>
The bootstrap script is never downloaded or executed. If I logon to the instance and view the logs, the output suggests something strange is happening:
At the top of the logs there are errors complaining that 'aws' is not recognized as the name of a cmdlet. Why should this error before it's even tried to install the aws cli?
After that the term
'C:\Users\Administrator\AppData\Local\Temp\NewBootstrap.ps1' is not recognized as the name of a cmdlet, function,
script file. Again - why is this erroring before we've tried to get that file?
Then the logs show that choco, python and awscli actually were installed correctly.
I don't understand what is happening with the order of execution. If I login to the box and execute the exact same user data script that is contained in C:\Windows\Temp it runs completely as expected.
Any help on understanding or debugging this would be most appreciated.
Output from C:\ProgramData\Amazon\EC2-Windows\Launch\Log\UserdataExecution.log with some choco output elided for brevity
2017/11/06 12:11:49Z: Userdata execution begins
2017/11/06 12:11:49Z: Zero or more than one <persist> tag was not provided
2017/11/06 12:11:49Z: Unregistering the persist scheduled task
2017/11/06 12:11:54Z: Zero or more than one <runAsLocalSystem> tag was not provided
2017/11/06 12:11:54Z: Zero or more than one <script> tag was not provided
2017/11/06 12:11:54Z: Zero or more than one <powershellArguments> tag was not provided
2017/11/06 12:11:54Z: <powershell> tag was provided.. running powershell content
2017/11/06 15:13:42Z: Userdata execution begins
2017/11/06 15:13:42Z: Zero or more than one <persist> tag was not provided
2017/11/06 15:13:42Z: Unregistering the persist scheduled task
2017/11/06 15:13:54Z: Zero or more than one <runAsLocalSystem> tag was not provided
2017/11/06 15:13:54Z: Zero or more than one <script> tag was not provided
2017/11/06 15:13:54Z: Zero or more than one <powershellArguments> tag was not provided
2017/11/06 15:13:55Z: <powershell> tag was provided.. running powershell content
2017/11/06 15:16:11Z: Userdata: is currently executing. To end it kill the process with id: 2828
2017/11/06 15:17:40Z: Message: The errors from user scripts: & : The term 'aws' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\Windows\TEMP\UserScript.ps1:15 char:3
+ & aws s3api get-object --bucket my-bucket-name --key bootstra ...
+ ~~~
+ CategoryInfo : ObjectNotFound: (aws:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
C:\Users\Administrator\AppData\Local\Temp\NewBootstrap.ps1 : The term
'C:\Users\Administrator\AppData\Local\Temp\NewBootstrap.ps1' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
At line:1 char:1
+ C:\Users\Administrator\AppData\Local\Temp\NewBootstrap.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Admini...ewBootstrap.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
2017/11/06 15:17:40Z: Message: The output from user scripts: This is the new bootstrap
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 11/6/2017 3:14 PM chocInstall
Getting latest version of the Chocolatey package for download.
Getting Chocolatey from https://chocolatey.org/api/v2/package/chocolatey/0.10.8.
... Chocolatey Install output ...
Chocolatey (choco.exe) is now ready.
You can call choco from anywhere, command line or powershell by typing choco.
Run choco /? for a list of functions.
You may need to shut down and restart powershell and/or consoles
first prior to using choco.
Ensuring chocolatey commands are on the path
Ensuring chocolatey.nupkg is in the lib folder
Installing awscli
Chocolatey v0.10.8
Installing the following packages:
python3
.. Python Download / Install output ...
Download of python-3.6.3-amd64.exe (30.16 MB) completed.
Hashes match.
Installing python3...
python3 has been installed.
Installed to 'C:\Python36'
python3 can be automatically uninstalled.
Environment Vars (like PATH) have changed. Close/reopen your shell to
see the changes (or in powershell/cmd.exe just type `refreshenv`).
The install of python3 was successful.
Software installed as 'EXE', install location is likely default.
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Chocolatey v0.10.8
Installing the following packages:
awscli
.. AWS CLI Download / Install output ...
The install of awscli was successful.
Software installed as 'msi', install location is likely default.
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Refreshing environment variables from registry for cmd.exe. Please wait...Finished..
2017/11/06 15:17:40Z: Userdata execution done

The issue was that when installed as part of the cloud init process, the Powershell profile fails to import Chocolatey. This means that packages will install fine via choco install, but are not made available in the environment, even if you call refreshenv (hence my call to aws failed even though it installed successfully.)
To fix this problem you can manually force Powershell to import the Chocolatey module by editing your Powershell profile.
# Updated profile content to explicitly import Choco
$ChocoProfileValue = #'
$ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
if (Test-Path($ChocolateyProfile)) {
Import-Module "$ChocolateyProfile"
}
'#
# Write it to the $profile location
Set-Content -Path "$profile" -Value $ChocoProfileValue -Force
# Source it
. $profile
You can read more on this in the chocolatey troubleshooting guide

Related

Path contains empty name

I am running the below task to Upload Notebook to Databricks with Azure DevOps release pipeline:
databricks workspace mkdirs //build
databricks workspace import --language PYTHON --format SOURCE
--overwrite _databricks/notebook/$(notebook_name)-$(Build.SourceVersion).py //build/$(notebook_name)-$(Build.SourceVersion).py
but getting the error: Path (//build/helloworld-04747aa082426141c5c286fbe5eab2d7d1bd5983.py) contains empty name
2020-05-16T18:54:01.5665867Z ##[section]Starting: Upload Notebook to Databricks
2020-05-16T18:54:01.5831890Z ==============================================================================
2020-05-16T18:54:01.5832257Z Task : Bash
2020-05-16T18:54:01.5832539Z Description : Run a Bash script on macOS, Linux, or Windows
2020-05-16T18:54:01.5832833Z Version : 3.163.2
2020-05-16T18:54:01.5833073Z Author : Microsoft Corporation
2020-05-16T18:54:01.5833436Z Help : https://learn.microsoft.com/azure/devops/pipelines/tasks/utility/bash
2020-05-16T18:54:01.5833824Z ==============================================================================
2020-05-16T18:54:01.8378449Z Generating script.
2020-05-16T18:54:01.8525502Z [command]"C:\Program Files\Git\bin\bash.exe" --noprofile --norc -c pwd
2020-05-16T18:54:01.8915864Z /d/a/_temp
2020-05-16T18:54:01.8975224Z
2020-05-16T18:54:01.9001870Z ========================== Starting Command Output ===========================
2020-05-16T18:54:01.9009310Z [command]"C:\Program Files\Git\bin\bash.exe" --noprofile --norc /d/a/_temp/5c6b246a-d6b4-45f3-9c35-c1f64320d54b.sh
2020-05-16T18:54:09.0829994Z **Error: b'{"error_code":"INVALID_PARAMETER_VALUE","message":"Path (//build/helloworld-04747aa082426141c5c286fbe5eab2d7d1bd5983.py) contains empty name"}'**
2020-05-16T18:54:09.1242892Z
2020-05-16T18:54:09.1369153Z ##[error]Bash exited with code '1'.
2020-05-16T18:54:09.1385662Z ##[section]Finishing: Upload Notebook to Databricks
Surprisingly, the same code was running fine without any error for other peoples.
Nothing found from google search. Any idea/clue/suggestion? Thanks
You are experiencing this error message due to incorrect path specified i.e. (//build). Make sure you pass the correct path i.e. (/build).
I would suggest you to correct the task to Upload Notebook to Databricks with Azure DevOps release pipeline as shown below:
databricks workspace mkdirs /build
databricks workspace import --language PYTHON --format SOURCE --overwrite _databricks-example/notebook/$(notebook_name)-$(Build.SourceVersion).py /build/$(notebook_name)-$(Build.SourceVersion).py
I had faced similar issue like mentioned in -: https://forums.databricks.com/questions/39420/path-contains-empty-name.html
This is because you might be using windows hosted agent. This can be solved by changing agent to use ubuntu. I used ubuntu 1604 (ubuntu-16.04).
Please use the path as mentioned below (no need to add "/" infront)
databricks workspace mkdirs /build
databricks workspace import --language PYTHON --format SOURCE --overwrite _databricks-example/notebook/$(notebook_name)-$(Build.SourceVersion).py /build/$(notebook_name)-$(Build.SourceVersion).py
I Hope this helps you solve it. Cheers!

Not able to install packages using chcolatey in docker container

I am building a windows container with following software installed
Notepad++
MariaDB
HeidiSQL
.NET Framework 2.0 and 3.5
This is the docker image I created.
https://hub.docker.com/repository/docker/mhhaji/winserver2016_base
What I tried :
Steps to run the container
docker run --name mycontainer mhhaji/winserver2016_base:v1 ping -t localhost
docker exec -it mycontainer powershell
Once powershell is running,
I execute the following commands
Get-PackageProvider
#Chocolatey is not existing so I install chocolatey
Find-Package -Provider chocolatey
#Enter [Y] when prompted
#Install notepad++
Find-Package -Provider chocolatey -name notepad*
I get the following error
PS C:\> Find-Package -Provider chocolatey -name notepad*
WARNING: NuGet: The request was aborted: Could not create SSL/TLS secure channel.
PS C:\> Find-Package -Provider chocolatey -name mariadb
Find-Package : No match was found for the specified search criteria and package name 'mariadb' as registered package sources.
At line:1 char:1
+ Find-Package -Provider chocolatey -name mariadb
+ Categorylnfo : ObjectNotFound: (Microsoft.Power...ets.FindPackage:FindPac
+ FullyQualifiedErrorld : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManage
PS C:\> Get-PackageSource
Name ProviderName IsTrusted Location
chocolatey Chocolatey False http://chocolatey.org/api/v
PSGallery PowerShellGet False https://www.powershellgalle
PS C:\> Get-PackageParameters
Get-PackageParameters : The term 'Get-PackageParameters' is not recognized as the name
o program. Check the spelling of the name, or if a path was included, verify that the path
At line:1 char:1
+ Get-PackageParameters
+ Categorylnfo : ObjectNotFound: (Get-PackageParameters:String) [], Command
+ FullyQualifiedErrorld : CommandNotFoundException
PS C:\> Get-PackageProvider
Name Version DynamicOptions
Chocolatey 2.8.5.130 SkipDependencies, ContinueOnFailure,
ExcludeVersion,ForceX86, PackageSaveMode, FilterOnTag, Contains,
AllowPrereleaseVersions, Conf
msi 3.0.0.0 AdditionalArguments
msu 3.0.0.0
PowerShellGet 1.0.0.1 PackageManagementProvider, Type, Scope, AllowClobber,SkipPublisherCheck, InstallUpdate, NoPathUpdate, Filter, Tag, Includes, DscRes
Programs 3.0.0.0 IncludeWindowsInstaller, IncludeSystemComponent
I was able to download chocolatey so connecting to external endpoints doesnt seem to be a problem.
Update:
Seems like nuget is not installed in my image. Looking for solution but not able to find.
Make sure your system is able to support TLS 1.2 as that is necessary for chocolatey to run
PS> [Enum]::GetNames([Net.SecurityProtocolType]) -contains 'Tls12'
Enable TLS 1.2 for your system
PS> [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Finally install chocolatey directly from source
PS> iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'));

Windows 10 IOT UWF Unified Write Filter implementation powershell applyupdate is not recognized as the name of cmdlet

I was trying to implement windows 10 iot Unified Write Filter implementation.
I wanted to run these commands to remote iot device through powershell.
change to the directory where you have copied your files
cd C:\UWFTemp
commands to install the packages to your IoT device system image:
applyupdate –stage .\Microsoft-IoTUAP-UnifiedWriteFilter-Package.cab
applyupdate –stage .\Microsoft-IoTUAP-UnifiedWriteFilter-Package_Lang_en-us.cab
applyupdate –commit
And I'm getting error as
PS C:\UWFTemp> applyupdate -stage Microsoft-IoTUAP-UnifiedWriteFilter-Package.cab
The term 'applyupdate' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
+ CategoryInfo : ObjectNotFound: (applyupdate:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
The file which I'm running this command exists and working fine. I'm new to shell scripting, I couldn't find how to install package for get running the applyupdate command.
It seems that you have not accessed the remote device via Powershell. Please try to copy the packages into your device and connect the remote device via Powershell. This document shows how to use UWF on Windows 10 IoT Core(https://learn.microsoft.com/en-us/windows/iot-core/secure-your-device/unifiedwritefilter).

Docker for Windows - Install certificates using sn.exe / Strong Name utility

We have a Docker image that we use to build our Visual Studio solutions. This works great. Now we have some solutions that require a key. To install the key you use sn.exe, but Microsoft has gone through great lengths to make sure human input is needed, namely the password..
The image is based off FROM microsoft/dotnet-framework:3.5
I tried several tricks, especially from this Stack Overflow thread: Auto-entering Password In Sn.exe
The last answer is mine (Thomas Rijsewijk). At least I have a working way to install the key automatically, but somehow SendWait doesn't work in Docker, or Docker for Windows, or microsoft/dotnet-framework:3.5 docker image.
# ---------
# Import all certificates in C:\keys
# ---------
[void][System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
[System.Windows.Forms.SendKeys]::SendWait("hello")
When I run this I get "Access Denied":
Exception calling "SendWait" with "1" argument(s): "Access is denied"
At K:\install-certificates.ps1:51 char:1
+ [System.Windows.Forms.SendKeys]::SendWait("hello")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : Win32Exception
As an alternative I tried SendKeys() from WScript.Shell:
$wshell = New-Object -com wscript.shell;
Sleep 5;
$wshell.sendkeys("test");
Again, this works perfectly on my machine (Windows 10 up to date) and an up to date Windows 2016 server. But NOT inside the docker image: nothing happens, no error but it's not entering "test" either.
Lot of talks about automating powershell, but basically I don't really care HOW I install the certificate when building my docker image, I just want it installed. I install the certificate locally using
Start-Process "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\sn.exe" -ArgumentList "-i `"D:\key.pfx`" VS_KEY_XXXXXXXX" -NoNewWindow;
At this point, it asks for a password which makes it impossible to use with docker build.
I did a whole lot of searching on Google and SO, I'm surprised to see that nobody else tried to install a key using sn.exe.
PS: Yes, I know VS_KEY_XXXXXXXX is not a valid VS_KEY. I already have a working mechanism for extracting the right VS_KEY, but that's out of scope of this question.
PPS: Yes, I know I could manually running the docker, install the certificate and manually commit and push the changes. But naturally, I want it to originate from my Dockerfile

Windows AWS EC2 Instance User Data PowerShell do not load Powershell Modules for System Account level

I have created a PowerShell script to run in the user data of an AWS Windows instance. If I manually execute the script as Administrator, it runs successfully and does work.
But when I send the script in user data (during instance creation) it throws an exception. This happens during the installation of the module from System Account
PowerShell Version on EC2 Windows 2012 R2 = v4.0
Cannot bind argument to parameter 'Path' because it is an empty string.
2017-04-10T18:24:25.004Z: Ec2HandleUserData: Message: Executing C:Windowssystem32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy unrestricted . 'C:\Program Files\Amazon\Ec2ConfigService\Scripts\UserScript.ps1' from System account
2017-04-10T18:24:25.006Z: Ec2HandleUserData: Message: Executing User Data with PID: 1084
2017-04-10T18:24:34.639Z: Ec2HandleUserData: Message: ExitCode of User Data with PID: 1084 is 1
2017-04-10T18:24:34.642Z: Ec2HandleUserData: Message: The errors from user scripts: iex : Cannot bind argument to parameter 'Path' because it is an empty string.
At C: Program Files Amazon Ec2ConfigService Scripts UserScript.ps1:5 char:79
+ (new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1")
| ie ...
+
~~
+ CategoryInfo : InvalidData: (:) [Invoke-Expression], ParameterB
indingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAl
lowed,Microsoft.PowerShell.Commands.InvokeExpressionCommand
2017-04-10T18:24:34.642Z: Ec2HandleUserData: Message: The output from user scripts:
2017-04-10T18:24:34.642Z: Background plugin complete: Ec2HandleUserData
Work Around /Solution : This is more of PsGet Module issue, not EC2 issue
https://github.com/psget/psget/issues/208
At System Account level PsGet Module was setting Path InCorrectly.
As of now I have Modified PsGet.ps1 to read my custom path $env:PSModulePath, and it works with no issues.
PsGet.Ps1 Line 1615
Comment the line #Add-PathToPSModulePath -PathToAdd:$Destination -PersistEnvironment:$PersistEnvironment -Global:$Global
Added : [Environment]::SetEnvironmentVariable("PSModulePath", ";C:{DirectoryIwantModulesToBe}\Modules", "Machine")
It works , at System Account level with no Issues
Thanks Alex for help.
I would advice to use specific paths. The userdata block executes under the windows system account and as such it doesn't have a profile directory nor a temp path.
For example [System.IO.Path]::GetTempFileName() fails when executing with this user.
This is the same when code-deploy packages execute.
If you have to work often with AWS-EC2 then it's best to try to replicate the environment as much as possible locally because an EC2 takes minimum 6 minutes to launch and that can be a major slow down in your troubleshooting efforts. For this reason, I've decided to setup a vagrant box with the matching operating system and on that box I execute/test what I need. When things get tough and I'm suspicious of the System user's special characteristics, I use psexec to launch my processes. This is a good starting point How to: become the LOCAL SYSTEM account with PsExec

Resources