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!
Related
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?
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()
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/
Here's a repro of my Powershell scenario:
function Call-Api {
[CmdletBinding()]
param(
[Parameter(Position = 0, Mandatory = $false)]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Invoke-RestMethod -Uri "http://localhost/api" -Method Get -Credential $Credential
}
The API has Basic Auth. If I call it like this:
$pwd = ConvertTo-SecureString "secret!" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("username", $pwd)
Call-Api $cred
Then I get a proper response. But if I call it without credentials like this:
Call-Api
I get:
Invoke-RestMethod : Object reference not set to an instance of an object.
I could of course do an if...else thing switching on whether $Credential is set or not, but that's not very elegant. From the relevant docs I understand that the default value of that cmdlet is "the current user".
How can I do something similar? What default do I set for $Credential so that it is the current user?
You can remove the Empty Credential that you are defining as default (I believe this is overwriting the cmdlets own default of current user), then use splatting and only add the $Credential Parameter if it present. If it's not present it will use the cmdlets own default value.
function Call-Api {
[CmdletBinding()]
param(
[Parameter(Position = 0)]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential
)
$params = #{}
$params['Uri'] = "http://google.com"
$params['Method'] = "Get"
if ($Credential) { $params['Credential'] = $Credential }
Invoke-RestMethod #params
}
I am trying to log on to an https site using a powershell script.
I've tried using a PSCredential, but I get a 401 unauthorized error when I do.
I am providing the username and password in the script. I want it to log me in without being prompted.
What is the best way to do this? Is it best to use an httprequest?
Here's what I have so far.
$userName = "username"
$secure_password = ConvertTo-SecureString "my password" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($userName, $secure_password)
$proxy = New-WebServiceProxy -Uri "url_for_the_download" -Credential $credential
Something like this should work:
$client = New-Object System.Net.Webclient
$client.Credentials = New-Object System.Net.NetworkCredential("user","pass")
$client.DownloadFile("http://somesite.com/somefile.zip","C:\somefile.zip")