I am trying to build an AWS AMI for a gitlab runner for building our .NET application.
I am using packer for building the image based one the official Windows Server 2019 base AWS AMI.
I am using WinRM, with HTTPS, not changing any password.
Here are the powershell commands to configure the virtual machine :
"Creating desktop directory"
mkdir C:\Windows\SysWOW64\config\systemprofile\Desktop
"Installing ntrights tools"
mkdir tools
Invoke-WebRequest -Uri "https://download.microsoft.com/download/8/e/c/8ec3a7d8-05b4-440a-a71e-ca3ee25fe057/rktools.exe" -OutFile "tools\tools.exe" -UseBasicParsing
Start-Process "tools\tools.exe" -ArgumentList "/T:$pwd\tools\ /C" -Wait
Start-Process "msiexec.exe" -ArgumentList "/i $pwd\tools\rktools.msi /qn" -Wait
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
Remove-Item tools -Recurse
"Setting rights of service logon to $Env:WINRMUSER"
ntrights.exe ntrights +r SeServiceLogonRight -u $Env:WINRMUSER
# Git lab runner
$path = ".\gitlab-runner.exe"
If(!(test-path $path))
{
"Downloading Gitlab Runner"
Invoke-WebRequest -Uri "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe" -OutFile $path -UseBasicParsing
}
"Scheduling runner to start at startup of the system"
schtasks.exe /create /tn "Gitlab Runner service start" /RU $Env:WINRMUSER /RP `"$Env:WINRMPASS`" /Sc ONSTART /tr "powershell -Command $pwd\register-gitlabrunner.ps1 -ExecutionPolicy Bypass"
There are obviously more scripts executed (install msbuild, install .net sdk 4.7.2, nugget, and git) I can provide them if relevant. Here I focus on the powershell code I came up with for the gitlab runner problem.
I want the virtual machine to start the runner on start so we just have to launch instances of the AMI to scale up.
To explain a bit more what I did try :
You can see I am trying to create the desktop directory in order for windows to get that it can run interactive things... Not working
I am setting up the SeServiceLogonRight in order to avoid the "failed to logon" error
The user is Administrator, and the password is the right password
The scheduled tasks is created and ready to run. Won't run on start, won't run If i start it through schtasks /Run (the last run time is never updated and show a value in 19XX)
Tried to cmd /c the task command, everything work as expected
I don't find any logs anywhere, event log seems to be empty of problem from Application, System and Powershell. The file in c:\Windows\Tasks\SchlogU (or something like that), does not exist (but the folder exists)
I have no UI for the scheduler, I use a light version of windows so all I can do is play with the schtasks.exe
Default folder is : c:\Users\Administrator
The powershell script is pushed by packer onto the server and is located in c:\Users\Administrator (as for the gitlab-runner.exe)
I connect directly through RDP to try debugging the situation.
Here is the script that should be started
Set-Location $PSScriptRoot
$path = ".\gitlab-runner.exe"
"Stopping runner"
Invoke-Expression "$path stop"
"Unregistering previous configuration"
Invoke-Expression "$path unregister --all-runners"
"Uninstalling runner"
Invoke-Expression "$path uninstall"
"Installing runner"
Invoke-Expression "$path install"
"Registering Gitlab Runner"
Invoke-Expression "$path register --non-interactive --url 'https://URL_HERE/' --registration-token 'TOKEN HERE' --executor shell"
"Starting the runner"
Invoke-Expression "$path start"
I can install the runner only once in the configuration using the user and password but this is not the problem here since the task never runs...
Answer the question with what I came up thanks :
I was told by so many docs and answers everywhere that the task scheduler is the way to go when you need to start scripts at startup or logon.
As I always worked with windows servers with GUIs, the Task Scheduler was working fine until now. Maybe I did something wrong somewhere, maybe not.
Anyway, after trying using powershell commands to create the task (with improvements but no sufficient solutions), I tried to put a command file in the C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp, did not work either.
the file look like this thanks to this link
PowerShell -Command "Set-ExecutionPolicy Unrestricted"
PowerShell -Command "c:\Users\Administrator\register-gitlabrunner.ps1" >> c:\startup.log.txt
I tried to delay the start of the script to 5 minutes after startup. Was to test if it was a problem with a slow initialization of network or something else. Still not working.
There is something preventing the script to be executed when it's launched at startup using this methods.
From there I added a persistent "user_data" script on my EC2 launch template in order to start what I was expecting on start. It works.
I don't feel it's the best way since I need to configure the template and not only the AMI but at least it works.
The script in user_data looks like this :
<script>
cmd /c "C:/ProgramData/Microsoft/Windows/Start Menu/Programs/StartUp/startup.cmd"
</script>
<persist>true</persist>
I kept the installation and registering in the startup script since I got logon errors when I install gitlab runner through WinRM using the account credentials (--user --password)
I still don't understand what is up with this issue. I guess it's a problem with the account used to start the script (localsystem or something like that, that would conflict with the gitlab runner service).
Since I have no GUI (the docs are mostly on GUI) and limited time, I won't investigate more for the moment and feel it's enough at least for the moment.
Hope this can help someone that will encounter the same situation
Related
I have powershell script. I need to run it as a service. I try this way to make it as a service.
Start-Process -FilePath C:\Users\xx\Downloads\nssm-2.24\win32\nssm.exe -ArgumentList 'install AgentService "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-command "& { . D:\SERVICE\Script.ps1}"" ' -NoNewWindow
Then I open run.exe and type services.msc. The service exist. And I try to start it. It show like this picture.
But I see the powershell script is not running. Because in my powershell script I use infinity loop to do some process, like copy and rename file. But It does not work.
Anyone can give me idea plese. Thank you.
A ordinary EXE executable, by default, is not ready to be run as a Windows Service.
A service process needs to register with the Service Control Manager on startup and listen for commands from the SCM. All the details you need are here:
C++: https://learn.microsoft.com/en-us/windows/win32/services/services
C# and .NET: https://learn.microsoft.com/en-us/dotnet/framework/windows-services/
However, if it helps, there are pre-built services that will launch and manage the process lifetime of any ordinary EXE. Google for run any windows exe as a service. One that I've personally used before is SrvStart.
I use a script to create a windows scheduled task to call a powershell script in elevated mode to run windows update by using boxstarter (a tool could automatically continue running code even there is reboot during the execution) when system startup. But not sure why, the task could be called after startup, but nothing has been done. If I manually start the scheduled task in task manager, it will run as expected.
Script to register a scheduled task:
$TaskActionArgument ="-noprofile -command "&{start-process powershell -argumentList '-File C:\users\administrator\updatescript\boxstarter.ps1 -verb runas'}""
$TaskAction = New-ScheduledTaskAction -Execute "C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe" -argument $TaskActionArgument
$TaskTrigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName boxstarter -Action $TaskAction -Trigger $TaskTrigger -User administrator -Password Vmc12svt -RunLevel Highest
I checked the event log viewer and see following error message for the scheduled job:
System
Provider
[ Name] PowerShell
EventID 403
[ Qualifiers] 0
Level 4
Task 4
Keywords 0x80000000000000
TimeCreated
[ SystemTime] 2018-01-10T18:21:12.000000000Z
EventRecordID 267
Channel Windows PowerShell
Computer WIN-6HSHKOKP31E
Security
EventData
Stopped Available NewEngineState=Stopped
PreviousEngineState=Available SequenceNumber=16 HostName=ConsoleHost
HostVersion=4.0 HostId=13ece112-b027-4051-9ddf-1a195d3aa30f
HostApplication=C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
-File C:\users\administrator\updatescript\boxstarter.ps1 -verb runas EngineVersion=4.0 RunspaceId=d158a216-18e3-4e86-9ade-b232201c9cdc
PipelineId= CommandName= CommandType= ScriptName= CommandPath=
CommandLine=
For the error message, I googled and found explain of error code here
In general, the page says such issue could be caused by following error:
The Task Scheduler service is disabled
The COM service is disabled
The Windows Event Log service is disabled
The RPC service is disabled
There is not enough free memory
Non of above is true for my system.
So what's error with my scheduled task? How could I make it work?
It looks like all your services are not setup. It's a common problem on things that run on startup/login. There's a -RandomDelay parameter to New-ScheduledTaskTrigger. I recommend you tinker with that if its your own machine you are testing this with. My example uses 1 minute.
$TaskTrigger = New-ScheduledTaskTrigger -AtStartup -Delay (New-TimeSpan -Minutes 1)
If you want a minute or so, all the services needed should be started up by then.
Another thing you'll want to do is have the your code in a try/catch, so the error is being written out to a log file, so you can see the error in the context of PowerShell, which might provide a more detailed message than what you are getting in the event log.
You can troubleshoot this by creating the scheduled task manually and then trying to run it.
Try changing the TaskActionArgument property to only the following string:
-NoProfile -ExecutionPolicy Bypass -File C:\users\administrator\updatescript\boxstarter.ps1
You don't need Start-Process or -Verb runas. In fact, -Verb runas will actually keep things from working, because it provokes a UAC prompt, which you don't want when trying to automate.
I'm trying to create a Powershell script that will be deployed to any node that is showing bad update health to automate some of the simple tasks without having to interrupt users during their workday. The Powershell script works perfectly if ran from an elevated PS prompt. It also runs fine when the same script is deployed to a test machine via SCCM with one exception: it won't call SFC.EXE /SCANNOW.
I've tried using:
Start-Process -FilePath "${env:Windir}\System32\SFC.EXE" -ArgumentList '/scannow' -Wait -NoNewWindow
Start-Process -FilePath "sfc.exe" -ArgumentList '/scannow' -Wait -NoNewWindow
Start-Process -FilePath "${env:Windir}\System32\SFC.EXE" -ArgumentList '/scannow' -RedirectStandardOutput "C:\SFC-Out.log" -RedirectStandardError "C:\SFC-Err.log" -Wait -NoNewWindow
& "sfc.exe" "/scannow"
Invoke-Command -ScriptBlock { sfc.exe /scannow }
Again, all of these examples work exactly as intended when run from an elevated PS prompt, but fail when run from the deployed PowerShell script. When I used the -RedirectStandardOutput, I checked the file SFC-Out.log and it read:
"Windows Resource Protection could not start the repair service"
I think this is because SCCM runs programs/scripts in the SYSTEM context instead of a user context (or even an elevated user context, but SYSTEM is supposed to be higher than an elevated session).
Is there a way to accomplish this? Sorry for the bad formatting, this is my first post on this site.
A bit late but I encountered the same issue. Not sure if this is the case for you but the cause was configuring the deployment of the script with SCCM to run as a 32 bit process. The script was being deployed to 64 bit systems. When I unchecked "run as 32 bit process" in the deployment configuration SFC worked without an issue under the context of a System account.
I created a package (not an application) in SCCM and had to use the redirect using the elusive sysnative folder for x64 machines:
https://www.thewindowsclub.com/sysnative-folder-in-windows-64-bit
So it would be:
C:\Windows\Sysnative\SFC.EXE /SCANNOW
What you have will work, just missing "-Verb RunAs" to elevate permissions. So your cmdlet should read:-
Start-Process -FilePath "${env:Windir}\System32\SFC.EXE" -ArgumentList '/scannow' -Wait -Verb RunAs
I've been reading and searching online for this, the only answer so far is that It can't be run due to sccm using the system account. It's also the same behavior when trying to run winmgt.
Fast forward to SCCM Current Branch 2109 and I was able to solve this problem by using the new Scripts feature built into SCCM. Using & 'sfc.exe' '/scannow' works, and I can manually run this script against any device collection showing devices in error. Start-Process -FilePath "sfc.exe" -ArgumentList "/scannow" -NoNewWindow -Wait works too.
I am trying to have a power shell script resume after a reboot. (I am rebooting to "apply" registry changes I have made") I believe I can accomplish what I want by making a registry edit to the Run Once key. I have looked at this question, but I can't get my similar code to execute at boot. The registry edit is made and at boot something runs because it disappears but it is not finishing the install.
$part2 = Get-ChildItem C:\Windows\ccmcache\ -Recurse -Force -Filter Full_Druva_Reinstall_part2.ps1
$FullPath = $part2.FullName
$KeyPath = "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce"
new-itemproperty -Path $KeyPath -Name !Install-Druva -propertytype String -value "Powershell -executionPolicy Unrestricted -File $FullPath"
Edit
This scrpit is inside a SCCM Package and any solution needs to automatic and require no user input.
Open task scheduler on general give a name> run wheter user logged in or not> trigger at startup>
action
program/script will be powershell.exe
arguments
-ExecutionPolicy Bypass -File "C:\myscripts.ps1"
I wasn't able to make the Run Once Registry work, plus it wouldn't tun with admin cred if a non admin logged in. I also wasn't able to make a schedule task in power shell because my environment is all Win7 and power shell v4.
The solution i used was making a task sequence in SCCM that ran part 1 of my script, restarted, and then ran part 2.
I am trying to use Chef to automate installation/deployment of an older version of a Windows product (Sharepoint 2007, specifically), and I almost have it working, but, at one point during the installation, the installer encounters an "application compatibility" problem and pops up a window that asks whether to continue or not. If I click to continue, the installation continues to the end, and it works properly.
I found a way to avoid the popup, by adding an "Appcompat" key in the windows registry, but if I use regedit to add the key during the Chef run, I have to get Chef to reboot the machine and then to continue with the rest of the installation afterwards.
I've tried a recipe with something like:
reboot 'Restart Computer' do
action :nothing
end
powershell_script "install-Sharepoint2007-PREREQUISITES" do
code <<-EOH
regedit /s .\appcompat.reg
EOH
notifies :reboot_now, 'reboot[Restart Computer]', :immediately
end
powershell_script "install-Sharepoint2007" do
code <<-EOH
... the rest of the installation....
EOH
notifies :reboot_now, 'reboot[Restart Computer]', :immediately
end
but the processing basically stops, after the reboot after setting the registry key.
So I was wondering: Is there a way to do this with Chef?
Thanks,
Jim
EDIT:
I find it hard to use just the comments because of lack of formatting so I'm adding information on what I have tried thus far here.
Basically, the only way I can get the chef-client to run in a scheduled task so far is to do a "ONCE" scheduled task, setting the time for the task to run (so far, I'm manually setting the time in my schtasks command, just to test).
When I do that, and set the "/RU" to SYSTEM, I can see the "chef-client -o" start to run and it actually seems to complete, but I see errors in the Sharepoint installer logs, and in particular, it appears that some of the steps in the psconfig (the Sharepoint command line configuration tool) are failing.
I think/guess that the reason for those failures is that the schtasks is running the "chef-client -o" as the wrong Windows user.
The thing is, if I run the "chef-client -o" on the 2nd part cookbook "manually", i.e., if I log into the Windows machine and type:
chef-client -o install-SHAREPOINT-PART2
Then, Sharepoint gets installed and configured correctly.
So, the thing I'm stuck on now is when I do that same "chef-client -o" command via schtasks, what should I use as the "/RU" and "/RP" for the schtasks command?
Thanks,
Jim
EDIT 2: Sorry, I forgot to include the schtasks line in the first cookbook/recipe, which sets up the task for the second cookbook/recipe chef run:
schtasks /create /tn Task_Name /tr "chef-client -o install-SHAREPOINT2007FULL-PART2" /sc once /RU "SYSTEM" /SD 06/27/2015 /ST 12:30
EDIT 3: The original reason that I was looking into this (having Chef work "through" a reboot) was that as part of installing Sharepoint, I had to set a Windows registry key, and I thought that I had to reboot to make that registry change effective for the rest of the install process.
However, I did some testing yesterday, and it appears that is not the case. I can make the registry change, then do the rest of the installation, without having to reboot in between.
So, bottom line is that I didn't need to process after the reboot after all.
But anyway, hopefully some of the info here may help someone later. The main thing I found was was I couldn't get it to work using ONSTART with the /Z /V1... I had to use the ONCE and would have had to have code in my Chef recipe to figure out the date and time to fire the ONCE tasks.
All in all I would say not as-is.
You have to tweak things to work there by doing a two pass run.
Your first pass will add the registry information, plan a chef-run in a few minutes (targetting after the reboot) if chef is not installed as a service, and reboot.
The second pass should go over the registry part and do the rest of the installation.
According to your code and assuming Chef is installed as an autostarting service on the node you could add just a guard to your powershell resource like this:
powershell_script "install-Sharepoint2007-PREREQUISITES" do
code <<-EOH
regedit /s .\appcompat.reg
EOH
notifies :reboot_now, 'reboot[Restart Computer]', :immediately
not_if registry_data_exists?(
KEY_PATH,
{ :name => "NAME", :type => TYPE, :data => VALUE },
ARCHITECTURE
)
end
Doc on the guards here and on the registry recipe helpers here
You can have chef run a scheduled task on start up to run chef.
windows_task 'Chef client' do
user 'SYSTEM'
command 'chef-client -L C:\chef\chef-client.log'
run_level :highest
frequency :onstart
frequency_modifier 30
action :create
end
Then when the node reboots, chef will run again.
Consider the following recipe that joins a windows computer to a domain, reboots, runs chef (as a scheduled task), then deletes the scheduled task.
https://github.com/NetDocuments/ad-join-cookbook/blob/master/resources/domain_join.rb
Update There is a RFC proposal to change the exit codes of chef to allow for intellegently handling reboots.
CHEF RFC #62
I have done it using FLAG file method, example given below.
Example of domain join-
---------------------------Script Start------------------------
powershell_script 'Domain_Join' do
guard_interpreter :powershell_script
code -domainJoin
$currentTime = Get-Date
$currentTimeString = $currentTime.ToString()
$systemDomain = (Get-WmiObject Win32_ComputerSystem).Domain
If (($systemDomain) -eq 'domainName')
{
Try {
write-host "$env:computerName is DOMAIN MEMBER"
Remove-Item C:\\DomainJoinFlag.txt -ErrorAction Stop
Unregister-ScheduledTask -TaskName "Chef client schedule_DJ" -Confirm:$false
} # end of Try
Catch [System.Management.Automation.ItemNotFoundException]
{ write-host "Server is already domain member, Or Exception raised due to either missing FLAG file or Server startup schedule task configuration."
eventcreate /t INFORMATION /ID 0909 /L APPLICATION /SO "ChefClient_$env:computerName" /D "Server is already domain member, Or Exception raised due to either missing FLAG file or Server startup schedule task configuration. Refer to the CHEF reciepie for DomainJoin or check Administrative credentials for creting schedule task"}
}
else { write-host "$env:computerName is NOT domain member, joining the server to the domain. Server will be rebooting in a while..."
eventcreate /t INFORMATION /ID 0909 /L APPLICATION /SO "ChefClient_$env:computerName" /D "Joining the server : $env:ComputerName to the domain ININLAB.COM (Server Time): $currentTimeString"
New-Item C:\\DomainJoinFlag.txt -type file -force
write-host "$env:computerName DOMAIN JOIN INITIATED for the server"
$cred = New-Object System.Management.Automation.PsCredential("domain\\domain_user", (ConvertTo-SecureString "Password" -AsPlainText -Force))
Add-Computer -DomainName "domainName" -Credential $cred -OUPath "OU=HyperV,OU=Infrastructure,OU=Servers,DC=domain,DC=name"
shutdown -r -t 120
} #end_of_else
domainJoin
notifies :run, 'windows_task[Chef client schedule_DJ]', :immediately
end
windows_task 'Chef client schedule_DJ' do
user 'SYSTEM'
command 'chef-client -L C:\chef\chef-client_after_reboot_domainJoin.log'
run_level :highest
frequency :onstart
frequency_modifier 30
action :create
only_if { ::File.exist?('C:\\DomainJoinFlag.txt') }
end
---------------------------Script Ends------------------------
Use rakefile to trigger the converge. You should also give some sleep time after windows reboot and re-converge again: Here's and example.
sh 'bundle exec kitchen converge'
sleep 120
sh 'bundle exec kitchen verify'