Emails with Graph API

Emails with Graph API

Last week we spoke about finding disabled users with licensing using PowerShell and graph API. Today, we will be expanding from that blog. We are going to send the results ourselves. Next week, we will create this into an automation using application rights and azure apps. However, today we will send Emails with Graph API and Powershell.

The Script

import-module Microsoft.Graph.Users
Import-module Microsoft.Graph.Users.Actions  

Connect-MgGraph -Scopes "User.Read.All, Mail.Send"
$users = Get-MgUser -filter "accountenabled eq false"
$ReturnString = ""
foreach ($user in $users) {
    if ($null -ne (Get-MgUserLicenseDetail -UserId $user.Id)) {
        [pscustomobject][ordered]@{
            UPN      = $user.UserPrincipalName
            Licenses = (Get-MgUserLicenseDetail -UserId $user.id).SkuPartNumber -join ", "
        }
        $ReturnString = $ReturnString + "$($user.UserPrincipalName): $((Get-MgUserLicenseDetail -UserId $user.id).SkuPartNumber -join ", ")`n"
    }
}

$EmailSend = Read-Host "Email Address to send (Cloud Only)"
$Emailreceive = Read-Host "Email Address to Receive"

$body = @"
<html>
<header>Licenses</header>
<body>
<center>
<h1>Disabled Users</h1>
<h2>With Licenses</h2>
</center>
$ReturnString
</body>
</html>
"@
$params = @{
    message = @{
        subject = "Disabled Users with Licenses"
        body = @{
            contentType = "HTML"
            content = $body
        }
        toRecipients = @(
            @{
                emailAddress = @{
                    address = $Emailreceive
                }
            }
        )
    }
    saveToSentItems = "false"
}

# A UPN can also be used as -UserId.
Send-MgUserMail -UserId $EmailSend -BodyParameter $params

The Breakdown

The same

Like last week, we are using the Microsoft Graph PowerShell module. The first part of this code is the same as last week. So you can take a good read on that one. The only difference is our scope. We are adding mail.send. Mail.Send allows us to send emails from cloud users. It will not work with inactive, soft-deleted, or on-premise-hosted devices. Thus the connect-mggraph will look like the below

Connect-MgGraph -Scopes "User.Read.All, Mail.Send"

The only other thing we have added to the original script is a return string. We initialize the return string with a $returnstring = “” and then we build the string out. Using the same as before, we grab the SKU part number. Finally, we use the join. The difference is we wrap the command in a bubble, $(), for our string. Then we put the sting, the new information, and a line break, `n, into the string.

$ReturnString = $ReturnString + "$($user.UserPrincipalName): $((Get-MgUserLicenseDetail -UserId $user.id).SkuPartNumber -join ", ")`n"

Emails with Graph API

The first thing we want to know is Who we are sending the email to and Who is sending the email. The one sending the email has limitations. First, it can’t be an inactive user. The user can’t be in a soft-deleted state. Finally, it has to be hosted in the cloud. The person we are sending to has to have an email box.

The next part is where we create the email we are going to send. Remember that returnstring we made a few moments ago, it’s time to use that. We are using a here string. Here strings allows large string data like an HTML page, to be placed into a string. Here strings are set apart using the @ symbol. Take a look at the $body below.

$body = @"
<html>
<header>Licenses</header>
<body>
<center>
<h1>Disabled Users</h1>
<h2>With Licenses</h2>
</center>
$ReturnString
</body>
</html>
"@

Params

Please note that some PowerShell ide does not like the tabbing inside a here-string. The next part is the parameters of the email system. We are sending a message. Additional documentation can be found here. We are going to use the following tags, subject, body, to recipient, and save to sent items. All of these items are setup as a Json file as the API uses Json as well.

  • Subject: What is the subject of the email
  • Body: body contains the content type and the content. Here is where we will be using our $body.
  • To Recipients: This is where the email addresses will go. We set up an email address and have it as an array.
  • Save to Sent Items: Finally, we determine if we want this item to stay in our sent items.
$params = @{
    message = @{
        subject = "Disabled Users with Licenses"
        body = @{
            contentType = "HTML"
            content = $body
        }
        toRecipients = @(
            @{
                emailAddress = @{
                    address = $Emailreceive
                }
            }
        )
    }
    saveToSentItems = "false"
}

Finally, we use the send-mgusermail command. This is where we use the send email. It will be the UPN of the target user we want to send email from. The body parameter will be the parameters we just built. Once you do this, you will see the email come in accordingly. That’s how you can send Emails with Graph API.

Find Disabled Users with Graph API and Powershell

Find Disabled Users with Graph API and Powershell

Microsoft licensing can cost a lot of money. It’s not logical to have a disabled account have licenses. Some licenses can cost up to $25 USD a month. So if you have 4 of these disabled accounts with licenses, that could easily be 100 per month. Let us Find Disabled Users with Graph API using PowerShell and find which ones have licenses.

Today’s post will be using the Microsoft.graph.users module. We can connect to graph API via the API, or we can use the Powershell module. In previous posts, I have shown how to connect to the API and pull information. This is still one of the best methods to use as the Graph API module has no way to search for things like shared mailboxes. I will cover that in a later post. So, let’s dive into the graph users module. You can read the documentation here.

The script

import-module Microsoft.Graph.Users
Connect-MgGraph -Scopes "User.Read.All"
$users = Get-MgUser -filter "accountenabled eq false"
foreach ($user in $users) {
    if ($null -ne (Get-MgUserLicenseDetail -UserId $user.Id)) {
        [pscustomobject][ordered]@{
            UPN = $user.UserPrincipalName
            Licenses = (Get-MgUserLicenseDetail -UserId $user.id).SkuPartNumber -join ", "
        }
    }
}
Disconnect-mggraph

The Breakdown

First of all, look at how little code there is compared to the previous post. The Connect-MGGraph removes so much back end work. When you run this command it will prompt you to grant it permissions. Once you disconnect, those permissions disappear. if you have a global admin account, if you don’t put in a scope, you gain access to everything. Which is super nice and scary. I prefer to have scope so I don’t break things.

If you don’t have the “Microsoft.Graph.Users” module, install it. You can install it by using the install-module commandlet.

Connect-MgGraph -Scopes "User.Read.All"

Like I said before, The connect-MGgraph command allows you to do scopes. This is very important. Back in the day we used msol. When we connected we had full control unless we limited our accounts which caused issues. In this case we are creating a temporary azure app. See the previous post about how to make an azure app. You will see how time saver this command can be. That azure app will have the scopes that you give it. If you don’t give it a scope, it has your rights. So, if you are a global admin, you can do damage on accident. It’s nice not to be in the scary ages anymore. So give it scope. In this case we are using User.Read.All as our scope. The User.Read.All permissions will help us Find Disabled Users.

$users = Get-MgUser -filter "accountenabled eq false"

The next part is where we grab all the disabled accounts. Using the Get-MgUser commandlet, we trigger the filter option. We want only accounts that are not enabled. thus the account enabled is equal to false. Very simple idea. If you run users[1] you can see the items you can search with. I do not suggest searching for anything to crazy.

The loop

Now we have all the disabled accounts we want to find the Licensed ones. We need to create a for each loop. Foreach loops are a staple for data controls. Without it… it’s just a pain. As we loop, we want to find the ones with a licenses. We need the user id from the account. So the best thing to do is do an if statement.

foreach ($user in $users) {
    if ($null -ne (Get-MgUserLicenseDetail -UserId $user.Id)) {
       #Do Something
    }
}

In this if statement we pull the licenses using the Get-MgUserLicenseDetail with the users id. If there is nothing that comes from this command it will return a null. So we test null against the command. It’s slightly faster than testing the command against null. Every user inside this if statement that is true will have a licensing. We want to display that information.

[pscustomobject][ordered]@{
        UPN = $user.UserPrincipalName
        Licenses = (Get-MgUserLicenseDetail -UserId $user.id).SkuPartNumber -join ", "
}

Here we create a PowerShell custom object. We want to display the User Principal Name, also known as, the sign name. We do this by using the $user from the foreach loop and just tag the user principal name. Next, we want to display all the licenses. The licenses come as an array. For example, my test account has 3 licenses. I want all that as a string. So, we use the Get-mguserlicensedetail command. We pull out the SKU part number. Then we do some array magic. The -join “, ” converts the array into a string. At the end of each line it adds a “,” and a space. Which makes it easier to read. The cool part about this is if it’s just one license, we it will not add the “, ” to the end. This makes it super readable.

One catch though, thanks to how Microsoft likes to hide things, the SKU is going to be coded. For example, it might say spe_f1. which means it’s an F1 license for Microsoft office. while of1 could mean the same thing but purchased from a different location. I use to try to keep a living list, however, these sku change daily and finding them will be hard. This is where Google is your friend.

Disconnect-MgGraph

Finally, we disconnect from graph API. We don’t want that app to stay there do we? Yeah, we disconnect like good admins we are. Once you are disconnected, you can review all the information this script provided. I am not a big fan of automating the removal of licenses through this method because many times other admins will licenses disabled accounts to keep email alive as a shared mailbox or other oddities. Right now, graph API poweshell module just doesn’t work with shared mailboxes. It is on the workbooks though.

Now go, Find Disabled Users With Graph API and Powershell, and Enjoy your day.

Is It S.A.F.E.S.

Is It S.A.F.E.S.

Do you struggle with any kind of addiction? Well, I should say, what is your addiction? Everyone has one. Each addiction is held to society’s standards which they live in. For example, here in America, overworking is praised while in other mature countries, it’s looked down upon as it makes you unproductive. Some addictions are needed parts of life. Like food. Sobriety isn’t starving yourself to death. So, how do you define Sobriety in human needs addiction? We follow an acronym “S.A.F.E.S.”

Secret, Abusive, Feelings, and Empty

S.ecret

Is it a secret? So, are you in the closet eating a doughnut? Are you hiding your financials from your SO because you are spending that money on sketchy massage places? How about other things? How about eating out to hide those emotions? If you can’t tell your SO, accountability partners, etc… It might be a good idea to leave it alone. I know it’s a hard concept because it’s simple.

A.busive

This one is really important. Is it abusive? Is the intent of eating xyz to damage you? To feed some core emotion? Is your long showers really good for you? How about buying that on amazon? Drinking that drink? How is it abusive to yourself? At first it’s hard to see if something is abusive to yourself. So, it’s important to look at your behavior in your addiction to see if it is. Sometimes we will take naturally happening items and say its abusive. For example, when a guy sees a woman and thinks she is attractive and focuses on what he sees as attractive. This is natural. Men are designed to see sexual compatibility. Now, if he takes it to the next level and starts the chase while being married, that is more abusive. At the end of that road is just pain and loneliness.

Another example would be politics. I spoke with a young lady who didn’t know if playing a black character in a game was racist. She spent hours and ended up crying in a corner. This is self-abuse. This was not a safe line of thinking for her. Abuse can come in many forms and each addiction has it’s own structure.

F.eelings

Feelings and abusive oftentimes go hand in hand. For example, when I am depressed, I will go out and eat. This is abusive to my finances and my body. However, it helps the depressive state I am feeling. Instead of addressing the feelings, I am masking my feelings. I have seen people drugs, sex, alcohol, and more. If you find yourself wanting to hide away from what you are feeling, what you are doing might not be safe. It’s always better to address the feelings instead of masking them. A bandaid can’t fix a broken arm.

E.mpty

Masking your feelings will leave you empty. If you start feeling emptiness and or loneliness, it’s time to pull back and ask yourself if what you are doing is part of S.A.F.E.S. or not. That loneliness will eat you alive and leave you in a space where you can’t see yourself anymore. Over time, you can start seeing additional issues crop up to hide the issues that you are using to mask. That emptiness is destructive.

S.hame

I have added Shame to Overeater’s anonymous. Shame can come in healthy and toxic forms. If you are feeling a sense of worthlessness, self-hate and more. It’s time to run. Run as fast as you can. Call your accountability partner. Call upon your higher power. Do something. you are not what your mind is telling you at this point. You have entered the results of the unsafe cycle. What you are doing or going to do will bring you down and more than likely lead to a full relapse.

S.A.F.E.S.

Just imagine a safe and each action you take should go through that safe. If you have more than one issue, like myself, it’s best to have a few of these safes. Don’t let the secret control what you do. Avoid self-abuse. It’s not ok to mask the emotions for too long as it brings emptiness and breath toxic shame into your life. Keep a sticky note with “S.A.F.E.S.” in your car, on the monitor of your computer. The refrigerator at the house. The candy jar, and any other place that you might find yourself doing actions outside of the safes.

Additional Resources

Values

Values

Values are the fundamental beliefs that guide our behaviors, decisions, and attitudes toward life. They are the principles that define our character, shape our perspective, and determine our priorities. We learn our default values through our community and families. As we grow, we change our values. Sometimes this is to match the communities we are in, sometimes we accept other values. We do this in a subconscious manner. Normally, this process is unintentional. There is a way to create value in our life though. Let’s define how, or Values defined as my dyslexic brain likes to say.

Seven Steps overview

Here is the overview list of each step. These are understandable as they are, but I like to expand on them with the concept of loving yourself or valuing yourself. This method comes from the book “Values Clarification” by Simmon and Kirschenbaum.

  1. freely chosen
  2. chosen from a consideration of alternatives
  3. chosen with clear knowledge of the consequences
  4. prized and cherished
  5. publicly proclaimed
  6. acted on
  7. acted on repeatedly.

Freely Chosen

Firstly, if you wish for your value to stay throughout your life, you must willfully accept it. I grew up in a Christian home. My beliefs and values were given to me by my parents. At the time, I did not freely choose them. As I grew older though, I choose to accept things like, loving others, helping those in need, and more as part of my core values. However, my belief system stated I was a bad person from birth. This birthed a value of self-worthlessness. A sense of unlovability. This value was reinforced through physical and sexual abuse.

For years, I acted upon this core value. I choose not to follow my dreams and stayed in the same job I had in high school. I didn’t believe I was worth more than scooping poop out of toilets. Many years later I started believing that I was worthy of love. Eventually, I broke down the religious dogma that taught me I was worthless. It was then I freely choose the value of self-love. This was the first step to integrating this self-love and care into me.

Other values I have chosen throughout my life are some of the core values of real Christianity. Treating others as equals and not less than. Being there for people. Raising my kids in love and not hate. Allowing anger to flow in a positive way. All of these I freely chose as a child, and as an adult, I still hold true to them.

Chosen from a Consideration of Alternatives

Growing up, you don’t get a chance to consider the alternatives. As an adult, you get to. When creating a new value willfully, it’s a must. Let’s look at the value of isolationism. My Uncle was a strong Republican. When I was younger, he believed in isolationism. I was able to be part of the changing of this value. This is a value he was thought while growing up. Isolationism value states that only those born in the country should receive help from the government and/or be part of the government processes, like voting or holding governmental positions. The alternative to this is a melting pot and involvement.

He changed his view because of an Indian man challenged his political beliefs through his spiritual beliefs. He considered the man’s spiritual standing and decided to consider the alternative to his value. The man was a critical thinker and helped my uncle reach that level of thinking. Using his critical thinking skills, he considered the idea of the Melting pot. He saw that the melting pot value would bring in new ideas and help the country grow. He was able to let go of his thought value for a value that he choose freely and considered himself.

We must weigh out the alternatives. By not doing so, we rob ourselves of the truth and longevity of our value. Now consider the alternatives to not loving yourself. What are they? Hating yourself, being indifferent to yourself, treating yourself less than, treating everyone greater than one? Each value has its own consequences.

Chosen with clear Knowledge of the Consequences

Knowing the alternatives is the first step. Knowing the consequences of your actions is the next part. If you value the diversity of animal life, global warming is painful to watch as destroys animal diversity. In my uncle’s case, accepting the melting pot meant he had to accept people as people and not what he was raised to believe. He had to decode his brain and way of thinking. Undo years of training. Which he was successful at doing. This was a hard process for him as he lost friends and family members. When you share a value with someone else, and you change, it can cause conflict.

It’s important to weigh out the consequences of the value that you choose. Lets look at self-love. The consequences of choosing to love yourself are somewhat painful but fulfilling. In self love, you must learn to say no, and set boundaries. This will push people away from you. As it is natural for people to take advantage of those who don’t love themselves.

Another consequence of self-love is integrating yourself. No longer can you say, I’m just born that way. Instead, you have to face your hurts and work through them. If you are comfortable with your current life and don’t want to grow, loving yourself is going to be hard as it forces you to grow.

However, loving yourself means you will grow. It means you will become whole. It means you will be happier with who you are. At one point or another, you will look in the mirror and not be disappointed to see yourself.

Value must be Prized and Cherished

Looking back at my Uncle. Before changing his values, he use to say something along the lines of, “all these people coming to our country stealing our jobs.” After changing his values, he said “What a beautiful mosaic of people. This is how we grow together.” To his deathbed, he cherished all races and people. He was excited when he heard of a governor for another country taking office. He would call them “Fresh Views” He went out of his way to help everyone equally.

In choosing to love yourself, You have to cherish moments where you do love yourself. For me, I cherish my front porch. I set a boundary of keeping it livable. Now, I sit on the porch each night and watch the sunset. I play with the kids on the front porch. School bus students have a place to sit and talk. I stand firm on my boundary as it is a way of self-love for me. You have to look at where your value brings you and what it does. Hold those to your heart. Remind yourself of them because it’s easy to forget.

Publicly Proclaimed

Next, you must be public about your value. Going back to my uncle, he did this by how he voted. When he spoke with other members of his family, and how he lived his life. Yes, he lost friends, however, going public kept him accountable. Baptists use baptism for this purpose when someone accepts Jesus. They take a public dunking in water to show all their friends and family what they believe and the values attached to that belief. During the start of Christianity, this would get you killed. Now-a-day, people clap.

When it comes to self-love, setting things like setting boundaries shows people that you are treating yourself better. Being willing to say, “I’m going to take some time for myself” and meaning it, shows it publically. Other things like taking care of your hair, shaving, exercising, going to the doctor, and more all show it. With self-love, the act of acting upon it is your public proclamation.

Act-On Your Values

It’s time to act on your values. If you value human life, you will help human life. A pro-life, states they love a child and want to see a child be born. It’s not a true value if the person doesn’t support adoption. It’s not a value if the person wants to defund programs that help mothers take care of their children. Free day care and other items should fall into pro-life. However, we don’t see it.

Acting upon your values is the meat and potato of the value. It gives the value, value. My uncle valued the melting pot. He Choose to vote and support those with good ideas, no matter what their nationality was. I saw him debate more than once with his former isolationists and even converted a few. He acted upon his value which enforced his value.

When it comes to self love, you have to act upon it. Taking care of your body is the start of self-love. When someone starts to value themselves, you will notice they will dress better. I started brushing my teeth each night. A family member chose to go to more social events and meet new people. There are many ways to act upon self-love. One way to proclaim it each morning. Try using the following statement:

I love myself. I will accept myself unconditionally.

Acting upon it over and over again

I am someone who likes to get projects off the ground and launch them into the sky. I’m an activator. If you want a dead project resurrected from its death, call me. However, I struggle with keeping it going once it was in the sky. This is very important. If you start reinforcing your chosen value, previous values will slip back in. As one man told me, it takes half the time to create a new habit when you are intentional than when you created the habit unintentionally.

To build the value, you must build the habit of that value. The action of acting on that value over and over again. It has to be drilled into your head. Especially if you have had values that are alternatives to your current values. Uncle would watch multiple news outlets instead of the same one. Always looking for fresh ideas and such. His actions reinforced his beliefs and values. Thus, at his funeral, he had a large crowd of people. The speaker said he had an open mind and it showed.

To love yourself, you have to take care of yourself daily. Brush your teeth each day. Take time for yourself each day. It’s ok to take care of yourself.

Final thoughts

Taking our values at face level will at some point fail us. We have to reevaluate our values from time to time. We need to make sure they still hold true to us. If they don’t, it’s time to let them go or reup those values. It’s not easy to make a new value. We are talking about the core of self when rebuilding a value. It takes time. There are no overnight changes in this world. As I have learned, there are three stages, initializing, processing, and defaulting. We have to initialize that change. We have to process it each day, sometimes multiple times a day, and then at some point, it becomes default behavior.

Continue Reading

O365 Mobile Devices

O365 Mobile Devices

I needed to grab all the mobile devices that had emails attached to them not too long ago. I could have gone through the GUI, and spent a few days trying my best to document everything, or I could use Powershell to pull the O365 Mobile Devices. Can you guess which one I did? Yep, PowerShell is a way of thinking nowadays in the system admin world.

The Script

Connect-ExchangeOnline
$Mailboxes = get-mailbox -all
$Devices = foreach ($Mail in $Mailboxes) {
    $MobileDevices = Get-MobileDevice -Mailbox $mail.userprincipalname
    foreach ($Device in $MobileDevices) {
        $Stats = Get-MobileDeviceStatistics -Identity $Device.Identity
        [pscustomobject]@{
            User = $mail.userprincipalname
            FriendlyName                  = $Device.FriendlyName
            name                          = $Device.name
            Identity                      = $Device.Identity
            DeviceID                      = $Device.DeviceId
            DeviceOS                      = $Device.DeviceOS
            DeviceType                    = $Device.DeviceType
            DeviceModel                   = $Device.DeviceModel 
            ClientType                    = $Stats.ClientType
            FirstSyncTime                 = $Device.FirstSyncTime
            WhenChanged                   = $Device.WhenChanged
            LastPolicyUpdateTime          = $Stats.LastPolicyUpdateTime
            LastSyncAttemptTime           = $Stats.LastSyncAttemptTime
            LastSuccessSync               = $stats.LastSuccessSync
            DeviceAccessState             = $Device.DeviceAccessState
            DeviceAccessStateReason       = $Device.DeviceAccessStateReason
            IsValid                       = $Device.IsValid
            Status                        = $Stats.Status
            DevicePolicyApplied           = $stats.DevicePolicyApplied
            DevicePolicyApplicationStatus = $stats.DevicePolicyApplicationStatus
        }
    }
}
$Devices

The Break Down

This script is pretty straightforward. We first connect to exchange online. Currently, this script is designed to work with MFA. Then we grab all the mailboxes from O365.

Connect-ExchangeOnline
$Mailboxes = get-mailbox -all

Next, we loop through these mailboxes. We drop all the information get gather from this loop into a variable. I called my devices. Once again, nothing great or grand.

$Devices = foreach ($Mail in $Mailboxes) {}

For each mailbox we have, we pull all of the devices from that mailbox. Since a single mailbox can have more than one device, we loop through these devices. For each loop, we want to grab that device’s stats to gain more insights.

$MobileDevices = Get-MobileDevice -Mailbox $mail.userprincipalname
    foreach ($Device in $MobileDevices) {
        $Stats = Get-MobileDeviceStatistics -Identity $Device.Identity

Finally, from there we gather the information into a single object. These commands produce a lot of information. It’s best to parse it down some. That’s what I did with the next part. That’s how I am able to get all the O365 Mobile Devices using PowerShell.

Additional Reading