AuthenticationContex missing method AcquireToken and CreateAuthorizationHeader - azure-ad-graph-api

I try to work with Azure AD.
This is the code I use:
Add-Type -Path "D:\GraphAPI\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
# Change these three values to your application and tenant settings
$clientID = "CLIENT ID for application"
$clientSecret = "KEY for application"
$tenant = "tenant domain name"
# Static values
$resAzureGraphAPI = "https://graph.windows.net";
$serviceRootURL = "https://graph.windows.net/$tenant"
$authString = "https://login.windows.net/$tenant";
# Creates a context for login.windows.net (Azure AD common authentication)
[Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext]$AuthContext = [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext]$authString
# Creates a credential from the client id and key
[Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential]$clientCredential = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential"($clientID, $clientSecret)
# Requests a bearer token
$authenticationResult = $AuthContext.AcquireTokenAsync($resAzureGraphAPI, $clientCredential);
# Output the token object
Write-Host -ForegroundColor Yellow "Token object:"
$authenticationResult | Format-List
# Example to get all users
Write-Host -ForegroundColor Yellow "Getting all users"
$users = Invoke-RestMethod -Method GET -Uri "$serviceRootURL/users?api-version=1.5" -Headers #{Authorization=$authenticationResult.CreateAuthorizationHeader()} -ContentType "application/json"
$users.value | Format-Table UserPrincipalName,DisplayName
But I have two errors
Method invocation failed because [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContex] does not contain a method named ‘AcquireToken’
Method invocation failed because [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContex] does not contain a method named ‘CreateAuthorizationHeader’
can you please help me to solve this errors?
Thanks or your help
Stefan

Sorry for the late response, but I just now had the same issue and found your question. I noticed that within Microsoft.IdentityModel.Clients.ActiveDirectory.XML for version 3.10.305231913 (the most recent), these methods were missing entirely, among some others. I grabbed version 2.26.305102204 instead via:
.\nuget.exe install Microsoft.IdentityModel.Clients.ActiveDirectory -Version 2.26.305102204
Everything seems to be in place in this older version.

string token =authContext.AcquireTokenAsync(resourceUri, clientID, new Uri(redirectUri), new PlatformParameters(0)).Result.AccessToken;
More information on below link:-
https://github.com/Microsoft/PowerBI-CSharp/issues/32

https://www.nuget.org/packages/microsoft.identitymodel.clients.activedirectory/2.19.208020213
The owner has unlisted this package. This could mean that the package is deprecated or shouldn't be used anymore.
Version doesn't exist ..

Related

Powershell and entering data

I am trying to automate checking tenant names using the o365.rock website. I want to enter the tenant name and click the button. however I keep getting errors when trying to put the data in the field.
My test code is:-
$site = "https://o365.rocks"
Start-Process "chrome.exe" $site
while ($site.Busy -eq $true){Start-Sleep -seconds 1;}
$input = $site.Document.getElementByID("INPUT");
$input.value = "testing";
I keep getting this error
You cannot call a method on a null-valued expression. At line:4 char:1
$input = $site.Document.getElementByID("INPUT");
I have inspected the elements and the field only has a tagname of "INPUT". The name & ID fields are blank.
Can anyone suggest what I am doing wrong or how else to do this?
You need to give the field ID name because you are using
site.Document.getElementByID
which is looking at the ID part of the field.
Or better use
$tag_name = document.getElementsByTagName("INPUT");
You can check for the availability of an Office 365 tenant name using the following code:
$TenantName = "contoso"
$URI = "https://tenantchecker.easy365manager.com/api/CheckTenantName/" + $TenantName
(Invoke-WebRequest -Uri $URI -Method GET -ContentType 'application/json').Content | ConvertFrom-Json
(source info: https://www.easy365manager.com/tenant-availability-checker/)

Powershell, EWS, OAuth2, and automation

I am trying to find documentation on how to implement non-interactive Oauth2 authentication to EWS using PowerShell, but I'm probably not using the correct search terms, because I can't find anything useful. The Microsoft documentation I can find on OAuth2 only has C# documentation.
So, does anyone know how to implement this?
No user input, should work with input that can be provided as script input
Should be in PowerShell, not C#
Details! Details! Not 'Now generate a login token', but the actual code to generate that token.
There’s a really good overview of this on the following blog:
https://ingogegenwarth.wordpress.com/2018/08/02/ews-and-oauth/#more-5139
I used the above blog to get it working in our PowerShell scripts - with a lot of trial and error. The following example script uses an applications's ClientID as registered in Azure AD. If you don't already have an application registered in Azure AD, you must do this first. There are various guides available on the web to register a new application in Azure AD. In order to utilise EWS with OAuth your registered application must have the correct permissions in Azure AD. You have two options for EWS:
Use Delegated Permissions and request the 'EWS.AccessAsUser.All' API permission in Azure AD - Legacy APIs | Exchange | Delegated Permissions | EWS.AccessAsUser.All (Access mailboxes as the signed-in user via Exchange Web Services). This permission gives your registered application the same access to Exchange mailboxes as the signed-in user. If you use this permission, the first time your application's ClientID is used by any Service or User Account to access Exchange Online, the account in question must approve the ClientID through an interactive pop-up notification. Therefore before using this script in an automated fashion, you must interactively access the Exchange Online Service using the ClientID of your registered application and approve the authorisation pop-up. The easiest way to do this is to log-in to a mailbox using Microsoft's free 'EWS Editor' application and specify your app's ClientID. Once your app's ClientID has been approved, your script can run fully automated without any interaction.
Use Application Permissions and request the 'full_access_as_app' API permission in Azure AD - Legacy APIs | Exchange | Delegated Permissions | EWS.AccessAsUser.All (Access mailboxes as the signed-in user via Exchange Web Services). This permission gives your registered application full access via Exchange Web Services to all mailboxes without a signed-in user. This type of permission gives the application full access to any mailbox in Exchange Online service and must be approved by an Azure AD global admin providing "admin consent". Your script will then authenticate to Exchange Online using the registered Azure AD application Client ID (effectively the username) and Client Secret (effectively the password).
The below example uses option 1. I haven't tested option 2. Whichever option you chose, you will need to handle requesting an OAuth token (example in the below code) from Azure AD and checking and refreshing the token at regularly intervals (no example). I haven't done that as all of our EWS scripts are simple, quick to run scripts that complete before the token needs to be refreshed (usually within 60 minutes). If this is something you're going to need, you will need to ask others for help. Hope this at least helps get you on the right track...
Here's the example script (the main body of the script calls the 'Get-EWSOAuthToken' function):
#Variables
$UserPrincipalName = "Enter the UPN of your Service Account ID"
$Password = "Password of your Service Account ID - store this securely"
$ClientIDfromAzureAD = "Client ID of your registered application in Azure AD"
$errRecip = "Email address of recipients to notify via email if errors occur"
$script = "Name of script"
$sender = "Email address of sender - normally the server name where your script runs"
$logfile = "Path and filename to log file"
$smtpServer = "Your SMTP server"
Function Get-EWSOAuthToken
{
<#
.SYNOPSIS
Request an OAuth EWS token from Azure AD using supplied Username and Password
.DESCRIPTION
Request an OAuth EWS token from Azure AD using supplied Username and Password
.PARAMETER UserPrincipalName
The UPN of the user that will authenticate to Azure AD to request the OAuth Token
.PARAMETER Password
The Password (SecureString) of the user that will authenticate to Azure AD to request the OAuth Token
.PARAMETER ADALPath
The full path and filename on the local file system to the ADAL (Active Directory Authentication Library) DLL. This library is installed as part of various modules such as Azure AD, Exchange Online, etc.
.PARAMETER ClientId
Identifier of the client application that is requesting the token. You must register your calling application in Azure AD. This will provide you with a ClientID and RedirectURI
.PARAMETER ConnectionUri
The URI of the Exchange Online EWS endpoint. Default URI of 'https://outlook.office365.com/EWS/Exchange.asmx' is used
.PARAMETER RedirectUri
Address to return to upon receiving a response from the authority. You must register your calling application in Azure AD. This will provide you with a ClientID and RedirectURI
.EXAMPLE
$token = Get-EWSOAuthtokenFromCredential -UserPrincipalName "ABC123#mydomain.com" -Password $mySecurePassword -ClientId "123444454545454767687878787" -RedirectUri "https://dummyredirectdomain.com"
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2013_SP1 -ErrorAction Stop
$ews.UseDefaultCredentials = $False
$ews.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$token
#>
[CmdletBinding()]
Param
(
[System.String]$UserPrincipalName,
[System.Security.SecureString]$Password,
[System.String]$ADALPath,
[System.String]$ClientId = "123444454545454767687878787",
[System.Uri]$ConnectionUri = "https://outlook.office365.com/EWS/Exchange.asmx",
[System.Uri]$RedirectUri = "https://dummyredirectdomain.com"
)
Begin
{
Write-Host "Starting Get-EWSOAuthTokenFromCredential function..." -ForegroundColor Yellow
#Determine ADAL location based on Azure AD module installation path
If([System.String]::IsNullOrEmpty($ADALPath))
{
Write-Host "Attempting to locate ADAL library..." -ForegroundColor Yellow
$ADALPath = (Get-InstalledModule -Name "AzureAD" -ErrorAction SilentlyContinue | Select-Object InstalledLocation).InstalledLocation
$ADALPath = Join-Path -Path $ADALPath -ChildPath "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
Write-Host "Located library # '$ADALPath'" -ForegroundColor Yellow
If([System.String]::IsNullOrEmpty($ADALPath))
{
#Get List of installed modules and check Azure AD DLL is available
$tmpMods = Get-Module -ListAvailable | Where-Object {$_.Name -eq "AzureAD"}
If($tmpMods)
{
$ADALPath = Split-Path $tmpMods.Path
$ADALPath = Join-Path -Path $ADALPath -ChildPath "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
Write-Host "Located library # '$ADALPath'" -ForegroundColor Yellow
}
Else
{
$err = "$($myinvocation.mycommand.name) requires the ADAL Library DLL files ('Microsoft.IdentityModel.Clients.ActiveDirectory.dll') that are installed as part of the 'AzureAD' module! Please install the AzureAD module from the Powershell Gallery. See: 'https://www.powershellgallery.com/packages/AzureAD' for more information"
Throw "$err"
}
}
}
#Load 'Microsoft.IdentityModel.Clients.ActiveDirectory' DLL
Try
{
Import-Module $ADALPath -DisableNameChecking -Force -ErrorAction Stop
Write-Host "Successfully imported ADAL Library" -ForegroundColor Yellow
}
Catch
{
$err = "$($myinvocation.mycommand.name): Could not load ADAL Library DLL '$ADALPath'. Error: $_"
Throw "$err"
}
}
Process
{
try
{
$resource = $connectionUri.Scheme + [System.Uri]::SchemeDelimiter + $connectionUri.Host
$azureADAuthorizationEndpointUri = "https://login.windows.net/common/oauth2/authorize/"
$AuthContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext($azureADAuthorizationEndpointUri) -ErrorAction Stop
$AuthCredential = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential($UserPrincipalName, $Password) -ErrorAction Stop
Write-Host "$($myinvocation.mycommand.name): Requesting a new OAuth Token..." -ForegroundColor Yellow
$authenticationResult = ([Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions]::AcquireTokenAsync($AuthContext, $resource, $clientId, $AuthCredential))
If ($authenticationResult.Status.ToString() -ne "Faulted") {
Write-Host "$($myinvocation.mycommand.name): Successfully retrieved OAuth Token" -ForegroundColor Yellow
}
else {
$err = "$($myinvocation.mycommand.name): Error occurred calling ADAL 'AcquireTokenAysnc' : $authenticationResult.Exception.ToString()"
Throw "$err"
}
}
catch
{
#create object
$returnValue = New-Object -TypeName PSObject
#get all properties from last error
$ErrorProperties =$Error[0] | Get-Member -MemberType Property
#add existing properties to object
foreach ($Property in $ErrorProperties)
{
if ($Property.Name -eq 'InvocationInfo')
{
$returnValue | Add-Member -Type NoteProperty -Name 'InvocationInfo' -Value $($Error[0].InvocationInfo.PositionMessage)
}
else
{
$returnValue | Add-Member -Type NoteProperty -Name $($Property.Name) -Value $($Error[0].$($Property.Name))
}
}
#return object
$returnValue
break
}
}
End
{
return $authenticationResult
}
}
###### Main script
#Ensure TLS 1.2 protocol is enabled
try {
If ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') {
[Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12
Write-Host "Enabled Tls1.2 in '[Net.ServicePointManager]::SecurityProtocol'" -ForegroundColor Yellow
}
else {
Write-Host "Tls1.2 is enabled in '[Net.ServicePointManager]::SecurityProtocol'" -ForegroundColor Yellow
}
}
Catch {
$err = "An error occurred enabling TLS1.2. Error: $_"
Write-Host "`n$err" -ForegroundColor Red
Send-MailMessage -To $errRecip -Subject "$script - Error occurred during processing" -Body $err -From $sender -Attachment $logfile -SmtpServer $smtpServer
Exit
}
#CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending | Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
If (Test-Path $EWSDLL)
{
Try
{
Import-Module $EWSDLL -DisableNameChecking -ErrorAction Stop
}
Catch
{
$err = "An error occurred importing the Exchange Web Services DLL '$EWSDLL'. Error: $_"
Write-Host "`n$err" -ForegroundColor Red
Send-MailMessage -To $errRecip -Subject "$script - Error occurred during processing" -Body $err -From $sender -Attachment $logfile -SmtpServer $smtpServer
Exit
}
}
Else
{
$err = "This script requires the EWS Managed API 1.2 or later. Please download and install the current version of the EWS Managed API from http://go.microsoft.com/fwlink/?LinkId=255472"
Write-Host "`n$err" -ForegroundColor Red
Send-MailMessage -To $errRecip -Subject "$script - Error occurred during processing" -Body $err -From $sender -Attachment $logfile -SmtpServer $smtpServer
Exit
}
#Create EWS Object
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList "Exchange2013_SP1" -ErrorAction Stop
#Authenticate EWS using OAuth
Try {
$ews.UseDefaultCredentials = $False
Write-Host "Requesting EWS OAuth Token using registered Client ID" -ForegroundColor Yellow
$OAuthResult = Get-EWSOAuthToken -UserPrincipalName $UserPrincipalName -Password $Password -ClientId "$ClientIDfromAzureAD" -ErrorAction Stop
$token = $OAuthResult.Result.AccessToken
#Check if we successfully retrieved an Oauth Token
If ([System.String]::IsNullOrEmpty($token))
{
$err = "Get-EWSOAuthtoken returned an empty Auth Token. Aborted. Latest error details:`n$_error $($OAuthResult.Exception)"
Write-Host "`n$err" -ForegroundColor Red
$OAuthResult | Format-List -Force
$OAuthResult.Result | Format-List -Force
Send-MailMessage -To $errRecip -Subject "$script - Error occurred during processing" -Body "$err" -From $sender -Attachment $logfile -SmtpServer $smtpServer
Exit
}
else
{
$OAuthchk = $true
$ews.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$token
Write-Host "Set EWS credentials to OAuth token" -ForegroundColor Yellow
}
}
Catch
{
$err = "An error occurred creating a new EWS object. Error:`n $_"
write-host "`n$err" -ForegroundColor Red
Send-MailMessage -To $errRecip -Subject "$script - Error occurred during processing" -Body "$err" -From $sender -Attachment $logfile -SmtpServer $smtpServer
Exit
}
# Do your processing using EWS
....
This is an extension on the information provided by #stukey, which is already graat. Instead of creating your own function to retrieve an access token, one can use the MSAL.PS library. This module can simply be installed from the PowerShell Gallery:
Install-Module -Name MSAL.PS
Configure Azure app
When you configure your "App Registration" in Azure you can use the following settings. This will allow you to use Integrated Windows Authentication and avoids storing passwords in your code (useful when running Windows Scheduled Tasks as a specific user to run your scripts):
Authentication > Advanced Settings > Treat application as a public client: Yes
Add the scope "EWS.AccessAsUser.All" in the section "API Permissions" (it can be found within the last option "Supported legacy API's: Exchange"):
Request token
When all this is configured you can request a new token when logged on with the correct Windows account that has Full control exchange permissions on the desired mailbox:
$msalParams = #{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
IntegratedWindowsAuth = $true
}
Get-MsalToken #msalParams
It might be required to add the switch -Interactive, so you can consent to the proposed scopes. This will only need to be done once.
Now that a valid token is acquired a refresh of the token can simply be done with the -Silent switch. This will get a valid token form the cache or request a new token when it's no longer valid:
$msalParams = #{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
Silent = $true
}
Get-MsalToken #msalParams
It would be great if both steps above can be combined into one call. For this I opened an issue.
Use the token with Exchange Web Services
$EWS = 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
Import-Module -Name $EWS -EA Stop
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList 'Exchange2013_SP1'
$Service.Url = 'https://outlook.office365.com/EWS/Exchange.asmx'
$Service.UseDefaultCredentials = $false
$msalParams = #{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
}
$token = Get-MsalToken #msalParams
$Service.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$token.AccessToken
Hopefully this will help others struggling with the same issues we did.

Configuring powershell core from .net core to provision a one drive

I'm attempting to provision a one drive in a dotnet core app using powershell core. Running powershell I've been able to successfully provision a one drive from the powershell command line following the directions provided below:
https://learn.microsoft.com/en-us/onedrive/pre-provision-accounts
Running it programatically in .net core however it looks like it uses a separate powershell that's bundled into .net core 2.1
I believe the unsuccessful in app runs are due to the powershell bundled with core not being setup correctly, namely the first 3 steps in the link above:
1.Download the latest SharePoint Online Management Shell.
2.Download and install the SharePoint Online Client Components SDK.
3.Connect to SharePoint Online as a global admin or SharePoint admin in Office 365. To learn how, see Getting started with SharePoint Online Management Shell.
How do I set up the powershell that gets run by my application to mirror those steps above?
My code looks like this:
using System.IO;
using System.Management.Automation;
namespace PowerShellApp
{
class Program
{
public static int Main(string[] args)
{
using (PowerShell ps = PowerShell.Create(
{
ps.AddScript(File.ReadAllText(<scriptLocation>))
.Invoke();
}
}
return 0;
}
}
How do I achieve these steps when executing within a .net core application
The powershell script I"m running is below and also within the link above:
<#
.SYNOPSIS
This script adds an entry for each user specified in the input file
into the OneDrive provisioning queue
.DESCRIPTION
This script reads a text file with a line for each user.
Provide the User Principal Name of each user on a new line.
An entry will be made in the OneDrive provisioning queue for each
user up to 200 users.
.EXAMPLE
.\BulkEnqueueOneDriveSite.ps1 -SPOAdminUrl https://contoso- admin.sharepoint.com -InputfilePath C:\users.txt
.PARAMETER SPOAdminUrl
The URL for the SharePoint Admin center
https://contoso-admin.sharepoint.com
.PARAMETER InputFilePath
The path to the input file.
The file must contain 1 to 200 users
C:\users.txt
.NOTES
This script needs to be run by a global or SharePoint administrator in Office 365
This script will prompt for the username and password of the administrator
#>
param
(
#Must be SharePoint Administrator URL
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string] $SPOAdminUrl,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string] $InputFilePath
)
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.R untime") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.U serProfiles") | Out-Null
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOAdminUrl)
$Users = Get-Content -Path $InputFilePath
if ($Users.Count -eq 0 -or $Users.Count -gt 200)
{
Write-Host $("Unexpected user count: [{0}]" -f $Users.Count) - ForegroundColor Red
return
}
$web = $ctx.Web
Write-Host "Enter an admin username" -ForegroundColor Green
$username = Read-Host
Write-Host "Enter your password" -ForegroundColor Green
$password = Read-Host -AsSecureString
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username,$password )
$ctx.Load($web)
$ctx.ExecuteQuery()
$loader = [Microsoft.SharePoint.Client.UserProfiles.ProfileLoader]::GetProfileLoader($ctx)
$ctx.ExecuteQuery()
$loader.CreatePersonalSiteEnqueueBulk($Users)
$loader.Context.ExecuteQuery()
Write-Host "Script Completed"
I'm afraid SP Online management Shell has dependencies from .Net Framework and will not work with Core (check this).
From the other side that module seemed to be a wrapper on top of their REST API. So if you want to integrate it with Core app, you may try to replace it with HTTP requests. Check this documentation
Also, below is a base powershell script to work with those REST API endpoints. I tested this one on my site:
$baseUrl = "http://sharepoint.com/sites/yourSite/_api"
$cred = Get-Credential
# retreive digest
$r = Invoke-WebRequest -Uri "$baseUrl/contextinfo" -Method Post -Credential $cred -SessionVariable sp
$digest = ([xml]$r.content).GetContextWebInformation.FormDigestvalue
# calling endpoint
$endpoint = "sp.userprofiles.profileloader.getprofileloader/getuserprofile"
$head = #{
"Accept" = "application/json;odata=verbose"
"X-RequestDigest" = $digest
}
$re = Invoke-WebRequest -Uri "$baseUrl/$endpoint" -Headers $head -Method Post -WebSession $sp
Write-Host $re.Content
This is a snippet for createpersonalsiteenqueuebulk, but I can't test it since I'm not domain admin. Hope it will work for you
#--- sample 2 (didn't test it since I'm not domain admin). Might need separate session/digest
$endpoint2 = "https://<domain>-admin.sharepoint.com/_api/sp.userprofiles.profileloader.getprofileloader/createpersonalsiteenqueuebulk"
$head = #{
"Accept" = "application/json;odata=verbose"
"X-RequestDigest" = $digest
}
$body = "{ 'emailIDs': ['usera#domain.onmicrosoft.com', 'userb#domain.onmicrosoft.com'] }"
$re2 = Invoke-WebRequest -Uri "$endpoint2" -Headers $head -body $body -Method Post -WebSession $sp
Write-Host $re2.Content

API to remotely upload secret to Thycotic Secret Server

I am total newbie to PowerShell, Thycotic Secret Server and writing APIs. I have been tasked with writing an API to remotely access Thycotic Secret Server and upload a secret together with attached files. Unfortunately, I haven’t gotten off the starting block. I am following the code here:
https://thycotic.force.com/support/s/article/REST-API-PowerShell-Scripts-Getting-Started
I have copied down:
3 – Searching Secrets
4 – Create Secret and
Get-Token from here:
https://thycotic.force.com/support/s/article/Secret-Server-Trial-Using-the-API
and have created functions for each one. The only changes I made are to change myurl, myusername and mypassword.
This is my PowerShell script:
$myUrl = "mysecretserver/Login.aspx?ReturnUrl=%2f"
$application = "https://mysecretserver/Login.aspx?ReturnUrl=%2fsecretserver"
# Ask for user name
$userName = Read-Host -Prompt "Please enter user name"
$userPassword = Read-Host -AsSecureString "Password"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Get-Token
Search-Secrets $userName,$userPassword
Create-Secret $userName,$userPassword
When I run Get-Token (no changes made to downloaded code)
function Get-Token
{
[CmdletBinding()]
Param(
[Switch] $UseTwoFactor
)
$creds = #{
username = $userName
password = $userPassword
grant_type = "password"
};
$headers = $null
If ($UseTwoFactor) {
$headers = #{
"OTP" = (Read-Host -Prompt "Enter your OTP for 2FA (displayed in your 2FA app): ")
}
}
try
{
$response = Invoke-RestMethod "$application/oauth2/token" -Method Post -Body $creds -Headers $headers;
$token = $response.access_token;
return $token;
}
catch
{
$result = $_.Exception.Response.GetResponseStream();
$reader = New-Object System.IO.StreamReader($result);
$reader.BaseStream.Position = 0;
$reader.DiscardBufferedData();
$responseBody = $reader.ReadToEnd() | ConvertFrom-Json
Write-Host "ERROR: $($responseBody.error)"
return;
}
}
It seems to run ok but when I display $token, it is empty.
I'm not 100% sure what this is doing and have looked at a lot of examples but seem to be missing the basic steps for reading the token and using it to access the secret server. Any help would be greatly appreciated.
Replace your Secret Server URL with the Server's FQDN, not the web URL you get in a browser. You need to make sure the Secret Server address is correct otherwise it won't be hitting the API (and maybe failing gracefully which is why you don't see any errors from the Get-Token function).
For example, instead of:
$application = "https://mysecretserver/Login.aspx?ReturnUrl=%2fsecretserver"
It may be something like:
$application = "https://mysecretserver.mydomain.com"

Add TFS Tag with REST API via powershell

I want to add a tag to a TFS project using the REST API in Powershell.
I am trying to make this request based on the documentation for
Visual Studio Integration
I am calling this:
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client')
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.WorkItemTracking.Client')
if ( (Get-PSSnapin -Name "Microsoft.TeamFoundation.Powershell" -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSSnapin "Microsoft.TeamFoundation.Powershell"
}
$SrcCollectionUrl = 'http://tfs.myCompany.com:8080/tfs/MyCollection'
$SrcProjectName = 'myProject'
[psobject] $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($SrcCollectionUrl)
[Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStoreFlags]$WorkItemBypass = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStoreFlags]::BypassRules
$tfstp = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection($SrcCollectionUrl)
$WorkItemStore = New-Object -TypeName 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore' -ArgumentList $tfs.TfsTeamProjectCollection, $WorkItemBypass
$SrcProject = $WorkItemStore.Projects[$SrcProjectName]
$ProjectGuid = Split-Path $SrcProject.Uri -Leaf
$AddTagsUrl = '{0}/_apis/tagging/scopes/{1}/tags?api-version=1.0' -f $SrcCollectionUrl,$ProjectGuid
$newTagParams = #{name="PWCreateTag2"}
$outjson = $newTagParams | ConvertTo-Json
$nresp = Invoke-RestMethod -Method POST -Uri $AddTagsUrl -UseDefaultCredentials -Body $outjson -ContentType 'application/json'
Everything works. The first time. However the documentation states: "If a tag by that name already exists, no tag is created. Instead, the response body includes the existing tag with that name."
The 2nd time I call the line I get: "The remote server returned an error: (400) Bad Request."
Anyone have any Idea why this fails the 2nd time?
FYI: TFS Server is 2015, Powershell is V4
I created powershell module for this - tfs
To add tags:
'tag1','tag2' | % { Add-TFSBuildTag -Id 520 -Tag $_ }