Checking remote PowerShell session information from within a function - powershell

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?

Related

Jenkins -> powershell Invoke-WebRequest with UseDefaultCredentials

I try to execute a PowerShell script on the Jenkins slave. It looks like:
stage ("Get") {
steps {
powershell(
script: '''
$srcCommonParams = #{
Method = 'GET'
Uri = $getUri
}
Invoke-WebRequest #srcCommonParams -UseDefaultCredentials -Verbose
The question is where the default credential comes from? I thought that they are the ones on which behalf my Jenkins slave windows service runs on. The problem is that my Jenkins slave runs as user A, but Invoke-WebRequest complains that user B doesn't have sufficient privileges to do a request.
You have to get credentials from Jenkins.
You have to add 'withCredentials' and in powershell similar to this:
stage ("Get") {
steps { withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'your-credentials-id',usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']])
powershell(
script: '''
$encryptedPassword = ConvertTo-SecureString "%PASSWORD%" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("%USERNAME%", $encryptedPassword)
$srcCommonParams = #{
Method = 'GET'
Uri = $getUri
}
Invoke-WebRequest #srcCommonParams -Credential $mycreds -Verbose

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

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

Problem to connect to TFS with user/password

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

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

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

invoke-webrequest returns 401 with Windows Authentication

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