m365-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +683 -0
- package/bin/m365.js +489 -0
- package/config/default.json +18 -0
- package/package.json +36 -0
- package/src/auth/device-flow.js +154 -0
- package/src/auth/token-manager.js +237 -0
- package/src/commands/calendar.js +279 -0
- package/src/commands/mail.js +353 -0
- package/src/commands/onedrive.js +423 -0
- package/src/commands/sharepoint.js +312 -0
- package/src/graph/client.js +875 -0
- package/src/utils/config.js +60 -0
- package/src/utils/error.js +114 -0
- package/src/utils/output.js +850 -0
- package/src/utils/trusted-senders.js +190 -0
package/README.md
ADDED
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
# M365 CLI
|
|
2
|
+
|
|
3
|
+
Modern command-line interface for Microsoft 365 personal accounts (Mail, Calendar, OneDrive, SharePoint).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📧 **Mail**: List, read, send, search emails (with attachments)
|
|
8
|
+
- 📅 **Calendar**: Manage events (list, create, update, delete)
|
|
9
|
+
- 📁 **OneDrive**: File management (upload, download, search, share)
|
|
10
|
+
- 🌐 **SharePoint**: Site and document management
|
|
11
|
+
- 🔐 **Secure**: OAuth 2.0 Device Code Flow authentication
|
|
12
|
+
- 🚀 **Fast**: Minimal dependencies, uses native Node.js fetch
|
|
13
|
+
- 🤖 **AI-friendly**: Clean text output + JSON option
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g m365-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If you prefer to install from source:
|
|
22
|
+
```bash
|
|
23
|
+
git clone <repo>
|
|
24
|
+
cd m365-cli
|
|
25
|
+
npm install
|
|
26
|
+
npm link
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
After linking, the `m365` command will be available globally.
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### 1. Login
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
m365 login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Follow the prompts to authenticate with your Microsoft 365 account using Device Code Flow.
|
|
40
|
+
|
|
41
|
+
### 2. List Emails
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
m365 mail list --top 5
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. View Calendar
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
m365 calendar list --days 7
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 4. Browse OneDrive
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
m365 onedrive ls
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Commands Reference
|
|
60
|
+
|
|
61
|
+
### Authentication
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
m365 login # Login with Device Code Flow
|
|
65
|
+
m365 logout # Clear stored credentials
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Mail Commands
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# List emails
|
|
72
|
+
m365 mail list [options]
|
|
73
|
+
--top <n> # Number of emails (default: 10)
|
|
74
|
+
--folder <name> # Folder to list (default: inbox)
|
|
75
|
+
--json # Output as JSON
|
|
76
|
+
|
|
77
|
+
# Supported folders:
|
|
78
|
+
# inbox - Inbox (default)
|
|
79
|
+
# sent - Sent Items
|
|
80
|
+
# drafts - Drafts
|
|
81
|
+
# deleted - Deleted Items
|
|
82
|
+
# junk - Junk Email
|
|
83
|
+
# Or use a folder ID directly
|
|
84
|
+
|
|
85
|
+
# Read email
|
|
86
|
+
m365 mail read <id> [options]
|
|
87
|
+
--force # Skip whitelist check
|
|
88
|
+
--json # Output as JSON
|
|
89
|
+
|
|
90
|
+
# Send email
|
|
91
|
+
m365 mail send <to> <subject> <body> [options]
|
|
92
|
+
--attach <file1> <file2> ... # Attach files
|
|
93
|
+
--json # Output as JSON
|
|
94
|
+
|
|
95
|
+
# Search emails
|
|
96
|
+
m365 mail search <query> [options]
|
|
97
|
+
--top <n> # Number of results (default: 10)
|
|
98
|
+
--json # Output as JSON
|
|
99
|
+
|
|
100
|
+
# Manage trusted senders whitelist
|
|
101
|
+
m365 mail trust <email> # Add to whitelist
|
|
102
|
+
m365 mail untrust <email> # Remove from whitelist
|
|
103
|
+
m365 mail trusted [options] # List whitelist
|
|
104
|
+
--json # Output as JSON
|
|
105
|
+
|
|
106
|
+
# List attachments
|
|
107
|
+
m365 mail attachments <id> [options]
|
|
108
|
+
--json # Output as JSON
|
|
109
|
+
|
|
110
|
+
# Download attachment
|
|
111
|
+
m365 mail download-attachment <message-id> <attachment-id> [local-path] [options]
|
|
112
|
+
--json # Output as JSON
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Examples:**
|
|
116
|
+
```bash
|
|
117
|
+
m365 mail list --top 5
|
|
118
|
+
m365 mail list --folder sent --top 10 # List sent emails
|
|
119
|
+
m365 mail list --folder drafts # List draft emails
|
|
120
|
+
m365 mail read AAMkADA5ZDE2Njk2...
|
|
121
|
+
m365 mail read AAMkADA5ZDE2Njk2... --force # Skip whitelist check
|
|
122
|
+
m365 mail send "user@example.com" "Meeting" "Let's meet tomorrow" --attach report.pdf
|
|
123
|
+
m365 mail search "project update" --top 20
|
|
124
|
+
|
|
125
|
+
# Whitelist management
|
|
126
|
+
m365 mail trusted # List trusted senders
|
|
127
|
+
m365 mail trust user@example.com # Trust specific sender
|
|
128
|
+
m365 mail trust @example.com # Trust entire domain
|
|
129
|
+
m365 mail untrust user@example.com # Remove from whitelist
|
|
130
|
+
|
|
131
|
+
# Attachment examples
|
|
132
|
+
m365 mail attachments AAMkADA5ZDE2Njk2... # List all attachments in an email
|
|
133
|
+
m365 mail download-attachment AAMkADA5... AAMkAGQ... # Download using attachment's original filename
|
|
134
|
+
m365 mail download-attachment AAMkADA5... AAMkAGQ... ~/Downloads/file.pdf # Specify output path
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Security: Trusted Senders Whitelist
|
|
138
|
+
|
|
139
|
+
The CLI includes a **phishing protection feature** that filters email content from untrusted senders.
|
|
140
|
+
|
|
141
|
+
**How it works:**
|
|
142
|
+
- When reading emails with `m365 mail read`, the sender is checked against a whitelist
|
|
143
|
+
- If the sender is not trusted, only metadata (sender, subject, date) is shown
|
|
144
|
+
- Email body is replaced with: `[Content filtered - sender not in trusted senders list]`
|
|
145
|
+
- Use `--force` to bypass the check when needed
|
|
146
|
+
|
|
147
|
+
1. `~/.m365-cli/trusted-senders.txt`
|
|
148
|
+
|
|
149
|
+
**Whitelist format:**
|
|
150
|
+
```
|
|
151
|
+
# Trust specific email addresses
|
|
152
|
+
user@example.com
|
|
153
|
+
other@example.com
|
|
154
|
+
user@example.com
|
|
155
|
+
|
|
156
|
+
# Trust entire domains (prefix with @)
|
|
157
|
+
@example.com
|
|
158
|
+
@microsoft.com
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Management commands:**
|
|
162
|
+
```bash
|
|
163
|
+
m365 mail trusted # View current whitelist
|
|
164
|
+
m365 mail trust user@example.com # Add to whitelist
|
|
165
|
+
m365 mail trust @example.com # Trust entire domain
|
|
166
|
+
m365 mail untrust user@example.com # Remove from whitelist
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Special handling:**
|
|
170
|
+
- Internal organization emails (Exchange DN format) are automatically trusted
|
|
171
|
+
- Marked emails in lists show a ⚠️ warning indicator for untrusted senders
|
|
172
|
+
|
|
173
|
+
### Calendar Commands
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# List events
|
|
177
|
+
m365 calendar list [options]
|
|
178
|
+
m365 cal list [options] # Alias
|
|
179
|
+
--days <n> # Look ahead N days (default: 7)
|
|
180
|
+
--top <n> # Maximum events (default: 50)
|
|
181
|
+
--json # Output as JSON
|
|
182
|
+
|
|
183
|
+
# Get event details
|
|
184
|
+
m365 calendar get <id> [options]
|
|
185
|
+
--json # Output as JSON
|
|
186
|
+
|
|
187
|
+
# Create event
|
|
188
|
+
m365 calendar create <title> [options]
|
|
189
|
+
--start <datetime> # Start time (required)
|
|
190
|
+
--end <datetime> # End time (required)
|
|
191
|
+
--location <location> # Event location
|
|
192
|
+
--body <description> # Event description
|
|
193
|
+
--attendees <email1,email2> # Attendee emails (comma-separated)
|
|
194
|
+
--allday # All-day event
|
|
195
|
+
--json # Output as JSON
|
|
196
|
+
|
|
197
|
+
# Update event
|
|
198
|
+
m365 calendar update <id> [options]
|
|
199
|
+
--title <title> # New title
|
|
200
|
+
--start <datetime> # New start time
|
|
201
|
+
--end <datetime> # New end time
|
|
202
|
+
--location <location> # New location
|
|
203
|
+
--body <description> # New description
|
|
204
|
+
--json # Output as JSON
|
|
205
|
+
|
|
206
|
+
# Delete event
|
|
207
|
+
m365 calendar delete <id> [options]
|
|
208
|
+
--json # Output as JSON
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Datetime formats:**
|
|
212
|
+
- Full datetime: `2026-02-17T14:00:00`
|
|
213
|
+
- Date only (for all-day events): `2026-02-17`
|
|
214
|
+
|
|
215
|
+
**Examples:**
|
|
216
|
+
```bash
|
|
217
|
+
m365 cal list --days 5
|
|
218
|
+
m365 cal get AAMkADA5ZDE2Njk2...
|
|
219
|
+
m365 cal create "Team Meeting" --start "2026-02-17T14:00:00" --end "2026-02-17T15:00:00" --location "Room A"
|
|
220
|
+
m365 cal create "Holiday" --start "2026-02-20" --end "2026-02-21" --allday
|
|
221
|
+
m365 cal update AAMkADA5... --location "Room B"
|
|
222
|
+
m365 cal delete AAMkADA5...
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### OneDrive Commands
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# List files
|
|
229
|
+
m365 onedrive ls [path] [options]
|
|
230
|
+
m365 od ls [path] [options] # Alias
|
|
231
|
+
--top <n> # Maximum items (default: 100)
|
|
232
|
+
--json # Output as JSON
|
|
233
|
+
|
|
234
|
+
# Get file/folder metadata
|
|
235
|
+
m365 onedrive get <path> [options]
|
|
236
|
+
--json # Output as JSON
|
|
237
|
+
|
|
238
|
+
# Download file
|
|
239
|
+
m365 onedrive download <remote-path> [local-path] [options]
|
|
240
|
+
--json # Output as JSON
|
|
241
|
+
|
|
242
|
+
# Upload file
|
|
243
|
+
m365 onedrive upload <local-path> [remote-path] [options]
|
|
244
|
+
--json # Output as JSON
|
|
245
|
+
|
|
246
|
+
# Search files
|
|
247
|
+
m365 onedrive search <query> [options]
|
|
248
|
+
--top <n> # Maximum results (default: 50)
|
|
249
|
+
--json # Output as JSON
|
|
250
|
+
|
|
251
|
+
# Create sharing link
|
|
252
|
+
m365 onedrive share <path> [options]
|
|
253
|
+
--type <view|edit> # Link type (default: view)
|
|
254
|
+
--json # Output as JSON
|
|
255
|
+
|
|
256
|
+
# Create folder
|
|
257
|
+
m365 onedrive mkdir <path> [options]
|
|
258
|
+
--json # Output as JSON
|
|
259
|
+
|
|
260
|
+
# Delete file/folder
|
|
261
|
+
m365 onedrive rm <path> [options]
|
|
262
|
+
--force # Skip confirmation
|
|
263
|
+
--json # Output as JSON
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Examples:**
|
|
267
|
+
```bash
|
|
268
|
+
m365 od ls
|
|
269
|
+
m365 od ls Documents
|
|
270
|
+
m365 od get "Documents/report.pdf"
|
|
271
|
+
m365 od download "Documents/report.pdf" ~/Downloads/
|
|
272
|
+
m365 od upload ~/Desktop/photo.jpg "Photos/vacation.jpg"
|
|
273
|
+
m365 od search "budget" --top 20
|
|
274
|
+
m365 od share "Documents/report.pdf" --type edit
|
|
275
|
+
m365 od mkdir "Projects/New Project"
|
|
276
|
+
m365 od rm "old-file.txt" --force
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Features:**
|
|
280
|
+
- 🚀 Large file upload support (automatic chunking for files ≥4MB)
|
|
281
|
+
- 📊 Progress display for downloads and uploads
|
|
282
|
+
- 💾 Human-readable file sizes (B/KB/MB/GB/TB)
|
|
283
|
+
- ⚠️ Confirmation prompt before deletion (unless `--force`)
|
|
284
|
+
|
|
285
|
+
### SharePoint Commands
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# List sites
|
|
289
|
+
m365 sharepoint sites [options]
|
|
290
|
+
m365 sp sites [options] # Alias
|
|
291
|
+
--search <query> # Search for sites
|
|
292
|
+
--top <n> # Maximum sites (default: 50)
|
|
293
|
+
--json # Output as JSON
|
|
294
|
+
|
|
295
|
+
# List site lists
|
|
296
|
+
m365 sharepoint lists <site> [options]
|
|
297
|
+
--top <n> # Maximum lists (default: 100)
|
|
298
|
+
--json # Output as JSON
|
|
299
|
+
|
|
300
|
+
# List list items
|
|
301
|
+
m365 sharepoint items <site> <list> [options]
|
|
302
|
+
--top <n> # Maximum items (default: 100)
|
|
303
|
+
--json # Output as JSON
|
|
304
|
+
|
|
305
|
+
# List files in document library
|
|
306
|
+
m365 sharepoint files <site> [path] [options]
|
|
307
|
+
--top <n> # Maximum files (default: 100)
|
|
308
|
+
--json # Output as JSON
|
|
309
|
+
|
|
310
|
+
# Download file
|
|
311
|
+
m365 sharepoint download <site> <file-path> [local-path] [options]
|
|
312
|
+
--json # Output as JSON
|
|
313
|
+
|
|
314
|
+
# Upload file
|
|
315
|
+
m365 sharepoint upload <site> <local-path> [remote-path] [options]
|
|
316
|
+
--json # Output as JSON
|
|
317
|
+
|
|
318
|
+
# Search content
|
|
319
|
+
m365 sharepoint search <query> [options]
|
|
320
|
+
--top <n> # Maximum results (default: 50)
|
|
321
|
+
--json # Output as JSON
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Site identifier formats:**
|
|
325
|
+
|
|
326
|
+
SharePoint commands accept sites in multiple formats:
|
|
327
|
+
|
|
328
|
+
1. **Path format** (recommended):
|
|
329
|
+
```
|
|
330
|
+
hostname:/sites/sitename
|
|
331
|
+
# Example: contoso.sharepoint.com:/sites/team
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
2. **Site ID format** (from `m365 sp sites` output):
|
|
335
|
+
```
|
|
336
|
+
hostname,siteId,webId
|
|
337
|
+
# Example: contoso.sharepoint.com,8bfb5166-...,ea772c4f-...
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
3. **URL format** (for some commands):
|
|
341
|
+
```
|
|
342
|
+
https://hostname/sites/sitename
|
|
343
|
+
# Example: https://contoso.sharepoint.com/sites/team
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Tip:** Run `m365 sp sites --json` to get the exact site ID for any site.
|
|
347
|
+
|
|
348
|
+
**Examples:**
|
|
349
|
+
```bash
|
|
350
|
+
m365 sp sites
|
|
351
|
+
m365 sp sites --search "marketing"
|
|
352
|
+
|
|
353
|
+
# Using path format (recommended)
|
|
354
|
+
m365 sp lists "contoso.sharepoint.com:/sites/team"
|
|
355
|
+
|
|
356
|
+
# Using site ID from sites list output
|
|
357
|
+
m365 sp lists "contoso.sharepoint.com,8bfb5166-7dff-4f15-8d44-3417d68f519a,ea772c4f-..."
|
|
358
|
+
|
|
359
|
+
m365 sp files "contoso.sharepoint.com:/sites/team" "Documents"
|
|
360
|
+
m365 sp download "contoso.sharepoint.com:/sites/team" "Documents/file.pdf"
|
|
361
|
+
m365 sp upload "contoso.sharepoint.com:/sites/team" ~/report.pdf "Documents/report.pdf"
|
|
362
|
+
m365 sp search "quarterly report" --top 20
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**Note:** SharePoint commands require `Sites.ReadWrite.All` permission. If you encounter permission errors, run `m365 logout` then `m365 login` to re-authenticate with updated permissions.
|
|
366
|
+
|
|
367
|
+
## Configuration
|
|
368
|
+
|
|
369
|
+
### Credentials Location
|
|
370
|
+
|
|
371
|
+
Credentials are stored at: `~/.m365-cli/credentials.json`
|
|
372
|
+
|
|
373
|
+
**Security:** File permissions are set to `600` (owner read/write only). Do not share this file.
|
|
374
|
+
|
|
375
|
+
### Azure AD Application
|
|
376
|
+
|
|
377
|
+
#### Option 1: Use Existing Application (Quick Start)
|
|
378
|
+
|
|
379
|
+
This tool comes pre-configured with a shared Azure AD application:
|
|
380
|
+
- **Tenant ID**: `5b4c4b46-4279-4f19-9e5d-84ea285f9b9c`
|
|
381
|
+
- **Client ID**: `091b3d7b-e217-4410-868c-01c3ee6189b6`
|
|
382
|
+
|
|
383
|
+
No additional setup required — just run `m365 login` and you're ready to go.
|
|
384
|
+
|
|
385
|
+
#### Option 2: Create Your Own Azure AD Application
|
|
386
|
+
|
|
387
|
+
For production use or organizational requirements, you can register your own Azure AD application.
|
|
388
|
+
|
|
389
|
+
##### Prerequisites
|
|
390
|
+
|
|
391
|
+
- Access to **Azure Portal** or **Azure CLI**
|
|
392
|
+
- Azure AD / Microsoft Entra ID tenant
|
|
393
|
+
- **Permissions**: Global Administrator or Application Administrator role
|
|
394
|
+
|
|
395
|
+
##### Method 1: Azure Portal (Recommended for First-Time Setup)
|
|
396
|
+
|
|
397
|
+
**Step 1: Create the Application**
|
|
398
|
+
|
|
399
|
+
1. Sign in to [Azure Portal](https://portal.azure.com)
|
|
400
|
+
2. Navigate to: **Microsoft Entra ID** > **App registrations** > **New registration**
|
|
401
|
+
3. Configure the application:
|
|
402
|
+
- **Name**: `M365 CLI` (or your preferred name)
|
|
403
|
+
- **Supported account types**: Select **"Accounts in this organizational directory only (Single tenant)"**
|
|
404
|
+
- **Redirect URI**: Leave empty (not needed for Device Code Flow)
|
|
405
|
+
4. Click **Register**
|
|
406
|
+
|
|
407
|
+
**Step 2: Enable Public Client Flow**
|
|
408
|
+
|
|
409
|
+
1. In your app's page, go to **Authentication** (left sidebar)
|
|
410
|
+
2. Scroll down to **Advanced settings** > **Allow public client flows**
|
|
411
|
+
3. Set **"Enable the following mobile and desktop flows"** to **Yes**
|
|
412
|
+
4. Click **Save** at the top
|
|
413
|
+
|
|
414
|
+
> ⚠️ **Important**: This setting is required for Device Code Flow authentication.
|
|
415
|
+
|
|
416
|
+
**Step 3: Configure API Permissions**
|
|
417
|
+
|
|
418
|
+
1. Go to **API permissions** (left sidebar)
|
|
419
|
+
2. Click **Add a permission** > **Microsoft Graph** > **Delegated permissions**
|
|
420
|
+
3. Add the following permissions:
|
|
421
|
+
- `Mail.ReadWrite` - Read and write mail
|
|
422
|
+
- `Mail.Send` - Send mail as the user
|
|
423
|
+
- `Calendars.ReadWrite` - Read and write calendar events
|
|
424
|
+
- `Files.ReadWrite.All` - Read and write all files the user can access
|
|
425
|
+
- `Sites.ReadWrite.All` - Read and write SharePoint sites
|
|
426
|
+
- `User.Read` - Sign in and read user profile (added by default)
|
|
427
|
+
4. Click **Add permissions**
|
|
428
|
+
5. Click **Grant admin consent for [Your Organization]** (admin approval required)
|
|
429
|
+
6. Confirm by clicking **Yes**
|
|
430
|
+
|
|
431
|
+
> 💡 **Tip**: Admin consent allows all users in your organization to use the app without individual approval.
|
|
432
|
+
|
|
433
|
+
**Step 4: Get Configuration Values**
|
|
434
|
+
|
|
435
|
+
1. Go to **Overview** page
|
|
436
|
+
2. Copy the following values:
|
|
437
|
+
- **Application (client) ID** → This is your `CLIENT_ID`
|
|
438
|
+
- **Directory (tenant) ID** → This is your `TENANT_ID`
|
|
439
|
+
|
|
440
|
+
**Step 5: Configure the CLI**
|
|
441
|
+
|
|
442
|
+
Choose one of these methods:
|
|
443
|
+
|
|
444
|
+
**Option A: Environment Variables (Recommended)**
|
|
445
|
+
```bash
|
|
446
|
+
export M365_TENANT_ID="your-tenant-id"
|
|
447
|
+
export M365_CLIENT_ID="your-client-id"
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Add these to your `~/.bashrc` or `~/.zshrc` to make them permanent.
|
|
451
|
+
|
|
452
|
+
**Option B: Configuration File**
|
|
453
|
+
|
|
454
|
+
Edit `config/default.json`:
|
|
455
|
+
```json
|
|
456
|
+
{
|
|
457
|
+
"tenantId": "your-tenant-id",
|
|
458
|
+
"clientId": "your-client-id"
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
##### Method 2: Azure CLI (One-Command Setup)
|
|
463
|
+
|
|
464
|
+
If you have [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) installed:
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
# Login to Azure
|
|
468
|
+
az login
|
|
469
|
+
|
|
470
|
+
# Create the application
|
|
471
|
+
APP_ID=$(az ad app create \
|
|
472
|
+
--display-name "M365 CLI" \
|
|
473
|
+
--sign-in-audience AzureADMyOrg \
|
|
474
|
+
--enable-access-token-issuance true \
|
|
475
|
+
--query appId -o tsv)
|
|
476
|
+
|
|
477
|
+
echo "Created app with ID: $APP_ID"
|
|
478
|
+
|
|
479
|
+
# Enable public client flow
|
|
480
|
+
az ad app update --id $APP_ID --is-fallback-public-client true
|
|
481
|
+
|
|
482
|
+
# Add Microsoft Graph permissions
|
|
483
|
+
# Permission IDs for Microsoft Graph (00000003-0000-0000-c000-000000000000):
|
|
484
|
+
# User.Read: e1fe6dd8-ba31-4d61-89e7-88639da4683d
|
|
485
|
+
# Mail.ReadWrite: e2a3a72e-5f79-4c64-b1b1-878b674786c9
|
|
486
|
+
# Mail.Send: e383f46e-2787-4529-855e-0e479a3ffac0
|
|
487
|
+
# Calendars.ReadWrite: 1ec239c2-d7c9-4623-a91a-a9775856bb36
|
|
488
|
+
# Files.ReadWrite.All: 5c28f0bf-8a70-41f1-8ab2-9032436ddb65
|
|
489
|
+
# Sites.ReadWrite.All: 89fe6a52-be36-487e-b7d8-d061c450a026
|
|
490
|
+
|
|
491
|
+
az ad app permission add --id $APP_ID \
|
|
492
|
+
--api 00000003-0000-0000-c000-000000000000 \
|
|
493
|
+
--api-permissions \
|
|
494
|
+
e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope \
|
|
495
|
+
e2a3a72e-5f79-4c64-b1b1-878b674786c9=Scope \
|
|
496
|
+
e383f46e-2787-4529-855e-0e479a3ffac0=Scope \
|
|
497
|
+
1ec239c2-d7c9-4623-a91a-a9775856bb36=Scope \
|
|
498
|
+
5c28f0bf-8a70-41f1-8ab2-9032436ddb65=Scope \
|
|
499
|
+
89fe6a52-be36-487e-b7d8-d061c450a026=Scope
|
|
500
|
+
|
|
501
|
+
# Grant admin consent
|
|
502
|
+
az ad app permission admin-consent --id $APP_ID
|
|
503
|
+
|
|
504
|
+
# Get tenant ID
|
|
505
|
+
TENANT_ID=$(az account show --query tenantId -o tsv)
|
|
506
|
+
|
|
507
|
+
# Display configuration
|
|
508
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
509
|
+
echo "✅ Azure AD Application Created Successfully"
|
|
510
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
511
|
+
echo "Tenant ID: $TENANT_ID"
|
|
512
|
+
echo "Client ID: $APP_ID"
|
|
513
|
+
echo ""
|
|
514
|
+
echo "Configure the CLI with:"
|
|
515
|
+
echo "export M365_TENANT_ID=\"$TENANT_ID\""
|
|
516
|
+
echo "export M365_CLIENT_ID=\"$APP_ID\""
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Copy the output values and configure them as shown in Step 5 above.
|
|
520
|
+
|
|
521
|
+
##### Verification
|
|
522
|
+
|
|
523
|
+
After configuration, test the setup:
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
# Login with your custom app
|
|
527
|
+
m365 login
|
|
528
|
+
|
|
529
|
+
# Test basic functionality
|
|
530
|
+
m365 mail list --top 3
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
You should see the Device Code Flow prompt. Follow the authentication steps in your browser.
|
|
534
|
+
|
|
535
|
+
### Permissions
|
|
536
|
+
|
|
537
|
+
The application requests the following Microsoft Graph permissions:
|
|
538
|
+
- `Mail.ReadWrite` - Read and write mail
|
|
539
|
+
- `Mail.Send` - Send mail
|
|
540
|
+
- `Calendars.ReadWrite` - Read and write calendar events
|
|
541
|
+
- `Files.ReadWrite.All` - Read and write files in OneDrive
|
|
542
|
+
- `Sites.ReadWrite.All` - Read and write SharePoint sites
|
|
543
|
+
|
|
544
|
+
## Output Formats
|
|
545
|
+
|
|
546
|
+
### Default (Text)
|
|
547
|
+
|
|
548
|
+
Clean, human-readable output with emoji icons:
|
|
549
|
+
|
|
550
|
+
```
|
|
551
|
+
📧 Mail List (top 3)
|
|
552
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
553
|
+
[1] 📩 Meeting Reminder
|
|
554
|
+
From: alice@example.com
|
|
555
|
+
Date: 2026-02-16 09:30
|
|
556
|
+
ID: AAMkAG...
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### JSON (--json)
|
|
560
|
+
|
|
561
|
+
Structured output for scripting and AI consumption:
|
|
562
|
+
|
|
563
|
+
```json
|
|
564
|
+
[
|
|
565
|
+
{
|
|
566
|
+
"id": "AAMkAG...",
|
|
567
|
+
"subject": "Meeting Reminder",
|
|
568
|
+
"from": {
|
|
569
|
+
"emailAddress": {
|
|
570
|
+
"name": "Alice",
|
|
571
|
+
"address": "alice@example.com"
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
"receivedDateTime": "2026-02-16T09:30:00Z",
|
|
575
|
+
"isRead": false
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
## Project Structure
|
|
581
|
+
|
|
582
|
+
```
|
|
583
|
+
m365-cli/
|
|
584
|
+
├── bin/
|
|
585
|
+
│ └── m365.js # CLI entry point
|
|
586
|
+
├── src/
|
|
587
|
+
│ ├── auth/ # Authentication
|
|
588
|
+
│ │ ├── token-manager.js # Token storage & refresh
|
|
589
|
+
│ │ └── device-flow.js # Device Code Flow
|
|
590
|
+
│ ├── graph/ # Graph API client
|
|
591
|
+
│ │ └── client.js # HTTP client with auto-refresh
|
|
592
|
+
│ ├── commands/ # Command implementations
|
|
593
|
+
│ │ ├── mail.js # Mail commands
|
|
594
|
+
│ │ ├── calendar.js # Calendar commands
|
|
595
|
+
│ │ ├── onedrive.js # OneDrive commands
|
|
596
|
+
│ │ └── sharepoint.js # SharePoint commands
|
|
597
|
+
│ └── utils/ # Utilities
|
|
598
|
+
│ ├── config.js # Config management
|
|
599
|
+
│ ├── output.js # Output formatting
|
|
600
|
+
│ └── error.js # Error handling
|
|
601
|
+
├── config/
|
|
602
|
+
│ └── default.json # Default configuration
|
|
603
|
+
├── package.json # Project metadata
|
|
604
|
+
├── README.md # This file
|
|
605
|
+
└── PLAN.md # Development roadmap
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
## Development
|
|
609
|
+
|
|
610
|
+
### Tech Stack
|
|
611
|
+
|
|
612
|
+
- **Node.js 18+** - ESM modules, native fetch API
|
|
613
|
+
- **commander.js** - CLI framework
|
|
614
|
+
- **Microsoft Graph API** - M365 services
|
|
615
|
+
|
|
616
|
+
### Local Testing
|
|
617
|
+
|
|
618
|
+
```bash
|
|
619
|
+
# Link for local development
|
|
620
|
+
npm link
|
|
621
|
+
|
|
622
|
+
# Test commands
|
|
623
|
+
m365 --help
|
|
624
|
+
m365 mail --help
|
|
625
|
+
m365 mail list --top 3
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
## Troubleshooting
|
|
629
|
+
|
|
630
|
+
### "Not authenticated" error
|
|
631
|
+
|
|
632
|
+
Run `m365 login` to authenticate.
|
|
633
|
+
|
|
634
|
+
### Token expired
|
|
635
|
+
|
|
636
|
+
Tokens refresh automatically. If refresh fails, run `m365 login` again.
|
|
637
|
+
|
|
638
|
+
### Permission denied (SharePoint)
|
|
639
|
+
|
|
640
|
+
SharePoint requires additional permissions. Run:
|
|
641
|
+
```bash
|
|
642
|
+
m365 logout
|
|
643
|
+
m365 login
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Network errors
|
|
647
|
+
|
|
648
|
+
- Check internet connection
|
|
649
|
+
- Verify firewall settings
|
|
650
|
+
- Ensure Microsoft Graph API is accessible
|
|
651
|
+
|
|
652
|
+
## Roadmap
|
|
653
|
+
|
|
654
|
+
- [x] **Phase 1**: Framework + Mail ✅
|
|
655
|
+
- [x] **Phase 2**: Calendar ✅
|
|
656
|
+
- [x] **Phase 3**: OneDrive ✅
|
|
657
|
+
- [x] **Phase 3.5**: SharePoint ✅
|
|
658
|
+
- [ ] **Phase 4**: Contacts & Advanced Features
|
|
659
|
+
- [ ] **Phase 5**: Optimization & Release
|
|
660
|
+
|
|
661
|
+
See [PLAN.md](./PLAN.md) for detailed roadmap and implementation notes.
|
|
662
|
+
|
|
663
|
+
## Security
|
|
664
|
+
|
|
665
|
+
- ✅ Credentials stored with `600` permissions
|
|
666
|
+
- ✅ OAuth 2.0 Device Code Flow
|
|
667
|
+
- ✅ Automatic token refresh
|
|
668
|
+
- ✅ No sensitive data in logs
|
|
669
|
+
- ✅ HTTPS-only communication
|
|
670
|
+
|
|
671
|
+
## License
|
|
672
|
+
|
|
673
|
+
MIT License - see LICENSE file for details.
|
|
674
|
+
|
|
675
|
+
## Contributing
|
|
676
|
+
|
|
677
|
+
Contributions welcome! Please open an issue or PR.
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
**Current Version**: 0.1.0
|
|
682
|
+
**Status**: Phases 1-3 Complete ✅
|
|
683
|
+
**Updated**: 2026-02-16
|