2

So I have some powershell I'm trying to use to setup a Scheduled Task during an ADO deployment. In order to get the task set to "Run whether user is logged on or not" I am required to create it using a User and Password according to these:

Set a Scheduled Task to run when user isn't logged in

Schedule task creation with option ""Run whether user is logged in or not"" using powershell

https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtaskprincipal?view=win10-ps

And several others.

So with the security rules of the company all passwords from ADO have to be in secret variables. These do not decrypt when called basically from within the scripts, you'll get null values. According to these, you have to pass them in as Environment Variables and/or Parameters to the script:

https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=classic%2Cbatch

https://github.com/Microsoft/azure-pipelines-tasks/issues/8345

VSTS: Pass build/release variables into Powershell script task

https://github.com/microsoft/azure-pipelines-agent/issues/145

https://adamtheautomator.com/azure-devops-variables-complete-guide/

Many of these also only show the yaml side, but I'm using classic so this is of no use and I suspect irrelevant based on the next link which then contradicts them saying you can only use parameters on file base scripts and not inline:

https://github.com/MicrosoftDocs/vsts-docs/issues/1083

I have setup an Environment Variable per the MS link on variable usage as part of the ADO step where by i have a name and a value defined as $(mySecret).

I have tried accessing this through various means described in the links above:

$MYSECRET

$env:MYSECRET

$($MYSECRET)

$($env:MYSECRET)

$(MYSECRET)

$(env:MYSECRET)

(All of the following with both Param and param)

param([string]$mySecret)

param($mySecret)

param($MYSECRET)

param($env:mySecret)

param($env:MYSECRET)

All of these return a "Param is not a recognized function" which according to these, is usually due to param not being the first word in the script, which is not the case for me, I have already checked, double checked, pulled out the text to notepad, notepad++ (both just in case) and compared, and verified it is really the very first word in the script:

PowerShell 2.0 and "The term 'Param' is not recognized as the name of a cmdlet, function, script file, or operable program"

PowerShell parameters - "The term 'param' is not recognized as the name of a cmdlet"

powershell unable to recognize parameter

I've even tried to copy and paste some of the Param solutions suggested above, even from the ADO git, and they all fail for this. I believe because of the git issue 1083 linked above.

None of the suggestions or answers from any of the links I've posted have worked.

One of the other links I came across had a suggestion to create up to three other deployment steps for creating variables, pulling them from the ADO environment, executing direct decryption and assignment. Completely over the top for what I believe should be required here. Another suggestion was to create an extra step to create a temp function to pull the secret and parse it with substring with a couple of different start and end values and to piece those back together as apparently the substring function could see beyond the encryption. Even if that did work, that is ridiculous. As such I haven't tried these last 2 suggestions. If that's really the case I would like someone to point me to the git docs stating as such or there needs to be a bug written up on it.

I'm simply at a loss. I just need to access a secret variable in an inline powershell script for a single task during and ADO deployment, does anyone know how to achieve this. Note the task creation code below does work when I use plain text inputs for the user and password, but that's against policy so not an option.

Here is my script:

param($taskPass)

$taskName = $env:ScheduledTaskName
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }

if(!$taskExists) {
     $Trigger = New-ScheduledTaskTrigger -Daily -At 3am
     $Actions = (New-ScheduledTaskAction -Execute "powershell curl -Method POST -Uri $env:VarURL"),
                (New-ScheduledTaskAction -Execute "powershell Invoke-Sqlcmd -ServerInstance $env:Server -Database 'MyDB' -Query 'EXEC NightlyProc'")

    #The following was suggested from here http://duffney.io/Create-ScheduledTasks-SecurePassword
     $SecurePassword = "$taskPass"
     Write-Host "Pass: $SecurePassword"
     $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $env:ScheduledTaskUser, $SecurePassword
     $Password = $Credentials.GetNetworkCredential().Password 

     $Task = New-ScheduledTask -Action $Actions -Trigger $Trigger
     $Task | Register-ScheduledTask -TaskName $taskName -User $env:ScheduledTaskUser -Password $Password
} 
Zexks Marquise
  • 1,497
  • 14
  • 18
  • Very interested to see how this one gets resolved. – Matthew Feb 20 '20 at 03:28
  • @Jawad Yes this is a release of a pipeline on Azure. I'm using secrete variable in several other places of this release, both in the direction of SQL script execution as well as in the config options of the ASP application this is servicing. As it states in the part you quoted "Making them availabe to tasks in the pipeline." This is a task in the pipeline. And to the second part I know. as stated in the part where I linked 5 sites saying they need to either be in parameters to the script or assigned to an environment variable per the microsoft link under the "Set Secret variables" section. – Zexks Marquise Feb 20 '20 at 03:45
  • @Jawad It's not in the middle of the script it is the very first word of the script. As shown in the code above. – Zexks Marquise Feb 20 '20 at 03:46
  • This sounds like a file encoding problem. I can replicate your error when I save a similar script as PC UTF-16 or UTF-16BE without a BOM header (using TextPad). If I include the BOM header, or save the file with encoding DOS, ANSI, or UTF-8, it seems to work without the param() error. Hope this helps. – leeharvey1 Feb 20 '20 at 12:27

2 Answers2

2

Ok so I finally worked this out. I used the YAML viewer to get a comparison of what the classic interface was creating vs what the MS link said it should be. This involved setting the Environment Variable to the value in the $(mySecret) format (no $env: here just the variable name). Then in the script using the $env:MYSECRET formatting. But also without all of the credential/password manipulation from the duffney.io site. Just setting the -Password parameter for the new Task directly to the $env:MYSECRET variable. No need for params. Task created as 'Run even when user not logged on' just as expected. Final code:

$taskName = $env:ScheduledTaskName
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }

if(!$taskExists) {
     $Trigger = New-ScheduledTaskTrigger -Daily -At 3am
     $Actions = (New-ScheduledTaskAction -Execute "powershell curl -Method POST -Uri $env:URL"),
 (New-ScheduledTaskAction -Execute "powershell Invoke-Sqlcmd -ServerInstance $env:Server -Database 'MyDB' -Query 'EXEC NightlyCache'")

     $Task = New-ScheduledTask -Action $Actions -Trigger $Trigger
     $Task | Register-ScheduledTask -TaskName $taskName -User $env:ScheduledTaskUser -Password  $env:TASKPASS
} 

Making sure to set an Environment Variable to the following values:

NOTE: CAPS on the name are not necessary here, seems to just be a standard. I've successfully deployed with both the CAPS version and 'TaskPass'. I say this because several of the links I posted above make it seem like they are.

Name: TASKPASS

Value $(ScheduledTaskPass)

Also of note that MS does it's best to hide this value from you. Even if you set it to a local script variable and try to output the value, as I was trying to do for confirmation purposes, you'll still only get asterisks. But it's really there, I/they promise.

Zexks Marquise
  • 1,497
  • 14
  • 18
0

In classic type, In order to access secret variable in inline powershell script,

step1:Define a variable and set it secret variable(using lock icon)( for ex Name: PASSWORD value: ********)

step2: Add/set an Environment variable(below inline script available as an option) to remap your secret variable[since you can't access secret variables directly in scripts(ref: MSdocs)] like for ex Name: PASSWORD value: $(PASSWORD)

step3: While using this variable in script access like $env: PASSWORD

Swetha
  • 11
  • 1