Blog Feed

Automatically Transcribe Sinhala Zoom Meetings with Python, FFmpeg and OpenAI GPT-Transcribe

Many organizations still prepare meeting minutes manually. That becomes especially difficult when meetings are long, multilingual, and recorded over Zoom.

I recently had exactly this problem.

Our board meetings are usually held over Zoom and conducted primarily in Sinhala, with frequent English technical and administrative terms mixed into the conversation. A typical meeting can run for almost three hours.

The old workflow was:

Zoom recording
Listen manually
Pause / rewind
Write notes
Prepare formal minutes

Preparing accurate minutes could take several additional hours.

I wanted to automate as much of the process as possible.

The final workflow I built looks like this:

Zoom meeting
M4A / MP4 recording
FFmpeg splits recording into 15-minute files
Python sends each file to OpenAI gpt-transcribe
Sinhala transcript is generated
All transcript sections are combined
AI converts the transcript into formal meeting minutes

The result worked surprisingly well, even with Sinhala mixed with English and Buddhist/Pali terminology.

OpenAI currently describes gpt-transcribe as a high-accuracy speech-to-text model for file and realtime transcription. It also supports contextual hints for domain terminology and multilingual/code-switched speech.

Why I Did Not Use Zoom Transcription

Zoom has built-in transcription features, but Sinhala support was the main issue in my case.

The meeting included:

  • Sinhala conversation
  • English words and phrases
  • names of board members
  • Buddhist terminology
  • Pali chanting
  • financial terminology
  • technical discussions

I therefore needed a transcription engine that could handle multilingual audio more reliably.

My First Attempt: Local Whisper

My first approach was to run the open-source Whisper model locally.

I tested:

Whisper medium
Whisper large-v3
whisper.cpp
Vulkan acceleration
quantized large-v3 models
VAD speech detection

The machine I was testing had an:

AMD Radeon RX 570

Since standard CUDA acceleration requires NVIDIA hardware, I experimented with whisper.cpp using Vulkan.

The GPU acceleration itself worked.

For example, whisper.cpp successfully detected the Radeon GPU:

Radeon RX 570 Series
using Vulkan backend

However, the Sinhala transcription quality was poor.

The model repeatedly produced phrases such as:

අපි අපි අපි අපි...

and other repeated or incorrect text.

I also tried:

large-v3-q5_0
VAD
shorter speech segments
reduced context

but the quality was still not reliable enough for official board minutes.

This was an important lesson:

GPU acceleration can solve performance problems, but it does not solve speech-recognition accuracy problems.

For this particular Sinhala recording, I decided to move transcription to the cloud.

The Working Solution: OpenAI GPT-Transcribe

OpenAI currently offers several transcription models, including gpt-transcribe, gpt-4o-transcribe, and realtime transcription models. gpt-transcribe is currently positioned as the high-accuracy general transcription option.

At the time of writing, OpenAI lists gpt-transcribe transcription pricing at approximately:

$0.0045 USD per audio minute

So a three-hour meeting is inexpensive to process compared with the time required to transcribe it manually.

Prerequisites

I used Windows, but the same overall process works on Linux or macOS.

You need:

Python 3
FFmpeg
OpenAI Python SDK
OpenAI API key
Zoom meeting recording

My working directory was:

C:\Users\ayesh\Desktop\Meeting

and the Zoom audio file was:

audio1963221958.m4a

Step 1: Install Python

Download Python from:

https://www.python.org/

During installation make sure:

Add Python to PATH

is selected.

Verify:

python --version

You should see something similar to:

Python 3.x.x

Step 2: Install FFmpeg

If Windows Package Manager is available:

winget install Gyan.FFmpeg

Close and reopen PowerShell.

Verify:

ffmpeg -version

Step 3: Install the OpenAI Python Library

Run:

python -m pip install -U openai

Step 4: Create an API Key

Create an API key from the OpenAI developer platform.

Do not hard-code the API key into the Python script.

Instead, set it as an environment variable.

In PowerShell:

$env:OPENAI_API_KEY="YOUR_API_KEY_HERE"

This applies to the current PowerShell session.

For security reasons, never publish your real API key in:

  • a blog post
  • GitHub
  • screenshots
  • scripts
  • configuration examples

Step 5: Test Five Minutes Before Processing the Whole Meeting

This step saved me a lot of time.

Rather than immediately processing a three-hour meeting, I first generated a five-minute test file.

ffmpeg -i "C:\Users\ayesh\Desktop\Meeting\audio1963221958.m4a" `
-t 300 `
-ar 16000 `
-ac 1 `
"C:\Users\ayesh\Desktop\Meeting\test5min.wav"

Then I tested the transcription API.

Create:

transcribe_test.py

with the following code:

from openai import OpenAI
client = OpenAI()
audio_path = r"C:\Users\ayesh\Desktop\Meeting\test5min.wav"
with open(audio_path, "rb") as audio_file:
result = client.audio.transcriptions.create(
model="gpt-transcribe",
file=audio_file,
prompt=(
"This is a Buddhist temple board meeting. "
"The speakers mainly speak Sinhala, with occasional English words. "
"Please transcribe the spoken Sinhala accurately. "
"Common terminology includes Buddhist and Pali terms."
)
)
print(result.text)
with open(
r"C:\Users\ayesh\Desktop\Meeting\gpt_transcribe_test.txt",
"w",
encoding="utf-8"
) as output_file:
output_file.write(result.text)

Run:

python transcribe_test.py

The difference compared with my local Whisper attempt was substantial.

The service correctly recognized conversational Sinhala such as:

එහෙනම් අපි board meeting එක පටන්ගමු...

while preserving English terms such as:

board meeting
agenda
approve
minutes
automatically transcribe

It also handled Pali religious phrases much better than my local experiments.

Step 6: Add Domain-Specific Context

Proper names are difficult for any speech-recognition system.

For better accuracy, I added commonly used names and terminology to the prompt.

For example:

PROMPT = (
"This is a board meeting of the Waterloo Wellington Buddhist "
"Monastery and Meditation Center (WWBMMC). "
"The meeting is mainly spoken in Sinhala, with occasional English "
"words and Buddhist Pali terminology. "
"Please transcribe the spoken content accurately in the language spoken. "
"Do not translate Sinhala into English. "
"Common terms include Vesak, Katina, Dansala, Dhamma School, "
"Buddha, Dhamma, Sangha and Pansil."
)

For a corporate environment, you could instead include terminology such as:

Microsoft Azure
VMware
Cisco
Palo Alto
Kubernetes
Active Directory
project names
employee names
department names

This can help reduce incorrect recognition of unusual vocabulary.

Step 7: Why I Split the Recording

Rather than sending one very large file, I split the recording into 15-minute sections.

Advantages include:

  • smaller upload sizes
  • easier troubleshooting
  • easier retrying
  • progress is preserved if the script stops
  • failed sections can be rerun independently

For a three-hour meeting this produces approximately 12 files.

Step 8: Complete Automated Python Script

The following script performs the entire workflow.

It:

  1. creates output directories
  2. splits the Zoom M4A file
  3. transcribes each section
  4. skips already-completed sections
  5. resumes after failures
  6. combines everything into one transcript

Save this as:

transcribe_full_meeting.py
from pathlib import Path
import subprocess
import time
from openai import OpenAI
# --------------------------------------------------
# SETTINGS
# --------------------------------------------------
MEETING_FOLDER = Path(r"C:\Users\ayesh\Desktop\Meeting")
INPUT_AUDIO = MEETING_FOLDER / "audio1963221958.m4a"
CHUNKS_FOLDER = MEETING_FOLDER / "meeting_chunks"
TRANSCRIPTS_FOLDER = MEETING_FOLDER / "meeting_transcripts"
FINAL_TRANSCRIPT = (
MEETING_FOLDER / "complete_meeting_transcript.txt"
)
MODEL = "gpt-transcribe"
# 15-minute chunks
CHUNK_SECONDS = 900
PROMPT = (
"This is a board meeting of the Waterloo Wellington Buddhist "
"Monastery and Meditation Center (WWBMMC). "
"The meeting is mainly spoken in Sinhala, with occasional English "
"words and Buddhist Pali terminology. "
"Please transcribe the spoken content accurately in the language spoken. "
"Do not translate Sinhala into English. "
"Common names and terms may include Buddhist monks, board members, "
"Vesak, Katina, Dansala, Dhamma School, Buddha, Dhamma, Sangha and Pansil."
)
# --------------------------------------------------
# INITIALIZE
# --------------------------------------------------
client = OpenAI()
CHUNKS_FOLDER.mkdir(exist_ok=True)
TRANSCRIPTS_FOLDER.mkdir(exist_ok=True)
if not INPUT_AUDIO.exists():
raise FileNotFoundError(
f"Audio file not found: {INPUT_AUDIO}"
)
# --------------------------------------------------
# STEP 1: SPLIT AUDIO
# --------------------------------------------------
existing_chunks = sorted(
CHUNKS_FOLDER.glob("chunk_*.m4a")
)
if not existing_chunks:
print(
"\nSTEP 1: Splitting meeting into "
"15-minute chunks...\n"
)
output_pattern = str(
CHUNKS_FOLDER / "chunk_%03d.m4a"
)
command = [
"ffmpeg",
"-i",
str(INPUT_AUDIO),
"-f",
"segment",
"-segment_time",
str(CHUNK_SECONDS),
"-reset_timestamps",
"1",
"-c",
"copy",
output_pattern,
]
subprocess.run(
command,
check=True
)
print(
"\nAudio splitting completed.\n"
)
else:
print(
"\nExisting audio chunks found. "
"Skipping split step.\n"
)
chunks = sorted(
CHUNKS_FOLDER.glob("chunk_*.m4a")
)
print(
f"Found {len(chunks)} audio chunks.\n"
)
# --------------------------------------------------
# STEP 2: TRANSCRIBE EACH CHUNK
# --------------------------------------------------
for index, chunk in enumerate(
chunks,
start=1
):
transcript_file = (
TRANSCRIPTS_FOLDER
/ f"{chunk.stem}.txt"
)
print("=" * 70)
print(
f"Chunk {index} of {len(chunks)}"
)
print(
f"Audio: {chunk.name}"
)
# Resume support:
# Skip completed transcript files
if (
transcript_file.exists()
and transcript_file.stat().st_size > 10
):
print(
"Transcript already exists - skipping."
)
continue
try:
print(
"Uploading and transcribing..."
)
with open(
chunk,
"rb"
) as audio_file:
result = (
client.audio.transcriptions.create(
model=MODEL,
file=audio_file,
prompt=PROMPT,
)
)
text = result.text.strip()
transcript_file.write_text(
text,
encoding="utf-8"
)
print(
f"Saved: {transcript_file.name}"
)
time.sleep(2)
except Exception as e:
print(
"\nERROR while transcribing:"
)
print(e)
print(
"\nStopping here so completed "
"work is preserved."
)
print(
"Run the script again later "
"and it will resume."
)
raise
# --------------------------------------------------
# STEP 3: COMBINE TRANSCRIPTS
# --------------------------------------------------
print(
"\n" + "=" * 70
)
print(
"Combining transcript files...\n"
)
all_text = []
transcript_files = sorted(
TRANSCRIPTS_FOLDER.glob(
"chunk_*.txt"
)
)
for index, transcript_file in enumerate(
transcript_files,
start=1
):
text = transcript_file.read_text(
encoding="utf-8"
).strip()
start_minutes = (
index - 1
) * 15
end_minutes = (
index * 15
)
header = (
"\n\n"
"============================================================\n"
f"SECTION {index} - approximately "
f"{start_minutes} to "
f"{end_minutes} minutes\n"
"============================================================\n\n"
)
all_text.append(
header + text
)
FINAL_TRANSCRIPT.write_text(
"".join(all_text),
encoding="utf-8"
)
print(
"DONE!"
)
print()
print(
"Final transcript saved to:"
)
print(
FINAL_TRANSCRIPT
)

Step 9: Run the Script

Open PowerShell:

cd "C:\Users\ayesh\Desktop\Meeting"

Set your API key:

$env:OPENAI_API_KEY="YOUR_API_KEY"

Then run:

python transcribe_full_meeting.py

Output will look similar to:

STEP 1: Splitting meeting into 15-minute chunks...
Found 12 audio chunks.
======================================================================
Chunk 1 of 12
Audio: chunk_000.m4a
Uploading and transcribing...
Saved: chunk_000.txt

Then:

Chunk 2 of 12
Chunk 3 of 12
Chunk 4 of 12
...

Resume Support

One feature I strongly recommend keeping is resume support.

Suppose the script stops while processing:

chunk_008.m4a

Chunks 1 through 7 already have transcripts.

Simply run:

python transcribe_full_meeting.py

again.

The script checks whether files such as:

chunk_000.txt
chunk_001.txt
chunk_002.txt

already exist.

If they do, it skips them.

You do not have to pay to retranscribe completed sections.

Folder Structure

After completion, my directory looked like:

Meeting
├── audio1963221958.m4a
├── transcribe_full_meeting.py
├── complete_meeting_transcript.txt
├── meeting_chunks
│ ├── chunk_000.m4a
│ ├── chunk_001.m4a
│ ├── chunk_002.m4a
│ └── ...
└── meeting_transcripts
├── chunk_000.txt
├── chunk_001.txt
├── chunk_002.txt
└── ...

The final file is:

complete_meeting_transcript.txt

Step 10: Turn the Transcript into Meeting Minutes

Speech transcription and meeting-minute generation are two separate tasks.

I recommend keeping them separate.

First:

Audio → accurate Sinhala transcript

Then:

Sinhala transcript → structured English minutes

This avoids forcing the speech-recognition model to simultaneously recognize speech, translate it, decide what is important, and summarize it.

Once I had the complete transcript, I supplied:

  1. the transcript
  2. a copy of our previous meeting minutes
  3. the names of our board members

I then asked AI to produce minutes with:

Meeting date
Time
Attendance
Agenda items
Financial updates
Motions
Proposed by
Seconded by
Decisions
Action items
Responsible person
Adjournment

The final document could then be reviewed by the secretary before Board approval.

One Important Limitation: Speaker Identification

One issue I encountered was that the transcript did not automatically identify every speaker.

For example:

I propose the motion.
I second it.

may be transcribed correctly, but without knowing who said each sentence.

That means the AI should not guess who proposed or seconded a motion.

For official minutes, always verify:

Mover
Seconder
Voting result
Attendance
Dates
Amounts

against the recording or meeting notes.

If speaker attribution is essential, OpenAI also offers transcription models that support speaker diarization.

That is something I plan to investigate further.

Security and Privacy Considerations

If you are processing board, corporate, nonprofit, legal, or internal meetings, consider the sensitivity of the recordings before sending them to any cloud service.

Some basic practices I recommend:

Do not publish meeting recordings publicly.
Do not hard-code API keys.
Limit access to transcripts.
Protect transcript folders with appropriate permissions.
Review your organization's privacy requirements.
Inform participants that the meeting is being recorded.
Delete temporary audio chunks if you no longer need them.

For organizational deployments, you should also review your organization’s retention and data-handling requirements.

Cleaning Up Temporary Audio Files

Once transcription is complete and verified, the M4A chunks can consume significant disk space.

If you no longer need them:

Remove-Item `
"C:\Users\ayesh\Desktop\Meeting\meeting_chunks\*" `
-Force

I recommend keeping the original Zoom recording and the final transcript according to your organization’s document-retention policy.

What Worked and What Didn’t

My testing produced a useful comparison.

Local Whisper / whisper.cpp

Advantages

No cloud upload
No per-minute API cost
Runs entirely locally
Vulkan can use AMD GPUs

Problems in my environment

Poor Sinhala recognition
Repeated hallucinated phrases
Large models required substantial VRAM
A lot of model/parameter experimentation

GPT-Transcribe API

Advantages

Much better Sinhala accuracy
Excellent Sinhala/English code-switching
Handled Buddhist and Pali terminology well
Simple Python API
Low transcription cost
Minimal local hardware requirements

Disadvantages

Requires Internet access
Requires API billing
Audio leaves the local machine
Speaker identification may require additional processing

For this use case, cloud transcription was clearly the better choice.

Cost Example

OpenAI currently lists gpt-transcribe at approximately:

$0.0045 USD/minute

A 175-minute board meeting is therefore approximately:

175 × $0.0045
= $0.7875 USD

or roughly:

$0.79 USD

before applicable taxes or other account-specific billing factors.

Compared with manually spending several hours transcribing a meeting, this was easily worthwhile for my use case.

Possible Improvements

There are several ways this system could be extended.

The next version could potentially automate:

Zoom recording folder monitoring
Automatic FFmpeg splitting
Automatic transcription
Speaker diarization
AI meeting summary
DOCX meeting minutes
PDF export
Email to board members

You could also integrate:

Microsoft Teams
SharePoint
OneDrive
Google Drive
AWS S3
Power Automate
Azure Functions
AWS Lambda

depending on the environment.

Final Thoughts

The most important lesson from this project was not simply that AI can transcribe meetings.

The useful part is combining several simple components:

Zoom
FFmpeg
Python
Speech-to-text API
AI summarization

into a repeatable workflow.

For long multilingual meetings, particularly languages such as Sinhala where built-in conferencing transcription may not perform well, this approach can dramatically reduce the administrative effort required to prepare meeting minutes.

The process is also generic.

It could be adapted for:

nonprofit board meetings
community organizations
religious organizations
municipal committees
technical meetings
project meetings
interviews
lectures
training sessions

The important rule is to treat the generated transcript and minutes as a draft requiring human review, especially when the content forms part of an official organizational record.


Useful Links

OpenAI currently documents gpt-transcribe as a high-accuracy file/realtime speech-to-text model and lists the Audio Transcriptions endpoint as supported.

OpenAI GPT-Transcribe documentation

OpenAI transcription model catalog

Fixing Kerberos SSO Failures After Recent Windows Updates

We have observed that Single Sign-On (SSO) may fail for some applications after installing recent Windows Server updates on domain controllers (KB5082123 and KB5087538).

This issue is caused by Microsoft’s continued efforts to strengthen Kerberos authentication security. The updates enforce stronger encryption requirements and reduce support for older, less secure encryption types.

If your application uses a keytab file to decrypt Kerberos tickets and the keytab was generated some time ago without explicitly specifying the encryption type, SSO authentication may start failing after these updates are applied.

Resolution

1. Enable Stronger Encryption on the Service Account

Update the service account used by the application to support modern Kerberos encryption types (such as AES256).

2. Reset the Service Account Password

After enabling stronger encryption, the service account password must be reset for the changes to take effect.

To avoid application disruptions, you can reset the password to the same value currently in use.

3. Generate a New Keytab File

Generate a new keytab file using the updated encryption settings. Run the following command on a domain controller. Be sure to open Command Prompt with Administrator privileges.

ktpass -out c:\temp\gateway.keytab ^
-princ HTTP/gateway.example.com@EXAMPLE.COM ^
-mapuser gateway-service-account ^
-crypto AES256-SHA1 ^
-ptype KRB5_NT_PRINCIPAL ^
-pass *

4. Update the Application

Upload the newly generated keytab file to the affected application and follow the vendor’s documentation for updating Kerberos credentials.

Conclusion

After replacing the old keytab file with one generated using AES256 encryption, Kerberos authentication should function normally again. Applications relying on older encryption types may require similar updates as Microsoft continues to strengthen Kerberos security requirements in future releases.

Outlook LTSC cannot connect to office 365

When tring to connect to office 365 using Office LTSC getting an error “Something went wrong and Outlook couldn’t set up your account.”

This caused by missing reg key for the Modern Auth, fix can be apply via adding below reg keys. Make sure you have done all other tshoots before jumping to this 🙂

I have tested this with LTSC 2021 on Server 2019

reg add "HKCU\Software\Microsoft\Office\16.0\Common\Identity" /v DisableAADWAM /t REG_DWORD /d 1 /f
reg add "HKCU\Software\Microsoft\Office\16.0\Common\Identity" /v EnableADAL /t REG_DWORD /d 1 /f
reg add "HKCU\Software\Microsoft\Exchange" /v AlwaysUseMSOAuthForAutoDiscover /t REG_DWORD /d 1 /f

AWS Migrating your virtual machines (AWS MGN Service)  

🔧 Additional Clarifications for Step 3 (Based on Real‑World Experience Using Oracle Linux)
While following the migration steps, I found a few practical details that can help ensure a smooth setup—especially when installing and configuring the AWS MGN vCenter Client on an Oracle Linux VM.

Here is the article for step by step,

https://sudoconsultants.com/migrate-your-vms-to-aws-a-step-by-step-guide/

✅ Ensure Network Connectivity to vCenter

The VM running the AWS MGN vCenter Client must have uninterrupted network access to the vCenter Server.
If the MGN client cannot reach vCenter (firewall, routing, DNS, or port issues), the installation will fail or the service will not start properly.
Make sure the following are open and reachable:

  • vCenter IP or hostname
  • Port 443 (HTTPS)
  • DNS resolution (if using hostname)
  • No outbound restrictions blocking AWS endpoints

This is a critical requirement that is easy to overlook.

📝 Useful Input Details During the Installer Prompts

When running the installer script on Oracle Linux, you will be asked for several parameters. Below is a clear reference for each field

These details help avoid confusion during installation, especially when using Oracle Linux instead of Ubuntu.

Add a Refresh option to the right‑click context menu in Windows

Open PowerShell as Administrator and run the command below, or copy it into Notepad, save the file as a .ps1, and run it as Administrator.

# Restore classic context menu in Windows 11
# Creates HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32 with empty default value

# Ensure we're in PowerShell
$ErrorActionPreference = 'Stop'

# Registry path and GUID
$basePath = 'HKCU:\Software\Classes\CLSID'
$guid     = '{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}'
$inproc   = Join-Path -Path (Join-Path $basePath $guid) -ChildPath 'InprocServer32'

# Create the keys if they don't exist
if (-not (Test-Path (Join-Path $basePath $guid))) {
    New-Item -Path $basePath -Name $guid | Out-Null
}
if (-not (Test-Path $inproc)) {
    New-Item -Path (Join-Path $basePath $guid) -Name 'InprocServer32' | Out-Null
}

# Set the (Default) value to empty string
# Using .NET to set the unnamed default value
New-ItemProperty -Path $inproc -Name '(Default)' -Value '' -PropertyType String -Force | Out-Null

# Restart Explorer to apply changes
Write-Host 'Restarting Windows Explorer...'
Get-Process explorer -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Process explorer.exe

Write-Host 'Done. The classic context menu should now appear.'

If you want the PS script,
https://github.com/ayeshsherman/right-click-context-menu-in-Windows.git

Windows update database error detected

Save this script as a batch file and run as a admin. After that reboot the system and run the windows updates.

@echo off
echo ============================================
echo Resetting Windows Update Components...
echo ============================================

:: Stop services
net stop wuauserv
net stop cryptSvc
net stop bits
net stop msiserver

:: Rename folders
Ren C:\Windows\SoftwareDistribution SoftwareDistribution.old
Ren C:\Windows\System32\catroot2 Catroot2.old

:: Restart services
net start wuauserv
net start cryptSvc
net start bits
net start msiserver

echo ============================================
echo Process Completed Successfully.
echo ============================================
pause

Credits goes here https://www.kapilarya.com/potential-windows-update-database-error-in-windows-10

Decommissioning Exchange Server

I had recently been tasked with removing one exchange server from an on-prem three-node cluster. These are the steps that I had to take to remove the server. As with any decommissioning process, make sure to take a full backup and arrange for downtime 🙂

Before runs command bring is exchange snap in for on Exchange PowerShell by running below

Exchange 2007:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin;

Exchange 2010:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010;

Exchange 2013:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn;

Before decom server mailboxes need to move to another DB.

Before you move the mailboxes, run the Set-ADServerSettings cmdlet, including the -ViewEntireForest parameter. This will let you view the objects in the entire forest.

Set-ADServerSettings -ViewEntireForest $true

  • Run the Get-MailboxDatabase cmdlet, including the -Status parameter, to check which mailbox databases are present and whether they are mounted.

Get-MailboxDatabase -Status | Sort Name | Format-Table Name, Server, Mounted

  • Run Get-Mailbox to find all mailboxes in the database that you are going to delete.

Get-Mailbox -Database “DB01” -ResultSize Unlimited

Move all mailboxes from one database to another with the New-MoveRequest cmdlet.

Get-Mailbox -Database “DB01” -ResultSize Unlimited | New-MoveRequest -TargetDatabase “DB02”

Move Archive mailbox

Find archive mailboxes in the database.

Get-Mailbox -ResultSize Unlimited | Where {$_.ArchiveDatabase -like “DB01”}

Move archive mailboxes to another database.

Get-Mailbox -ResultSize Unlimited | Where {$_.ArchiveDatabase -like “DB01”} | New-MoveRequest -ArchiveTargetDatabase “DB02”

Move Public folder mailbox

Find public folder mailboxes in the database.

Get-Mailbox -Database “DB01” -PublicFolder

Move public folder mailboxes to another database.

Get-Mailbox -Database “DB01” -PublicFolder | New-MoveRequest -TargetDatabase “DB02”

Move Arbitration mailbox

Find arbitration mailboxes in the database.

Get-Mailbox -Database “DB01” -Arbitration

Move arbitration mailbox to another database.

Get-Mailbox -Database “DB01” -Arbitration | New-MoveRequest -TargetDatabase “DB02”

Move Audit Log mailbox

Find audit log mailboxes in the database.

Get-Mailbox -Database “DB01” -AuditLog

Move audit log mailboxes to another database.

Get-Mailbox -Database “DB01” -AuditLog | New-MoveRequest -TargetDatabase “DB02”

Disable Monitoring mailbox

Find monitoring mailboxes associated with the mailbox database.

Get-Mailbox -Database “DB01” -Monitoring | Format-Table Name, DisplayName, Database, Servername

Disable monitoring mailboxes.

Get-Mailbox -Database “DB01” -Monitoring | Disable-Mailbox -Confirm:$false

Please note that the above listed steps need to be done for each DB on the server that is going to remove in order to remove all the mailbox DBs from the server.

Verify mailboxes move

Verify that all the mailboxes are moved. After that, remove  completed move requests. If you don’t, you will get the error this mailbox database is associated with one or more move requests. If you want to remove all move requests, run the third command.

Get-MoveRequestStatistics -MoveRequestQueue “DB02”

To remove only selected DB moves,

Get-MoveRequest -SourceDatabase “DB02” -MoveStatus Completed -ResultSize Unlimited | Remove-MoveRequest -Confirm:$false

If you want to remove all the move request run,

Get-MoveRequest -MoveStatus Completed -ResultSize Unlimited | Remove-MoveRequest -Confirm:$false

Get-MoveRequest -ResultSize Unlimited | Remove-MoveRequest -Confirm:$false

Reboot the server

Make sure to check send connectors and Firewall to see any dependencies before remove completely.

Set the Exchange to maintenance mode

Set-ServerComponentState <ServerName> -Component ServerWideOffline -State Inactive -Requester Maintenance

Validate

Get-ServerComponentState <ServerName> | Format-Table Component,State -Autosize

After that you will need to go to ECP and delete the DBs. After that on the exchange server you will be able to uninstall from add/remove in control panel.

Some Useful Documents:

https://practical365.com/decommissioning-exchange-on-premises-servers-and-consolidating-email-smtp-relays/
https://www.alitajran.com/list-mailboxes-in-database/
https://www.alitajran.com/get-exchange-mailbox-database-mount-status-with-powershell/
https://www.alitajran.com/cannot-delete-mailbox-database-exchange/

Search and Delete an Email from office365.

Here is the steps to find and delete a specific mail from mailbox(s) from the office365 exchange.

1. Install PowerShell 7 using the following command:  winget install –id Microsoft.Powershell –source winget . Because complaince task need new PS.

2. PowerShell 7 will install side-by-side with your current version of Powershell. You will be able to find it using Search or in Start->All Programs. Start it

3. Install the Exchange Online Management Module using the command : install-module exchangeonlinemanagement

4. Connect to Exchange Online using the command: connect-exchangeonline. You will be asked to authenticate using your credentials ( Make sure the account that using has proper permission)

5. Connect to Security and Compliance Online using the command:  Connect-IPPSSession. You will be asked to authenticate using your credentials

6. Create a new compliance search: New-ComplianceSearch -Name “Give it a title” -ExchangeLocation All -ContentMatchQuery ‘(Received>=10/22/2020 -AND Received<=10/25/2020) AND (Subject:”provide words/phrase to look for in the subject”) AND (From:sender email address)’

7. Start the search with the command: start-compliancesearch “use the title you gave it above”

8. Check on the status of the search with the commanD: get-compliancesearch “user the title you gave it”. You can also use the command – get-compliancesearch “user the title you gave it” | fl, for more details and find out if any emails were found. You will not see a list in the results, but just a number.

9. If there were emails and you want to delete them then use the command: New-ComplianceSearchAction -SearchName “provide the title from above” -Purge -PurgeType SoftDelete

10. Check on the status: Get-ComplianceSearchAction “the title from above and append _purge”

References: 

1. https://learn.microsoft.com/en-us/powershell/exchange/connect-to-scc-powershell?view=exchange-ps 

2. https://learn.microsoft.com/en-us/purview/ediscovery-search-for-and-delete-email-messages

3. https://adamtheautomator.com/office-365-delete-email/

Install Patch on ESXI Server

I’m not going to detail the steps here to update the ESXI server. These are quick steps to get your ESXI server updated via the VMware patch bundle. In this installation, I have patched the ESXI 7.0U3 server to the latest 7.0U3o patch level.

Go to vmware and download the patch bundle VMware-ESXi-7.0U3o-22348816-depot.zip and upload it to your ESXI server datastore.

Then note down the store location, safely shutdown or move servers, and put the host in maintenance mode.

SSH into the server and run( Make sure to edit your line as needed for file location, esxcli software sources profile list -d /vmfs/volumes/Store1/ISO/VMware-ESXi-7.0U3o-22348816-depot.zip

It will shows package content

Then run ( in this insttance I have selected esxi standard) esxcli software profile update -d /vmfs/volumes/Store1/ISO/VMware-ESXi-7.0U3o-22348816-depot.zip -p ESXi-7.0U3o-22348816-standard

After sometimes, you will see a notifcation that update has been completed and server needs a reboot

Go ahead and reboot and done.

Here is some links for detail ver of above,

https://www.youtube.com/watch?v=UOFf56VuodU

https://www.vinchin.com/en/blog/esxi-update-upgrade.html

https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.esxi.upgrade.doc/GUID-FE668788-1F32-4CB2-845C-5547DD59EB48.html

https://www.experts-exchange.com/articles/34250/HOW-TO-Update-VMware-ESXi-7-0-GA-to-ESXi-7-0b-in-5-easy-steps.html

How to import IP address in bulk to Palo Alto Firewall

***Prepare Text file with all the address needed,

set address test ip-netmask 10.0.0.1
set address test2 ip-netmask 10.0.0.2
set address test33 ip-netmask 10.0.0.3

***SSH into PA CLI and enter configure, Now past the what you copied from text file. You can enter ” show address” to see added address

***If you want to add thses to address group same as before prepare text file and enter those to CLI

set address-group MyCustomAddressGroup static test
set address-group MyCustomAddressGroup static test2

***Enter "commit” to commite the changes

***See the address group “show address-group”

More info https://live.paloaltonetworks.com/t5/general-topics/how-to-import-address-objects-in-csv-to-pa-firewall/td-p/453559