Azure Cloud Service Startup task that needs to run a PowerShell script - powershell

All,
Note: I have updated the question after some feedback.
Thanks to #jisaak for his help so far.
I have the need to run a PowerShell script that adds TCP bindings and some other stuff when I deploy my Cloud Service.
Here is my Cloud Service Project:
Here is my Cloud Service Project and Webrole project:
Here is my task in ServiceDefinition.csdef:
And here is the PowerShell script I want to run:
here is my attempt at the Startup.cmd:
When I deploy I get this in the Azure log:
And this in the powershell log:
Any help would be very much appreciated.
I think I am nearly there but following other people syntax on the web doesn't seem to get me there.
thanks
Russ

I think the issue is that the working directory of the batch command interpreter when it runs Startup.cmd runs is not as expected.
The Startup.cmd is located in the \approot\bin\Startup directory but the working directory is \approot\bin.
Therefore the command .\RoleStartup.ps1 is not able to find the RoleStartup.ps1 as it is looking in the bin directory not in the bin\Startup directory.
Solutions I know to this are:
Solution 1:
Use ..\Startup\RoleStartup.ps1 to call the RoleStartup.ps1 from Startup.cmd.
Soltuion 2:
Change the current working directory in Startup.cmd so that the relative path .\RoleStartup.ps1 is found. I do this by CHDIR %~dp0 (see here) to change into the directory that contains Startup.cmd.
Solution 3:
As Don Lockhart's answer suggested, do not copy the Startup directory to the output, instead leave it set as "Content" in the Visual Studio project. This means the files within it will exist in the \approot\Startup directory on the Azure instance. (You would then want to make sure that the Startup folder is not publically accessible via IIS!). Then update the reference to Startup.cmd in ServiceDefinition.csdef to ..\Startup\Startup.cmd, and update the reference to RoleStartup.ps1 in Startup.cmd to ..\Startup\RoleStartup.ps1. This works on the fact that the working directory is bin and uses ..\Startup to always locate the Startup directory relative to it.

You don't need to set the executionpolicy within your cmd - just call the script. Also, you should use a relative path because you can't rely that there is C disk.
Change your batch to:
powershell -executionpolicy unrestricted -file .\RoleStartup.ps1
Right click on the RoleStartup.ps1 and Startup.cmdin Visual Studio and ensure that the Copy to Output directory is set to copy always.
If this still doesn't work, remove the startup call in your csdef, deploy the service, rdp into it and try to invoke the script by yourself to retrieve any errors.
Edit:
Try to adopt your script as below:
Import-Module WebAdministration
$site = $null
do # gets the first website until the result is not $null
{
$site = Get-WebSite | select -first 1
Sleep 1
}
until ($site)
# get the appcmd path
$appcmd = Join-Path ([System.Environment]::GetFolderPath('System')) 'inetsrv\appcmd.exe'
# ensure the appcmd.exe is present
if (-not (Test-Path $appcmd))
{
throw "appcmd.exe not found in '$appcmd'"
}
# The rest of your script ....

I've found it easier in the past to not copy the content to the output directory. I have approot\bin as the working directory. My startUp task element's commandLine attribute uses a relative reference to the .cmd file like so:
The .cmd file references the PowerShell script relatively from the working directory as well:
PowerShell -ExecutionPolicy Unrestricted -f ..\StartUp\RoleStartup.ps1

Ok,
So I am coming back to this after many different attempts to make it work.
I have tried using:
Startup config in the ServiceDefinition.csdef
I have tried registering a scheduled task on the server that scans the Windows Azure log looking for [System[Provider[#Name='Windows Azure Runtime 2.6.0.0'] and EventID=10004]]
Nothing worked either due to security or the timing of events and IIS not being fully setup yet.
So I finally bit the bullet and used my Webrole.cs => public override bool OnStart() method:
Combined with this in the ServiceDefinition.csdef:
Now it all works. This was not the most satisfying result as some of the other ways to do it felt more elegant. Also, many others posted that they got the other ways of doing it to work. Maybe I would have got there eventually but my time was restricted.
thanks
Russ

Related

Powershell command to run for everyone

I am running into a problem with a PowerShell script. I want to add a Microsoft store app with a PowerShell command:
Add-Appxpackage -path C:\Temp\whiteboard.appx
The command is working fine, but only for 1 user not for everyone. It must be installed for everyone. How can that be done?
As #WafflesAndCustard already mentioned, the issue for executing the script is the ExecutionPolicy.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7
The PowerShell-Script Execution takes another road as you probably might think of ... PS-User-Policy takes precedence over PS-Computer-Policy, but Local- (gpedit) and Domain-Policies (gpmc) overrides anything and takes the final precedence (Domain policies have highest priority)
By default -> no PowerShell Script execution is allowed.
When you want to use your script for all users, without predefining the PS-executionpolicy, you should use the native command like
powershell.exe -ExecutionPolicy ByPass -Script ....
BUT, and that's really IMPORTANT when it comes to security:
Please don't use the temp folder as this is usual something everybody can write to!
E.g. a user/program can place a malicious executable file into that folder with same name and your task (or whatever) will execute it with high privileges.

Application cannot be executed when launch from a different folder

I have a third party application that has following two files in c:\sandbox folder.
SomeApplication.exe
SomeApplication.ini
The executable uses the ini file for various configuration settings. When I run this executable from the powershell command prompt after change my directory to c:\sandbox, all works great.
PS C:\sandbox> SomeApplication.exe
INFO: Its working great
However when I try to run same application without changing my directory to sandbox folder, it does not work.
PS C:\> .\Sandbox\SomeApplication.exe
ERROR: SomeApplication.ini could not be found
I try to do following before running the application
PS C:\> Set-Location -Path "C:\Sandbox"
But still get same error. Any idea what could be wrong?
The program assumes that it will be launched from the current directory and looks for the ini file using windows apis that search the current direction and the path. If you add it to the path it might work.

MSBuild from Powershell

I'm trying to run a Sync from MSBuild (From Powershell) that also includes Pre Sync Commands.
I am unable to get the commands right. I've tried multiple ways, but the final way I'm up to is :
[string[]]$msdeployArgs = #(
"-verb:sync",
"-preSync:runCommand='$preSyncCommand',waitInterval=30000",
"-source:dirPath=$sourceFolder",
"-dest:computerName=$serverName,userName=$username,password=$password,authType=basic,dirPath=$serviceFolder",
"-postSync:runCommand=$postSyncCommand,waitInterval=30000"
)
& "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" $msdeployArgs
I get the following error.
Error: Unrecognized argument
'"-preSync:runCommand='F:\Projects\Unleashed\Release_Scripts\WindowsServices\deployTopShelfServicePreCommands.cmd
Unleashed.Maintenance.JobScheduler
C:\MyCompany\Services\MyCompany.Maintenance.JobScheduler',waitInterval=30000"'.
All arguments must begin with "-".
Note that after the PreSyncCommand, is params that I want to pass to the CMD file (For it to know where to uninstall the existing service from etc.
I've ran that params via EchoArgs.exe, and the args are fine.
If it matters (It might), I'm running the powershell script from TeamCity.
I've found the issue. As it turns out, it isn't powershell with the issue, but MSDeploy. MSDeploy as far as I can see does not allow you to pass batch files with parameters. Removing the parameters works fine (But then you need to hardcode them in your batch file, or work out some other way of generating the bat files on the fly).

Startup Task not running on Azure Cloud Service role

I'm having difficulties trying to setup a startup task in an Azure role.
The ultimate goal is to disable RC4 cipher, along with other SSL configurations. In my (VS2012Express) project (solution partially achieved following another answer here in SO that led me to https://gist.github.com/sidshetye/29d6d48dfa0c2f5488a4 ) I created a Startup.cmd file like this:
# Execute powershell command to disable RC4 and imporve SSL security settings
ECHO Batch started >> "StartupLog.txt" 2>&1
PowerShell -ExecutionPolicy Unrestricted .\HardenSSL.ps1 >> log- HardenSSL.txt 2>&1
EXIT /B 0
HardenSSL.ps1 is the PowerShell script from the previous link. Both the .cmd and .ps1 scripts are placed in the application root directory, marked as "Content" with properties set to "CopyLocal=Always".
In my service definition, I put this:
<Startup>
<Task commandLine="Startup.cmd" executionContext="elevated" taskType="background"></Task>
</Startup>
Now, when I deploy the application to Azure, "nothing" happens. I configured the role instance to allow remote desktop, connected to the machine. I verified the scripts where published, and there were no log files, RC4 still enabled. I tried to manually run the .cmd and the machine runs the scripts to completion, disables RC4 and restarts. So the scripts are actually "correct".
The problem is that the scripts are not getting fired up at startup. I may be wrong, but I don't see anything related looking Windows events. Actually, the server now keeps all the configurations, but I have to be sure the scripts get executed in case I'll have to publish to new instances/cloud services.
I also tried to:
1. place the scripts on a child directory
2. create other 2 "simpler" .cmd that just create a log file with "script started" to exclude problems related to the .cmd calling the PowerShell script.
None of those scripts got executed.
Hope I've been sufficiently clear, any help would be greatly appreciated.
Thank you in advance,
Alberto
UPDATE 1
Reading through various discussions, I missed one very important thing: the script files are actually published in 2 distinct places, one being inside the /bin folder.
Ex: I placed my scripts in a /StartupScripts folder in my project, and when I connect via Remote Desktop to the Azure server I find the scripts both in "approot/StartupScripts" and in "approot/bin/StartupScripts".
The scripts the are actually executing are those placed inside the "bin" folder. the real problem is that I have probably a path problem inside the .cmd since I now found the execution logs with an error.
Now I will try to change it up and update the question here on SO.
Ok.
In the end it was indeed a problem with a path in my Startup.cmd file: .\HardenSSL.ps1 could not be found if the StartUp Task pointed to a subfolder.
Solution was to place both Startup.cmd and HardenSSL.ps1 files in the application root, remove the ".\" part when calling the PowerShell Script and all worked well.
Anyway, I would like to suggest anyone to pick this other solution I found in stack exchage:
https://security.stackexchange.com/a/79957
It links to a NuGet package that does the same thing as the script I found on the link to github in the original post, just "better"; mainly:
Better configuration of cipher suites, with support for ForwardSecrecy for all reference browsers on SSLLabs
Retain SSL support for Internet Explorer 8 on windows XP (unfortunately still a necessity for us)
Alberto.

MSBuild fails when run via Powershell

I have an MSBuild script that I want to call from a PowerShell script as part of a deployment process. If I call the build script via a bat file all works well. If I do the exact same thing in PowerShell I get CS1668 error looking for wierd and wonderful paths that dont exist on my machine.
I know I am getting into the MSBuild script as these errors are occuring from within the MSBuild script targets (logging output is showing this).
The bat file and the PowerShell script reside in the same place, right next to the build script.
Errors:
error CS1668 : Warning as error :
Invalid search path 'C:\Program
Files\Microsoft Visual Studio
8\VC\AtlMfc\Lib' specified in 'LIB
environment variable' -- 'The system
cannot find the path specified. '
error CS1668 : Warning as error :
Invalid search path 'C:\Program
Files\Microsoft Visual Studio
8\VC\PlatformSDK\Lib' specified in
'LIB environment variable'-- 'The
system cannot find the path specified.
'
I have checked and neiter of these paths do NOT exist on my machine.
Why would running from PowerShell change what paths MSBuild look for?
Thanks in advance
RhysC
EDIT- adding in code: NB the name of the MSBuild script is AutomatedDebug.build
POWERSHELL SCRIPT:
#Begining of script
$CurrentPath = Split-Path (Split-Path $myinvocation.mycommand.path )
#Assign the Build script paths. 1 is for building and testsing, 1 is for deployment (to keep things clean)
$MSBuildScriptBuildAndTestPath = $CurrentPath + "\Tools\AutomatedDebug.build"
$MSBuildScriptDeployPath = $CurrentPath + "\Tools\Deploy.build"
#Run the automated build with tests
Write-Host "*** Run the automated build with tests ***"
C:\Windows\Microsoft.NET\Framework\v3.5\MSbuild.exe $MSBuildScriptBuildAndTestPath "/t:AllTests" "/l:FileLogger,Microsoft.Build.Engine;logfile=AllTests.log"
if($LastExitCode -ne 0)
{
throw "AllTests failed"
}
Write-Host "*** FINISHED: Run the automated build with tests ***"
Bat File
#C:\Windows\Microsoft.NET\Framework\v3.5\MSbuild.exe AutomatedDebug.build /t:AllTests /l:FileLogger,Microsoft.Build.Engine;logfile="AllTests.log"
#pause
enter code here
Ok, what is actually happening is that I have dowloaded the Powershell Community Extensions (http://pscx.codeplex.com) many moons ago and there is a Environment.VisualStudio2005.ps1 file in there that adds EnvVars that dont exist. This is (I assume) becuase i dont use VS2005. I have commmented this out and all is well. I have tried to look for the 2008 equivilent but dint have too much luck. To be honest i dont use powershell to its full potential so i doubt i even need the PSCX on my machine anyway.
Thanks guys for your help.
It is most likely due to how you are passing parameters into the MSBuild script. There are some key parameter parsing differences between CMD and PowerShell and by using a batch file, you are implicitly using CMD's parameter parsing engine to hand off the parameters to MSBuild. If you post the command line you're using, one of the PowerShell gurus here can probably help debug where the parameters are getting confused.
I am wondering, basically you get "Warning as error" here. You can either try turning off treating warnings as errors (I mean, having a lib path which doesn't exist doesn't sound that bad to me) or you'll let your scripts print out the respective environment variables (using echo %LIB% and $Env:LIB respectively) from the scripts and look for differences.
However, since the envvars for VS aren't set globally by default (that's why there are the three Visual Studio command prompts) you have to set all variables somewhere. If you're doing this within the scripts you may have a typo somewhere?