I can't find any clue about it except a deprecated article using tweetpic which is now closed.
Any alternative that works in Powershell ?
Update: my question is not about if there is a Twitter API of course I know there is, but as it is not trivial to use like this Powershell Guy who is stuck https://twittercommunity.com/t/media-upload-doesnt-work-powershell/93861 I'm looking for a module.
Credit to Adam Bertram from https://www.adamtheautomator.com/twitter-module-powershell/.
Disclaimer: this only allows to post tweets and DM.
You can try using the PSM1 module below, but you need to create your own Twitter application on apps.twitter.com and generate an access token under the API keys section of the application. Once you do so, I recommend copying/pasting your API key, API secret, access token and access token secret as default parameters under the Get-OAuthAuthorization function.
<#
===========================================================================
Created on: 8/31/2014 3:11 PM
Created by: Adam Bertram
Filename: MyTwitter.psm1
------------------------------------------------------------------------
===========================================================================
#>
function Get-OAuthAuthorization {
<#
.SYNOPSIS
This function is used to setup all the appropriate security stuff needed to issue
API calls against Twitter's API. It has been tested with v1.1 of the API. It currently
includes support only for sending tweets from a single user account and to send DMs from
a single user account.
.EXAMPLE
Get-OAuthAuthorization -DmMessage 'hello' -HttpEndPoint 'https://api.twitter.com/1.1/direct_messages/new.json' -Username adam
This example gets the authorization string needed in the HTTP POST method to send a direct
message with the text 'hello' to the user 'adam'.
.EXAMPLE
Get-OAuthAuthorization -TweetMessage 'hello' -HttpEndPoint 'https://api.twitter.com/1.1/statuses/update.json'
This example gets the authorization string needed in the HTTP POST method to send out a tweet.
.PARAMETER HttpEndPoint
This is the URI that you must use to issue calls to the API.
.PARAMETER TweetMessage
Use this parameter if you're sending a tweet. This is the tweet's text.
.PARAMETER DmMessage
If you're sending a DM to someone, this is the DM's text.
.PARAMETER Username
If you're sending a DM to someone, this is the username you'll be sending to.
.PARAMETER ApiKey
The API key for the Twitter application you previously setup.
.PARAMETER ApiSecret
The API secret key for the Twitter application you previously setup.
.PARAMETER AccessToken
The access token that you generated within your Twitter application.
.PARAMETER
The access token secret that you generated within your Twitter application.
#>
[CmdletBinding(DefaultParameterSetName = 'None')]
[OutputType('System.Management.Automation.PSCustomObject')]
param (
[Parameter(Mandatory)]
[string]$HttpEndPoint,
[Parameter(Mandatory, ParameterSetName = 'NewTweet')]
[string]$TweetMessage,
[Parameter(Mandatory, ParameterSetName = 'DM')]
[string]$DmMessage,
[Parameter(Mandatory, ParameterSetName = 'DM')]
[string]$Username,
[Parameter()]
[string]$ApiKey = '2R3aJXohHmSABPaiQGaeprny7',
[Parameter()]
[string]$ApiSecret = '',
[Parameter()]
[string]$AccessToken = '',
[Parameter()]
[string]$AccessTokenSecret = ''
)
begin {
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
Set-StrictMode -Version Latest
try {
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Net") | Out-Null
} catch {
Write-Error $_.Exception.Message
}
}
process {
try {
## Generate a random 32-byte string. I'm using the current time (in seconds) and appending 5 chars to the end to get to 32 bytes
## Base64 allows for an '=' but Twitter does not. If this is found, replace it with some alphanumeric character
$OauthNonce = [System.Convert]::ToBase64String(([System.Text.Encoding]::ASCII.GetBytes("$([System.DateTime]::Now.Ticks.ToString())12345"))).Replace('=', 'g')
Write-Verbose "Generated Oauth none string '$OauthNonce'"
## Find the total seconds since 1/1/1970 (epoch time)
$EpochTimeNow = [System.DateTime]::UtcNow - [System.DateTime]::ParseExact("01/01/1970", "dd/MM/yyyy", $null)
Write-Verbose "Generated epoch time '$EpochTimeNow'"
$OauthTimestamp = [System.Convert]::ToInt64($EpochTimeNow.TotalSeconds).ToString();
Write-Verbose "Generated Oauth timestamp '$OauthTimestamp'"
## Build the signature
$SignatureBase = "$([System.Uri]::EscapeDataString($HttpEndPoint))&"
$SignatureParams = #{
'oauth_consumer_key' = $ApiKey;
'oauth_nonce' = $OauthNonce;
'oauth_signature_method' = 'HMAC-SHA1';
'oauth_timestamp' = $OauthTimestamp;
'oauth_token' = $AccessToken;
'oauth_version' = '1.0';
}
if ($TweetMessage) {
$SignatureParams.status = $TweetMessage
} elseif ($DmMessage) {
$SignatureParams.screen_name = $Username
$SignatureParams.text = $DmMessage
}
## Create a string called $SignatureBase that joins all URL encoded 'Key=Value' elements with a &
## Remove the URL encoded & at the end and prepend the necessary 'POST&' verb to the front
$SignatureParams.GetEnumerator() | sort name | foreach {
Write-Verbose "Adding '$([System.Uri]::EscapeDataString(`"$($_.Key)=$($_.Value)&`"))' to signature string"
$SignatureBase += [System.Uri]::EscapeDataString("$($_.Key)=$($_.Value)&".Replace(',','%2C').Replace('!','%21'))
}
$SignatureBase = $SignatureBase.TrimEnd('%26')
$SignatureBase = 'POST&' + $SignatureBase
Write-Verbose "Base signature generated '$SignatureBase'"
## Create the hashed string from the base signature
$SignatureKey = [System.Uri]::EscapeDataString($ApiSecret) + "&" + [System.Uri]::EscapeDataString($AccessTokenSecret);
$hmacsha1 = new-object System.Security.Cryptography.HMACSHA1;
$hmacsha1.Key = [System.Text.Encoding]::ASCII.GetBytes($SignatureKey);
$OauthSignature = [System.Convert]::ToBase64String($hmacsha1.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($SignatureBase)));
Write-Verbose "Using signature '$OauthSignature'"
## Build the authorization headers using most of the signature headers elements. This is joining all of the 'Key=Value' elements again
## and only URL encoding the Values this time while including non-URL encoded double quotes around each value
$AuthorizationParams = $SignatureParams
$AuthorizationParams.Add('oauth_signature', $OauthSignature)
## Remove any API call-specific params from the authorization params
$AuthorizationParams.Remove('status')
$AuthorizationParams.Remove('text')
$AuthorizationParams.Remove('screen_name')
$AuthorizationString = 'OAuth '
$AuthorizationParams.GetEnumerator() | sort name | foreach { $AuthorizationString += $_.Key + '="' + [System.Uri]::EscapeDataString($_.Value) + '", ' }
$AuthorizationString = $AuthorizationString.TrimEnd(', ')
Write-Verbose "Using authorization string '$AuthorizationString'"
$AuthorizationString
} catch {
Write-Error $_.Exception.Message
}
}
}
function Send-Tweet {
<#
.SYNOPSIS
This sends a tweet under a username.
.EXAMPLE
Send-Tweet -Message 'hello, world'
This example will send a tweet with the text 'hello, world'.
.PARAMETER Message
The text of the tweet.
#>
[CmdletBinding()]
[OutputType('System.Management.Automation.PSCustomObject')]
param (
[Parameter(Mandatory)]
[ValidateLength(1, 140)]
[string]$Message
)
process {
$HttpEndPoint = 'https://api.twitter.com/1.1/statuses/update.json'
$AuthorizationString = Get-OAuthAuthorization -TweetMessage $Message -HttpEndPoint $HttpEndPoint
## Convert the message to a Byte array
#$Body = [System.Text.Encoding]::ASCII.GetBytes("status=$Message");
$Body = "status=$Message"
Write-Verbose "Using POST body '$Body'"
Invoke-RestMethod -URI $HttpEndPoint -Method Post -Body $Body -Headers #{ 'Authorization' = $AuthorizationString } -ContentType "application/x-www-form-urlencoded"
}
}
function Send-TwitterDm {
<#
.SYNOPSIS
This sends a DM to another Twitter user. NOTE: You can only send up to
250 DMs in a 24 hour period.
.EXAMPLE
Send-TwitterDm -Message 'hello, Adam' -Username 'adam','bill'
This sends a DM with the text 'hello, Adam' to the username 'adam' and 'bill'
.PARAMETER Message
The text of the DM.
.PARAMETER Username
The username(s) you'd like to send the DM to.
#>
[CmdletBinding()]
[OutputType('System.Management.Automation.PSCustomObject')]
param (
[Parameter(Mandatory)]
[ValidateLength(1, 140)]
[string]$Message,
[Parameter(Mandatory)]
[string[]]$Username
)
process {
$HttpEndPoint = 'https://api.twitter.com/1.1/direct_messages/new.json'
## Convert the message to a Byte array
#$Message = [System.Uri]::EscapeDataString($Message)
foreach ($User in $Username) {
$AuthorizationString = Get-OAuthAuthorization -DmMessage $Message -HttpEndPoint $HttpEndPoint -Username $User -Verbose
$User = [System.Uri]::EscapeDataString($User)
$Body ="text=$Message&screen_name=$User"
Write-Verbose "Using POST body '$Body'"
Invoke-RestMethod -URI $HttpEndPoint -Method Post -Body $Body -Headers #{ 'Authorization' = $AuthorizationString } -ContentType "application/x-www-form-urlencoded"
}
}
}
Export-ModuleMember Send-Tweet
Export-ModuleMember Send-TwitterDm
Related
I am attempting to create a sonarqube service endpoint in azure devops using this api script below. It succesffuly generates the service connection, and visually looks identical to one manually created in the azure devops portal. How ever when used in a yaml pipeline, fails at the Prepare analysis on SonarQube step with the following error
The token you provided doesn't have sufficient rights to check license.
If i manually changed every avaiable field of this connection (url/token/name) it still fails.
if i recreate with these values but through the portal it works.
function createDevOpsServiceConnection {
<#
.SYNOPSIS
Creates a DevOps service connection through REST API
.DESCRIPTION
The scrip will help you creating an Azure DevOps service connection through the REST API.
.PARAMETER PersonalToken
Personal Access Token. Check https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
.PARAMETER Organisation
The Azure DevOps organisation name
.PARAMETER ProjectName
The Azure DevOps project where the service connection will be made
.PARAMETER ManagementGroupId
The management group id created in the tenant
.PARAMETER ManagementGroupName
The management group name created in the tenant
.PARAMETER SubscriptionId
The subscription id in the tenant where to connect
.PARAMETER SubscriptionName
The subscription name in the tenant where to connect
.PARAMETER TenantId
The tenant id where to connect
.PARAMETER ApplicationId
The application id (service principal) in the Azure AD
.PARAMETER ApplicationSecret
The application secret, in plain text
.EXAMPLE
create-DevOpsServiceConnection.ps1 -personalToken xxx -organisation DevOpsOrganisation -ProjectName WVD -ManagementGroupId MGTGROUP1 -ManagementGroupName 'MGT GROUP 1' -TenantId xxx-xxx -ApplicationId xxx-xxx-xxx -ApplicationSecret 'verysecret'
#>
Param(
[Parameter(Mandatory = $True)]
[string]$PersonalToken,
[Parameter(Mandatory = $True)]
[string]$Organisation,
[Parameter(Mandatory = $True)]
[string]$ProjectName,
[Parameter(Mandatory = $True, ParameterSetName = 'Subscription')]
[string]$SubscriptionId,
[Parameter(Mandatory = $True, ParameterSetName = 'Subscription')]
[string]$SubscriptionName,
[Parameter(Mandatory = $True)]
[string]$TenantId,
[Parameter(Mandatory = $True)]
[string]$ApplicationId,
[Parameter(Mandatory = $True)]
[string]$ApplicationSecret
)
$AzureDevOpsAuthenicationHeader = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalToken)")) }
## Get ProjectId
$URL = "https://dev.azure.com/$($organisation)/_apis/projects?api-version=6.0"
Try {
$ProjectNameproperties = (Invoke-RestMethod $URL -Headers $AzureDevOpsAuthenicationHeader -ErrorAction Stop).Value
Write-Verbose "Collected Azure DevOps Projects"
}
Catch {
$ErrorMessage = $_ | ConvertFrom-Json
Throw "Could not collect project: $($ErrorMessage.message)"
}
$ProjectID = ($ProjectNameproperties | Where-Object { $_.Name -eq $ProjectName }).id
Write-Verbose "Collected ID: $ProjectID"
$ConnectionName = "sonarqube"
switch ($PsCmdlet.ParameterSetName) {
Subscription {
$data = #{
}
}
}
# Create body for the API call
$Body = #{
data = $data
name = $ConnectionName
type = "sonarqube"
url = "http://mysonarqube:9000/"
authorization = #{
parameters = #{
username = "admin"
password = 'SONARQUBETOKEN'
}
scheme = "UsernamePassword"
}
isShared = $True
isReady = $True
serviceEndpointProjectReferences = #(
#{
projectReference = #{
id = "xxxxxxxx"
name = "projectname"
}
name = $ConnectionName
}
)
}
$URL = "https://dev.azure.com/$organisation/$ProjectName/_apis/serviceendpoint/endpoints?api-version=6.1-preview.4"
$Parameters = #{
Uri = $URL
Method = "POST"
Body = ($Body | ConvertTo-Json -Depth 3)
Headers = $AzureDevOpsAuthenicationHeader
ContentType = "application/json"
Erroraction = "Stop"
}
try {
Write-Verbose "Creating Connection"
$Result = Invoke-RestMethod #Parameters
Write-Host "$($Result.name) service connection created"
}
Catch {
$ErrorMessage = $_ | ConvertFrom-Json
Throw "Could not create Connection: $($ErrorMessage.message)"
}
}
createDevOpsServiceConnection -personalToken $env:AZURE_DEVOPS_EXT_PAT -organisation $env:org -ProjectName "Bicep" `
-TenantId $env:ARM_TENANT_ID -ApplicationId $env:ARM_CLIENT_ID -ApplicationSecret $env:ARM_CLIENT_SECRET -SubscriptionId $ENV:ARM_SUBSCRIPTION_ID `
-SubscriptionName $env:sbname
Original script that this is based on can be found here; https://raw.githubusercontent.com/srozemuller/Azure/main/DevOps/Automation/create-DevOpsServiceConnection.ps1
I am trying to write a PowerShell script that allows me to update all the names of our devices in Intune [430ish devices] to reflect our asset tags. When they were imported into our tenant, they were given the serialNumber of the device as their deviceName. All permissions for the API have been applied:
API Permissions:
Device Read
Device Read all
DeviceManagementApps.ReadAll
DeviceManagementApps.ReadWriteAll
DeviceManagementConfiguration.ReadAll
DeviceManagementConfiguration.ReadWriteAll
DeviceManagementManagedDevices.PrivilegedOperations.All
DeviceManagementManagedDevices.ReadAll
DeviceManagementManagedDevices.ReadWriteAll
DeviceManagementRBAC.ReadAll
DeviceManagementRBAC.ReadWriteALL
DeviceManagementServiceConfig.ReadAll
DeviceManagementServiceConfig.ReadWriteAll
User Read
This is the code as far as I can get it, but I am still getting the following error [I apologise for ugly or poorly formatted code, I have had no formal training, all learnt using google-fu!]:
# Setting variables for connecting to the MS API
$ApplicationID = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
$TenantDomainName = "contoso.com"
$AccessSecret = Read-Host "Enter Secret"
# Connect to MSGraph command to run
Connect-MSGraph
# Setting the body of the json
$Body = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
client_Id = $ApplicationID
Client_Secret = $AccessSecret
}
# Authenticating the connection to MSGraph
$ConnectGraph = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantDomainName/oauth2/v2.0/token" `
-Method POST -Body $Body
$token = $ConnectGraph.access_token
# Importing the CSV of device information
$csvfile = "C:\<Path to file>"
Import-Csv $csvfile | ForEach-Object {
$serialNumber = $_.serialNumber;
$tag = $_.tag;
$deviceId = $serialNumber
Write-Host "Renaming machine from: $deviceID to: $tag" -ForegroundColor Cyan
# Getting the Device from the CSV and then putting it into MSGraph compatible Json
$DeviceToRename = Get-IntuneManagedDevice -Filter ("serialNumber eq '$serialNumber'")
Foreach ($Device in $DeviceToRename) {
$Resource = "deviceManagement/managedDevices('$DeviceId')/setDeviceName"
$graphApiVersion = "Beta"
$uri = "https://graph.microsoft.com/beta/deviceManagement/managedDevices/executeAction"
#This JSON format doesnt work
# $JSONPayload = #"
# { <NEW>
# "body": <NEW>
# {
# action: "setDeviceName",
# actionName: "setDeviceName",
# deviceName: "$tag",
# realaction: "setDeviceName",
# restartNow: false
# }
# } <NEW>
#"#
#Don't know if this works properly either?
$JSONPayload = #"
{
"#odata.type": "#microsoft.graph.managedDevice",
"actionName": "setDeviceName",
"deviceName": "$tag"
}
"#
# Writing out to check if this is working correctly
Write-Host $JSONPayload
# Converting $JSONPayload to an actual workable JSON
$convertedJSON = ConvertTo-Json $JSONPayload
try {
Invoke-MSGraphRequest -Url $uri -HttpMethod PATCH -Body $JSONPayload -ContentType "application/Json" -Verbose
} catch {
# Dig into the exception to get the Response details.
Write-Host "StatusCode:" "$_.Exception.Response.StatusCode.value__"
Write-Host "StatusDescription:" "$_.Exception.Response.StatusDescription"
Write-Host "StatusCode2:" "$_.ErrorDetails.Message"
}
}
}
Error response:
StatusCode: A parameter cannot be found that matches parameter name 'Body'..Exception.Response.StatusCode.value__
StatusDescription: A parameter cannot be found that matches parameter name 'Body'..Exception.Response.StatusDescription
StatusCode2: A parameter cannot be found that matches parameter name 'Body'..ErrorDetails.Message
Thanks
Tom
I had similar problems some months ago manipulating intune devices from an powershell runbook over graph. In my case the json body was the problem. I had to define the body first as hashtable and then convert it to json. Try something like this:
# JSONPayload as hashtable instead of string
$JSONPayload = #{
"#odata.type" = "#microsoft.graph.managedDevice"
"actionName" = "setDeviceName"
"deviceName" = "$tag"
}
# Writing out to check if this is working correctly
$JSONPayload
# Converting $JSONPayload to an actual workable JSON
$convertedJSON = $JSONPayload | ConvertTo-Json
And then pass the $convertedJSON to your graph call as body:
Invoke-MSGraphRequest -Url $uri -HttpMethod POST -Content $convertedJSON -Verbose
EDIT:
You are calling the endpoint /deviceManagement/managedDevices/executeAction with the http method PATCH. According to this ms docs article you have to call the endpoint with the http method POST.
I'm new to Powershell and as best as I can find it doesn't have anything like PEP8/PEP484 in Python. I found this document from Microsoft and this third party guide from Posh Code. I have written the following function:
function Invoke-Authenticate {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]
# IP address of the OME server
$Ip,
[Parameter(Mandatory)]
# Credentials for the OME server
[pscredential] $Credentials
)
$SessionUrl = "https://$($IpAddress)/api/SessionService/Sessions"
$Type = "application/json"
$UserDetails = #{"UserName"=$Credentials.username;"Password"=$Credentials.GetNetworkCredential().password;
"SessionType"="API"} | ConvertTo-Json
$Headers = #{}
try {
$SessResponse = Invoke-WebRequest -Uri $SessionUrl -Method Post -Body $UserDetails -ContentType $Type `
-SkipCertificateCheck
if ($SessResponse.StatusCode -eq 200 -or $SessResponse.StatusCode -eq 201) {
# Successfully created a session - extract the auth token from the response
# header and update our headers for subsequent requests
$Headers."X-Auth-Token" = $SessResponse.Headers["X-Auth-Token"]
} else {
Write-Error "OME did not return a 200 or 201 status code. Received $($SessResponse.StatusCode).
We are unsure why this happened."
}
}
catch [Microsoft.PowerShell.Commands.HttpResponseException] {
Write-Error "There was a problem authenticating with OME. Are you sure you have the right username and password?"
return $null
}
catch [System.Net.Http.HttpRequestException] {
Write-Error "There was a problem connecting to OME. Are you sure you have the right IP and that it is available?"
return $null
}
return $Headers
<#
.SYNOPSIS
Authenticates with OME and creates a session
.DESCRIPTION
Authenticates with OME and creates a session
.PARAMETER Ip
IP address of the OME server
.PARAMETER Credentials
Credentials for the OME server
.INPUTS
None. You cannot pipe objects to Invoke-Authenticate.
.OUTPUTS
hashtable. The Invoke-Authenticate function returns a hashtable with the headers resulting from authentication
against the OME server
#>
}
As far as I can tell based on the guides that is correct however, it looks very goofy to me to have the description at the end. Are there set coding style guidelines I'm missing for Powershell or is this correct? Are you supposed to just delete the fields not applicable for a function? For example I have no .INPUTS. Should I just delete that entirely?
It's called "comment-based help" (about_Comment_Based_Help)
You have 3 options where to put the documentation:
• At the beginning of the function body.
• At the end of the function body.
• Before the function keyword. There cannot be more than one blank
line between the last line of the function help and the function
keyword.
So, you can easily put them at the top of your function (either inside or outside):
function Invoke-Authenticate {
<#
.SYNOPSIS
...
#>
or
<#
.SYNOPSIS
...
#>
function Invoke-Authenticate {
Not all sections are required, you can just include whichever you want. It depends on your use-case and company guidelines. I usually include at least:
.SYNOPSIS
.DESCRIPTION
.PARAMETERS
.EXAMPLES
Another useful thing, if you happen to have a company internal help page (like a wiki), you can add a link:
.LINK
https://wiki.my-company.com/my-module/help
I have a script that is supposed to reach out to a server and update a value for a user. Right now I can get that script to do it for a single user but I am trying to get it so that it will do it for multiple users from a text file. The script has three functions, the first creates the connection to the server, the second search for the user, and pulls the users GUID from the server's database, and the third set the user's value.
I have tried to update the getuser function so that it pulls the user data from a text file using get-content and then for foreach-object but when I run the script it continues to ask for an email address then errors out.
Here are the snippets from the getuser and the main functions. If anyone has any suggestion I would greatly appreciate it.
function getUser($email)
{
$methodName = "getUser()";
enterMethod($methodName);
$response = $null;
<# Create and set the headers for the REST request #>
$headers = #{}
$headers.add("Authorization", $global:authString);
$headers.add("Content-Type", "application/vnd.blackberry.users-v1+json");
$request = $global:uemBaseUrl + "/users?query=emailAddress=" + $email;
# Invoke RESTMethod to call users API to obtain users in the system
try
{
$response = Invoke-RestMethod -Method GET -Headers $headers -Uri $request;
if (($response.users -ne $null) -and ($response.users.length -eq 1))
{
Write-Host([string]::Format("User with email address '{0}' was found", $email));
}
else
{
Write-Host([string]::Format("User with email address '{0}' not found", $email));
exit(1);
}
}
catch
{
handleError $_;
}
exitMethod($methodName);
return $response;
}
function main
{
$methodName = "main()";
enterMethod($methodName);
try
{
if (setup)
{
$getUserResponse = get-content .\users.txt $emailaddress;
$getUserResponse = ForEach-Object
$userGUID = $getUserResponse.users.guid;
if($actionType -eq "Set")
{
if([string]::IsNullOrEmpty($expiry))
{
throw [System.ArgumentNullException]"The expiry argument is required when actionType=Set";
}
if(setActivationpassword($userGUID))
{
Write-Host([string]::Format("Random activation password has been set for user '{0}'", $emailAddress));
}
}
elseif($actionType -eq "ReplaceAll")
{
if([string]::IsNullOrEmpty($expiry))
{
throw [System.ArgumentNullException]"The expiry argument is required when actionType=ReplaceAll";
}
if(replaceActivationpassword($userGUID))
{
Write-Host([string]::Format("Activation password has been replaced for user '{0}'. Existing passwords have been expired.", $emailAddress ));
}
}
elseif($actionType -eq "ExpireAll")
{
if(expireActivationpasswords($userGUID))
{
Write-Host([string]::Format("All activation passwords expired for user '{0}'", $emailAddress));
}
}
}
}
catch
{
handleError $_;
}
exitMethod($methodName);
Write-Host("Complete!");
exit(0);
}
EDIT:
Here is the full working Script. This script allows you to do one user at a time.
<#
.DESCRIPTION
Authenticate and call either "Set", "Expire all" or "Replace" activation passwords for user BWS REST API depending what actionType is used.
.PARAMETER uemHostAndPort
Host and port of the UEM.
.PARAMETER tenantGuid
tenantGuid to use for authentication.
.PARAMETER authType
Authentication type to use. (Local or AD).
.PARAMETER username
username to use for authentication.
.PARAMETER password
password to use for authentication.
.PARAMETER domain
domain to use for authentication if authType=AD.
.PARAMETER actionType
Action to perform. (Set, ExpireAll or ReplaceAll)
.PARAMETER emailAddress
Email address of the user to perform the action on.
.PARAMETER expiry
The date and time the activation password will expire in ISO-8601 format.
#>
Param(
[Parameter(
Mandatory=$true,
HelpMessage="UEM Host and port."
)]
[ValidateNotNullorEmpty()]
[string]$uemHostAndPort,
[Parameter(
Mandatory=$true,
HelpMessage="Tenant guid to authenticate with."
)]
[ValidateNotNullorEmpty()]
[string]$tenantGuid,
[Parameter(
Mandatory=$true,
HelpMessage="Choose (AD | Local) authType."
)]
[ValidateSet('AD', 'Local')]
[string]$authType,
[Parameter(
Mandatory=$true,
HelpMessage="Username to authenticate with."
)]
[ValidateNotNullorEmpty()]
[string]$username,
[Parameter(
Mandatory=$true,
HelpMessage="Password to authenticate with."
)]
[ValidateNotNullorEmpty()]
[string]$password,
[Parameter(
Mandatory=$false
)]
[string]$domain,
[Parameter(
Mandatory=$true,
HelpMessage="Choose (Set | ExpireAll | ReplaceAll) actionType."
)]
[ValidateSet('Set', 'ExpireAll', 'ReplaceAll')]
[string]$actionType,
[Parameter(
Mandatory=$true,
HelpMessage="User email address to add or remove from group."
)]
[string]$emailAddress,
[Parameter(
Mandatory=$false,
HelpMessage="The date and time the activation password will expire in ISO-8601 format."
)]
[string]$expiry
)
$global:authString = $null;
$global:uemBaseUrl = $null;
<#
* Generate authorization header required to perform the REST call.
*
* #return
* True if successful, false otherwise.
#>
function setup()
{
$methodName = "setup()";
enterMethod($methodName);
$provider = $null;
$global:uemBaseUrl = "https://" + $uemHostAndPort + "/" + $tenantGuid + "/api/v1";
# Create and set the headers for the REST request
$headers = #{}
$headers.add("Content-Type", "application/vnd.blackberry.authorizationrequest-v1+json")
# Create body for REST call
$body = #{}
$body.add("provider",$authType);
$body.add("username", $username);
$body.add("password", [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($password)));
if($authType -eq "AD")
{
if(-not($domain))
{
throw [System.ArgumentNullException]"The domain argument is required when authType=AD";
}
$body.add("domain", $domain);
}
$request = $global:uemBaseUrl + "/util/authorization";
# Invoke RESTMethod to call authorization route to generate the authorization headers
try
{
$response = Invoke-RestMethod -Method POST -Headers $headers -Uri $request -Body ($body | ConvertTo-Json);
$global:authString = $response
}
catch
{
handleError $_;
}
Write-Host([string]::Format("Authorization header string generated: {0}", $global:authString));
Write-Host("Setup Complete...");
exitMethod($methodName);
return $true;
}
<#
* Generate authorization header required to perform the REST call.
*
* #param email
* Email of the user to get.
* #return
* User that was found.
#>
function getUser($email)
{
$methodName = "getUser()";
enterMethod($methodName);
$response = $null;
<# Create and set the headers for the REST request #>
$headers = #{}
$headers.add("Authorization", $global:authString);
$headers.add("Content-Type", "application/vnd.blackberry.users-v1+json");
$request = $global:uemBaseUrl + "/users?query=emailAddress=" + $email;
# Invoke RESTMethod to call users API to obtain users in the system
try
{
$response = Invoke-RestMethod -Method GET -Headers $headers -Uri $request;
if (($response.users -ne $null) -and ($response.users.length -eq 1))
{
Write-Host([string]::Format("User with email address '{0}' was found", $email));
}
else
{
Write-Host([string]::Format("User with email address '{0}' not found", $email));
exit(1);
}
}
catch
{
handleError $_;
}
exitMethod($methodName);
return $response;
}
<#
* Set acctivation password for a user.
*
* #param userGuid
* Guid of user.
* #return
* True if successful, false otherwise.
#>
function setActivationpassword($userGuid)
{
$methodName = "setActivationpassword()";
enterMethod($methodName);
# Create and set the headers for the REST command
$headers = #{}
$headers.add("Authorization", $global:authString);
$headers.add("Content-Type", "application/vnd.blackberry.activationpasswords-v1+json");
# Create body for REST call
$body = #{};
$innerBody = #(#{
"password" = $null;
"emailTemplate" = $null;
"expiry" = $expiry;
"expireAfterUse" = "true";
"activationProfile"= $null;
});
$body.add("activationPasswords",$innerBody);
$request = $global:uemBaseUrl + "/users/" + $userGuid + "/activationPasswords";
# Invoke RESTMethod to set activation password.
try
{
$response = Invoke-RestMethod -Method POST -Headers $headers -Uri $request -Body ($body | ConvertTo-Json);
}
catch
{
handleError $_;
}
exitMethod($methodName);
return $true;
}
<#
* Expire all acctivation passwords for a user.
*
* #param userGuid
* Guid of user.
* #return
* True if successful, false otherwise.
#>
function expireActivationpasswords($userGuid)
{
$methodName = "expireActivationpasswords()";
enterMethod($methodName);
# Create and set the headers for the REST command
$headers = #{}
$headers.add("Authorization", $global:authString);
$headers.add("Content-Type", "application/vnd.blackberry.activationpasswords-v1+json");
$request = $global:uemBaseUrl + "/users/" + $userGuid + "/activationPasswords";
# Invoke RESTMethod to exipre all activation passwords.
try
{
$response = Invoke-RestMethod -Method DELETE -Headers $headers -Uri $request
}
catch
{
handleError $_;
}
exitMethod($methodName);
return $true;
}
<#
* Replace all acctivation passwords for a user.
*
* #param userGuid
* Guid of user.
* #return
* True if successful, false otherwise.
#>
function replaceActivationpassword($userGuid)
{
$methodName = "replaceActivationpassword()";
enterMethod($methodName);
# Create and set the headers for the REST command
$headers = #{}
$headers.add("Authorization", $global:authString);
$headers.add("Content-Type", "application/vnd.blackberry.activationpasswords-v1+json");
# Create body for REST call
$body = #{};
$innerBody = #(#{
"password" = $null;
"emailTemplate" = $null;
"expiry" = $expiry;
"expireAfterUse" = "true";
"activationProfile"= $null;
});
$body.add("activationPasswords",$innerBody);
$request = $global:uemBaseUrl + "/users/" + $userGuid + "/activationPasswords";
# Invoke RESTMethod to set activation password.
try
{
$response = Invoke-RestMethod -Method PUT -Headers $headers -Uri $request -Body ($body | ConvertTo-Json);
}
catch
{
handleError $_;
}
exitMethod($methodName);
return $true;
}
<#
* Logging for method entry.
*
* #param methodName
* Name of the method to log
#>
function enterMethod($methodName)
{
Write-Host([string]::Format("Entering {0}...", $methodName));
}
<#
* Logging for method exit.
*
* #param methodName
* Name of the method to log.
#>
function exitMethod($methodName)
{
Write-Host([string]::Format("Exiting {0}...", $methodName));
}
<#
* Handle any errors that occur when performing the REST call.
*
* #param error
* The group create context.
#>
function handleError($error)
{
Write-Error ("The command cound not be completed. `r`nReason: " + $error.exception.message + " `r`nDetails: "+ $error.errordetails);
exit(1);
}
function main
{
$methodName = "main()";
enterMethod($methodName);
try
{
if (setup)
{
$getUserResponse = getuser $emailaddress;
$userGUID = $getUserResponse.users.guid;
if($actionType -eq "Set")
{
if([string]::IsNullOrEmpty($expiry))
{
throw [System.ArgumentNullException]"The expiry argument is required when actionType=Set";
}
if(setActivationpassword($userGUID))
{
Write-Host([string]::Format("Random activation password has been set for user '{0}'", $emailAddress));
}
}
elseif($actionType -eq "ReplaceAll")
{
if([string]::IsNullOrEmpty($expiry))
{
throw [System.ArgumentNullException]"The expiry argument is required when actionType=ReplaceAll";
}
if(replaceActivationpassword($userGUID))
{
Write-Host([string]::Format("Activation password has been replaced for user '{0}'. Existing passwords have been expired.", $emailAddress ));
}
}
elseif($actionType -eq "ExpireAll")
{
if(expireActivationpasswords($userGUID))
{
Write-Host([string]::Format("All activation passwords expired for user '{0}'", $emailAddress));
}
}
}
}
catch
{
handleError $_;
}
exitMethod($methodName);
Write-Host("Complete!");
exit(0);
}
# Call main function.
main;
Your problem is most likely here:
$getUserResponse = get-content .\users.txt $emailaddress;
$getUserResponse = ForEach-Object
It's going to be hard to debug this without running it but what are you trying to do with this?:
$getUserResponse = get-content .\users.txt $emailaddress
$emailAddress from what I can see is a never defined. Is the users.txt just a line by line file full of users files?
ForEach-Object would also need data to be piped to.
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"