Access Denied on Powershell Start-Process within AzureDevOps task - powershell

I have an Azure DevOps task which needs to execute a Powershell script on a VM. The inline script generates a credential which is used as a parameter for the Powershell process being started.
- task: AzureCLI#2
inputs:
azureSubscription: 'MySubscription'
scriptType: 'ps'
scriptLocation: 'inlineScript'
inlineScript: |
az vm run-command invoke --command-id RunPowerShellScript --name $(MyVmName) -g My-RG --scripts `
"`$pw = ConvertTo-SecureString `"$(PasswordSecret)`" -AsPlainText -Force" `
"`$cred = New-Object System.Management.Automation.PSCredential 'Vm1\localadmin',`$pw" `
"Start-Process PowerShell -Cred `$cred -ArgumentList '-noexit','-File','C:\Users\localadmin\Documents\deploy.ps1'"
However, it appears that the Start-Process itself is getting Access Denied:
2021-04-21T22:15:29.6078202Z "message": "Start-Process : This command cannot be run due to the error: Access is denied.\nAt C:\\Packages\\Plugins\\Microsoft.CPlat.Core.RunCommandWindows\\1.1.8\\Downloads\\script11.ps1:3 char:1\n+ Start-Process PowerShell -Cred $cred -ArgumentList '-noexit','-File', ...\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n + CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException\n + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand"
The inline script below can be found on the vm and executed successfully using the same credentials that are used to generated the $cred. But, I'm guessing that since the DevOps task is running under a different, less privileged account, it doesn't have access to the Start-Process cmdlet.
Is there a way around this?
(Note: for several reasons beyond the scope of this post, I can't use the Powershell on Target Machines task, but I have in fact tried that.)

Are you running as a hosted agent? Are you using a deployment pool?
What I've tried is setting the local deployment agent service credentials on the machine- the service has a name like Azure Pipelines Agent. You can configure a Log On As account in the services pane and restart the service to enable the agent to run as that account.
This isn't a full answer but I can revisit and update based on your response and maybe we can figure out our problems together.
Edit: ** After a couple hours of labor I've unblocked myself by using .cmd instead of powershell. I discovered though that because the agents are running as services the .exe is not being launched unless in interactive mode. The deployment will continually 'run' while the .exe is running, otherwise. Instead of doing this, I decided to just reboot the computer using cmd and having the start up task run what I need.
Maybe your answer could be similar: place the script with the agent into the startup task, then reboot the computer and allow it to run it on it's own.

Related

Unable to change active subscription in yaml/Azure PowerShell pipeline

This is kind of continuation of the issue I faced in here
Let me give a backgroud. This is my yaml pipleine:
parameters:
- name: sub_name # name of the subscription; required
type: string
default: false
steps:
- script: echo "Here is subscription name:" ${{ parameters.sub_name }}
- task: AzurePowerShell#5
displayName: 'Launching Main.yml'
inputs:
azurePowerShellVersion: LatestVersion
azureSubscription: My-SPN # This is my almighty Service Principal
ScriptType: 'FilePath'
ScriptPath: '$(System.DefaultWorkingDirectory)/MyPowerShell.ps1'
ScriptArguments: -sub_name ${{ parameters.sub_name }}
and this is my MyPowerShell.ps1 file:
#param ($sub_name)
Get-AzContext -ListAvailable | Where{$_.Name -match $sub_name} | Set-AzContext
$SID=(Get-AzContext).Subscription.id
Write-Output "The active subscription SID is" $SID
No matter what value the $sub_name is given the output of $SID is always the Subscription Id of my service principal - "My-SPN"
How should I set AzContext properly so it changes active subscription?
The same PowerShell script works fine in Azure CLI but not when yaml has got service principal.
I tried to use Set-AzContext -Subscription $sub_name -TenantId 2a1c169e-715a-412b-b526-05da3f8412fa but ended up with following error:
Starting: Launching Main.yml
==============================================================================
Task : Azure PowerShell
Description : Run a PowerShell script within an Azure environment
Version : 5.209.0
Author : Microsoft Corporation
Help : https://aka.ms/azurepowershelltroubleshooting
==============================================================================
Generating script.
========================== Starting Command Output ===========================
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a_temp\adfb7562-7db5-4be6-ae08-dca4664e460c.ps1'"
Added TLS 1.2 in session.
Import-Module -Name C:\Modules\az_7.5.0\Az.Accounts\2.9.1\Az.Accounts.psd1 -Global
WARNING: Both Az and AzureRM modules were detected on this machine. Az and AzureRM modules cannot be imported in the
same session or used in the same script or runbook. If you are running PowerShell in an environment you control you can
use the 'Uninstall-AzureRm' cmdlet to remove all AzureRm modules from your machine. If you are running in Azure
Automation, take care that none of your runbooks import both Az and AzureRM modules. More information can be found
here: https://aka.ms/azps-migration-guide
Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue
Clear-AzContext -Scope Process
Connect-AzAccount -ServicePrincipal -Tenant 2a1c169e-715a-412b-b526-05da3f8412fa -Credential System.Management.Automation.PSCredential -Environment AzureCloud #processScope
Set-AzContext -SubscriptionId 72245732-XXXXXXX -TenantId 2a1c169e-XXXXXXXX
##[error]Please provide a valid tenant or a valid subscription.
##[error]PowerShell exited with code '1'.
Added TLS 1.2 in session.
Finishing: Launching Main.yml
Please help on how to change an active subscription either in a yaml or in powershell file.
Thanks.
AzurePowerShell task uses Service Principal to authenticate and access Azure resources. Therefore, your service principal needs to have subscription owner or contributor permission.
Like #ZiyangLiu-MSFT mentioned above the service principal I was using hasn't had enough rights on the subscription. Changed it to the one which have had proper permission and this resolved the issue.

az cli login session scope to process

In PowerShell you can do the following:
$result = Connect-AzAccount `
-SubscriptionId $SubscriptionId `
-TenantId $TenantId `
-Credential $credential `
-ContextName $contextName `
-Scope Process `
-ServicePrincipal
As per the doc, if you specify the -Scope Process the Az Context will be bound to that specific PS Process.
Determines the scope of context changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
Is there any way of replicating this behaviour with az cli?
My use case
I will connect to Azure from a Jenkins job. If I start two jobs, maybe one of them will disconnect via az logout -u <user> and affect the other job.
I would like to isolate the az cli session.
I haven't personally used it yet, but according to this GitHub issue which links to this documentation, it should be possible using a process scoped environment variable.
Unfortunately, there is not such an equivalent feature as -Scope Process in Azure CLI, all the available parameters here.
https://learn.microsoft.com/en-us/cli/azure/reference-index?view=azure-cli-latest#az_login

Azure Devops Connect to SharePoint Online tenant - Connect-SPOService cmdlet timing out

Been working with using Azure DevOps to automate some PowerShell scripts against SharePoint Online. From what I understand, my first step needs to be getting authenticated against that tenant. So here's what I've got so far:
trigger:
- master
pool:
vmImage: 'windows-latest'
steps:
powershell: Install-Module -Name Microsoft.Online.SharePoint.PowerShell -RequiredVersion 16.0.8029.0 -force
displayName: 'Install SP Online PowerShell'
powershell: $cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $env:USERNAME, $(convertto-securestring $env:PASSWORD -asplaintext -force)
displayName: 'form the credentials var from previous vars'
powershell: Connect-SPOService -Url https://$env:ORG-admin.sharepoint.com -Credential $cred
displayName: 'connect to Tenant'
Environment variables username, password, and org are defined at the pipeline and seem to be working correctly (as in, I was getting different errors before deploying those). Now, I get to the final step and it just runs forever until I cancel it. It's as if it's getting some prompt on Connect-SPOService that, of course, I can't see, and so I can't respond to.
There are no errors to react to, just sits and spins and doesn't finish. My last error was that connect-sposervice wasn't a recognized cmdlet. To resolve that, I worked on my install-module command and got that resolved, so it seems like it's running that command properly now (no errors).
I can run all the same powershells from my local machine and get there without prompts or having to enter anything extra.
Anyone have any ideas?
Thanks!
It seems that you're following this document to connect to Sharepoint online.
Note: When prompted with the Windows PowerShell credential request dialog box, type the password for the SharePoint Online SharePoint administrator account.
When using Microsoft-hosted agent to run the PowerShell task, we can't access the UI to enter password in dislog box. So this is not supported way.
Instead, you may get help from these two documents: Installing the Office 365 CLI and Connecting to SharePoint Online.

Get-CrmConnection failing when executed from non-admin context (3.3.0.857)

I'm trying to execute Get-CrmConnection to connect to Dynamics 365 from Powershell, but the command returns the following when executed from a non-administrative Powershell context:
Get-CrmConnection -ConnectionString "AuthType=Office365;Username=xxx;Password=xxx;Url=https://xxx.crm.dynamics.com"
Get-CrmConnection : Failed to connect to CRM: Unable to Login to Dynamics CRM
At line:1 char:1
+ Get-CrmConnection -ConnectionString "AuthType=Office365;Username=crm_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [Get-CrmConnection], Exception
+ FullyQualifiedErrorId : -10,Microsoft.Xrm.Tooling.CrmConnector.Powershell.Commands.GetCrmConnectionCommand
I have version 3.3.0.857 of the connector installed.
Additional Info
If I execute the same command within the context of an Administrator prompt, I'm able to connect without issue.
I need this command to work outside of an Administrator context because this script will be called as part of an Azure DevOps pipeline. When executing this code within the pipeline, hosted in Azure DevOps, the same issue occurs.
I was able to find a solution to my issue that doesn't involve elevating to Admin.
Using the -Verbose option when running Get-CrmConnection, I saw that the error that was occurring was that the connection was being forcibly closed by the host. After a little Googling, I ran across this forum post. The last post had a suggestion to try adding this to my script:
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
I tried that and now everything works, admin or not.
You can run any script in elevated mode with the following:
$script = "-file C:\crmscript.ps1"
Start-Process powershell -Verb RunAs -ArgumentList $script
You can get valid verbs for any process using the System.Diagnostics.ProcessStartInfo object under the verbs property. Which, in this case, RunAs is a valid verb to start the powershell process in elevated mode.
You can then incorporate this into your Azure Pipelines/DevOps.
Hope this helps!

teamcity powershell - unable to run batch file

I've spent quite a bit of time banging my head on this one. A little StackOverflow help please, good folks!
Scenario: We are trying to run a custom .bat file located on the CI server via the TeamCity Powershell step.
When powershell script is run on local box manually, it kicks off .bat file correctly.
When powershell script is run through TeamCity, it successfully 'sees' the .bat file (validated by receiving a 'cannot find file' response when I rename the .bat file it is expecting)
HOWEVER, we have not seen any indication that the .bat file was actually kicked off.
What we've tried:
We've added the 'RedirectStandardOutput' and 'RedirectStandardError' for attempt to diagnose, but although the log file is created, it is returned blank.
We've granted filepath permissions and tried two different credentials including the credential of the TC build agent
Added "-wait" at one point to see if we needed to 'tell' PS to wait on the .bat file.
Two questions...
What is preventing us from running this .bat file?
How do we diagnose issues like this? ATM it is a 'blackbox' to us.
TeamCity Powershell settings:
Powershell Run Mode: Version 1.0; Bitness x64 (tried x86 as well)
Working Directory: Tried as blank, and specific filepath of .bat file (so, 'D:\folder\folder2\')
Script: Source Code
Script Execution: Execute .ps1 from external file (tried with 'Put script into PowerShell stdin with "-Command -" argument' as well)
Add -NoProfile argument (tried both)
Powershell script:
#Predefine necessary information
$Username = "DOMAIN\username"
$Password = "password"
$ComputerName = "CI Build Server Name"
#Create credential object
$SecurePassWord = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $Username, $SecurePassWord
#Start batch file
Start-Process "testbat.bat" -WorkingDirectory D:\file\path\ -Credential ($Cred)-NoNewWindow -RedirectStandardError stderr.txt -RedirectStandardOutput stdout.txt
Write-Host "Executed powershell."
UPDATE 1: If we remove the '-Credential ($Cred)' portion we are able to kick off the testbat.bat file from TeamCity, as expected. The problem must lie with that "-Credential ($Cred)" argument, somehow. Any thoughts?
UPDATE 2: If we set the '-Credential ($Cred)' portion to the credential of the build agent user we are able to kick off the test.bat file from TeamCity. The problem only occurs when we set the credential to a user other than the one running the build agent. This seems to indicate that credential syntax is fine.
UPDATE 3: Tried running with PowerShell executionpolicy set to 'RemoteSigned' and 'Unrestricted'. Problem persists.
UPDATE 4: Gave the BuildAgent user, and the user of whom we want to run this as, full permissions to powershell via 'Set-PSSessionConfiguration'. Problem persists.
$credential = New-Object System.Management.Automation.PsCredential(".\user", (ConvertTo-SecureString "pass" -AsPlainText -Force))
Start-Process powershell -Credential $credential -ArgumentList '-noprofile -command &{Start-Process D:\file\path\test.bat -NoNewWindow -RedirectStandardError stderr.txt -RedirectStandardOutput stdout.txt }'
note:
first i get credential "user" ur user then convert your pass to plain text
then start-process with your credential set
If agent is running as service under Local System account, then it's not possible to run PowerShell under specified account. The workarounds are:
Run agent via command line.
Try to run agent service under another account (not Local System) with administrator rights, probably it will help.
Try RunAs plugin. It provides an ability to run builds under the specified user account.