Jenkins -> powershell Invoke-WebRequest with UseDefaultCredentials - powershell

I try to execute a PowerShell script on the Jenkins slave. It looks like:
stage ("Get") {
steps {
powershell(
script: '''
$srcCommonParams = #{
Method = 'GET'
Uri = $getUri
}
Invoke-WebRequest #srcCommonParams -UseDefaultCredentials -Verbose
The question is where the default credential comes from? I thought that they are the ones on which behalf my Jenkins slave windows service runs on. The problem is that my Jenkins slave runs as user A, but Invoke-WebRequest complains that user B doesn't have sufficient privileges to do a request.

You have to get credentials from Jenkins.
You have to add 'withCredentials' and in powershell similar to this:
stage ("Get") {
steps { withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'your-credentials-id',usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']])
powershell(
script: '''
$encryptedPassword = ConvertTo-SecureString "%PASSWORD%" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("%USERNAME%", $encryptedPassword)
$srcCommonParams = #{
Method = 'GET'
Uri = $getUri
}
Invoke-WebRequest #srcCommonParams -Credential $mycreds -Verbose

Related

Authenticate to Azure DevOps without user's DevOps PAT

Currently we use an approach to reach DevOps and trigger "release pipelines" from a specific VM1 by utilizing user's DevOps PAT. We run PowerShell commands below at VM1:
$userPatToken = "xxxdfdgklfdgofkglfg4565gfhgfhgfh4gf54h54545fhfghfdffg"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "", $userPatToken)))
$url = "https://vsrm.dev.azure.com/MyOrg/MyProject/_apis/release/releases?definitionId=7&$top=100&api-version=6.0"
Invoke-RestMethod -Method Get -Uri $url -ContentType "application/json" -Headers #{Authorization = ("Basic {0}" -f $base64AuthInfo) }
The user is AAD one, is there a way to use it's let say AAD credentials and authenticate to DevOps and do the same?
Or may there is a way to use VMs system managed (or any user managed) identity to authenticate into DevOps and trigger release pipelines? We do not want to be dependent of the user's PAT.
It should be written in PowerShell.
If you don't want to use the PAT, you can install Az powershell module, login with a user account which has the permission in your devops org via Connect-AzAccount.
Then, you can get the token via below command. Please note don't change the 499b84ac-1321-427f-aa17-267ca6975798 in the script, it is the well-known resource id of the DevOps REST API.
$token = (Get-AzAccessToken -ResourceUrl "499b84ac-1321-427f-aa17-267ca6975798").Token
Then, you can pass the token to your powershell script. You can find more details/sample script here.
Edit:
Add username&Password automation script sample:
Install-Module -Name Az -Confirm:$False -Force -AllowClobber
Import-Module Az
$username = "useremail"
$password = "password"
$SecurePassword = ConvertTo-SecureString "$password" -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($username, $SecurePassword)
Connect-AzAccount -Credential $credentials -TenantId yourTenantID
$token = (Get-AzAccessToken -ResourceUrl "499b84ac-1321-427f-aa17-267ca6975798").Token
$URL = 'https://dev.azure.com/{orgname}/{Projectname}/_apis/pipelines/{pipelineID}/runs?api-version=6.0-preview.1'
$header = #{
'Authorization' = 'Bearer ' + $token
'Content-Type' = 'application/json'
}
$body = #"
{
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/master"
}
}
}
}
"#
Invoke-RestMethod -Method Post -Uri $URL -Headers $header -Body $body

Checking remote PowerShell session information from within a function

I've written a PS function to set a mailbox to a shared mailbox. The function works by calling a remote PS session to the exchange admin PS using
$session = New-PSSession -configurationName Microsoft.Exchange -connectionURI xxxx -Auth xxx
Import-PSSession $session
this all works fine.
But when i call the function from my leavers script it always tries to load the $session even if its already been done, this throws verious issues, but fundamentally the script works fine.
So i added a check to see if the session was already in place by using
If(($session.state -eq "closed") -or (!($session))){then load session}
but it seems to think the session doesn't exist and tries to re-import the session causing the errors. If i put a write-host $session before the IF statement it returns $null, so i don't understand why i get the error about the session already been in memory.
if i run the script outside of the function i get the expected behaviour of not loading the session if its already been loaded.
i could add a close session at the end of the function, but its not as efficient having to re-load it every time it runs.
this is the function
Function SetMailbox-ToShared {
#This function sets the mailbox to type shared
Param(
[Parameter(Mandatory=$true)]
$upn
)
#Get password details for on premises service account
# Application (client) ID, tenant Name and secret
$clientId = "xxx" #application ID
$tenantName = "xxx"
$clientSecret = "xxx"
$ReqTokenBody = #{
Grant_Type = "client_credentials"
Scope = "https://vault.azure.net/.default"
client_Id = $clientID
Client_Secret = $clientSecret
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
$secretURL = "https://xxx/secrets/xxx?api-version=2016-10-01"
$secretValue = (Invoke-RestMethod -Headers #{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $secretURL).value
$exchUserName = "xxx"
$exchpwdTxt = "$secretValue"
$exchangeConnectionURI = "http://xxx/PowerShell/"
If(($session.state -eq "Closed") -or (!($session))){
$securePwd = $exchpwdTxt | ConvertTo-SecureString -asplaintext -force
$credObject = New-Object System.Management.Automation.PSCredential -ArgumentList $exchUserName, $securePwd
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $exchangeConnectionURI -Authentication Kerberos -Credential $credObject
Import-PSSession $Session
}
Try{
Set-RemoteMailbox $upn -type Shared
}
Catch{
Write-Host -ForegroundColor Red "Error setting mailbox for $upn to type shared. The error was $_"
}
}
Which i then call from my main script using setmailbox-toshared -upn xxx.xxx#xxx.com
i hope i've explained that ok?

-UseDefaultCredential vs. -Credential in PowerShell (401 Error)

I am writing a script in PowerShell that is testing login credentials to a target SharePoint 2013 URL that are passed through to an Invoke-WebRequest command that calls the URL in question. When I use -UseDefaultCredential, the returned status is a 200, but when I replace that and try the following code passed in to a -Credential property of the same command, I get a 401 error:
[string][ValidateNotNullOrEmpty()] $userPassword = "password"
[SecureString] $userPassword = ConvertTo-SecureString -String $userPassword -AsPlainText -Force
[PSCredential] $userCredential = New-Object -TypeName
System.Management.Automation.PSCredential("userName", $userPassword)
Invoke-Webrequest -Credential $userCredential -uri "https://connect.adler.edu"
powershell -noexit
Any thoughts as to why I'm getting the 401 Error when using the -Credential property? Thank you!

Problem to connect to TFS with user/password

When I try to connect to tfs the function Get-Data failed with 401 error although the function Get-DataWithCred succeed with the same argument.
And don't understand the difference with this two ?
function Get-Data([string]$username, [string]$password, [string]$url)
{
# Step 1. Create a username:password pair
$credPair = "$($username):$($password)"
# Step 2. Encode the pair to Base64 string
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair))
# Step 3. Form the header and add the Authorization attribute to it
$headers = #{ Authorization = "Basic $encodedCredentials" }
# Step 4. Make the GET request
$responseData = Invoke-WebRequest -Uri $url -Method Get -Headers $headers
return $responseData
}
function Get-DataWithCred([string]$username, [string]$password, [string]$url)
{
$p = ConvertTo-SecureString -String $password -AsPlainText -Force
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $p
$responseData = Invoke-WebRequest -Uri $url -Method Get -Credential $Cred
return $responseData
}
The purpose is too connect through tfs with python script who failed the same way that the function Get-Data when I use the requests library.
>>> r = requests.get('https://tfs-url.com', auth=('user', 'pass'))
>>> r.status_code
401
Looks like there is a problem with $encodedCredentials.
Take a look at Choosing the right authentication mechanism
For my script who connect to TFS i use the following code :
$strUser = 'domain\userID'
$password = "YOURPASSWORD"
$strPass = ConvertTo-SecureString -String $password -AsPlainText -Force
$cred= New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($strUser, $strPass)
And than connect to the TFS as you did :
$responseData = Invoke-WebRequest -Uri $url -Method Get -Credential $cred
Or, If you would like to connect to the TFS with the user who runs the script you can use
-UseDefaultCredentials
code snippet :
$responseData = Invoke-WebRequest -Uri $url -Method Get -UseDefaultCredentials
You need to use a microsoft way to pass your credential : the ntlm protocol.
This protocol are not supported by default by requests but a library requests_ntlm extend requests by adding support to ntlm.
A simple example:
import os
import requests
from requests_ntlm import HttpNtlmAuth
def main():
user = "user"
password = "password"
session = requests.Session()
session.auth = HttpNtlmAuth(user, password)
url = "https://tfs-url.com"
response = session.get(url)
print(response)
if __name__ == "__main__":
main()

Login to power bi service online (silently i.e. without the popup) using powershell

I would like to login to Power BI Online service and remove rows from a dataset using the REST API. I have the rest of the code going fine but the login seems to not work. This is what I tried. Can someone help me please? Thank you!
$pbiUsername = "abc.xyz#xxx.com"
$pbiPassword = "Password"
$clientId = "a81b2cc1-4c97-2323-bal4-eeb21c4c6e46"
$body = #{"resource" = "https://analysis.windows.net/powerbi/api"
"client_id" = $clientId;
"grant_type" = "password";
"username" = $pbiUsername;
"password" = $pbiPassword;
"scope" = "openid"
}
$authUrl = "https://login.windows.net/common/oauth2/token/"
$authResponse = Invoke-RestMethod -Uri $authUrl –Method POST -Body $body
$headers = #{
"Content-Type" = "application/json";
"Authorization" = $authResponse.token_type + " " +
$authResponse.access_token
}
$restURL = "https://api.powerbi.com/v1.0/myorg/groups"
$restResponse = Invoke-RestMethod -Uri $restURL –Method GET -Headers $headers
"Login doesn't seems to work" doesn't give us enough information to hint you what is the problem.
I will recommend you to use the official Microsoft Power BI Cmdlets to do tasks like this. It has big advantage - you don't need to register an application to use it. Here is how your code would look like in this case:
Import-Module MicrosoftPowerBIMgmt
Import-Module MicrosoftPowerBIMgmt.Profile
$password = "Password" | ConvertTo-SecureString -asPlainText -Force
$username = "abc.xyz#xxx.com"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/tables/xxxxxx/rows' -Method Delete
Disconnect-PowerBIServiceAccount
Since PowerBI now has enabled the Service Principal, you don't need to worry about the username and password and more importantly, you DON'T NEED PRO Licenses
using the Service Principal you can now able to log in without popup as well as username, password
$applicationId = "xxxxxxxx";
$securePassword = "xxxxxx" | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $applicationId, $securePassword
Connect-PowerBIServiceAccount -ServicePrincipal -Credential $credential -TenantId "xxxx"
The error is not handled with try catch - you still get the same error with this:
try {Connect-PowerBIServiceAccount} catch {"Boo"}
I follow the steps to fix this issue.
RESOLUTION
To resolve this issue, we need to install the correct module. It may not be the latest build, but the builds have to match in order for things to work for us. In my scenario, I installed the MicrosoftPowerBIMgmt.Workspaces 1.0.830 so that it matched the MicrosoftPowerBIMgmt.Profile.
I went to the PowerShell Gallery to get the Install-Module cmd.
https://www.powershellgallery.com/packages/MicrosoftPowerBIMgmt/1.0.326
From an Administrative Command-Prompt, type Install-Module -Name MicrosoftPowerBIMgmt.Workspaces -RequiredVersion 1.0.830
NOTE: Remember, for my lab scenario, I used the MicrosoftPowerBIMgmt.Workspaces Module. You will need to install the module that you are focused.
Once installed, close all PowerShell Windows or open a brand new PowerShell window and then type Get-Module. Now the installed modules should match.
NOTE: You have to start a new PowerShell session. If you don’t the error may not go away.
https://dastrongman.wordpress.com/2020/01/11/pbiwiki-login-with-the-power-bi-service-account/