Use Exchange PowerShell to count old emails in inbox folder - powershell-2.0

Does anyone know of a PowerShell script that uses EWS to look into a user's Exchange 2010 SP3 Inbox and get a count of email messages and the sizes older than 60 days for example? I can't believe no one has been able to do this. I see a lot of people asking how to do this. Help please :-)

There are a few example on this http://gsexdev.blogspot.com.au/2012/10/reporting-on-item-age-count-and-size-in.html and http://gsexdev.blogspot.com.au/2014/07/creating-mailbox-folder-growth-map-with.html
Specifically for what you want to do something like this should work
## Get the Mailbox to Access from the 1st commandline argument
$MailboxName = $args[0]
$DateFrom = (Get-Date).AddDays(-60)
## Load Managed API dll
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll"
## Set Exchange Version
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
## Create Exchange Service Object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
#Credentials Option 1 using UPN for the windows Account
$psCred = Get-Credential
$creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())
$service.Credentials = $creds
#Credentials Option 2
#service.UseDefaultCredentials = $true
## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=#'
namespace Local.ToolkitExtensions.Net.CertificatePolicy{
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'#
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
## end code from http://poshcode.org/624
## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
#CAS URL Option 1 Autodiscover
$service.AutodiscoverUrl($MailboxName,{$true})
"Using CAS Server : " + $Service.url
#CAS URL Option 2 Hardcoded
#$uri=[system.URI] "https://casservername/ews/exchange.asmx"
#$service.Url = $uri
## Optional section for Exchange Impersonation
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
# Bind to the Inbox Folder
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)
$Inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
#Define ItemView to retrive just 1000 Items
$ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(250)
$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly)
$psPropset.Add([Microsoft.Exchange.WebServices.Data.ItemSchema]::Size)
$psPropset.Add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived)
$psPropset.Add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeCreated)
$ivItemView.PropertySet = $psPropset
$sfItemSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThan([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived,$DateFrom)
$rptObj = "" | Select Mailbox,TotalNumber,TotalSize
$rptObj.Mailbox = $MailboxName
$rptObj.TotalNumber = 0
$rptObj.TotalSize = [Int64]0
$fiItems = $null
do{
$fiItems = $service.FindItems($Inbox.Id,$sfItemSearchFilter,$ivItemView)
#[Void]$service.LoadPropertiesForItems($fiItems,$psPropset)
foreach($Item in $fiItems.Items){
$rptObj.TotalNumber += 1
$rptObj.TotalSize += [Int64]$Item.Size
}
$ivItemView.Offset += $fiItems.Items.Count
}while($fiItems.MoreAvailable -eq $true)
$rptObj | select Mailbox,TotalNumber,#{label="TotalSize(MB)";expression={[math]::Round($_.TotalSize/1MB,2)}}

Related

How generate OAuth for azure vm

I installed Grafana on my Azure virtual machine. Now I want to set OAuth.
In defaults.ini I set the
name = my app
enabled = true
allow_sign_up = true
client_id = with my id
client_secret = with my client_secret
scopes = openid email name
auth_url =
token_url =
api_url =
team_ids =
allowed_organizations =
And this not work. Can anyone have some idea where I wrong.
Do not edit defaults.ini!
Use the following link to create or locate grafana.ini or custom.ini depending on your OS:
https://grafana.com/docs/grafana/latest/installation/configuration/
I would recommend that you copy the block of code for the OAuth provider you want to use to grafana.ini/custom.ini and then edit it to suit your need.
You may have to edit the URL under the [server] settings to allow for the correct redirect when using external OAuth

update Jenkins credentials by script

I have a Jenkins server running on Windows. It stores a username:password in the credentials plugin. This is a service user that gets its password updated regularly.
I'm looking for a way to run a script, preferably Powershell, that will update that credential in the Jenkins password store so that it's always up to date when I use it in a build job script.
The password is managed by a Thycotic Secret Server install so I should be able to automate the process of keeping this password up to date, but I have found almost no leads for how to accomplish this, even though the blog post by the guy who wrote the credentials api mentions almost exactly this scenario and then proceeds to just link to the credentials plugin's download page that says nothing about how to actually use the api.
Update
The accepted answer works perfectly, but the rest method call example is using curl, which if you're using windows doesn't help much. Especially if you are trying to invoke the REST URL but your Jenkins server is using AD Integration. To achieve this you can use the following script.
Find the userId and API Token by going to People > User > configure > Show API Token.
$user = "UserID"
$pass = "APIToken"
$pair = "${user}:${pass}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = #{ Authorization = $basicAuthValue }
Invoke-WebRequest `
-uri "http://YourJenkinsServer:8080/scriptler/run/changeCredentialPassword.groovy?username=UrlEncodedTargetusername&password=URLEncodedNewPassword" `
-method Get `
-Headers $headers
Jenkins supports scripting with the Groovy language. You can get a scripting console by opening in a browser the URL /script of your Jenkins instance. (i.e: http://localhost:8080/script)
The advantage of the Groovy language (over powershell, or anything else) is that those Groovy scripts are executed within Jenkins and have access to everything (config, plugins, jobs, etc).
Then the following code would change the password for user 'BillHurt' to 's3crEt!':
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
def changePassword = { username, new_password ->
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance
)
def c = creds.findResult { it.username == username ? it : null }
if ( c ) {
println "found credential ${c.id} for username ${c.username}"
def credentials_store = Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
def result = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
c,
new UsernamePasswordCredentialsImpl(c.scope, c.id, c.description, c.username, new_password)
)
if (result) {
println "password changed for ${username}"
} else {
println "failed to change password for ${username}"
}
} else {
println "could not find credential for ${username}"
}
}
changePassword('BillHurt', 's3crEt!')
Classic automation (/scriptText)
To automate the execution of this script, you can save it to a file (let's say /tmp/changepassword.groovy) and run the following curl command:
curl -d "script=$(cat /tmp/changepassword.groovy)" http://localhost:8080/scriptText
which should respond with a HTTP 200 status and text:
found credential 801cf176-3455-4b6d-a461-457a288fd202 for username BillHurt
password changed for BillHurt
Automation with the Scriptler plugin
You can also install the Jenkins Scriptler plugin and proceed as follow:
Open the Scriptler tool in side menu
fill up the 3 first field taking care to set the Id field to changeCredentialPassword.groovy
check the Define script parameters checkbox
add 2 parameters: username and password
paste the following script:
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
def changePassword = { username, new_password ->
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
jenkins.model.Jenkins.instance
)
def c = creds.findResult { it.username == username ? it : null }
if ( c ) {
println "found credential ${c.id} for username ${c.username}"
def credentials_store = jenkins.model.Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
def result = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
c,
new UsernamePasswordCredentialsImpl(c.scope, null, c.description, c.username, new_password)
)
if (result) {
println "password changed for ${username}"
} else {
println "failed to change password for ${username}"
}
} else {
println "could not find credential for ${username}"
}
}
changePassword("$username", "$password")
and click the Submit button
Now you can call the following URL to change the password (replacing the username and password parameter): http://localhost:8080/scriptler/run/changeCredentialPassword.groovy?username=BillHurt&password=s3crEt%21 (notice the need to urlencode the parameters' value)
or with curl:
curl -G http://localhost:8080/scriptler/run/changeCredentialPassword.groovy --data-urlencode 'username=BillHurt' --data-urlencode "password=s3crEt!"
sources:
Printing a list of credentials and their IDs
Create UserPrivateKeySource Credential via Groovy?
credential plugin source code
Scriptler plugin
Search engine tip: use keywords 'Jenkins.instance.', 'com.cloudbees.plugins.credentials' and UsernamePasswordCredentialsImpl
Decided to write a new answer although it is basically some update to #Tomasleveil's answer:
removing deprecated calls (thanks to jenkins wiki, for other listing options see plugin consumer guide)
adding some comments
preserve credentials ID to avoid breaking existing jobs
lookup credentials by description because usernames are rarely so unique (reader can easily change this to ID lookup)
Here it goes:
credentialsDescription = "my credentials description"
newPassword = "hello"
// list credentials
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
// com.cloudbees.plugins.credentials.common.StandardUsernameCredentials to catch all types
com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials.class,
Jenkins.instance,
null,
null
);
// select based on description (based on ID might be even better)
cred = creds.find { it.description == credentialsDescription}
println "current values: ${cred.username}:${cred.password} / ${cred.id}"
// not sure what the other stores would be useful for, but you can list more stores by
// com.cloudbees.plugins.credentials.CredentialsProvider.all()
credentials_store = jenkins.model.Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
// replace existing credentials with a new instance
updated = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
cred,
// make sure you create an instance from the correct type
new com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl(cred.scope, cred.id, cred.description, cred.username, newPassword)
)
if (updated) {
println "password changed for '${cred.description}'"
} else {
println "failed to change password for '${cred.description}'"
}
I never found a way to get the Groovy script to stop updating the credential ID, but I noticed that if I used the web interface to update credentials, the ID did not change.
With that in mind the script below will in effect script the Jenkins web interface to do the updates.
Just for clarification, the reason this is important is because if you are using something like the Credentials binding plugin to use credentials in your job, updating the ID to the credential will break that link and your job will fail. Please excuse the use of $args rather than param() as this is just an ugly hack that I will refine later.
Note the addition of the json payload to the form fields. I found out the hard way that this is required in this very specific format or the form submission will fail.
$username = $args[0]
$password = $args[1]
Add-Type -AssemblyName System.Web
#1. Log in and capture the session.
$homepageResponse = Invoke-WebRequest -uri http://Servername.domain.com/login?from=%2F -SessionVariable session
$loginForm = $homepageResponse.Forms['login']
$loginForm.Fields.j_username = $username
$loginForm.Fields.j_password = $password
$loginResponse = Invoke-WebRequest `
-Uri http://Servername.domain.com/j_acegi_security_check `
-Method Post `
-Body $loginForm.Fields `
-WebSession $session
#2. Get Credential ID
$uri = "http://Servername.domain.com/credential-store/domain/_/api/xml"
foreach($id in [string]((([xml](Invoke-WebRequest -uri $uri -method Get -Headers $headers -WebSession $session).content)).domainWrapper.Credentials | Get-Member -MemberType Property).Name -split ' '){
$id = $id -replace '_',''
$uri = "http://Servername.domain.com/credential-store/domain/_/credential/$id/api/xml"
$displayName = ([xml](Invoke-WebRequest -uri $uri -method Get -Headers $headers -WebSession $session).content).credentialsWrapper.displayName
if($displayName -match $username){
$credentialID = $id
}
}
#3. Get Update Form
$updatePage = Invoke-WebRequest -Uri "http://Servername.domain.com/credential-store/domain/_/credential/$credentialID/update" -WebSession $session
$updateForm = $updatePage.Forms['update']
$updateForm.Fields.'_.password' = $password
#4. Submit Update Form
$json = #{"stapler-class" = "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl";
"scope"="GLOBAL";"username"="domain\$username";"password"=$password;"description"="";"id"=$id} | ConvertTo-Json
$updateForm.Fields.Add("json",$json)
Invoke-WebRequest `
-Uri "http://Servername.domain.com/credential-store/domain/_/credential/$credentialID/updateSubmit" `
-Method Post `
-Body $updateForm.Fields `
-WebSession $session

Redeployment with Powershell in Multi Tenant Environment

I want to redeploy a multiple tenants using powershell. We have 100+ tenants in UIT and I don't want to do this manually. In order to redeploy, I have to use a specific link and log in. My question is, if it is possible to do this in an automated way using powershell. Here is what I have so far:
Function SendRequest($tenantName)
{
$url = "http://<machine-name>/$tenantName/Account /LogOn?ReturnUrl=%2f$tenantName%2fadmin%2fdeploytenant%3fsyncmetadata%3dtrue&syncmetadata=true"
$req = [system.Net.WebRequest]::Create($url)
$req.Credentials = [System.Net.NetworkCredential]::($username, (ConvertTo-SecureString $pwd -AsPlainText -force))
try
{
$res = $req.GetResponse()
}
catch [System.Net.WebException]
{
$res = $_.Exception.Response
}
$int = [int]$res.StatusCode
$status = $res.StatusCode
Write-Host $status
return "$int $status"
}
The status that is returned is "200 OK" but it does not redeploy. Maybe I need to log in first and then send another request with the redeployment parameters. So what would be the best way to accomplish this?
Maybe this is just a snippet of your code, but I'm seeing you reference $username and $pwd without actually feeding in a username and password.
Perhaps that could that explain the lack of a successful redeploy.

Powershell EWS Send Email from Shared Mailbox

I am using Powershell and the Exchange Web Service (v1.2) to send an email through Office 365. As long as I use my credentials the script is able to send without an issue. However, for tracking purposes, on script errors I need to send the email from a shared mailbox instead of through my account. The error I get is:
Exception calling "AutodiscoverUrl" with "2" argument(s): "The Autodiscover service couldn't be located."
At F:\Scripting\1-Dev\Modules\Include.ps1:387 char:31
+ $service.AutodiscoverUrl <<<< ($Credential.UserName, {$true})
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
I'm sure the problem is authentication. How can I authenticate and send from a shared mailbox in o365?
EDIT:
Here is the code that I'm using to send the email:
Function Send-O365Email {
[CmdletBinding()]
param(
[Parameter(Position=1, Mandatory=$true)]
[String[]] $To,
[Parameter(Position=2, Mandatory=$true)]
[String] $Subject,
[Parameter(Position=3, Mandatory=$true)]
[String] $Body,
[Parameter(Position=4, Mandatory=$true)]
[System.Management.Automation.PSCredential] $Credential,
[Parameter(Mandatory=$false)]
[String]$PathToAttachment
)
begin {
#Load the EWS Managed API Assembly
Add-Type -Path 'C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll'
}
process {
#Create the EWS service object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2010_SP1
#Set the credentials for Exchange Online
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList `
$Credential.UserName, $Credential.GetNetworkCredential().Password
#Determine the EWS endpoint using autodiscover
$service.AutodiscoverUrl($Credential.UserName, {$true})
#Create the email message and set the Subject and Body
$message = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service
$message.Subject = $Subject
$message.Body = $Body
$message.Body.BodyType = 'HTML'
if (Test-Path $Attachment) {
$message.Attachments.AddFileAttachment("$Attachment");
}
#Add each specified recipient
$To | ForEach-Object {
$null = $message.ToRecipients.Add($_)
}
#Send the message and save a copy in the users Sent Items folder
try {
$message.SendAndSaveCopy()
}
catch [exception] {
Add-Content -Path $LOGFILE -Value "$_"
}
} # End Process
}
You may want to try the 2.0 assembly, though I don't think that is the issue http://www.microsoft.com/en-us/download/details.aspx?id=35371
My environment is a little different, in that our credentials and email address are not the same name. (one is initialLastName#Comp.com and the other is first.Last#Comp.com) so I have to be a little different in how I approach names, always needing a Credential and a MailBox name.
When I try to use a Resource account, I have to use my email for the autodiscovery. Possibly because the Service account doesn't have a user license. I am speculating.
I found a good amount of resources at http://gsexdev.blogspot.com/.
Specifically, this may be what you need:
## Optional section for Exchange Impersonation
# http://msdn.microsoft.com/en-us/library/exchange/dd633680(v=exchg.80).aspx
$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, "SupportResource#comp.com")
#or clear with
#$service.ImpersonatedUserId = $null
similar 'discussion' # EWS Managed API: how to set From of email? also.

Google Docs: Cannot export/download user's document using administrative access/impersonation (forbidden 403) in python

I have read this thoroughly: https://developers.google.com/google-apps/documents-list/#using_google_apps_administrative_access_to_impersonate_other_domain_users
I have googled this to death.
So far I have been able to:
Authorise with:
clientLogin
OAuth tokens (using my domain key)
retrieve document feeds for all users in the domain (authorised either way in #1)
I am using the "entry" from the feed to Export/Download documents and always get forbidden for other users for documents not shared with admin. The feed query I am using is like:
https://docs.google.com/feeds/userid#mydomain.com/private/full/?v=3
(I have tried with and without the ?v=3)
I have also tried adding the xoauth_requestor_id (which I have also seen in posts as xoauth_requestor), both on the uri, and as a client property: client.xoauth_requestor_id = ...
Code fragments:
Client Login (using administrator credentials):
client.http_client.debug = cfg.get('HTTPDEBUG')
client.ClientLogin( cfg.get('ADMINUSER'), cfg.get('ADMINPASS'), 'HOSTED' )
OAuth:
client.http_client.debug = cfg.get('HTTPDEBUG')
client.SetOAuthInputParameters( gdata.auth.OAuthSignatureMethod.HMAC_SHA1, cfg.get('DOMAIN'), cfg.get('APPS.SECRET') )
oatip = gdata.auth.OAuthInputParams( gdata.auth.OAuthSignatureMethod.HMAC_SHA1, cfg.get('DOMAIN'), cfg.get('APPS.SECRET') )
oat = gdata.auth.OAuthToken( scopes = cfg.get('APPS.%s.SCOPES' % section), oauth_input_params = oatip )
oat.set_token_string( cfg.get('APPS.%s.TOKEN' % section) )
client.current_token = oat
Once the feed is retrieved:
# pathname eg whatever.doc
client.Export(entry, pathname)
# have also tried
client.Export(entry, pathname, extra_params = { 'v': 3 } )
# and tried
client.Export(entry, pathname, extra_params = { 'v': 3, 'xoauth_requestor_id': 'admin#mydomain.com' } )
Any suggestions, or pointers as to what I am missing here?
Thanks
You were very close to having a correct implementation. In your example above, you had:
client.Export(entry, pathname, extra_params = { 'v': 3, 'xoauth_requestor_id': 'admin#mydomain.com' } )
xoauth_requestor_id must be set to the user you're impersonating. Also what you need is to use 2-Legged OAuth 1.0a with the xoauth_requestor_id set either in the token or in the client.
import gdata.docs.client
import gdata.gauth
import tempfile
# Replace with values from your Google Apps domain admin console
CONSUMER_KEY = ''
CONSUMER_SECRET = ''
# Set this to the user you're impersonating, NOT the admin user
username = 'userid#mydomain.com'
destination = tempfile.mkstemp()
token = gdata.gauth.TwoLeggedOAuthHmacToken(
consumer_key, consumer_secret, username)
# Setting xoauth_requestor_id in the DocsClient constructor is not required
# because we set it in the token above, but I'm showing it here in case your
# token is constructed via some other mechanism and you need another way to
# set xoauth_requestor_id.
client = gdata.docs.client.DocsClient(
auth_token=token, xoauth_requestor_id=username)
# Replace this with the resource your application needs
resource = client.GetAllResources()[0]
client.DownloadResource(resource, path)
print 'Downloaded %s to %s' % (resource.title.text, destination)
Here is the reference in the source code to the TwoLeggedOAuthHmacToken class:
http://code.google.com/p/gdata-python-client/source/browse/src/gdata/gauth.py#1062
And here are the references in the source code that provide the xoauth_requestor_id constructor parameter (read these in order):
http://code.google.com/p/gdata-python-client/source/browse/src/atom/client.py#42
http://code.google.com/p/gdata-python-client/source/browse/src/atom/client.py#179
http://code.google.com/p/gdata-python-client/source/browse/src/gdata/client.py#136

Resources