PowerShell authenticate and read google calendar events - powershell

Using PowerShell, I am trying to authenticate to Google calendar using a service account, and read events. With the help of stack overflow, I was able to install and import the required packages in my PowerShell session.
Newtonsoft.Json
Google.Apis.Core
Google.Apis
Google.Apis.Auth
Google.Apis.Calendar.v3
I then tried to read Google calendar events
# Set the credentials and calendar ID
$credentials = Get-Content "C:\Users\Windows\Desktop\powershell-376318-70973daa61d9.json" | ConvertFrom-Json
$calendarId = "primary"
# Build the calendar service
$service = New-Object Google.Apis.Calendar.v3.CalendarService
$service.Credentials = New-Object Google.Apis.Auth.OAuth2.GoogleCredential($credentials)
# Get the current time
$now = Get-Date
# Get the events for the next hour
$events = $service.Events.List($calendarId)
$events.TimeMin = $now
$events.TimeMax = $now.AddHours(1)
$events.SingleEvents = $true
$events.OrderBy = "startTime"
$events = $events.Execute()
# Print the events
foreach ($event in $events.Items) {
Write-Host "Event: $($event.Summary)"
Write-Host "Start Time: $($event.Start.DateTime)"
Write-Host "End Time: $($event.End.DateTime)"
Write-Host ""
}
But I get this error
New-Object : A constructor was not found. Cannot find an appropriate constructor for type
Google.Apis.Auth.OAuth2.GoogleCredential.
At line:7 char:24
+ ... edentials = New-Object Google.Apis.Auth.OAuth2.GoogleCredential($cred ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand
Exception calling "Execute" with "0" argument(s): "The service calendar has thrown an exception. HttpStatusCode is
Forbidden. The request is missing a valid API key."
At line:18 char:1
+ $events = $events.Execute()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : GoogleApiException
Obviously, there's an issue with "Google.Apis.Auth.OAuth2.GoogleCredential". I'm not sure it's even possible to authenticate and read events using a service account, but right now I don't know how to proceed with this.
I want to avoid using OAuth2 client id and client secret for authentication if possible, because I've had issues in the past with token expiries, whereas a service account doesn't expire.

The error message tells you exactly what the problem is:
Cannot find an appropriate constructor for type Google.Apis.Auth.OAuth2.GoogleCredential.
Having a look at the docs shows: There really is no constructor like GoogleCredential(string). But you can use different static methods to create a GoogleCredential object. E. g. FromJson(String):
# Set the credentials and calendar ID
$credentials = Get-Content -Raw -Path "C:\Users\Windows\Desktop\powershell-376318-70973daa61d9.json"
# Build the calendar service
$service = New-Object Google.Apis.Calendar.v3.CalendarService
$service.Credentials = [Google.Apis.Auth.OAuth2.GoogleCredential]::FromJson($credentials)
You can also pass the file directly to GoogleCredential via FromFile:
# Build the calendar service
$service = New-Object Google.Apis.Calendar.v3.CalendarService
$service.Credentials = [Google.Apis.Auth.OAuth2.GoogleCredential]::FromFile('C:\Users\Windows\Desktop\powershell-376318-70973daa61d9.json')

Related

ExecuteCrmOrganizationRequest fails with PublishThemeRequest

I'm trying to write a powershell script to publish a theme in my on-premise installation of Dynamics CRM.
According to this page it should be really straight forward, I create an object of type PublishThemeRequest which derives from OrganizationRequest and call the method ExecuteCrmOrganizationRequest.
This is the code I'm running:
Import-Module Microsoft.Xrm.Data.Powershell
Add-PSSnapin Microsoft.Xrm.Tooling.Connector
$orgName = "<my organization name>";
$serverUrl = "http://server_url";
$Cred = Get-Credential -UserName "<my username>" -Message "Please Enter admin credentials for CRM"
$conn = Get-CrmConnection -Credential $Cred -OrganizationName $orgName -ServerUrl $serverUrl
$req = New-Object Microsoft.Crm.Sdk.Messages.PublishThemeRequest
$req.Target = New-CrmEntityReference -EntityLogicalName "theme" -Id "DB80D57A-6410-4D11-B784-0093122802AC"
$result = [Microsoft.Crm.Sdk.Messages.PublishThemeResponse]$conn.ExecuteCrmOrganizationRequest($req, $null)
This is what I get when I execute the code above:
Cannot convert argument "req", with value: "Microsoft.Crm.Sdk.Messages.PublishThemeRequest", for "ExecuteCrmOrganizationRequest" to type
"Microsoft.Xrm.Sdk.OrganizationRequest": "Cannot convert the "Microsoft.Crm.Sdk.Messages.PublishThemeRequest" value of type
"Microsoft.Crm.Sdk.Messages.PublishThemeRequest" to type "Microsoft.Xrm.Sdk.OrganizationRequest"."
At C:\Users\xxxxxxxxxx\Desktop\PublishTheme.ps1:21 char:1
+ $result = [Microsoft.Crm.Sdk.Messages.PublishThemeResponse]$conn.Exec ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
I have been reading the documentation and other websites for a couple of hours now but seem to have hit a wall.
Any ideas of what my problem might be?

Office 365 Graph API 400 Bad Request

I'm using the following module
https://psmsgraph.readthedocs.io/en/latest/
When attempting to pass in the following $AuthCode
#{AuthCodeCredential=System.Management.Automation.PSCredential; ResultURL=https://localhost/?code=AQABAAIAAADX8GCi6Js6SK82TsD2Pb7rsheCqji8MFS19OlJ8dFqrxjfk9
TTz9sPIyErZzaOD45niqpvZz5vnViz6tAU2BoKGQfX1-tW781HweG4jHoznO09NQpJDTiDl8i8yv6O_xT7RqUzitK59gssyyOPjc-4k5BEVa0hPJpXJCFHwUokCRzRBo4tS6Frv5XbxQkR8huM2Y1pK8o6Mq
PxKMPxGSfcrzS7vRjh-99qeD-DsXbc1eGGh1AQsWfTl1wqUlUcLJnMstF6ePnxIuM2XpRbFo7kYZ-5md7xrSD4Fw9L02NQjA-7TuOFM_4xXeM6gKL9SG8iW9Hxow0aNUm8ZtsLPBvAPJWJVrzhglVqz9pmmV
c9nAD1ujn2au2J9OlT_zwlXsJyHb3Gf4GqjQraYm91dV_7HzRj92LlCwjAwPypXFAhllYXPflUCgUtUYvvJfxSVS5Nc1meRUXlk-qedwv1RpbbT-pNHMPUuJmbEEM-sxAY1Oxg9GC93oH3S-rSMF5kZydr40
UOFwlnRIp10Vti6VA3IAA&session_state=25644a38-645f-4c8b-a6d9-be01838fa932; Application=Guid: 91ba65d8-2aa9-4771-9f9c-d05756da6931 Name: PowerShell Module; Au
thCodeBaseURL=https://login.microsoftonline.com/<mytenantid>/oauth2/authorize; Response=System.Collections.Hashtable; Issued=19/06/2
018 6:46:38 PM; Success=System.Management.Automation.PSScriptProperty; Expires=System.Management.Automation.PSScriptProperty; IsExpired=System.Management.Au
tomation.PSScriptProperty}
I get the following error:
Get-GraphOauthAccessToken : The remote server returned an error: (400) Bad Request.
At line:24 char:21
+ ... cessToken = Get-GraphOauthAccessToken -BaseURL 'https://login.microso ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WebException
+ FullyQualifiedErrorId : System.Net.WebException,Get-GraphOauthAccessToken
Here is the full code:
Import-Module -name 'PSMSGraph'
#In the credential prompt, provide your application's Client ID as the username and Client Secret as the password
$ClientCredential = Get-Credential
$GraphAppParams = #{
Name = 'PowerShell Module'
ClientCredential = $ClientCredential
RedirectUri = 'https://localhost/'
Tenant = '<mytenantid>'
}
$GraphApp = New-GraphApplication #GraphAppParams
Write-Host "Application"
Write-Host $GraphApp
Write-Host "-------------"
# This will prompt you to log in with your O365/Azure credentials.
# This is required at least once to authorize the application to act on behalf of your account
# The username and password is not passed back to or stored by PowerShell.
$AuthCode = Get-GraphOauthAuthorizationCode -BaseURL 'https://login.microsoftonline.com/<mytenantid>/oauth2/authorize' -Application $GraphApp
Write-Host 'Authorization Code'
Write-Host $AuthCode
Write-Host '----------------'
# see the following help for what resource to use.
# get-help Get-GraphOauthAccessToken -Parameter Resource
$GraphAccessToken = Get-GraphOauthAccessToken -BaseURL 'https://login.microsoftonline.com/<mytenantid>/oauth2/token' -AuthenticationCode $AuthCode -Resource "https://graph.microsoft.com"
$GraphAccessToken | Export-GraphOAuthAccessToken -Path 'c:\Temp\AccessToken.XML'
My problem is that there are numerous URLS that I could connect to and conflicting ideas of what my tenant id is so I'm not sure if I have either correct. This is for a company not a single user.
Edit - at the end of the day, all I want to be able to do is pull reports that are visible in https://portal.office.com/adminportal/home#/reportsUsage

Powershell compare size of local file to file on sharepoint

I am using the current code to download a file from a sharepoint...
$webClient = New-Object System.Net.WebClient
$webClient.UseDefaultCredentials = $true
$webClient.DownloadFile($sharepointPathFile, $localPathFile) | Out-Null
But what if I wanted to check if the file is already at the local location and the size matches or is different? How would I do this using powershell?
Update
This was the closest I could get...
$url = $sharepointPathFile
$clnt = [System.Net.WebRequest]::Create($url)
$resp = $clnt.GetResponse()
$fileSize = $resp.ContentLength
Write-Host $fileSize
But I am getting the following error:
Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (401) Unauthorized."
At C:\Scripts\Tests\testCheckUpdatedSearchFiles.ps1:345 char:2
+ $resp = $clnt.GetResponse()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
I have full read and download rights, so is there something else not going right here?
I'm not sure if the "GetResponse" method will return exactly what you're looking for. And depending on the ContentLength, you may want to explicitly define your types. I would try something like this:
$webClient = New-Object System.Net.WebClient
$webClient.OpenRead("path/to/file")
[Int64]$fileSize = $webClient.ResponseHeaders["Content-Length"]
Write-Host $fileSize

Binding to a different active directory ldap instance in Powershell

I am trying to connect to some independent LDAP stores (ADAM - Active Directory Application Mode) using a specific set of credentials to bind with, but having trouble working out the best way to do this. Here is an example which I had hoped would work:
$ldapHost = New-Object System.DirectoryServices.DirectoryEntry("LDAP://{serverip}:{port}/dc=acme,dc=com","cn=myuser,dc=acme,dc=com","myPassw0rd")
$ldapQuery = New-Object System.DirectoryServices.DirectorySearcher
$ldapQuery.SearchRoot = $ldapHost
$ldapQuery.Filter = "(objectclass=*)"
$ldapQuery.SearchScope = "Base"
$ldapQuery.FindAll()
This will get me:
Exception calling "FindAll" with "0" argument(s): "A local error has occurred.
"
At line:1 char:19
+ $ldapQuery.FindAll <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
I also tried:
$ldapHost = New-Object System.DirectoryServices.DirectoryEntry("LDAP://{myip}:{port}/dc=acme,dc=com")
$ldapHost.Username = "cn=myuser,dc=acme,dc=com"
which results:
The following exception occurred while retrieving member "Username": "The specified directory service attribute or valu
e does not exist.
"
At line:1 char:11
+ $ldapHost. <<<< Username = "cn=myuser,DC=acme,dc=com"
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
I've tried a few variations with filter etc. Most of the documentation I can find on this just assumes that I'm connecting to ldap from within the same directory/am connecting with the correct user for the query.
If you're familiar with Python's ldap module, this is how I do it in that:
import ldap
ld = ldap.initialize("ldap://{myip}:{port}")
ld.bind_s("cn=myuser,dc=acme,dc=com","Passw0rd")
ld.search_s("dc=acme,dc=com",ldap.SCOPE_BASE,"objectclass=*")
Any pointers on how to approach this? I can definitely connect via the various LDAP clients out there. I might need to explicitly specify authentication, but I'm not sure because there is so little information on querying from outside the domain.
You can try this...I use it to connect to an OpenLDAP instance and it works well. Works against AD also so it should fit your needs. You'll need to update the $basedn variable and the host/username ones.
$hostname = ''
$username = ''
$Null = [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols")
#Connects to LDAP
$LDAPConnect = New-Object System.DirectoryServices.Protocols.LdapConnection "$HostName"
#Set session options (SSL + LDAP V3)
$LDAPConnect.SessionOptions.SecureSocketLayer = $true
$LDAPConnect.SessionOptions.ProtocolVersion = 3
# Pick Authentication type:
# Anonymous, Basic, Digest, DPA (Distributed Password Authentication),
# External, Kerberos, Msn, Negotiate, Ntlm, Sicily
$LDAPConnect.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
# Gets username and password.
$credentials = new-object "System.Net.NetworkCredential" -ArgumentList $UserName,(Read-Host "Password" -AsSecureString)
# Bind with the network credentials. Depending on the type of server,
# the username will take different forms.
Try {
$ErrorActionPreference = 'Stop'
$LDAPConnect.Bind($credentials)
$ErrorActionPreference = 'Continue'
}
Catch {
Throw "Error binding to ldap - $($_.Exception.Message)"
}
Write-Verbose "Successfully bound to LDAP!" -Verbose
$basedn = "OU=Users and Groups,DC=TEST,DC=NET"
$scope = [System.DirectoryServices.Protocols.SearchScope]::Subtree
#Null returns all available attributes
$attrlist = $null
$filter = "(objectClass=*)"
$ModelQuery = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $basedn,$filter,$scope,$attrlist
#$ModelRequest is a System.DirectoryServices.Protocols.SearchResponse
Try {
$ErrorActionPreference = 'Stop'
$ModelRequest = $LDAPConnect.SendRequest($ModelQuery)
$ErrorActionPreference = 'Continue'
}
Catch {
Throw "Problem looking up model account - $($_.Exception.Message)"
}
$ModelRequest
Credit for most of this goes here..
http://mikemstech.blogspot.com/2013/03/searching-non-microsoft-ldap.html
This worked for me. Only use this for testing purposes since password is not secured at all.
Add-Type -AssemblyName System.DirectoryServices.Protocols
$server = test.com
$username = "CN=username,OU=users,DC=test,DC=com"
$password = "userpassword"
$Credentials = new-object System.Net.NetworkCredential($username, $password)
$LdapConnection = New-Object System.DirectoryServices.Protocols.LdapConnection $server
# Basic auth, cleartext password using port 389
$LdapConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
$LdapConnection.Bind($Credentials)
$LdapConnection.Dispose()

Powershell CMDLET Cross Domain Managment

I'm logged in at domain "domain1" with my account. I wish via powershell to be able to update users in domain "domain2" via my supe ruser account "suaccount" with password "password1". Trust is established between the two.
Running PowerShell 2.0 and .NET 3.5 SP1
I have gotten this far:
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$context = New-Object -TypeName
System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, "domain2", "OU=TestOU,DC=domain2", "suaccount", "password1"
$usr = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal -ArgumentList $context
$usr.Name = "AM Test1"
$usr.DisplayName = "AM Test1"
$usr.GivenName = "AM"
$usr.SurName = "Test1"
$usr.SamAccountName = "AMTest1"
$usr.UserPrincipalName = "amtest1#mtest.test"
$usr.PasswordNotRequired = $false
$usr.SetPassword("errr")
$usr.Enabled = $true
$usr.Save()
Pretty new to PowerShell, any pointers? I want to edit/create users on the "other" domain so to speak.
I get the error:
"Exception calling "Save" with "0" argument(s): "General access denied error
"
At C:\Script\Sandbox\Morris PowerShell Application\includes\mo\mo.ps1:104 char:14
+ $usr.Save <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException"
Any pointers?
From comments: Try using for username this format domain2\username, and always use the FQDN for the domain. – Christian yesterday