Deleting Gmail Emails via Google API using Powershell v2.0 - powershell

$user = "example#gmail.com"
$pass= "examplepassword"
$secpasswd = ConvertTo-SecureString $user -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($pass, $secpasswd)
Invoke-RestMethod 'https://www.googleapis.com/gmail/v1/users/me/messages/0' -Method Delete -Credentials $cred
So, my problem here is twofold.
I originally tried using Invoke-WebRequest to delete gmail emails via the Google API with a http delete request. However, this did not work because Powershell 2.0 does not support Invoke-WebRequest.
Thereafter, I turned to attempting to utilize Invoke-RestMethod after experimentation with IMAP and POP3, which both required external dependencies (Adding .dlls to the machines I am working with is not optimal).
Therefore, if someone could show me the appropriate way to delete an email via the Google API in Powershell, I would appreciate it. I have provided some sample code as to what I am working with above. Please excuse any mistakes it may contain, as I am relatively new to Powershell, and my experience remains limited in working with RESTful services.

The GMail API is going to require Oauth2 authentication unless this is a gsuit / domain admin / GMail account in which case you can use a service account for authentication. In either case you cant use login and password.
My powershell knowledge is very limited have you considered doing this directly though the mail server IMAP and SMTP and not using the API. No idea if that's possible or not with powershell
Update:
I was able to do it using Invoke-WebRequest you will still need to get an access token first.
Invoke-WebRequest -Uri "https://www.googleapis.com/gmail/v1/users/me/messages/0?access_token=$accesstoken"-Method Get | ConvertFrom-Json
seams to also work
Invoke-RestMethod -Uri "https://www.googleapis.com/gmail/v1/users/me/messages/0?access_token=$accesstoken"-Method Get
Put up a the code for OAuth on GitHub if your interested: Google Oauth Powershell

Related

Authentication error when using SharePoint Migration Tool PowerShell cmdlets

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.

How to Fix PowerShell Script from Basic Auth to Modern Auth

I have a PowerShell script that, after pinging a server address, uses Basic Auth to send an automated email via Task Scheduler. Microsoft has deprecated Basic Auth in Exchange Online in favor of Modern Auth, but I do not see clear directions for updating a PowerShell script to use Modern Auth.
This is an example of the Basic Auth that I need to convert.
$secpasswd = ConvertTo-SecureString “password” -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential (“user#place.com”, $secpasswd)
Send-MailMessage -SmtpServer smtp.office365.com -Port 587 -From user#place.com -To otheruser#place.com -Subject test -Body test -Credential $mycreds -UseSsl"
Can someone point me to an example of Modern Auth being used in a similar script or share what I need to do to update and run the above script?
Many Thanks!
As per the resources in my original comment.
Send-MailMessage is obsolete and no longer supported. Microsoft says this cmdlet does not guarantee a secure connection to SMTP servers. As per:
https://aka.ms/SendMailMessage
Therefore use the below:
Send-MgUserMail - MS Docs
Note: Send-MgUserMail requires a more complex parameter structure.
$EmailMessageContent=#'
<Strong> This is a Test Message</Strong><br>
Modern auth testing
'#
$params = #{
Message = #{
Subject = "Using MSGraph"
Body = #{
ContentType = "html"
Content = $EmailMessageContent
}
ToRecipients = #(
#{
EmailAddress = #{
Address = "SomeRecipientEmaiAddress"
}
}
)
}
}
Import-Module Microsoft.Graph.Users.Actions
Connect-MgGraph -Scopes Mail.Read
Send-MgUserMail -UserId 'SomeSenderEmailAddress' -BodyParameter $params
Point of note:
SMTP AUTH will still be available when Basic authentication is permanently disabled on October 1, 2022. The reason SMTP will still be available is that many multi-function devices such as printers and scanners can't be updated to use modern authentication.
See also the below for full details of the why and so on... (and more sample code):
Authenticate an IMAP, POP or SMTP connection using OAuth
Moving on from Send-MailMessage: Sending Email from PowerShell using
the Graph API
The Send-MailMessage Conundrum
Largely because of history, Exchange Online supports a wide variety of
connectivity protocols. Microsoft is making some progress to convince
customers to disable basic authentication for protocols they never
use, and has upgraded older protocols like POP3 and IMAP4 to use OAuth
2.0 for modern authentication. As discussed in this blog, tenants will need to find PowerShell scripts which call the Send-MailMessage cmdlet
and eventually upgrade the code with a more modern method to send
email.
The Send-MailMessage cmdlet depends on the SMTP AUTH protocol to send
email using basic authentication. Microsoft announced OAuth 2.0
support for SMTP AUTH in April 2020, but this doesn’t mean that an
off-the-shelf replacement cmdlet is available. Microsoft says that the
announcement “is for interactive applications to enable OAuth for IMAP
and SMTP [AUTH].” In effect, this means mail clients or other
applications which send, read, or otherwise process email. A quick
trip to the referenced page leaves no doubt that this means more than
replacing a few lines of code in a PowerShell script.
Thanks #postanote for your suggestions, the fix eventually came down to this:
from user#place.com I had to drop the 'place.com' and just keep the alias
with -SmtpServer smtp.office365.com I had to drop 'office365.com' and replace with '[uni].edu'

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

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

Send login username with REST API + Powershell

I've got the following Powershell script:
$url = "http://somerandomapikeyhere#prestashop.dev/my-store/api"
$request = [System.Net.WebRequest]::Create($url)
$response = $request.GetResponse()
echo $response
which attempts to access my Prestashop API REST service.
I can access the URL from Chrome without a problem, but in PowerShell I get a 401 Unauthorized response, which is understandeable as the somerandomapikeyhere bit in the URL needs to get dealt with differently in PowerShell.
The question is, how? Any ideas / advice?
It's not powershel, but the .net class that is not able to take an url in that format. You need to provide the credentials seperate. See here or here.
But if you have powershell v3 you are better off using the build in commands for web requests or even REST requests.
Invoke-restmethod -uri 'prestashop.dev/my-store/api' -credential 'someapikey'