PowerShell: Goodbye old Azure Rights Management module

Today I decided to say goodbye to a PowerShell command module, its name is Azure Rights Management, for short AADRM. Why? If you remember or read my old blog post about Rights Management in Azure then you know why I am saying Goodbye to it. Remember the old Azure Portal? https://manage.windowsazure.com

Before saying Goodbye, I was glad to experience this generation of Azure Rights Management, in 2017 and seeing the improvement and growth of it makes me happy. Now I am moving forward to the AIP Service module, where the new Rights Management named “Azure Information Protection”. AADRM End-of-life is on July 2020. During my first experience with AADRM, it was quite complicated to understand and manage it, because of its commands different from what I usually do.

Alright to install AIP Service module, what you should do first? When you already have AADRM installed, you have to uninstall it via PowerShell Run as Administrator. If you try to install the AIP Service module before uninstalling AADRM, it will give you an error saying “You already have the following commands ‘Get-AADRM and etc…’“.

This new AIP Service Module contains the new commands which are the AIP Service commands, don’t worry this new module still has the AADRM commands.

aip01.PNG If you happen to have MFA enabled, AADRM module and the new AIP service module does support.

 

 

PowerShell: Understading the use of Format-Table and Select

Just past a few days one of my colleagues was having trouble exporting the result that he wants. So I help him out to clarify what he must do and what must not do.

His PowerShell command was;

Get-Team | Format-Table DisplayName, MailNickName
  • Format-Table or ft command is used for formatting the selected properties into table form.
  • Gives you a nice view of the table form of the properties in the PowerShell console only.
  • If you were to export the Format-Table into a CSV, it will look like one whole chunk together in a column.

09.PNG

To export the result into CSV you got to use the “Select” command and then pipe with the Export-Csv command.

  •  “Select” or “Select-Object” command it serves the purpose of selects specified properties of an object or set of objects.
Get-Team | Select DisplayName, MailNickName | Export-Csv "<filename.csv>"

OR

Get-Team | Select DisplayName, MailNickName > "<filename.csv>"

 

PowerShell to detect Packet Loss

A friend of mine has been asking assistance from me to clarify with him on his PowerShell coding, he said he only knows one person does PowerShell and that is why he came to me. Anyway, thanks and I am feeling a little shy, HAHAHA! Glad to help out a good friend.

He has been trying to code out packet loss detection via PowerShell, and yes I do agree that sometimes it is tricky when comes to understanding the variables, example how is this reading and the outputting is a different thing?

So back and forth of clarification, he finally did it! Congratulations! You could check it out his program he has written and posted up on GitHub;

Cheah Eng Soon – Packet Loss Detection

PowerShell for Packet Loss Detection

Today I receive a message from a good friend in Singapore, asking for help on PowerShell. Well, is glad that someone comes to me asking for help on PowerShell. Sorry I could get a little bit excited whenever question on PowerShell. There are many ways to achieve this though, so don’t limit yourself. It is kind of an experimental situation with him on this packet loss detection too. This post is kind of to give you a hint of how you could create your own packet loss detection.

So this is mine but you can modify it,

  1. This is a constant IP address value (you can include hostname)
    • Try{
          #Stop progress if failure to achieve a successful return
          Test-Connection <IP address> -ErrorAction Stop
      }
      
      Catch{
          #Return an error message
          $ErrorMessage = $_.Exception.Message
          Write-Host $ErrorMessage
      }
  2. You can have it in data entry form too
    • #Data Entry of IP address that you wish to test connection, 
      #if connection successful there will be test conenction result 4 times (by default)
      $IPAddress=Read-Host "IP address"
      
      Try{
          #Stop progress if failure to achieve a successful return
          Test-Connection $IPAddress -ErrorAction Stop
      }
      
      Catch{
          #Return an error message
          $ErrorMessage = $_.Exception.Message
          Write-Host $ErrorMessage
      }
    • Testing how are the result and behavior is. I disconnected from the Internet and an error message return instantly.
    • ps01_LI (3).jpg
  3. For repetitive capability or 24×7, you got to be careful the resource exhaustion. Please check your task manager what is the performance when the PowerShell is running.
  4. You can even have it to return to send an email using the Send-MailMessage command, you can use default SMTP or your organization SMTP Server (this is a bit tricky)
    • Send-MailMessage -From 'User01 <user01@fabrikam.com>' -To 'User02 <user02@fabrikam.com>', 'User03 <user03@fabrikam.com>' -Subject 'Sending the Attachment' -Body "Forgot to send the attachment. Sending now." -Attachments .\data.csv -Priority High -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer 'smtp.fabrikam.com'

Good luck with your testing! 

References:

  1. https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-6

Troubleshoot Group Policy Object showing Extra Registry Settings

When your environment migrates from legacy or lower version of Windows Server to a newer version. Example, from Windows Server 2008 to Windows Server 2016.  You will experience this. This is why I am writing this post.

I notice when I launch the Group Policy Management and direct to one of the Group Policy Object > Settings Tab > Show all and saw a part says “Extra Registry Settings“. I open up the Edit, trying to locate that part but failed to do so. What I did is I research on the browser, checking whether has anyone experience it and what are the solutions to it.

There is a message display inside the “Extra Registry Settings” but not helpful in getting any information in the browser. The message is “Display names for some settings cannot be found. You might be able to resolve this issue by updating the .ADM files used by Group Policy Management.”

 

gpo01.PNG
Example, of the part

 

Thank god that PowerShell can remove this registry using the Remove-GPRegistryValue Command. You may refer to the reference below too.

First I run the GET command just to make sure the registry value is valid;

#This command retrieve information of an extra registry of the
Get-GPRegistryValue -Name "<GPO Name>" -Key "HKLM\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\"

#If result is valid then move on to REMOVE command, note that sensitivity on the Key Path Value "\" at the end must not be included
Remove-GPRegistryValue -Name "<GPO Name>"  -Key "HKLM\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\" -ValueName "<Registry Value Name>"

#A result will be shown after the REMOVE command executed, result contain GPO Name, Owner, creation time and modification time

 

Reference:

  1. https://sdmsoftware.com/group-policy-blog/tips-tricks/removing-extra-registry-settings-from-gpos/
  2. https://deploywindows.com/2017/10/12/extra-registry-settings-need-access-to-old-group-policy-settings/

 

PowerShell with Windows Forms

On a Friday night, after my work, I was wondering (finally some self-daydream) is there a way that PowerShell can create application-like. All I needed to get the theory and functionality working, beauty is later.

I texted my buddy in Singapore (.Net Dev) first then Europe (PowerShell master) and asked them, both of them gave me different platform answers but a similar answer was using Windows Form. The surprising thing was PowerShell can do it, I was like “Hmm…a platform the I am familiar with, let’s give that a try.”. Visual Studio also has Windows Form but I prefer to start off the platform that I familiarize first, you know, give myself a base to kick-start. Well, that does not mean that I won’t give Visual Studio a try.
Thanks very much for these 2 Masters!

So this is why I am writing this post, after gathering enough information from these 2 buddies (Masters), I start my journey towards Windows Form. Well, for a beginner is usually start off with “Hello world” statement. I try out the first reference link, this is what I get the outcome;

  • A simple pop out of “Hello World with an OK button”
  • Behavior: A Message pop up and selecting OK will returning a result

ps01.PNG

A simple pop up gets me excited to explore more of this Windows Form namespace.

So to gain further understanding, I tried to type something else, I am trying to get a behavior where I click on the “Good Luck!” button then a cute cat or Pikachu meme will pop out, not sure whether it is possible. Oh well, more exploring to do.

ps02.PNG

#A form with a simple display at the Center of the Screen and a button
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object System.Windows.Forms.Form
$Form.StartPosition = 'CenterScreen'

#Attributes or Controls for your form
$Form.Text = "Windows Form"
$Label.Text = "Sabrina's first Windows Form"
$GoodluckButton = New-Object System.Windows.Forms.Button
$GoodluckButton.Text = 'Good Luck!'
$GoodluckButton.Location = New-Object System.Drawing.Point(100,120)
$GoodluckButton.DialogResult = [System.Windows.Forms.DialogResult]::OK

#What are the controls to be added into the form
$Form.Controls.Add($Label)
$Form.Controls.Add($GoodluckButton)

#The result
$Form.ShowDialog()

References:

  1. https://www.powershellmagazine.com/2015/04/09/pstip-use-windows-forms-to-generate-gui-messagebox/

PowerShell: Disable users from creating Office 365 Groups

Before things or infrastructure of your SharePoint Online, Exchange Online’s Office 365 Groups, and Microsoft Teams go uncontrollable, it is better to disable the freedom of creating Office 365 groups for users. You can only do this via PowerShell and this may take 24 hours or probably a few hours to take effect. Think about what is the best procedure for this.

*Note:

  • Requires PowerShell Module
  • Requires AzureAD Module
  • This doesn’t impact Global Administrators
  • Users got the freedom to create Office 365 groups from application or web platforms, such as Outlook, Yammer, SharePoint Online, Teams and many more.
  1. Open Windows PowerShell or Windows Azure AD PowerShell module
  2. Type the following command, to connect to Azure AD Services
    • Connect-MsolServices
  3. Enter your Global Administrator Credential
  4. Type this command to get your company information
    • Get-MsolCompanyInformation
  5. Is will show you “UsersPermissionToCreateGroupsEnabled” is set to True
    • capture.png
  6. Type this following command to turn off the freedom for users to create Office 365 groups
    • Set-MsolCompanySettings -UsersPermissionToCreateGroupsEnabled $False
  7. This will then change the “UsersPermissionToCreateGroupsEnabled” to False
  8. Wait for 24 hours to take effect and try to test out whether it works from the user side.

Identify Azure Active Directory Connect in the Environment (Sync Service)

Ever encounter in an environment where IT does not have visibility of the previous IT actions? Frustrating and irritating right? They were unsure whether is sync service running or not or exist or not.

At first, you will go to portal.office.com to find the DirSync Status, but this is where the funny part, there is a DirSync Management and it has resulted or hint that this Office 365 had Synchronization Service. As you can see below, there is no service account and no last directory sync.

aadc01

Next, I went into their Domain controller > Active Directory Users and Computers > Users OU. I was able to locate 2 Synchronize’s Service accounts, that are not disabled. To locate their location (server), double click on the account to launch the properties. At the description attribute or value, you can identify the location (server name).

  • 1 Service account with no indication of this sync service’s server location in the Description Information
    • Able to locate it, it was inside a Window Server 2008 R2
  • 1 Service account with an indication of its location (inside one of the Domain controller, Windows Server 2012 R2)

I access both of these servers, able to capture

  • Sync tool exist
  • Sync service is running (inside the services.msc)
  • No Operation of sync
  • No connectors in the sync service to be found
  • Windows Server 2008 R2 running Microsoft Online Services Directory Synchronize Service version 2013 year
  • Window Server 2012 R2 running Windows Azure Active Directory Service tool version 2014 year

New version Sync tool naming is “Azure Active Directory Sync Service”.

Another round to proof your findings is to run the PowerShell command to get all attributes of the user list in Active Directory on-premises and Azure Active Directory user list. (If you prefer to filter only a few attributes, then it is up to you.)

For Active Directory

#Run this command in domain controller's windows PowerShell

Get-ADUser -Properties * -Filter * | Export-Csv "filename.csv"

Get one of the oldest (before the year of 2013) and an active employee’s objectGUID.

For Azure Active Directory

Requirements:

  1. .NET Framework installed (latest)
  2. Microsoft  Azure Active Directory Module or PowerShell
  3. Windows PowerShell
#Connect to Azure AD service

Connect-MsolService

#Key in your Global admin credential

#Run this get command to get all user list with its attribute

Get-MsolUser | Export-Csv "filename.csv"

Next, you find the same oldest employee’s immutable id value, if there is value means this environment had sync service running before. You could compare the value that is valid and convert the objectGUID to an immutable ID or the other way around, using this converter.

After locating all this, now you can plan your clean up and recommendations. This may take a longer process, due to you need matching and creation.

 

 

PowerShell Script: Schedule Litigation Hold Enabled Exchange Online

To share how to perform enabled litigation hold for User Mailbox using task scheduler. However, this may trigger your security application/detection in your environment (a.k.a “Unexpected script ran….”). This blog requires you to know how to use Task Scheduler.

*Note:

  • If you don’t specify license type in your script, is alright, the script will skip that user and move on with another one.
  • Some license doesn’t provide the litigation hold feature, such as E1 license.
  • This script is not a limited capability.

There are pretty much lots of ways you could perform this.

  1. You could perform based by checking on the user’s creation date and litigation hold status.
  2.  You could perform based by checking on the user’s department and litigation hold status
  3. You could perform based by checking only the litigation hold status
  4. You could perform based by checking the license type and litigation hold status
  5. You could perform based all 4 above

Well, it all depends on the requirements and necessary in the environment.

When I was scripting it, I notice if to perform manually running the script is best to make use “function” type, to avoid duplication. Anyways,

If you are planning to have this in task scheduler, you could have this PowerShell script save in any windows platform that has Windows PowerShell with the required module installed.

Before moving on, 

You would need to manually run a retrieve of office 365 global admin credential, save and encrypted into a file. If you are terrified of the file being accessed by others, just make some security adjustments towards the file. 

References:

  1. https://practical365.com/blog/saving-credentials-for-office-365-powershell-scripts-and-scheduled-tasks/
#Name: Sabrina Kay
#Purpose: This powershell is to enabled litigation hold

function Run-LitigationHoldEnabled{
#Parameter to get the path
param([string]$FilePath)

#retrieve the path
$File = Get-ChildItem -Path $FilePath -Filter *.cred

#Identify the file path iss found
if($File -eq $true){

#Have to convert to string, or get only the name, because the type is File System type
$UserName = $File.BaseName
$PwdSecureString = Get-Content "$($FilePath)\$($UserName).cred" | ConvertTo-SecureString

#Create a storable attribute object for username and password, (passsword won't be shown in plain text)
$UserCredential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName, $PwdSecureString

#Connect to Exchange Online
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session -DisableNameChecking
#Get user mailbox with litigation hold not enabled, set them to enabled
Get-Mailbox -RecipientTypeDetails UserMailbox | where-object {$_.litigationholdenabled -eq $false} | Set-Mailbox -LitigationHoldEnabled $true

#Finish and end session
Remove-PSSession $Session
}

Else{
#End Session if file path not found
    Remove-PSSession $Session
    }
}

#Main Program
#attribute for the office 365 credential file path
$KeyPath = "C:\xxx\"

#Task to run
Run-LitigationHoldEnabled -FilePath $KeyPath

Get-AIPFileStatus Script for users

Just having thought about how to extract the AIP File status from storage via PowerShell Scripting. Hope this helps. Do leave comments if you find some faulty or beside faulty.

*Note:

  1. This script doesn’t limit to what you want, you could modify it.

 

Assumption;

  1. Has AADRM module installed
  2. Has the Execution Policy modified
  3. Has PowerShell 3.0  above or Azure Module PowerShell console

Below is the script;

#Purpose: To export data of AIP labelled files from users devices
#You can do this into a GPO but beware of vulnerabilities and 50-50 percent chance that this could actually work
#If you want to run this in a GPO, you have to modify this script

#Connect to the aadrm service
$AADRM = Connect-AADRMService

if($AADRM){
#Please enter the path
 $ReadPath = Read-Host -Prompt "Enter Path that you wish to check"
 $ReadPath = $ReadPath.ToString()
 $AIPFileStatus = Get-AIPFileStatus -Path "$ReadPath" | where-object {$_.IsLabeled -eq $true}

#Count number of AIP files inside the path
 $CountFile = $AIPFileStatus.Count
 Write-Host "There are total $CountFile AIP File(s)."

#Prompt for export
 $a = Read-Host -Prompt "Do you want to export this data? (Yes/No)"

 $CurrentDate = Get-Date
 $CurrentDate = $CurrentDate.ToString('MM-dd-yyyy_hh-mm-ss')

 If ($a -eq "Yes" -Or $a -eq "yes"){ 
 $Export = $AIPFileStatus | Export-Csv "AIPFileStatus_$CurrentDate.csv"
 Write-Host "Successfully Exported!"
 }

 else{
 Write-Host "End..."
 }

}
else{
 Write-Host "Fail to connect"
}