I'm working on a script to login to a sharepoint 2013 site and navigate to a few pages to make sure the site is working after updates and DR drills. I'm calling Invoke-WebRequest like this:
$site = Invoke-WebRequest -uri 'https://spsite' -Credential $(Get-Credential) -SessionVariable s
when I make the call I get a 401 Unauthorized error back. I have tried using basic authentication and building out the headers like this:
$u = 'domain\user'
$p = 'password'
$header = #{ Authorization = "Basic {0}" -f [convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $u,$p))) }
$site = Invoke-WebRequest -uri 'https://spsite' -Headers $header
with the same result. I'm hoping someone could offer another way to make this connection?
so I found a way to make this work in my situation and wanted to post the basics in case someone else runs into this.
I found that when the exception is thrown you can get the actual response from the web server from the exception object like this:
try{
$site = Invoke-WebRequest -uri 'https://spsite' -Credential $(Get-Credential) -SessionVariable s
}
catch{
$site = $_.Exception.Response
}
after that I was able to manipulate the $site variable to follow the redirection and submit the credentials as needed.
Use Export-PSCredential and Import-PSCredential from WFTools - you'll only have to enter your credentials once per box, and it will last as long as your password doesn't change: https://github.com/RamblingCookieMonster/PowerShell
Install-Module -Name WFTools -RequiredVersion 0.1.44
Import-Module WFTools;
$getCredentialMessage = "Please provide your Windows credentials";
$importedCredential = Import-PSCredential;
if ($importedCredential) {
Write-Host -ForegroundColor Yellow "Imported your cached credential."
while (-not $(Test-Credential -Credential $credential)) {
Write-Host -ForegroundColor Yellow "Your cached credentials are not valid. Please re-enter."
$credential = Get-Credential -Message $getCredentialMessage;
}
$credential = $importedCredential;
}
else {
$credential = Get-Credential -Message $getCredentialMessage;
while (-not $(Test-Credential -Credential $credential)) {
$credential = Get-Credential -Message $getCredentialMessage;
}
Export-PSCredential $credential;
}
# Here is where the magic happens
$site = Invoke-WebRequest -uri 'https://spsite' -Credential $credential
Related
I have a Jenkins Job, and that needs to get triggered by Octopus deploy. For that I have used the step template - Jenkins -Queue Job from Octopus library Installed Community Step Templates.
In the existing powershell script of the template, I have updated my parameters to run the Jenkins job. And finally during execution, I am facing the below error:
Exception in jenkins job: The remote server returned an error: (403) Forbidden.
The remote script failed with exit code 1.
I tried the ways to authenticate Octopus with Jenkins, and still couldn't find a way. Can someone provide inputs with this ? Thanks in advance!
I encountered the same issue just now. I ended up just copying their template and making changes. The issue is related to not keeping the session cookie across requests. Note: I had to move their authentication code out of the function because the session variable data would not work for some reason.
$jenkinsServer = $OctopusParameters['jqj_JenkinsServer']
$jenkinsUserName = $OctopusParameters['jqj_JenkinsUserName']
$jenkinsUserPassword = $OctopusParameters['jqj_JenkinsUserPasword']
$jobURL = $jenkinsServer + $OctopusParameters['jqj_JobUrl']
$failBuild = [System.Convert]::ToBoolean($OctopusParameters['jqj_FailBuild'])
$jobTimeout = $OctopusParameters['jqj_JobTimeout']
$buildParam = $OctopusParameters['jqj_BuildParam']
$checkIntervals = $OctopusParameters['jqj_checkInterval']
$jobUrlWithParams = "$jobURL$buildParam"
Write-Host "job url: " $jobUrlWithParams
try {
$params = #{}
if ($jenkinsUserName -ne "") {
$securePwd = ConvertTo-SecureString $jenkinsUserPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($jenkinsUserName, $securePwd)
$head = #{"Authorization" = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($jenkinsUserName + ":" + $jenkinsUserPassword ))}
$params = #{
Headers = $head;
Credential = $credential;
ContentType = "text/plain";
}
}
# If your Jenkins uses the "Prevent Cross Site Request Forgery exploits" security option (which it should),
# when you make a POST request, you have to send a CSRF protection token as an HTTP request header.
# https://wiki.jenkins.io/display/JENKINS/Remote+access+API
try {
$tokenUrl = $jenkinsServer + "crumbIssuer/api/json?tree=crumbRequestField,crumb"
$crumbResult = Invoke-WebRequest -Uri $tokenUrl -Method Get #params -UseBasicParsing -SessionVariable session | ConvertFrom-Json
Write-Host "CSRF protection is enabled, adding CSRF token to request headers"
$params.Headers += #{$crumbResult.crumbRequestField = $crumbResult.crumb}
} catch {
Write-Host $Error[0]
}
Write-Host "Start the build"
$returned = Invoke-WebRequest -Uri $jobUrlWithParams -WebSession $session -Method Post -UseBasicParsing #params
Write-Host "Job URL Link: $($returned.BaseResponse.Headers['Location'])"
$jobResult = "$($returned.BaseResponse.Headers['Location'])/api/json"
$response = Invoke-RestMethod -Uri $jobResult -Method Get #params -WebSession $session
$buildUrl = $Response.executable.url
while ($buildUrl -eq $null -or $buildUrl -eq "") {
$response = Invoke-RestMethod -Uri $jobResult -Method Get #params -WebSession $session
$buildUrl = $Response.executable.url
}
Write-Host "Build Number is: $($Response.executable.number)"
Write-Host "Job URL Is: $($buildUrl)"
$buildResult = "$buildUrl/api/json?tree=result,number,building"
$isBuilding = "True"
$i = 0
Write-Host "Estimate Job Duration: " $jobTimeout
while ($isBuilding -eq "True" -and $i -lt $jobTimeout) {
$i += 5
Write-Host "waiting $checkIntervals secs for build to complete"
Start-Sleep -s $checkIntervals
$retyJobStatus = Invoke-RestMethod -Uri $buildResult -Method Get #params -WebSession $session
$isBuilding = $retyJobStatus[0].building
$result = $retyJobStatus[0].result
$buildNumber = $retyJobStatus[0].number
Write-Host "Retry Job Status: " $result " BuildNumber: " $buildNumber " IsBuilding: " $isBuilding
}
if ($failBuild) {
if ($result -ne "SUCCESS") {
Write-Host "BUILD FAILURE: build is unsuccessful or status could not be obtained."
exit 1
}
}
}
catch {
Write-Host "Exception in jenkins job: $($_.Exception.Message)"
exit 1
}
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?
I need a script that downloads a certain folder and all its subfolders + files to my pc from a webserver. It needs to be in powershell. I searched a bit and found this:
Invoke-WebRequest http://www.example.com/package.zip -OutFile package.zip
I get this error when I try to run it. But I can't figure out how I can pass the username and password with it. If anyone can help me that would be greatly appreciated! Also how can I specify the folder it should be saved to? Thanks in advance
Following up regarding my comment.
I ask that question because some sites require you to be specific in the credential presentation vs just one blob of stuff. For example:
$credentials = Get-Credential
$webServerUrl = 'http://SomeWebSite'
$r = Invoke-WebRequest $webServerUrl -SessionVariable my_session
$form = $r.Forms[0]
$form.fields['Username'] = $credentials.GetNetworkCredential().UserName
$form.fields['Password'] = $credentials.GetNetworkCredential().Password
$InvokeWebRequestSplat = #{
Uri = $($webServerUrl + $form.Action)
WebSession = $my_session
Method = 'GET '
Body = $form.Fields
}
$r = Invoke-WebRequest #InvokeWebRequestSplat
Update
The follow-up to the comment. This is using IE with PowerShell for site automation.
# Scrape the site to find form data
$url = 'https://pwpush.com'
($FormElements = Invoke-WebRequest -Uri $url -SessionVariable fe)
($Form = $FormElements.Forms[0]) | Format-List -Force
$Form | Get-Member
$Form.Fields
# Use the info on the site
$IE = New-Object -ComObject "InternetExplorer.Application"
$FormElementsequestURI = "https://pwpush.com"
$Password = "password_payload"
$SubmitButton = "submit"
$IE.Visible = $true
$IE.Silent = $true
$IE.Navigate($FormElementsequestURI)
While ($IE.Busy) {
Start-Sleep -Milliseconds 100
}
$Doc = $IE.Document
$Doc.getElementsByTagName("input") | ForEach-Object {
if ($_.id -ne $null){
if ($_.id.contains($SubmitButton)) {$SubmitButton = $_}
if ($_.id.contains($Password)) {$Password = $_}
}
}
$Password.value = "1234"
$SubmitButton.click()
Invoke-WebRequest is Powershell's version of curl. Its alias is even named curl.
SO, in the IVR use case, all you really need to do something like the Facebook and Linkedin examples:
$cred = Get-Credential
$login = Invoke-WebRequest 'facebook.com/login.php' -SessionVariable 'fb'
$login.Forms[0].Fields.email = $cred.UserName
$login.Forms[0].Fields.pass = $cred.GetNetworkCredential().Password
$mainPage = Invoke-WebRequest $login.Forms[0].Action -WebSession $fb -Body $login -Method Post
$cred = Get-Credential
$login = Invoke-WebRequest 'https://www.linkedin.com/uas/login?goback=&trk=hb_signin' -SessionVariable 'li'
$login.Forms[0].Fields.email = $cred.UserName
$login.Forms[0].Fields.pass = $cred.GetNetworkCredential().Password
$mainPage = Invoke-WebRequest $login.Forms[0].Action -WebSession $LI -Body $login -Method Post
Yet, notice I on the FB/LI login page, and I'd need to know that even existed before trying this. Note this is old code, That I've not used in a very long while and I don't have a FB account. I passed this on to someone who did.
$cred = Get-Credential
Invoke-WebRequest http://www.example.com/package.zip -OutFile package.zip -Credential $cred
Very confused on this issue. Here is what I am dealing with currently.
I have an API endpoint which looks like this /subscriptions/:id. This endpoint serves as both a GET & a DELETE endpoint. When I run a GET, it returns the object as it normally does, but changing the action to a DELETE gives me back a 404 for the very same resource which was just returned in the GET, I don't know why.
Here is my Powershell code.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$user = '*********'
$pass = ConvertTo-SecureString '*********' -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
$base = "https://*********.hosted.xmatters.com/api/xm/1"
$del_path = "$base/subscriptions/********uuid***********"
$path = "$base/subscriptions"
$payload = #{
id = '********uuid***********'
description = '**** NEW DESCRIPTION ****'
}
$params = $payload | ConvertTo-Json
// **** SUCCESS
$thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method GET
// **** FAILS
$thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method DELETE
// **** FAILS
$thing = Invoke-WebRequest -Credential $cred -Uri $path -Method POST -Body $params -ContentType 'application/json'
So, like mentioned previously, I am POSITIVE that the resource exists from the API. I am able to get it when running a GET but both POST (to update) & DELETE throw 404 errors. Here is the error I get.
Invoke-WebRequest : The remote server returned an error: (404) Not Found.
At \\mmfile\ct32373$\Appsense\Desktop\Line of Business Revisions.ps1:24 char:10
+ $thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method D ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebReque
st) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Comman
ds.InvokeWebRequestCommand
The strange thing is that I am able to run the DELETE request successfully using POSTMAN, however because of the volume of data I need to process, this is not a good option
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/