Authentication error when using SharePoint Migration Tool PowerShell cmdlets - powershell

Server 2012 R2 file share to SharePoint Online migration
I am attempting to automate scheduling some file share synchronization to SharePoint Online using the migration tool, however I get an error that my credentials are incorrect.
The same credentials work using the GUI version of the SPMT so I know they are correct, and these credentials are for the global administrator of 365 so there should absolutely be no permissions issues.
The error that I receive:
Task 7967a651-6a2a-47ed-afcd-6b1567496e7d did NOT pass the parameter validation, the error message is 'Username or password for target site https://tenant.sharepoint.com/sites/FileShareSite is not correct' Migration finished, but some tasks failed! You can find the report and log at X:\log.log
The code I am using:
Import-Module Microsoft.SharePoint.MigrationTool.PowerShell
$SPOUrl = "https://tenant.sharepoint.com/sites/FileShareSite"
$Username = "admin#tenant.onmicrosoft.com"
$Password = ConvertTo-SecureString -String "PasSWorD" -AsPlainText -Force
$SPOCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $Password
Register-SPMTMigration -SPOCredential $SPOCredential -Force -MigrateWithoutRootFolder -PreserveUserPermissionsForFileShare $true -WorkingFolder "X:\log"
Add-SPMTTask -FileShareSource "\\file-server\shares\ShareOne" -TargetSiteUrl $SPOUrl -TargetList "ShareOne" -TargetListRelativePath "/"
Start-SPMTMigration -NoShow
According to the logs, I am seeing 400 response codes, as well as some 'An existing connection was forcibly closed by the remote host.'
Something so simple so I don't know what the problem could be; OS is supported, credentials are correct, URL is correct, all these settings work in the GUI version of the tool.
In the logs I see references to logging into AAD, we do not have AAD on this tenant, I am a little curious to know if that is just semantics or if that is part of the problem. I would have assumed the GUI and the PowerShell module use the same mechanisms behind the scenes. Error happened in AAD login MSAL.Desktop.4.37.0.0.MsalServiceException: ErrorCode: user_realm_discovery_failed Microsoft.Identity.Client.MsalServiceException: Response status code does not indicate success: 400 (BadRequest).

So I figured it out, the issue turned out to be PowerShell using an outdated SSL/TLS cipher. I forced TLS1.2 on the PowerShell session using [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 and it is now working as expected.

Related

Execute an App registration without AzureAD

For a professional project, a chunk of the pipeline must be able to create an application (the first App registration, so I only have a global Admin) automatically within Azure AD. So far I used AzureAD which works well with Powershell 5.6 on Windows.
I now must be able to run the code with Ubuntu 20.04 and its Powershell 7.2. Unfortunately for me, AzureAD module is only supported on non-core Windows PowerShell, therefore it does not work on core PS6 or PS7. A very simplified piece of code is the following:
# Connection infos
$tenantId = "abcdef12345-1234-1234-124-abcdef12346789"
$account = "my_admin#domain.com" # Is cloud Admin by default
$password = ConvertTo-SecureString "MyPassword" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential -ArgumentList ($account, $password)
Connect-AzureAD -Credential $psCred -Tenant $tenantId
# Create app
$appName = "MyApp"
New-App -appName $appName -tenant_id $tenantId
I am stuck and my question is the following: how could I run such an operation with Powershell 7.2 considering AzureAD is not usable? I did check Connect-MgGraph for the connection part only (https://github.com/microsoftgraph/msgraph-sdk-powershell) but the clientId is an infos that I don't have -and want to create-.
Thanks in advance
You can use DeviceLogin as explained in this article to obtain an oAuth access token for you Global Administrator account in PowerShell (independent of the version) but this first step needs a human interaction.
After obtaining the token, you can use it to make Graph API calls with your Global Administrator permissions to create an application.
Once you create your first application, you must attribute required permissions and use it to automate the process (obtain token programmatically using API calls) for application creation in PowerShell.
You could use Resource Owner Password Credentials (ROPC) to authenticate, however Microsoft actively discourages it in their documentation due to the security implications of sending a password over the wire.
If the security issues present with this method of authentication are still tolerated within your acceptance criteria, you would still need a ClientID. Luckily, AzureAD has a well-known ClientID that you can use to authenticate. This ID is 1950a258-227b-4e31-a9cf-717495945fc2
The below Powershell code should get you started. I've basically translated the HTTP request within Microsoft's documentation into a splatted Invoke-RestMethod command.
$LoginWithROPCParameters = #{
URI = "https://login.microsoftonline.com/contoso.onmicrosoft.com/oauth2/v2.0/token"
Method = "POST"
Body = #{
client_id = "1950a258-227b-4e31-a9cf-717495945fc2"
scope = "user.read openid profile offline_access"
username = "username#contoso.onmicrosoft.com"
password = "hunter2"
grant_type = "password"
}
}
Invoke-RestMethod #LoginWithROPCParameters

Authentication error using SharePoint (Online) Migration?

Using SharePoint Migration Tool for document migration to SharePoint Online. Everything is going pretty smoothly, but for some unknown reason it keeps spitting back this error:
Task 5f91e154-64ad-4f64-bf26-c73368fcd77b did NOT pass the parameter validation, the error message is 'Username or password for target site https://{company}.sharepoint.com/sites/it-test-team/Temp%20Location/Forms/AllItems.aspx is not correct'
Have checked and doublechecked my credentials. I even changed my password (and updated it in my code) in case that was the issue. My guess is that something with multi-factor authentication is causing an issue. In order to login, my company requires the use of the Microsoft Authenticator app (I need to input a code that the app gives me). If that's the issue, how do I work that into my code? If it's not, what IS the issue?
Notes: I have the correct permissions (I am owner of the SharePoint Online site, I am running Powershell ISE as an administrator, I've set the correct Execution Policies)
Here's my code:
Import-Module Microsoft.SharePoint.MigrationTool.PowerShell
$Global:SPOUrl = "https://o365gcoslo.sharepoint.com/sites/it-test-team/Temp%20Location/Forms/AllItems.aspx"
$cred = (Get-Credential ~my company email~)
$Global:SPOCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $cred
#Define SPMT task vars
$Global:FileshareSource = "I:\Applications\Temp_PTAX"
$Global:TargetListName = "Temp Location"
#Register the SPMT session with SPO credentials#
Register-SPMTMigration -SPOCredential $Global:SPOCredential -Force
#File Migration task
Add-SPMTTask -FileShareSource $Global:FileshareSource -TargetSiteUrl $Global:SPOUrl -TargetList $Global:TargetListName
Start-SPMTMigration -NoShow
$session = Get-SPMTMigration
#migration stuff here

Wait for Active Directory Authentication URL list to update within a Powershell Azure Function

I need to ensure a reply url is added to a v2 Active Directory App before returning a HTTP response within a Powershell Serverless Function.
Currently I've successfully managed connecting to azure using a service principal, getting the active directory application & updating the authentication list with a new reply url.
This works great but there seems to be some propagation period on completing the job. Everything happens as mentioned in a Powershell Serverless Function & returns a 200 HTTP status when finished.
Once the response (HTTP 200 OK) is received I'm using the Active Directory Authentication Library (ADAL) to log in from some JS app using a full page redirect.
This is where the issue lies, once the Powershell runs & returns the client app tries to login with ADAL but that Active Directory prompts with an error, the supplied url isn't one currently on the authentication list.
I've looked into Start-ThreadJob & Wait-Job but not sure if number one I'm using it correctly or number two it is the best approach.
Example code:
$appId = <ACTIVE_DIRECTORY_APP_ID>
$url = <NEW REPLY URL>
$password = ConvertTo-SecureString -String $env:SERVICE_PRINCIPAL_SECRET -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($env:SERVICE_PRINCIPAL_ID, $password)
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $env:TENANT_ID
$app = Get-AzADApplication -ApplicationId $appId
$replyUrlList = $app.ReplyUrls
$replyUrlList.Add($url)
Update-AzADApplication -ApplicationId $appId -ReplyUrl $replyUrlList
$status = [HttpStatusCode]::Created
$body = "URL Added Successfully"
Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{
StatusCode = $status
Body = $body
})
At the moment the AD authentication list is updated anywhere from 1 minute - 5 minutes in some cases. Depending if the function is booting from cold-start.
Should I use a loop to check the AD Application information within the Powershell script?
Should I use job threading & wait job cmdlets?
Maybe throw in a bit of sleep?
Just looking for the best approach here to guarantee the new callback url is 100% added before trying to authenticate with the ADAL library.
Any help would be great!
This is not an answer with a solution. But I think I'm reading something that I have experienced on several occasions.
I've been using python and Hashicorp vault to try and manage tokens/RBAC on applications. But very often it would break because it had not updated yet, due to the propagation from AAD to back end being asynchronous from what I was told.
I even did checks where I used ADAL to loop over the application to verify if it was good. But even then it would still fail on some occasions. Which hurt the automation I was trying to put in place.
Now you are having some issue that seems similar, but instead while adding the reply url to an existing application.
My question for testing is; does the reply URL work when it is supplied upon creation of the application? If so, and testing is 100%, then you are having the same issue.
For me, pre-creation of all necessary properties on applications is what helped me circumvent this annoying issue. As I don't think adding a sleep anywhere is a good way to move forward, and the reply from the API isn't reliable enough to work on.
If pre-creation is not an option, I suppose the sleep timer is probably some way forward. For me, that ended up being 2-5m in some cases. And in some lucky cases 7-30s

access sharepoint REST api using powershell with windows authentication

I have a sharepoint 2013 server, which I can log into using Windows Authentication via a web-browser. When I have logged on using my browser, if I then - using that same browser - browse to http://mysharepointserver/_api/web I get some useful XML.
However, I want to write a powershell script that uses this XML. To that end, following the suggestions from this page:
How to make an authenticated web request in Powershell?
I wrote the following code:
$PWord = ConvertTo-SecureString –String "MyAwesomePassword" –AsPlainText -Force
$creds = New-Object System.Net.NetworkCredential("MyUserName",$PWord,"TheDomain")
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = $creds
$url = "http://mysharepointserver/_api/web"
$output = $webclient.DownloadString($url)
echo $output
However, when I run this code, I get the error message:
Exception calling "DownloadString" with "1" argument(s): "The remote server returned an error: (403) Forbidden."
Even though I can access the same URL using a web-browser, if I type in the (same) credentials using the Windows login dialog that pops up for authentication purposes.
Does anyone know if it is possible to do this using Powershell?
thanks heaps all
Why aren't you using the default CMDlets that come with Powershell (unless using PS2 or lower)?
Invoke-Webrequest and Invoke-Restmethod both support the -credential switch which can be used to authenticate against the webserver.
You can also use Get-credential to store your credentials (though you can't get yhem from a file or string that way, at least not the password)
Script (in pseudo code and since i'm on my phone no code tags) would look like this :
Invoke-Restmethod -uri 'http://bla/api' -credential (get-credential)

Setting up CredSSP properly for powershell multi-hop issue

I've encountering the double-hop issue with a script I'm writing. Issue right now is that when I get to New-PSSession on the computer remoting in. I get the following error:
Image Link if its too hard to read
Here's the code that runs on the original server:
$password = ConvertTo-SecureString "password" -AsPlainText -Force
$cred= New-Object System.Management.Automation.PSCredential ("domain\admin", $CApassword)
$sesh = new-pssession -computername "MSSCA" -credential $CAcred -Authentication CredSSP
This $sesh variable comes back null and throws the error above.
Server executing powershell script/remoting is set to delegate fresh credentials to mssca (I DID specify the FQDN for this target server), and likewise mssca is set to receive.
I followed the instructions of the error message to modify the group policy, enabling Allow Delegating Fresh Credentials under Configuration -> Administrative Templates -> System -> Credentials Delegation -> Allow Delegating Fresh Credentials which was already set up to delegate fresh credentials to mssca.
Any ideas how I can fix this?
Figured it out. Though the error message said to use the FQDN, my script was not using the FQDN. After using the "NTLM-only server authentication" option instead as well as changing the the group policy setting to just mssca and NOT the FQDN, it worked.