diff --git a/.gitignore b/.gitignore index 0a46c85688..6b1048d24e 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,14 @@ output/ renders/ !packages/producer/tests/*/output/ !packages/producer/tests/distributed/*/output/ +# Learn companion-video projects live under learn/output// and MUST be +# tracked (script, scenes, assembled index). The blanket output/ rule above +# would otherwise hide every new body scene from git. +!learn/output/ +!learn/output/** +# Never commit licensed Segoe WOFF2 stand-ins dropped into a project fonts/. +learn/output/**/fonts/*.woff2 +learn/output/**/fonts/fonts.css # Source dir that the renders/ output rule accidentally shadows (its files are # tracked; without this, pre-commit's format re-stage fails on them). !packages/studio/src/components/renders/ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/BRIEF.md b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/BRIEF.md new file mode 100644 index 0000000000..ea24d8971f --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/BRIEF.md @@ -0,0 +1,24 @@ +# Bulk Identity Management with Graph PowerShell + +- **Profile:** `unit-video` — Unit video (~4 min) +- **Target:** ~240s content (180–300s), word budget 435–726 (target 580) @ 2.42 w/s +- **Scenes:** aim ~10 (chrome 5 stamped + ~5-16 body) +- **Max static hold:** 5.0s · **Voice:** en-US-Ava:DragonHDLatestNeural +- **Source:** C:\learn-pr\learn-m365-pr\learn-m365-pr\wwl\provision-govern-identities-entra\includes\3-bulk-identity-management-graph.md + +## Fill the placeholders + +Every `__FILL__` below must be replaced before render (guarded by `tools/check_placeholders.py`). + +- `opening.bumper` → [scenes/01-bumper.html](scenes/01-bumper.html) +- `opening.title` → [scenes/02-title.html](scenes/02-title.html) +- `opening.objectives` → [scenes/03-objectives.html](scenes/03-objectives.html) +- `closing.recap` → [scenes/90-recap.html](scenes/90-recap.html) +- `closing.cta` → [scenes/91-cta.html](scenes/91-cta.html) + +## Next steps + +1. Write the script + beat plan (script-writer) and fill the chrome placeholders above. +2. Author the teaching-body scenes into `scenes/` and insert them into `scenes.json` between the opening and closing chrome (see `scenes.json` → `body_slot`). +3. Run the gated pipeline (voice → fact-check QA → build → snapshot QA → render). +4. Guard: `py tools/check_placeholders.py --project .` must be clean before render. diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.js b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.js new file mode 100644 index 0000000000..d057c93c7c --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.js @@ -0,0 +1,53 @@ +// GENERATED by tools/word_anchors.py - do not hand-edit. +// Every value is a REAL spoken-word time from transcript.json, +// with a 3.0s lead-in applied. Regenerate after any re-record. +window.__anchors = { + "connect_cmd": 57.32, + "connect_cmdEnd": 58.97, + "connect_scope": 68.08, + "connect_scopeEnd": 71.31, + "contacts_trap": 218.54, + "contacts_trapEnd": 220.43, + "create_newmguser": 109.12, + "create_newmguserEnd": 110.25, + "csv_columns": 92.67, + "csv_columnsEnd": 96.44, + "cta_exercise": 258.23, + "cta_exerciseEnd": 260.18, + "hook_question": 17.67, + "hook_questionEnd": 20.35, + "import_csv": 80.12, + "import_csvEnd": 82.81, + "least_privilege": 156.94, + "least_privilegeEnd": 158.61, + "loop_count30": 121.21, + "loop_count30End": 122.31, + "loop_creates": 113.37, + "loop_createsEnd": 116.76, + "loop_enabled": 116.79, + "loop_enabledEnd": 117.75, + "loop_forcepw": 117.75, + "loop_forcepwEnd": 119.65, + "loop_foreach": 104.39, + "loop_foreachEnd": 106.72, + "match_scope_question": 143.74, + "match_scope_questionEnd": 145.28, + "newmailcontact": 228.37, + "newmailcontactEnd": 229.64, + "objectives_scope": 31.86, + "objectives_scopeEnd": 33.68, + "overview_steps": 53.38, + "overview_stepsEnd": 55.33, + "pattern_scales": 162.94, + "pattern_scalesEnd": 165.38, + "read_scope": 165.38, + "read_scopeEnd": 167.25, + "recap_one_pass": 242.52, + "recap_one_passEnd": 244.73, + "remove_cmd": 205.97, + "remove_cmdEnd": 207.63, + "repeatable": 127.28, + "repeatableEnd": 129.19, + "update_cmd": 198.74, + "update_cmdEnd": 200.2 +}; diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.json new file mode 100644 index 0000000000..d2976555f1 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/anchors.json @@ -0,0 +1,41 @@ +{ + "_schema": "cue id -> exact spoken phrase (contiguous, case/punctuation-insensitive substring of narration.txt). Builder resolves to real times: py tools/word_anchors.py transcript.json --spec anchors.json -o anchors.js --lead-in ", + "_builder_note": "overview_steps was respoken/transcribed as \"Connect, loop\" (the TTS elided \"import\"); the phrase is bound to what the WAV actually says so the lock-up lands on the real word. loop_* cues added by the builder for the custom 07-loop console.", + "_note": "Phrases intentionally land on ORDINARY words next to each cmdlet/scope token, never the token itself — how 'New-MgUser' / 'User.ReadWrite.All' tokenize in the transcript is unpredictable, so anchoring on plain words is robust. Each phrase is unique; if the TTS re-run makes one ambiguous, append '#2' to pick an occurrence.", + "_run_id": "bulk-identity-management-graph-202608071310", + + "hook_question": "how do you create every one of those accounts", + "objectives_scope": "the right permission scope", + + "overview_steps": "Connect, loop", + + "connect_cmd": "session starts with", + "connect_scope": "you ask for exactly one scope", + + "import_csv": "reads your spreadsheet into a collection", + "csv_columns": "a display name, a user principal name", + + "loop_foreach": "Now the loop does the work", + "create_newmguser": "hands each row to", + "loop_creates": "creates the account", + "loop_enabled": "switches it on", + "loop_forcepw": "and forces a password reset", + "loop_count30": "30 rows in", + + "repeatable": "A script is repeatable", + + "match_scope_question": "and not the broader", + "least_privilege": "match the scope to the task", + + "pattern_scales": "scales to every bulk job", + "read_scope": "Reading users for an audit", + + "update_cmd": "runs the very same", + "remove_cmd": "when an account has to go", + + "contacts_trap": "doesn't manage mail contacts", + "newmailcontact": "That job belongs to", + + "recap_one_pass": "the whole roster in one pass", + "cta_exercise": "The next exercise takes you" +} diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/AI_End_Card.mp4 b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/AI_End_Card.mp4 new file mode 100644 index 0000000000..58e482f319 Binary files /dev/null and b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/AI_End_Card.mp4 differ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-content-wash.png b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-content-wash.png new file mode 100644 index 0000000000..96c264bc16 Binary files /dev/null and b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-content-wash.png differ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-hero-swoosh.png b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-hero-swoosh.png new file mode 100644 index 0000000000..53e48f3d4a Binary files /dev/null and b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-hero-swoosh.png differ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-section-field.png b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-section-field.png new file mode 100644 index 0000000000..dc94c26720 Binary files /dev/null and b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/grounds/ground-section-field.png differ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/vendor/gsap.min.js b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/vendor/gsap.min.js new file mode 100644 index 0000000000..72c17a8309 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/assets/vendor/gsap.min.js @@ -0,0 +1,10 @@ +/*! + * GSAP 3.15.0 + * https://gsap.com + * + * @license Copyright 2026, GreenSock. All rights reserved. + * Subject to the terms at https://gsap.com/standard-license. + * @author: Jack Doyle, jack@greensock.com + */ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).window=t.window||{})}(this,function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function r(t){return"string"==typeof t}function s(t){return"function"==typeof t}function t(t){return"number"==typeof t}function u(t){return void 0===t}function v(t){return"object"==typeof t}function w(t){return!1!==t}function x(){return"undefined"!=typeof window}function y(t){return s(t)||r(t)}function R(t){return(i=bt(t,ht))&&Fe}function S(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function T(t,e){return!e&&console.warn(t)}function U(t,e){return t&&(ht[t]=e)&&i&&(i[t]=e)||ht}function V(){return 0}function ga(t){var e,r,i=t[0];if(v(i)||s(i)||(t=[t]),!(e=(i._gsap||{}).harness)){for(r=yt.length;r--&&!yt[r].targetTest(i););e=yt[r]}for(r=t.length;r--;)t[r]&&(t[r]._gsap||(t[r]._gsap=new Xt(t[r],e)))||t.splice(r,1);return t}function ha(t){return t._gsap||ga(Pt(t))[0]._gsap}function ia(t,e,r){return(r=t[e])&&s(r)?t[e]():u(r)&&t.getAttribute&&t.getAttribute(e)||r}function ja(t,e){return(t=t.split(",")).forEach(e)||t}function ka(t){return Math.round(1e5*t)/1e5||0}function la(t){return Math.round(1e7*t)/1e7||0}function ma(t,e){var r=e.charAt(0),i=parseFloat(e.substr(2));return t=parseFloat(t),"+"===r?t+i:"-"===r?t-i:"*"===r?t*i:t/i}function na(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++ia;)s=s._prev;return s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t,e}function Ba(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function Ca(t,e){t.parent&&(!e||t.parent.autoRemoveChildren)&&t.parent.remove&&t.parent.remove(t),t._act=0}function Da(t,e){if(t&&(!e||e._end>t._dur||e._start<0))for(var r=t;r;)r._dirty=1,r=r.parent;return t}function Fa(t,e,r,i){return t._startAt&&(I?t._startAt.revert(ft):t.vars.immediateRender&&!t.vars.autoRevert||t._startAt.render(e,!0,i))}function Ha(t){return t._repeat?wt(t._tTime,t=t.duration()+t._rDelay)*t:0}function Ja(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function Ka(t){return t._end=la(t._start+(t._tDur/Math.abs(t._ts||t._rts||q)||0))}function La(t,e){var r=t._dp;return r&&r.smoothChildTiming&&t._ts&&(t._start=la(r._time-(0q)&&e.render(r,!0)),Da(t,e)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur(n=Math.abs(n))&&(a=i,o=n);return a}function wb(t){return Ca(t),t.scrollTrigger&&t.scrollTrigger.kill(!!I),t.progress()<1&&At(t,"onInterrupt"),t}function zb(t){if(t)if(t=!t.name&&t.default||t,x()||t.headless){var e=t.name,r=s(t),i=e&&!r&&t.init?function(){this._props=[]}:t,n={init:V,render:_e,add:$t,kill:Te,modifier:ve,rawVars:0},a={targetTest:0,get:0,getSetter:ue,aliases:{},register:0};if(Lt(),t!==i){if(mt[e])return;ta(i,ta(xa(t,n),a)),bt(i.prototype,bt(n,xa(t,a))),mt[i.prop=e]=i,t.targetTest&&(yt.push(i),dt[e]=1),e=("css"===e?"CSS":e.charAt(0).toUpperCase()+e.substr(1))+"Plugin"}U(e,i),t.register&&t.register(Fe,i,we)}else Dt.push(t)}function Cb(t,e,r){return(6*(t+=t<0?1:1>16,e>>8&zt,e&zt]:0:Rt.black;if(!p){if(","===e.substr(-1)&&(e=e.substr(0,e.length-1)),Rt[e])p=Rt[e];else if("#"===e.charAt(0)){if(e.length<6&&(e="#"+(n=e.charAt(1))+n+(a=e.charAt(2))+a+(s=e.charAt(3))+s+(5===e.length?e.charAt(4)+e.charAt(4):"")),9===e.length)return[(p=parseInt(e.substr(1,6),16))>>16,p>>8&zt,p&zt,parseInt(e.substr(7),16)/255];p=[(e=parseInt(e.substr(1),16))>>16,e>>8&zt,e&zt]}else if("hsl"===e.substr(0,3))if(p=d=e.match(rt),r){if(~e.indexOf("="))return p=e.match(it),i&&p.length<4&&(p[3]=1),p}else o=+p[0]%360/360,u=p[1]/100,n=2*(h=p[2]/100)-(a=h<=.5?h*(u+1):h+u-h*u),3=X?u.endTime(!1):t._dur;return r(e)&&(isNaN(e)||e in o)?(a=e.charAt(0),s="%"===e.substr(-1),n=e.indexOf("="),"<"===a||">"===a?(0<=n&&(e=e.replace(/=/,"")),("<"===a?u._start:u.endTime(0<=u._repeat))+(parseFloat(e.substr(1))||0)*(s?(n<0?u:i).totalDuration()/100:1)):n<0?(e in o||(o[e]=h),o[e]):(a=parseFloat(e.charAt(n-1)+e.substr(n+1)),s&&i&&(a=a/100*(K(i)?i[0]:i).totalDuration()),1=r&&te)return i;i=i._next}else for(i=t._last;i&&i._start>=r;){if("isPause"===i.data&&i._start=n._start)&&n._ts&&h!==n){if(n.parent!==this)return this.render(t,e,r);if(n.render(0=this.totalDuration()||!v&&_)&&(f!==this._start&&Math.abs(l)===Math.abs(this._ts)||this._lock||(!t&&g||!(v===m&&0=i&&(a instanceof te?e&&n.push(a):(r&&n.push(a),t&&n.push.apply(n,a.getChildren(!0,e,r)))),a=a._next;return n},e.getById=function getById(t){for(var e=this.getChildren(1,1,1),r=e.length;r--;)if(e[r].vars.id===t)return e[r]},e.remove=function remove(t){return r(t)?this.removeLabel(t):s(t)?this.killTweensOf(t):(t.parent===this&&Ba(this,t),t===this._recent&&(this._recent=this._last),Da(this))},e.totalTime=function totalTime(t,e){return arguments.length?(this._forcing=1,!this._dp&&this._ts&&(this._start=la(It.time-(0r:!r||s.isActive())&&n.push(s):(i=s.getTweensOf(a,r)).length&&n.push.apply(n,i),s=s._next;return n},e.tweenTo=function tweenTo(t,e){e=e||{};var r,i=this,n=Ot(i,t),a=e.startAt,s=e.onStart,o=e.onStartParams,u=e.immediateRender,h=te.to(i,ta({ease:e.ease||"none",lazy:!1,immediateRender:!1,time:n,overwrite:"auto",duration:e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale())||q,onStart:function onStart(){if(i.pause(),!r){var t=e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale());h._dur!==t&&Ua(h,t,0,1).render(h._time,!0,!0),r=1}s&&s.apply(h,o||[])}},e));return u?h.render(0):h},e.tweenFromTo=function tweenFromTo(t,e,r){return this.tweenTo(e,ta({startAt:{time:Ot(this,t)}},r))},e.recent=function recent(){return this._recent},e.nextLabel=function nextLabel(t){return void 0===t&&(t=this._time),ub(this,Ot(this,t))},e.previousLabel=function previousLabel(t){return void 0===t&&(t=this._time),ub(this,Ot(this,t),1)},e.currentLabel=function currentLabel(t){return arguments.length?this.seek(t,!0):this.previousLabel(this._time+q)},e.shiftChildren=function shiftChildren(t,e,r){void 0===r&&(r=0);var i,n=this._first,a=this.labels;for(t=la(t);n;)n._start>=r&&(n._start+=t,n._end+=t),n=n._next;if(e)for(i in a)a[i]>=r&&(a[i]+=t);return Da(this)},e.invalidate=function invalidate(t){var e=this._first;for(this._lock=0;e;)e.invalidate(t),e=e._next;return i.prototype.invalidate.call(this,t)},e.clear=function clear(t){void 0===t&&(t=!0);for(var e,r=this._first;r;)e=r._next,this.remove(r),r=e;return this._dp&&(this._time=this._tTime=this._pTime=0),t&&(this.labels={}),Da(this)},e.totalDuration=function totalDuration(t){var e,r,i,n=0,a=this,s=a._last,o=X;if(arguments.length)return a.timeScale((a._repeat<0?a.duration():a.totalDuration())/(a.reversed()?-t:t));if(a._dirty){for(i=a.parent;s;)e=s._prev,s._dirty&&s.totalDuration(),o<(r=s._start)&&a._sort&&s._ts&&!a._lock?(a._lock=1,Na(a,s,r-s._delay,1)._lock=0):o=r,r<0&&s._ts&&(n-=r,(!i&&!a._dp||i&&i.smoothChildTiming)&&(a._start+=la(r/a._ts),a._time-=r,a._tTime-=r),a.shiftChildren(-r,!1,-Infinity),o=0),s._end>n&&s._ts&&(n=s._end),s=e;Ua(a,a===L&&a._time>n?a._time:n,1,1),a._dirty=0}return a._tDur},Timeline.updateRoot=function updateRoot(t){if(L._ts&&(qa(L,Ja(t,L)),f=It.frame),It.frame>=vt){vt+=Y.autoSleep||120;var e=L._first;if((!e||!e._ts)&&Y.autoSleep&&It._listeners.length<2){for(;e&&!e._ts;)e=e._next;e||It.sleep()}}},Timeline}(qt);ta(Gt.prototype,{_lock:0,_hasPause:0,_forcing:0});function cc(t,e,i,n,a,o){var u,h,l,f;if(mt[t]&&!1!==(u=new mt[t]).init(a,u.rawVars?e[t]:function _processVars(t,e,i,n,a){if(s(t)&&(t=Qt(t,a,e,i,n)),!v(t)||t.style&&t.nodeType||K(t)||J(t))return r(t)?Qt(t,a,e,i,n):t;var o,u={};for(o in t)u[o]=Qt(t[o],a,e,i,n);return u}(e[t],n,a,o,i),i,n,o)&&(i._pt=h=new we(i._pt,a,t,0,1,u.render,u,0,u.priority),i!==c))for(l=i._ptLookup[i._targets.indexOf(a)],f=u._props.length;f--;)l[u._props[f]]=h;return u}function ic(t,r,e,i){var n,a,s=r.ease||i||"power1.inOut";if(K(r))a=e[t]||(e[t]=[]),r.forEach(function(t,e){return a.push({t:e/(r.length-1)*100,v:t,e:s})});else for(n in r)a=e[n]||(e[n]=[]),"ease"===n||a.push({t:parseFloat(t),v:r[n],e:s})}var Zt,Wt,$t=function _addPropTween(t,e,i,n,a,o,u,h,l,f){s(n)&&(n=n(a||0,t,o));var c,d=t[e],p="get"!==i?i:s(d)?l?t[e.indexOf("set")||!s(t["get"+e.substr(3)])?e:"get"+e.substr(3)](l):t[e]():d,_=s(d)?l?se:ae:ie;if(r(n)&&(~n.indexOf("random(")&&(n=rb(n)),"="===n.charAt(1)&&(!(c=ma(p,n)+(_a(p)||0))&&0!==c||(n=c))),!f||p!==n||Wt)return isNaN(p*n)||""===n?(d||e in t||S(e,n),function _addComplexStringPropTween(t,e,r,i,n,a,s){var o,u,h,l,f,c,d,p,_=new we(this._pt,t,e,0,1,pe,null,n),m=0,g=0;for(_.b=r,_.e=i,r+="",(d=~(i+="").indexOf("random("))&&(i=rb(i)),a&&(a(p=[r,i],t,e),r=p[0],i=p[1]),u=r.match(at)||[];o=at.exec(i);)l=o[0],f=i.substring(m,o.index),h?h=(h+1)%5:"rgba("===f.substr(-5)&&(h=1),l!==u[g++]&&(c=parseFloat(u[g-1])||0,_._pt={_next:_._pt,p:f||1===g?f:",",s:c,c:"="===l.charAt(1)?ma(c,l)-c:parseFloat(l)-c,m:h&&h<4?Math.round:0},m=at.lastIndex);return _.c=m")}),s.duration();else{for(l in u={},k)"ease"===l||"easeEach"===l||ic(l,k[l],u,k.easeEach);for(l in u)for(A=u[l].sort(function(t,e){return t.t-e.t}),o=R=0;o=t._tDur||e<0)&&t.ratio===u&&(u&&Ca(t,1),r||I||(At(t,u?"onComplete":"onReverseComplete",!0),t._prom&&t._prom()))}else t._zTime||(t._zTime=e)}(this,t,e,r);return this},e.targets=function targets(){return this._targets},e.invalidate=function invalidate(t){return t&&this.vars.runBackwards||(this._startAt=0),this._pt=this._op=this._onUpdate=this._lazy=this.ratio=0,this._ptLookup=[],this.timeline&&this.timeline.invalidate(t),E.prototype.invalidate.call(this,t)},e.resetTo=function resetTo(t,e,r,i,n){d||It.wake(),this._ts||this.play();var a,s=Math.min(this._dur,(this._dp._time-this._start)*this._ts);return this._initted||Ht(this,s),a=this._ease(s/this._dur),function _updatePropTweens(t,e,r,i,n,a,s,o){var u,h,l,f,c=(t._pt&&t._ptCache||(t._ptCache={}))[e];if(!c)for(c=t._ptCache[e]=[],l=t._ptLookup,f=t._targets.length;f--;){if((u=l[f][e])&&u.d&&u.d._pt)for(u=u.d._pt;u&&u.p!==e&&u.fp!==e;)u=u._next;if(!u)return Wt=1,t.vars[e]="+=0",Ht(t,s),Wt=0,o?T(e+" not eligible for reset. Try splitting into individual properties"):1;c.push(u)}for(f=c.length;f--;)(u=(h=c[f])._pt||h).s=!i&&0!==i||n?u.s+(i||0)+a*u.c:i,u.c=r-u.s,h.e&&(h.e=ka(r)+_a(h.e)),h.b&&(h.b=u.s+_a(h.b))}(this,t,e,r,i,a,s,n)?this.resetTo(t,e,r,i,1):(La(this,0),this.parent||Aa(this._dp,this,"_first","_last",this._dp._sort?"_start":0),this.render(0))},e.kill=function kill(t,e){if(void 0===e&&(e="all"),!(t||e&&"all"!==e))return this._lazy=this._pt=0,this.parent?wb(this):this.scrollTrigger&&this.scrollTrigger.kill(!!I),this;if(this.timeline){var i=this.timeline.totalDuration();return this.timeline.killTweensOf(t,e,Zt&&!0!==Zt.vars.overwrite)._first||wb(this),this.parent&&i!==this.timeline.totalDuration()&&Ua(this,this._dur*this.timeline._tDur/i,0,1),this}var n,a,s,o,u,h,l,f=this._targets,c=t?Pt(t):f,d=this._ptLookup,p=this._pt;if((!e||"all"===e)&&function _arraysMatch(t,e){for(var r=t.length,i=r===e.length;i&&r--&&t[r]===e[r];);return r<0}(f,c))return"all"===e&&(this._pt=0),wb(this);for(n=this._op=this._op||[],"all"!==e&&(r(e)&&(u={},ja(e,function(t){return u[t]=1}),e=u),e=function _addAliasesToVars(t,e){var r,i,n,a,s=t[0]?ha(t[0]).harness:0,o=s&&s.aliases;if(!o)return e;for(i in r=bt({},e),o)if(i in r)for(n=(a=o[i].split(",")).length;n--;)r[a[n]]=r[i];return r}(f,e)),l=f.length;l--;)if(~c.indexOf(f[l]))for(u in a=d[l],"all"===e?(n[l]=e,o=a,s={}):(s=n[l]=n[l]||{},o=e),o)(h=a&&a[u])&&("kill"in h.d&&!0!==h.d.kill(u)||Ba(this,h,"_pt"),delete a[u]),"all"!==s&&(s[u]=1);return this._initted&&!this._pt&&p&&wb(this),this},Tween.to=function to(t,e,r){return new Tween(t,e,r)},Tween.from=function from(t,e){return Ya(1,arguments)},Tween.delayedCall=function delayedCall(t,e,r,i){return new Tween(e,0,{immediateRender:!1,lazy:!1,overwrite:!1,delay:t,onComplete:e,onReverseComplete:e,onCompleteParams:r,onReverseCompleteParams:r,callbackScope:i})},Tween.fromTo=function fromTo(t,e,r){return Ya(2,arguments)},Tween.set=function set(t,e){return e.duration=0,e.repeatDelay||(e.repeat=0),new Tween(t,e)},Tween.killTweensOf=function killTweensOf(t,e,r){return L.killTweensOf(t,e,r)},Tween}(qt);ta(te.prototype,{_targets:[],_lazy:0,_startAt:0,_op:0,_onInit:0}),ja("staggerTo,staggerFrom,staggerFromTo",function(r){te[r]=function(){var t=new Gt,e=Ct.call(arguments,0);return e.splice("staggerFromTo"===r?5:4,0,0),t[r].apply(t,e)}});function qc(t,e,r){return t.setAttribute(e,r)}function yc(t,e,r,i){i.mSet(t,e,i.m.call(i.tween,r,i.mt),i)}var ie=function _setterPlain(t,e,r){return t[e]=r},ae=function _setterFunc(t,e,r){return t[e](r)},se=function _setterFuncWithParam(t,e,r,i){return t[e](i.fp,r)},ue=function _getSetter(t,e){return s(t[e])?ae:u(t[e])&&t.setAttribute?qc:ie},fe=function _renderPlain(t,e){return e.set(e.t,e.p,Math.round(1e6*(e.s+e.c*t))/1e6,e)},de=function _renderBoolean(t,e){return e.set(e.t,e.p,!!(e.s+e.c*t),e)},pe=function _renderComplexString(t,e){var r=e._pt,i="";if(!t&&e.b)i=e.b;else if(1===t&&e.e)i=e.e;else{for(;r;)i=r.p+(r.m?r.m(r.s+r.c*t):Math.round(1e4*(r.s+r.c*t))/1e4)+i,r=r._next;i+=e.c}e.set(e.t,e.p,i,e)},_e=function _renderPropTweens(t,e){for(var r=e._pt;r;)r.r(t,r.d),r=r._next},ve=function _addPluginModifier(t,e,r,i){for(var n,a=this._pt;a;)n=a._next,a.p===i&&a.modifier(t,e,r),a=n},Te=function _killPropTweensOf(t){for(var e,r,i=this._pt;i;)r=i._next,i.p===t&&!i.op||i.op===t?Ba(this,i,"_pt"):i.dep||(e=1),i=r;return!e},be=function _sortPropTweensByPriority(t){for(var e,r,i,n,a=t._pt;a;){for(e=a._next,r=i;r&&r.pr>a.pr;)r=r._next;(a._prev=r?r._prev:n)?a._prev._next=a:i=a,(a._next=r)?r._prev=a:n=a,a=e}t._pt=i},we=(PropTween.prototype.modifier=function modifier(t,e,r){this.mSet=this.mSet||this.set,this.set=yc,this.m=t,this.mt=r,this.tween=e},PropTween);function PropTween(t,e,r,i,n,a,s,o,u){this.t=e,this.s=i,this.c=n,this.p=r,this.r=a||fe,this.d=s||this,this.set=o||ie,this.pr=u||0,(this._next=t)&&(t._prev=this)}ja(Tt+"parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger,easeReverse",function(t){return dt[t]=1}),ht.TweenMax=ht.TweenLite=te,ht.TimelineLite=ht.TimelineMax=Gt,L=new Gt({sortChildren:!1,defaults:j,autoRemoveChildren:!0,id:"root",smoothChildTiming:!0}),Y.stringFilter=Ib;function Gc(t){return(Oe[t]||Me).map(function(t){return t()})}function Hc(){var t=Date.now(),o=[];2`), prefer SVG: + +| Beat | Icon | Library path | +|---|---|---| +| 03 · B1 · B2 · B4 · B8 | **PowerShell** (Graph PowerShell tool mark) | `Azure/general/10825-icon-service-Powershell.svg` | +| B7 | **Users** (read row) | `Azure/identity/10230-icon-service-Users.svg` | +| B7 | **Groups** (group-member row) | `Azure/identity/10223-icon-service-Groups.svg` | +| B7 | **Entra** (recipient — "tells Entra ID what your script may touch") | `Microsoft-Security-product-icons-kit/Entra/SVG/Entra.svg` | +| B9 | **Exchange** (the boundary — Graph ✕ Exchange Online) | `Azure/intune/10339-icon-service-Exchange-Access.svg` | + +No dedicated "Microsoft Graph" icon exists in the library — represent Graph PowerShell with the +**PowerShell** mark throughout. One clear icon per concept; icons label meaning, they are not +decoration. + +## Signaling — cues tied to spoken words + +Each beat has one focal element and reacts *on the word* (the builder anchors these to +`transcript.json` via `word_anchors.py`, never to a guessed offset): + +| # | Focal object | Cue → spoken phrase | Reaction | +|---|---|---|---| +| B1 | the 3-move lock-up | `overview_steps` → "Connect, import, loop" | all three stages light simultaneously | +| B2 | the `-Scopes` value | `connect_cmd` → "starts with Connect-MgGraph"; `connect_scope` → "exactly one scope" | line reveal, then highlight **lifts to** `"User.ReadWrite.All"` | +| B3 | the four column rows | `import_csv` → "Import-Csv reads your spreadsheet"; `csv_columns` → "a display name, a user principal name" | rows stagger in as each field is named | +| B4 | the streaming output → **30** | `loop_foreach` → "A foreach walks that list"; `create_newmguser` → "hands each row to New-MgUser" | loop body reveals; each `New-MgUser` line **pulses** as accounts stream; counter punches to 30 | +| B5 | the term **Repeatable** | `repeatable` → "A script is repeatable" | card scale-in with accent-tab wipe | +| B6 | the lifted scope row | `match_scope_question` → "the broader Directory.ReadWrite.All"; `least_privilege` → "match the scope to the task" | `User.ReadWrite.All` **lifts** exactly on `least_privilege`; the broad scope recedes | +| B7 | each task→scope row | `pattern_scales` → "scales to every bulk job"; `read_scope` → "User.Read.All, read-only" | rows populate as each task is named (brisk, 3 rows) | +| B8 | the swapped cmdlet | `update_cmd` → "Update-MgUser runs the very same"; `remove_cmd` → "Remove-MgUser follows the identical shape" | cmdlet name swaps **in place** to read as "same shape" | +| B9 | the boundary | `contacts_trap` → "doesn't manage mail contacts"; `newmailcontact` → "belongs to New-MailContact" | Graph side dims / strikes, Exchange side lights on `newmailcontact` | + +## Motion budget + +`unit-video` → `max_static_stretch_seconds` **5.0s**. No beat may sit still longer than that. Every +body beat carries a word-anchored carrier motion (reveal, lift, pulse, swap) above, so none idles. +B4's streaming console and the count-to-30 keep the payoff continuously alive — it is the densest +beat by design. `data-reveal-after` pins B4's `New-MgUser` result lines behind the loop start, and +the lifted row in B6 behind its peers, so nothing resolves early. + +## Hero-swoosh budget + +Spent on beats: **01-bumper, 02-title, 91-cta** (three total; `01-bumper` is the mandatory brand +sting). Each is a brand/title/closing frame — never a content frame: +- **01-bumper** — mandatory opening sting. +- **02-title** — the title card; hero is its home ground. +- **91-cta** — the closing send-off; brand doctrine lists "closing" as a sanctioned hero use, and + it brackets the open. `90-recap` is intentionally **not** hero (kept on wash) so the CTA stays the + single scarce close and the gradient does not become wallpaper. + +Bottom-right-third rule honoured on both hero beats: display type stays left-anchored. + +## Dark-field budget + +Spent on **one** beat: **B4 `07-loop`** — the loop-runs console. It is the narration's peak +("thirty rows in, thirty accounts out"), the payoff of the whole spine, and a terminal is dark by +nature, so the ground is motivated rather than decorative. No other beat uses dark-field. + +## Contrast declarations + +WCAG 2.1, measured against the FRAME tokens. Every readable pixel is ink (or white on dark); no +brand accent carries normal-size text anywhere. + +| Text / ground pair | Ratio | Verdict | +|---|---|---| +| ink `#091F2E` on content-wash (all body beats) | **16.02** | AAA — any size | +| ink display on hero-swoosh (01, 02, 91) — left column | 15.6 | AAA (left) | +| ink display on hero-swoosh — worst zone | 5.95 | AA-large ✓ (keep display out of bottom-right third) | +| white ink on dark-field console (B4) | ~17 | AAA | +| success/output line teal-light `#49C5B1` on dark-field (B4) | 7.94 | AAA | +| code body ink on the code-window's **pure #FFFFFF** panel (B2, B8) | ~18 | AAA | +| blue syntax keyword `#0078D4` on pure #FFFFFF (B2, B8) | **4.53** | AA ✓ — **worst readable ratio** | +| text-muted `#33414D` captions on wash (sparingly) | ~9 | AA | + +**Worst readable ratio in the plan: 4.53** (blue syntax keyword on pure white). All readable text +clears AA; all body / label / caption text clears AAA at 16.02. + +### Contrast risk — the one thing to watch + +Coloured PowerShell syntax in the light code-window (B2, B8) clears 4.5 **only on a pure `#FFFFFF` +panel** — on the warm wash, blue drops to **4.31 and fails**. So the builder must keep the +code-window's inner surface pure white (the light-IDE block already does) and never let a coloured +token sit on the wash. Zero-risk fallback: render code as **ink `#091F2E` with weight-only +emphasis** (16.02) and reserve colour for the active-line tint band, which is a non-text mark. + +Semantic-accent note for B7: `AdministrativeUnit.ReadWrite.All` is reproduced from the source unit's +scope table (the standalone Docs permissions page wasn't fetched this pass). It is a focal row — +spot-check it against current admin-unit cmdlet docs before render (per the script's open questions). + +Re-run after any palette edit: +``` +py tools/contrast_gate.py brand/_extract/palette.json --min 3.0 +``` + +## Fonts + +Segoe UI / Segoe UI Semibold, embedded from `fonts/`. Monospace code/console: the code-window's +own monospace face on its pure-white panel; the B4 console renders monospace white on dark. +No Space Grotesk / JetBrains Mono / Fraunces — not brand fonts. diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/fonts/STANDIN.md b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/fonts/STANDIN.md new file mode 100644 index 0000000000..3264a1ff96 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/fonts/STANDIN.md @@ -0,0 +1,15 @@ +# LOCAL GATE STAND-IN — NOT SEGOE UI. DO NOT RENDER WITH THESE. + +`segoeui-regular.woff2` / `segoeui-semibold.woff2` in this folder are **Noto Sans**, built +locally so `npx hyperframes check` could evaluate real text metrics, layout, and WCAG contrast +in a Linux container that has no Segoe UI and no network access to Selawik. + +Noto Sans is *wider* than Segoe UI, so a layout that clears the gate here also clears it with +the real face — the check is conservative, not optimistic. + +Both files are gitignored (`learn/.gitignore` -> `fonts/*.woff2`) and are never committed. + +**Before rendering, regenerate the real faces on the render host:** + + py tools/sync_fonts.py --css # Windows: converts the licensed system Segoe UI + # non-Windows: install Selawik (SIL OFL, metric-compatible) per the learn-ilt preset diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.html new file mode 100644 index 0000000000..c6e3a9cf5a --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.html @@ -0,0 +1,226 @@ + + + + + + Bulk Identity Management with Graph PowerShell + + + + + +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ +
+
+ + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.motion.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.motion.json new file mode 100644 index 0000000000..9715770606 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/index.motion.json @@ -0,0 +1,15 @@ +{ + "version": 1, + "duration": 271.8, + "assertions": [ + { + "kind": "keepsMoving", + "maxStaticSec": 5.0 + }, + { + "kind": "before", + "a": "#lp-cmd-1", + "b": "#lp-out-0" + } + ] +} diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/manifest.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/manifest.json new file mode 100644 index 0000000000..09d974f9ff --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/manifest.json @@ -0,0 +1,13 @@ +{ + "title": "Bulk Identity Management with Graph PowerShell", + "type": "unit-video", + "profile": "unit-video", + "status": "scaffolded", + "voice": "en-US-Ava:DragonHDLatestNeural", + "source": "C:\\learn-pr\\learn-m365-pr\\learn-m365-pr\\wwl\\provision-govern-identities-entra\\includes\\3-bulk-identity-management-graph.md", + "deliverables": { + "mp4": "Bulk-Identity-Management-With-Graph-PowerShell.mp4", + "captions_vtt": "Bulk-Identity-Management-With-Graph-PowerShell.vtt", + "thumbnail": "Bulk-Identity-Management-With-Graph-PowerShell_thumbnail.png" + } +} diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.ssml b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.ssml new file mode 100644 index 0000000000..ff49c459ca --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.ssml @@ -0,0 +1,31 @@ + + + +

Relecloud's overseas office opens Monday, and the stack of new-hire names on your desk keeps growing. Thirty accounts, clicked in one at a time in the portal, won't be ready before the doors open. So here's the question this unit answers: how do you create every one of those accounts in a single pass, and run it again the next time a batch of hires lands?

+ +

Microsoft Graph PowerShell is the way, and by the end you'll be able to do three things with it. Connect with the right permission scope. Pull your new hires from a spreadsheet. And let one command create the whole list.

+ +

The whole thing is really just three moves, and they never change. First, you connect and request a scope. Next, you import a CSV of your users. Then you loop over that list and create each account. Connect, import, loop.

+ +

Every Graph PowerShell session starts with Connect-MgGraph, and the scope you request right there decides what the rest of the script is allowed to do. To create accounts, you ask for exactly one scope: User.ReadWrite.All. Ask for less, and the create step simply fails.

+ +

Then Import-Csv reads your spreadsheet into a collection of objects, one for every new hire. Each row carries the same fields you'd type into the portal's bulk-create sheet: a display name, a user principal name, a mail nickname, and a temporary password. Same columns, just driven from a file.

+ +

Now the loop does the work. A foreach walks that list and hands each row to New-MgUser, one at a time. That single cmdlet creates the account, switches it on, and forces a password reset at first sign-in. Thirty rows in, thirty accounts out.

+ +

Here's why that beats clicking through a browser. A script is repeatable. Run it again next quarter, when the next wave of hires arrives, and you don't reopen a single blade. You point it at a new file and go.

+ +

Now, one small detail is doing more than it looks. Why User.ReadWrite.All, and not the broader Directory.ReadWrite.All? Both of them would work. But the broad one grants far more than user management alone, and that's the decision actually being tested. You match the scope to the task, not to whatever also happens to work.

+ +

And that same rule scales to every bulk job. Reading users for an audit? That's User.Read.All, read-only, no changes. Adding people to a group? GroupMember.ReadWrite.All. Building an administrative unit? AdministrativeUnit.ReadWrite.All. None of them stand in for each other. Each scope tells Entra ID exactly what your script may touch.

+ +

Creating accounts isn't the only bulk task, either. A department change, a manager swap: Update-MgUser runs the very same CSV-and-loop pattern, under that same User.ReadWrite.All scope. And when an account has to go, Remove-MgUser follows the identical shape. Learn the pattern once, reuse it everywhere.

+ +

One trap, though, before you reach for this out of habit. Microsoft Graph doesn't manage mail contacts at all. Scripting a vendor contact with New-MgUser just won't work, because that contact was never a user object. That job belongs to New-MailContact, over in Exchange Online PowerShell, not Graph.

+ +

So the overseas office is covered. You connected with a scope, imported a CSV, and let New-MgUser build the whole roster in one pass. Then you reused that same loop to update and to delete, matching every scope to its task along the way. One pattern for the entire directory.

+ +

Ready to run it yourself? The next exercise takes you through bulk-provisioning with Graph PowerShell, hands-on. For the parameters, open the New-MgUser reference on Microsoft Learn.

+
+
+
diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.txt b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.txt new file mode 100644 index 0000000000..a8042ee63c --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.txt @@ -0,0 +1,25 @@ +Relecloud's overseas office opens Monday, and the stack of new-hire names on your desk keeps growing. Thirty accounts, clicked in one at a time in the portal, won't be ready before the doors open. So here's the question this unit answers: how do you create every one of those accounts in a single pass, and run it again the next time a batch of hires lands? + +Microsoft Graph PowerShell is the way, and by the end you'll be able to do three things with it. Connect with the right permission scope. Pull your new hires from a spreadsheet. And let one command create the whole list. + +The whole thing is really just three moves, and they never change. First, you connect and request a scope. Next, you import a CSV of your users. Then you loop over that list and create each account. Connect, import, loop. + +Every Graph PowerShell session starts with Connect-MgGraph, and the scope you request right there decides what the rest of the script is allowed to do. To create accounts, you ask for exactly one scope: *User.ReadWrite.All*. Ask for less, and the create step simply fails. + +Then Import-Csv reads your spreadsheet into a collection of objects, one for every new hire. Each row carries the same fields you'd type into the portal's bulk-create sheet: a display name, a user principal name, a mail nickname, and a temporary password. Same columns, just driven from a file. + +Now the loop does the work. A foreach walks that list and hands each row to New-MgUser, one at a time. That single cmdlet creates the account, switches it on, and forces a password reset at first sign-in. Thirty rows in, thirty accounts out. + +Here's why that beats clicking through a browser. A script is *repeatable*. Run it again next quarter, when the next wave of hires arrives, and you don't reopen a single blade. You point it at a new file and go. + +Now, one small detail is doing more than it looks. Why *User.ReadWrite.All*, and not the broader Directory.ReadWrite.All? Both of them would work. But the broad one grants far more than user management alone, and that's the decision actually being tested. You match the scope to the task, not to whatever also happens to work. + +And that same rule scales to every bulk job. Reading users for an audit? That's User.Read.All, read-only, no changes. Adding people to a group? GroupMember.ReadWrite.All. Building an administrative unit? AdministrativeUnit.ReadWrite.All. None of them stand in for each other. Each scope tells Entra ID exactly what your script may touch. + +Creating accounts isn't the only bulk task, either. A department change, a manager swap: Update-MgUser runs the very same CSV-and-loop pattern, under that same *User.ReadWrite.All* scope. And when an account has to go, Remove-MgUser follows the identical shape. Learn the pattern once, reuse it everywhere. + +One trap, though, before you reach for this out of habit. Microsoft Graph doesn't manage mail contacts at all. Scripting a vendor contact with New-MgUser just won't work, because that contact was never a user object. That job belongs to New-MailContact, over in Exchange Online PowerShell, not Graph. + +So the overseas office is covered. You connected with a scope, imported a CSV, and let New-MgUser build the whole roster in one pass. Then you reused that same loop to update and to delete, matching every scope to its task along the way. One pattern for the entire directory. + +Ready to run it yourself? The next exercise takes you through bulk-provisioning with Graph PowerShell, hands-on. For the parameters, open the New-MgUser reference on Microsoft Learn. diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.wav b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.wav new file mode 100644 index 0000000000..25bb9f2db4 Binary files /dev/null and b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/narration.wav differ diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/gates.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/gates.json new file mode 100644 index 0000000000..8b6700ea7e --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/gates.json @@ -0,0 +1,26 @@ +[ + { + "gate": 1, + "name": "Concept and source", + "status": "passed", + "artifact": null, + "note": "Source: C:\\learn-pr\\learn-m365-pr\\learn-m365-pr\\wwl\\provision-govern-identities-entra\\includes\\3-bulk-identity-management-graph.md", + "at": "2026-08-07T18:02:18" + }, + { + "gate": 2, + "name": "Video type and profile", + "status": "passed", + "artifact": null, + "note": "Profile LOCKED: unit-video (~240s, 580 words, ~10 scenes, 5.0s static). Scaffolded by new_project.py.", + "at": "2026-08-07T18:02:19" + }, + { + "gate": 6, + "name": "Fact-check QA", + "status": "passed", + "artifact": null, + "note": "SHIP 20/20; all cmdlets/scopes verified; keep code panel pure-white", + "at": "2026-08-07T19:00:28" + } +] \ No newline at end of file diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/index.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/index.html new file mode 100644 index 0000000000..de01b3db88 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/index.html @@ -0,0 +1,101 @@ + + +Review — Bulk-Identity-Management-With-Graph-PowerShell + +

Bulk-Identity-Management-With-Graph-PowerShell

+

3 of 9 gates passed · newest attempt shown, full history in +review/gates.json · stage timing summary missing

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#GateStatusArtifactNoteWhen
1Concept and sourcepassedSource: C:\learn-pr\learn-m365-pr\learn-m365-pr\wwl\provision-govern-identities-entra\includes\3-bulk-identity-management-graph.md2026-08-07 18:02:18
2Video type and profilepassedProfile LOCKED: unit-video (~240s, 580 words, ~10 scenes, 5.0s static). Scaffolded by new_project.py.2026-08-07 18:02:19
3Lookpending
4Voicepending
5Scriptpending
6Fact-check QApassedSHIP 20/20; all cmdlets/scopes verified; keep code panel pure-white2026-08-07 19:00:28
7Snapshot QApending
8Renderpending
9Deliverypending
diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/stage-timing-events.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/stage-timing-events.json new file mode 100644 index 0000000000..d805675e1b --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/review/stage-timing-events.json @@ -0,0 +1,47 @@ +[ + { + "kind": "start", + "stage": "designer", + "run_id": "bulk-identity-management-graph-202608071310", + "at": "2026-08-08T01:47:00+00:00", + "status": null, + "note": null, + "meta": {} + }, + { + "kind": "end", + "stage": "designer", + "run_id": "bulk-identity-management-graph-202608071310", + "at": "2026-08-08T01:47:00+00:00", + "status": "passed", + "note": null, + "meta": {} + }, + { + "kind": "start", + "stage": "builder", + "run_id": "bulk-identity-management-graph-202608071310", + "at": "2026-08-08T03:09:42+00:00", + "status": null, + "note": null, + "meta": {} + }, + { + "kind": "end", + "stage": "builder", + "run_id": "bulk-identity-management-graph-202608071310", + "at": "2026-08-08T03:39:52+00:00", + "status": "passed", + "note": null, + "meta": {} + }, + { + "kind": "end", + "stage": "builder", + "run_id": "bulk-identity-management-graph-202608071310", + "at": "2026-08-08T03:40:13+00:00", + "status": "passed", + "note": null, + "meta": {} + } +] \ No newline at end of file diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes.json new file mode 100644 index 0000000000..7ed78dfa4b --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes.json @@ -0,0 +1,126 @@ +{ + "title": "Bulk Identity Management with Graph PowerShell", + "composition_id": "root", + "width": 1920, + "height": 1080, + "root_background": "#fff8f3", + "gsap": "assets/vendor/gsap.min.js", + "anchors": "anchors.js", + "fonts": [ + { + "family": "Segoe UI", + "weight": 400, + "style": "normal", + "src": "fonts/segoeui-regular.woff2" + }, + { + "family": "Segoe UI Semibold", + "weight": 600, + "style": "normal", + "src": "fonts/segoeui-semibold.woff2" + } + ], + "narration": { + "src": "narration.wav", + "start": 3.0, + "duration": 267.27, + "track": 10 + }, + "endcard": { + "src": "assets/AI_End_Card.mp4", + "duration": 10.667, + "track": 11 + }, + "bookend": { + "intro": 0.5, + "outro": 0.7, + "color": "#000" + }, + "_timing": "Every boundary below is a REAL transcript word time (transcript.json) plus a 3.0s silent bumper lead-in, cut ~0.10s ahead of the first spoken word of the incoming beat. Re-derive if the VO is re-recorded.", + "scenes": [ + { + "id": "01-bumper", + "src": "scenes/01-bumper.html", + "duration": 3.0, + "seam": "hard" + }, + { + "id": "02-title", + "src": "scenes/02-title.html", + "duration": 22.15, + "seam": "hard" + }, + { + "id": "03-objectives", + "src": "scenes/03-objectives.html", + "duration": 14.03, + "seam": "cut-left" + }, + { + "id": "04-spine", + "src": "scenes/04-spine.html", + "duration": 16.05, + "seam": "cut-left" + }, + { + "id": "05-connect", + "src": "scenes/05-connect.html", + "duration": 23.82, + "seam": "cut-left" + }, + { + "id": "06-csv", + "src": "scenes/06-csv.html", + "duration": 25.24, + "seam": "cut-left" + }, + { + "id": "07-loop", + "src": "scenes/07-loop.html", + "duration": 20.13, + "seam": "cut-up" + }, + { + "id": "08-repeatable", + "src": "scenes/08-repeatable.html", + "duration": 16.78, + "seam": "cut-down" + }, + { + "id": "09-scope-match", + "src": "scenes/09-scope-match.html", + "duration": 20.0, + "seam": "cut-left" + }, + { + "id": "10-scope-pattern", + "src": "scenes/10-scope-pattern.html", + "duration": 30.84, + "seam": "cut-left" + }, + { + "id": "11-update-delete", + "src": "scenes/11-update-delete.html", + "duration": 22.38, + "seam": "cut-left" + }, + { + "id": "12-contacts", + "src": "scenes/12-contacts.html", + "duration": 20.59, + "seam": "cut-left" + }, + { + "id": "90-recap", + "src": "scenes/90-recap.html", + "duration": 20.71, + "seam": "cut-up" + }, + { + "id": "91-cta", + "src": "scenes/91-cta.html", + "duration": 16.08, + "seam": "cut-left" + } + ] +} diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/01-bumper.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/01-bumper.html new file mode 100644 index 0000000000..17fdc78a0d --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/01-bumper.html @@ -0,0 +1,125 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/02-title.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/02-title.html new file mode 100644 index 0000000000..de0d3ca8ed --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/02-title.html @@ -0,0 +1,238 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/03-objectives.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/03-objectives.html new file mode 100644 index 0000000000..1f74357b0a --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/03-objectives.html @@ -0,0 +1,282 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/04-spine.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/04-spine.html new file mode 100644 index 0000000000..27c449334d --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/04-spine.html @@ -0,0 +1,273 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/05-connect.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/05-connect.html new file mode 100644 index 0000000000..bb8883939f --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/05-connect.html @@ -0,0 +1,285 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/06-csv.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/06-csv.html new file mode 100644 index 0000000000..f4fede118f --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/06-csv.html @@ -0,0 +1,244 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/07-loop.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/07-loop.html new file mode 100644 index 0000000000..f4f0499a09 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/07-loop.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/08-repeatable.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/08-repeatable.html new file mode 100644 index 0000000000..4f6d8d9d0c --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/08-repeatable.html @@ -0,0 +1,246 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/09-scope-match.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/09-scope-match.html new file mode 100644 index 0000000000..ae1ac634a0 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/09-scope-match.html @@ -0,0 +1,324 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/10-scope-pattern.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/10-scope-pattern.html new file mode 100644 index 0000000000..2af50f20ca --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/10-scope-pattern.html @@ -0,0 +1,243 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/11-update-delete.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/11-update-delete.html new file mode 100644 index 0000000000..39b2130274 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/11-update-delete.html @@ -0,0 +1,287 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/12-contacts.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/12-contacts.html new file mode 100644 index 0000000000..4b8e26e405 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/12-contacts.html @@ -0,0 +1,246 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/90-recap.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/90-recap.html new file mode 100644 index 0000000000..1eec909163 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/90-recap.html @@ -0,0 +1,237 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/91-cta.html b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/91-cta.html new file mode 100644 index 0000000000..42bdbabf1a --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/scenes/91-cta.html @@ -0,0 +1,238 @@ + + + + + + + + + + + diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/script.md b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/script.md new file mode 100644 index 0000000000..1dfa15e93f --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/script.md @@ -0,0 +1,133 @@ +# Bulk Identity Management with Graph PowerShell + + + +| | | +|---|---| +| Source | `wwl/provision-govern-identities-entra/includes/3-bulk-identity-management-graph.md` (Unit 3) | +| Module | Provision and govern identities in Microsoft Entra (`learn.wwl.provision-govern-identities-entra`) | +| Profile | `unit-video` | +| Voice | `en-US-Vance:DragonHDLatestNeural` | +| Word budget | 435–726 (target 580) | +| Actual words | 595 | +| Est. runtime | 4:06 content (595 ÷ 2.42 w/s ≈ 246s) + 0:11 AI end card | + +## Narration + +Relecloud's overseas office opens Monday, and the stack of new-hire names on your desk keeps growing. Thirty accounts, clicked in one at a time in the portal, won't be ready before the doors open. So here's the question this unit answers: how do you create every one of those accounts in a single pass, and run it again the next time a batch of hires lands? + +Microsoft Graph PowerShell is the way, and by the end you'll be able to do three things with it. Connect with the right permission scope. Pull your new hires from a spreadsheet. And let one command create the whole list. + +The whole thing is really just three moves, and they never change. First, you connect and request a scope. Next, you import a CSV of your users. Then you loop over that list and create each account. Connect, import, loop. + +Every Graph PowerShell session starts with Connect-MgGraph, and the scope you request right there decides what the rest of the script is allowed to do. To create accounts, you ask for exactly one scope: *User.ReadWrite.All*. Ask for less, and the create step simply fails. + +Then Import-Csv reads your spreadsheet into a collection of objects, one for every new hire. Each row carries the same fields you'd type into the portal's bulk-create sheet: a display name, a user principal name, a mail nickname, and a temporary password. Same columns, just driven from a file. + +Now the loop does the work. A foreach walks that list and hands each row to New-MgUser, one at a time. That single cmdlet creates the account, switches it on, and forces a password reset at first sign-in. Thirty rows in, thirty accounts out. + +Here's why that beats clicking through a browser. A script is *repeatable*. Run it again next quarter, when the next wave of hires arrives, and you don't reopen a single blade. You point it at a new file and go. + +Now, one small detail is doing more than it looks. Why *User.ReadWrite.All*, and not the broader Directory.ReadWrite.All? Both of them would work. But the broad one grants far more than user management alone, and that's the decision actually being tested. You match the scope to the task, not to whatever also happens to work. + +And that same rule scales to every bulk job. Reading users for an audit? That's User.Read.All, read-only, no changes. Adding people to a group? GroupMember.ReadWrite.All. Building an administrative unit? AdministrativeUnit.ReadWrite.All. None of them stand in for each other. Each scope tells Entra ID exactly what your script may touch. + +Creating accounts isn't the only bulk task, either. A department change, a manager swap: Update-MgUser runs the very same CSV-and-loop pattern, under that same *User.ReadWrite.All* scope. And when an account has to go, Remove-MgUser follows the identical shape. Learn the pattern once, reuse it everywhere. + +One trap, though, before you reach for this out of habit. Microsoft Graph doesn't manage mail contacts at all. Scripting a vendor contact with New-MgUser just won't work, because that contact was never a user object. That job belongs to New-MailContact, over in Exchange Online PowerShell, not Graph. + +So the overseas office is covered. You connected with a scope, imported a CSV, and let New-MgUser build the whole roster in one pass. Then you reused that same loop to update and to delete, matching every scope to its task along the way. One pattern for the entire directory. + +Ready to run it yourself? The next exercise takes you through bulk-provisioning with Graph PowerShell, hands-on. For the parameters, open the New-MgUser reference on Microsoft Learn. + +## Chrome copy (fill the scaffolded scenes) + +**`opening.bumper`** — kicker sub-line: `Provision and govern identities in Microsoft Entra` + +**`opening.title`** — title (2 lines) + subtitle: +- Title: `Bulk Identity Management` / `with Graph PowerShell` +- Subtitle: `Provision hundreds of accounts in a single pass` + +**`opening.objectives`** — three one-line chips (labels, not the spoken sentences): +1. `Connect with the least-privileged scope` +2. `Import your users from a CSV` +3. `Create every account with one cmdlet` + +**`closing.recap`** — three recap chips (answers the opening hook): +1. `Connect · Import · Loop — one repeatable pattern` +2. `Match the scope to the task, not the broadest` +3. `Create, update, delete — same CSV-and-loop shape` + +**`closing.cta`** — call to action: +- Primary: `Try it: Exercise — Bulk provision with Graph PowerShell` +- Learn more: `New-MgUser reference · learn.microsoft.com` + +## Beat plan + +Chrome scenes `01-bumper`, `02-title`, `03-objectives`, `90-recap`, `91-cta` are scaffolded; body +scenes below are authored into the `body_slot`. Kit blocks are candidates — the designer owns final +selection. `Cue → phrase` names match `anchors.json`; the builder resolves them to real word times. + +| # | Scene id | Narration slice | On screen (focal object) | Kit block · ground | Cue → spoken phrase | Motion note | +|---|---|---|---|---|---|---| +| — | `01-bumper` | *(silent)* | Microsoft Learn mark + kicker | `bumper` · hero-swoosh | — | Scaffolded open, no VO. | +| — | `02-title` | "…how do you create every one of those accounts in a single pass…" | Title lines + subtitle; the **hook question** is the beat | `title-hero` · hero-swoosh | `hook_question` → "how do you create every one of those accounts" | Waterfall title; hold on the question, don't answer it yet. | +| — | `03-objectives` | "Connect with the right permission scope. Pull your new hires… let one command create the whole list." | 3 objective chips (short labels) | `objectives` (scaffolded) · content-wash | `objectives_scope` → "the right permission scope" | Chips stagger in as each is named (temporal contiguity). | +| B1 | `04-spine` | "…just three moves… First, you connect… Next, you import a CSV… Then you loop… Connect, import, loop." | 3 numbered steps: **Connect → Import → Loop** | `list-steps` · content-wash | `overview_steps` → "Connect, import, loop" | Steps reveal top-to-bottom as each is spoken; final "Connect, import, loop" lands all three lit. | +| B2 | `05-connect` | "Every Graph PowerShell session starts with **Connect-MgGraph**… you ask for exactly one scope: **User.ReadWrite.All**." | Code: `Connect-MgGraph -Scopes "User.ReadWrite.All"` — active line = the Connect line; **`-Scopes` value** is the focus | `code-window` · content-wash | `connect_cmd` → "starts with Connect-MgGraph"; `connect_scope` → "exactly one scope" | Line reveal; highlight lifts to the scope string on `connect_scope`. | +| B3 | `06-csv` | "**Import-Csv** reads your spreadsheet… a display name, a user principal name, a mail nickname, and a temporary password. Same columns…" | Spec rows = CSV columns: `DisplayName`, `UserPrincipalName`, `MailNickname`, `TempPassword` | `list-specs` · content-wash | `import_csv` → "Import-Csv reads your spreadsheet"; `csv_columns` → "a display name, a user principal name" | Rows stagger as the four fields are named; label ≠ spoken sentence. | +| B4 | `07-loop` | "A **foreach** walks that list and hands each row to **New-MgUser**… creates the account, switches it on, and forces a password reset… Thirty rows in, thirty accounts out." | Code: the `foreach { New-MgUser … -AccountEnabled -PasswordProfile … }` loop — active line = `New-MgUser` | `code-window` · content-wash | `loop_foreach` → "A foreach walks that list"; `create_newmguser` → "hands each row to New-MgUser" | Reveal loop body; pulse the `New-MgUser` line on `create_newmguser` (this is the payoff of the spine). | +| B5 | `08-repeatable` | "A script is *repeatable*. Run it again next quarter… you don't reopen a single blade." | KEY POINT card — term **Repeatable**, body: rerun on next batch, no portal blades | `callout-note` · content-wash | `repeatable` → "A script is repeatable" | Panel scale-in with accent-tab wipe; single emphasized takeaway. | +| B6 | `09-scope-match` | "Why *User.ReadWrite.All*, and not the broader **Directory.ReadWrite.All**?… match the scope to the task, not to whatever also happens to work." | Two peer scope rows; **`User.ReadWrite.All` lifts** with accent tab, `Directory.ReadWrite.All` recedes (too broad) | `list-select` (selectedIndex = the matched scope) · content-wash | `match_scope_question` → "the broader Directory.ReadWrite.All"; `least_privilege` → "match the scope to the task" | The chosen row lifts exactly on `least_privilege`; this is the decision being tested. | +| B7 | `10-scope-pattern` | "Reading users… User.Read.All… Adding people to a group? GroupMember.ReadWrite.All. Building an administrative unit? AdministrativeUnit.ReadWrite.All… what your script may touch." | Task → scope spec rows: read → `User.Read.All`; group members → `GroupMember.ReadWrite.All`; admin unit → `AdministrativeUnit.ReadWrite.All` | `list-specs` · content-wash | `pattern_scales` → "scales to every bulk job"; `read_scope` → "User.Read.All, read-only" | Rows populate as each task is named; the rule generalizes — keep the reveal brisk (3 rows). | +| B8 | `11-update-delete` | "**Update-MgUser** runs the very same CSV-and-loop pattern, under that same *User.ReadWrite.All* scope… **Remove-MgUser** follows the identical shape." | Code: the `foreach { Update-MgUser … }` loop; caption notes `Remove-MgUser` = same shape | `code-window` · content-wash | `update_cmd` → "Update-MgUser runs the very same"; `remove_cmd` → "Remove-MgUser follows the identical shape" | Echo B4's layout so the "same shape" reads visually; swap the cmdlet name in place. | +| B9 | `12-contacts` | "Microsoft Graph doesn't manage mail contacts… **New-MgUser** just won't work… That job belongs to **New-MailContact**… Exchange Online PowerShell, not Graph." | TRAP card — term **New-MailContact**, body: Exchange Online PowerShell, not Microsoft Graph | `callout-note` · content-wash | `contacts_trap` → "doesn't manage mail contacts"; `newmailcontact` → "belongs to New-MailContact" | Single warning beat; the boundary (Graph vs Exchange Online) is the point. | +| — | `90-recap` | "You connected with a scope, imported a CSV, and let **New-MgUser** build the whole roster in one pass… matching every scope to its task… One pattern for the entire directory." | Recap chips (answers the opening hook) | `90-recap` (scaffolded) · hero-swoosh | `recap_one_pass` → "the whole roster in one pass" | Chips resolve the three objectives; pays off the Monday-deadline hook. | +| — | `91-cta` | "The next exercise takes you through bulk-provisioning with Graph PowerShell… open the New-MgUser reference on Microsoft Learn." | CTA: next exercise + Learn more link | `91-cta` (scaffolded) · hero-swoosh | `cta_exercise` → "The next exercise takes you" | Hand off to Unit 4 exercise. | + +## Source-fidelity ledger + +Every claim → source line and/or Docs URL. Referent / quantifier / modality checked against the +source before ✅. + +| Claim in narration | Where it comes from | Verified | +|---|---|---| +| Overseas office opens Monday; ~thirty new hires; one-at-a-time in the portal won't be ready in time | Source ¶1: "Relecloud's overseas office opens Monday… Creating each account one at a time in the portal doesn't get thirty people set up before the doors open" | ✅ verbatim scenario; quantifier "thirty" preserved | +| Graph PowerShell path = connect with a scope → loop over a CSV → one cmdlet creates every account | Source ¶1: "connect with the right scope, loop over a spreadsheet of names, and let a single cmdlet create every account in the list" | ✅ | +| Every session starts with `Connect-MgGraph`; the requested scope decides what the script may do | Source §"Connect with a scope": "Every Graph PowerShell session starts with `Connect-MgGraph`, and the scope you request there determines what the rest of the script is allowed to do" · Docs: create-user-accounts-with-microsoft-365-powershell (`Connect-MgGraph -Scopes "User.ReadWrite.All"`) | ✅ | +| To create accounts the scope is `User.ReadWrite.All`; a narrower scope doesn't cover creation ("ask for less, and the create step fails") | Source: "For creating accounts, that scope is `User.ReadWrite.All`" + "the least-privileged delegated scope documented for creating and updating users… no narrower built-in scope covers user creation" · Docs: New-MgUser permissions list least-privileged = User.ReadWrite.All | ✅ modality checked — "no narrower scope covers creation" → a lesser scope won't authorize the create | +| `Import-Csv` reads the spreadsheet into a collection of objects | Source §"Connect with a scope": "`Import-Csv` reads the spreadsheet into a collection of objects" | ✅ | +| CSV columns = display name, user principal name, mail nickname, temporary password; same fields as the portal Bulk create sheet | Source code block (`-DisplayName $hire.DisplayName -UserPrincipalName … -MailNickname … PasswordProfile @{ Password = $hire.TempPassword …}`) + "the same display name, user principal name, and initial password columns you'd upload through the portal's **Bulk create** feature" | ✅ referent = portal Bulk create | +| `foreach` hands each row to `New-MgUser` one at a time; it enables the account and forces a password change at first sign-in | Source: "the `foreach` loop hands each row to `New-MgUser` one at a time" + code `-AccountEnabled` and `ForceChangePasswordNextSignIn = $true` | ✅ "switches it on" = `-AccountEnabled`; "password reset at first sign-in" = `ForceChangePasswordNextSignIn` | +| A script is repeatable; rerun next quarter for the next batch without reopening a blade | Source: "a script is repeatable. Run it again next quarter when the next batch of hires arrives, and you don't reopen a single blade" | ✅ near-verbatim | +| `Directory.ReadWrite.All` also works but grants far more; match the scope to the task, not the one that also happens to work | Source §"Match the scope…": "easy to reach for `Directory.ReadWrite.All`… since it also works, but it grants far more than user management alone… picking the one that matches the operation—not the one that happens to also work" | ✅ modality "would work" = source "also works" | +| The rule scales: read/export → `User.Read.All`; add/remove members → `GroupMember.ReadWrite.All`; admin units → `AdministrativeUnit.ReadWrite.All`; none substitute for each other; the scope tells Entra ID what the script may touch | Source scope table + "None of these four scopes substitute for one another" + "The scope you request tells Microsoft Entra ID exactly what the script is allowed to touch" · Docs: New-MgGroupMemberByRef (Microsoft.Graph.Groups); Get-MgUser read scope User.Read.All | ✅ `AdministrativeUnit.ReadWrite.All` cited from source table (Docs page not separately fetched; consistent with the Graph least-privilege model) | +| `Update-MgUser` uses the same CSV-and-loop pattern under the same `User.ReadWrite.All`; `Remove-MgUser` follows the same shape | Source §"Update and delete…": "`Update-MgUser` still runs under `User.ReadWrite.All`, the same scope that created the accounts… and `Remove-MgUser` follows the same shape again" | ✅ | +| Microsoft Graph doesn't manage mail contacts; `New-MgUser` won't create one; use `New-MailContact` in Exchange Online PowerShell, not Graph | Source §"Contacts stay off this toolkit": "Microsoft Graph doesn't manage mail contacts at all… The cmdlet that belongs to that job is `New-MailContact`, and it runs in Exchange Online PowerShell, not Microsoft Graph PowerShell" · Docs: Manage mail contacts in Exchange Online → `New-MailContact` (Exchange PowerShell) | ✅ | +| CTA: next unit is a hands-on bulk-provision exercise; New-MgUser reference on Learn | Module TOC: Unit 4 `4-exercise-bulk-provision-graph-powershell.md` · Source link `/powershell/module/microsoft.graph.users/new-mguser` | ✅ | + +## Open questions + +- **Audition the cmdlet/scope reads before final render.** The teaching content is literal cmdlet + and scope tokens (`Connect-MgGraph`, `New-MgUser`, `New-MailContact`, `User.ReadWrite.All`, + `Directory.ReadWrite.All`). Run `tools/audition_voices.py --from-script script.md` on the Vance + voice; if the hyphen or dots read unnaturally, prefer an SSML `say-as`/reword fix over `--rate`. +- **`AdministrativeUnit.ReadWrite.All` (B7)** is reproduced from the source unit's scope table; the + standalone Docs permissions page wasn't fetched this pass. If the designer surfaces it as a + focal row, spot-check it against current admin-unit cmdlet docs before render. +- On-screen code uses the source's `-MailNickname` spelling (docs example casing `-MailNickName` is + equivalent — PowerShell parameter names are case-insensitive). diff --git a/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/transcript.json b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/transcript.json new file mode 100644 index 0000000000..d82276eaf1 --- /dev/null +++ b/learn/output/Bulk-Identity-Management-With-Graph-PowerShell/transcript.json @@ -0,0 +1,3207 @@ +[ + { + "text": "Relacloud's", + "start": 0.03, + "end": 0.69 + }, + { + "text": "overseas", + "start": 0.69, + "end": 1.2 + }, + { + "text": "office", + "start": 1.2, + "end": 1.58 + }, + { + "text": "opens", + "start": 1.58, + "end": 1.88 + }, + { + "text": "Monday", + "start": 1.92, + "end": 2.53 + }, + { + "text": "and", + "start": 2.6, + "end": 2.76 + }, + { + "text": "the", + "start": 2.76, + "end": 2.78 + }, + { + "text": "stack", + "start": 2.78, + "end": 3.16 + }, + { + "text": "of", + "start": 3.16, + "end": 3.25 + }, + { + "text": "new", + "start": 3.25, + "end": 3.4 + }, + { + "text": "hire", + "start": 3.4, + "end": 3.74 + }, + { + "text": "names", + "start": 3.74, + "end": 3.99 + }, + { + "text": "on", + "start": 4.04, + "end": 4.16 + }, + { + "text": "your", + "start": 4.16, + "end": 4.32 + }, + { + "text": "desk", + "start": 4.32, + "end": 4.72 + }, + { + "text": "keeps", + "start": 4.89, + "end": 5.34 + }, + { + "text": "growing.", + "start": 5.37, + "end": 6.34 + }, + { + "text": "30", + "start": 6.42, + "end": 6.74 + }, + { + "text": "accounts", + "start": 6.78, + "end": 7.22 + }, + { + "text": "clicked", + "start": 7.22, + "end": 7.62 + }, + { + "text": "in", + "start": 7.62, + "end": 7.68 + }, + { + "text": "one", + "start": 7.72, + "end": 7.9 + }, + { + "text": "at", + "start": 7.9, + "end": 8.01 + }, + { + "text": "a", + "start": 8.01, + "end": 8.06 + }, + { + "text": "time", + "start": 8.06, + "end": 8.29 + }, + { + "text": "in", + "start": 8.29, + "end": 8.4 + }, + { + "text": "the", + "start": 8.4, + "end": 8.62 + }, + { + "text": "portal", + "start": 8.62, + "end": 9.19 + }, + { + "text": "won't", + "start": 9.32, + "end": 9.44 + }, + { + "text": "be", + "start": 9.44, + "end": 9.49 + }, + { + "text": "ready", + "start": 9.5, + "end": 9.64 + }, + { + "text": "before", + "start": 9.75, + "end": 10.04 + }, + { + "text": "the", + "start": 10.07, + "end": 10.25 + }, + { + "text": "doors", + "start": 10.33, + "end": 10.82 + }, + { + "text": "open.", + "start": 10.82, + "end": 11.52 + }, + { + "text": "So", + "start": 11.52, + "end": 11.69 + }, + { + "text": "here's", + "start": 11.69, + "end": 12.21 + }, + { + "text": "the", + "start": 12.21, + "end": 12.47 + }, + { + "text": "question", + "start": 12.47, + "end": 13.1 + }, + { + "text": "this", + "start": 13.18, + "end": 13.5 + }, + { + "text": "unit", + "start": 13.55, + "end": 13.88 + }, + { + "text": "answers.", + "start": 13.88, + "end": 14.64 + }, + { + "text": "How", + "start": 14.67, + "end": 14.85 + }, + { + "text": "do", + "start": 14.93, + "end": 15 + }, + { + "text": "you", + "start": 15, + "end": 15.21 + }, + { + "text": "create", + "start": 15.21, + "end": 15.66 + }, + { + "text": "every", + "start": 15.66, + "end": 16.03 + }, + { + "text": "one", + "start": 16.03, + "end": 16.25 + }, + { + "text": "of", + "start": 16.25, + "end": 16.31 + }, + { + "text": "those", + "start": 16.4, + "end": 16.76 + }, + { + "text": "accounts", + "start": 16.76, + "end": 17.35 + }, + { + "text": "in", + "start": 17.35, + "end": 17.48 + }, + { + "text": "a", + "start": 17.51, + "end": 17.53 + }, + { + "text": "single", + "start": 17.6, + "end": 18 + }, + { + "text": "pass", + "start": 18, + "end": 18.29 + }, + { + "text": "and", + "start": 18.29, + "end": 18.51 + }, + { + "text": "run", + "start": 18.51, + "end": 18.73 + }, + { + "text": "it", + "start": 18.73, + "end": 18.87 + }, + { + "text": "again", + "start": 18.87, + "end": 19.24 + }, + { + "text": "the", + "start": 19.24, + "end": 19.36 + }, + { + "text": "next", + "start": 19.53, + "end": 19.82 + }, + { + "text": "time", + "start": 19.87, + "end": 20.3 + }, + { + "text": "a", + "start": 20.3, + "end": 20.39 + }, + { + "text": "batch", + "start": 20.4, + "end": 20.99 + }, + { + "text": "of", + "start": 20.99, + "end": 21.22 + }, + { + "text": "hires", + "start": 21.22, + "end": 21.8 + }, + { + "text": "lands?", + "start": 21.8, + "end": 22.73 + }, + { + "text": "Microsoft", + "start": 22.8, + "end": 23.42 + }, + { + "text": "Graph", + "start": 23.42, + "end": 23.78 + }, + { + "text": "PowerShell", + "start": 23.78, + "end": 24.47 + }, + { + "text": "is", + "start": 24.48, + "end": 24.62 + }, + { + "text": "the", + "start": 24.73, + "end": 24.88 + }, + { + "text": "way,", + "start": 24.88, + "end": 25.24 + }, + { + "text": "and", + "start": 25.24, + "end": 25.5 + }, + { + "text": "by", + "start": 25.5, + "end": 25.55 + }, + { + "text": "the", + "start": 25.56, + "end": 25.57 + }, + { + "text": "end", + "start": 25.81, + "end": 25.87 + }, + { + "text": "you'll", + "start": 25.87, + "end": 26.1 + }, + { + "text": "be", + "start": 26.13, + "end": 26.23 + }, + { + "text": "able", + "start": 26.23, + "end": 26.5 + }, + { + "text": "to", + "start": 26.5, + "end": 26.58 + }, + { + "text": "do", + "start": 26.63, + "end": 26.76 + }, + { + "text": "three", + "start": 26.76, + "end": 27.1 + }, + { + "text": "things", + "start": 27.1, + "end": 27.51 + }, + { + "text": "with", + "start": 27.51, + "end": 27.77 + }, + { + "text": "it.", + "start": 27.86, + "end": 28.11 + }, + { + "text": "Connect", + "start": 28.11, + "end": 28.59 + }, + { + "text": "with", + "start": 28.59, + "end": 28.86 + }, + { + "text": "the", + "start": 28.86, + "end": 28.99 + }, + { + "text": "right", + "start": 29.06, + "end": 29.4 + }, + { + "text": "permission", + "start": 29.4, + "end": 30.09 + }, + { + "text": "scope.", + "start": 30.09, + "end": 30.68 + }, + { + "text": "Pull", + "start": 30.68, + "end": 30.72 + }, + { + "text": "your", + "start": 30.72, + "end": 30.82 + }, + { + "text": "new", + "start": 30.95, + "end": 31.13 + }, + { + "text": "hires", + "start": 31.21, + "end": 31.61 + }, + { + "text": "from", + "start": 31.61, + "end": 31.96 + }, + { + "text": "a", + "start": 31.96, + "end": 32.01 + }, + { + "text": "spreadsheet", + "start": 32.04, + "end": 33 + }, + { + "text": "and", + "start": 33, + "end": 33.26 + }, + { + "text": "let", + "start": 33.26, + "end": 33.45 + }, + { + "text": "one", + "start": 33.52, + "end": 33.78 + }, + { + "text": "command", + "start": 33.79, + "end": 34.38 + }, + { + "text": "create", + "start": 34.43, + "end": 34.91 + }, + { + "text": "the", + "start": 34.91, + "end": 35.17 + }, + { + "text": "whole", + "start": 35.17, + "end": 35.55 + }, + { + "text": "list.", + "start": 35.56, + "end": 36.28 + }, + { + "text": "The", + "start": 36.28, + "end": 36.39 + }, + { + "text": "whole", + "start": 36.39, + "end": 36.59 + }, + { + "text": "thing", + "start": 36.59, + "end": 36.64 + }, + { + "text": "is", + "start": 36.64, + "end": 36.93 + }, + { + "text": "really", + "start": 36.93, + "end": 37.43 + }, + { + "text": "just", + "start": 37.43, + "end": 37.8 + }, + { + "text": "three", + "start": 37.8, + "end": 38.25 + }, + { + "text": "moves", + "start": 38.25, + "end": 38.7 + }, + { + "text": "and", + "start": 38.7, + "end": 38.97 + }, + { + "text": "they", + "start": 38.97, + "end": 39.33 + }, + { + "text": "never", + "start": 39.33, + "end": 39.69 + }, + { + "text": "change.", + "start": 39.77, + "end": 40.62 + }, + { + "text": "First", + "start": 40.62, + "end": 41.05 + }, + { + "text": "you", + "start": 41.05, + "end": 41.23 + }, + { + "text": "connect", + "start": 41.35, + "end": 41.9 + }, + { + "text": "and", + "start": 41.9, + "end": 42.06 + }, + { + "text": "request", + "start": 42.16, + "end": 42.58 + }, + { + "text": "a", + "start": 42.58, + "end": 43.26 + }, + { + "text": "scope.", + "start": 43.26, + "end": 43.47 + }, + { + "text": "Next", + "start": 43.56, + "end": 43.69 + }, + { + "text": "you", + "start": 43.75, + "end": 43.93 + }, + { + "text": "import", + "start": 44.01, + "end": 44.51 + }, + { + "text": "a", + "start": 44.59, + "end": 44.63 + }, + { + "text": "CSV", + "start": 44.63, + "end": 44.9 + }, + { + "text": "of", + "start": 44.9, + "end": 45.08 + }, + { + "text": "your", + "start": 45.08, + "end": 45.39 + }, + { + "text": "users.", + "start": 45.48, + "end": 46.16 + }, + { + "text": "Then", + "start": 46.16, + "end": 46.51 + }, + { + "text": "you", + "start": 46.52, + "end": 46.79 + }, + { + "text": "loop", + "start": 46.86, + "end": 47.15 + }, + { + "text": "over", + "start": 47.15, + "end": 47.51 + }, + { + "text": "that", + "start": 47.51, + "end": 47.87 + }, + { + "text": "list", + "start": 47.87, + "end": 48.23 + }, + { + "text": "and", + "start": 48.23, + "end": 48.44 + }, + { + "text": "create", + "start": 48.68, + "end": 49.05 + }, + { + "text": "each", + "start": 49.05, + "end": 49.38 + }, + { + "text": "account.", + "start": 49.38, + "end": 50.29 + }, + { + "text": "Connect,", + "start": 50.38, + "end": 51.64 + }, + { + "text": "loop.", + "start": 51.67, + "end": 52.33 + }, + { + "text": "Every", + "start": 52.33, + "end": 52.83 + }, + { + "text": "Graph", + "start": 52.83, + "end": 53.31 + }, + { + "text": "PowerShell", + "start": 53.4, + "end": 54.32 + }, + { + "text": "session", + "start": 54.32, + "end": 55.01 + }, + { + "text": "starts", + "start": 55.01, + "end": 55.61 + }, + { + "text": "with", + "start": 55.61, + "end": 55.97 + }, + { + "text": "Connect", + "start": 56.09, + "end": 56.36 + }, + { + "text": "MG", + "start": 56.53, + "end": 56.71 + }, + { + "text": "Graph", + "start": 56.77, + "end": 57.23 + }, + { + "text": "and", + "start": 57.23, + "end": 57.35 + }, + { + "text": "the", + "start": 57.6, + "end": 57.76 + }, + { + "text": "scope", + "start": 58.09, + "end": 58.34 + }, + { + "text": "you", + "start": 58.34, + "end": 58.64 + }, + { + "text": "request", + "start": 58.64, + "end": 59.4 + }, + { + "text": "right", + "start": 59.43, + "end": 59.82 + }, + { + "text": "there", + "start": 59.82, + "end": 60.19 + }, + { + "text": "decides", + "start": 60.25, + "end": 60.81 + }, + { + "text": "what", + "start": 60.88, + "end": 61.17 + }, + { + "text": "the", + "start": 61.17, + "end": 61.42 + }, + { + "text": "rest", + "start": 61.42, + "end": 61.76 + }, + { + "text": "of", + "start": 61.76, + "end": 61.92 + }, + { + "text": "the", + "start": 61.93, + "end": 62.18 + }, + { + "text": "script", + "start": 62.18, + "end": 62.69 + }, + { + "text": "is", + "start": 62.69, + "end": 62.86 + }, + { + "text": "allowed", + "start": 62.86, + "end": 63.45 + }, + { + "text": "to", + "start": 63.45, + "end": 63.62 + }, + { + "text": "do.", + "start": 63.62, + "end": 64.05 + }, + { + "text": "To", + "start": 64.05, + "end": 64.18 + }, + { + "text": "create", + "start": 64.29, + "end": 64.58 + }, + { + "text": "accounts", + "start": 64.66, + "end": 65.08 + }, + { + "text": "you", + "start": 65.08, + "end": 65.445 + }, + { + "text": "ask", + "start": 65.445, + "end": 65.81 + }, + { + "text": "for", + "start": 65.81, + "end": 66.15 + }, + { + "text": "exactly", + "start": 66.15, + "end": 67.01 + }, + { + "text": "one", + "start": 67.01, + "end": 67.38 + }, + { + "text": "scope.", + "start": 67.38, + "end": 68.31 + }, + { + "text": "User,", + "start": 68.38, + "end": 69.09 + }, + { + "text": "read", + "start": 69.09, + "end": 69.58 + }, + { + "text": "write.", + "start": 69.58, + "end": 70.5 + }, + { + "text": "All.", + "start": 70.55, + "end": 71.3 + }, + { + "text": "Ask", + "start": 71.3, + "end": 71.48 + }, + { + "text": "for", + "start": 71.74, + "end": 71.9 + }, + { + "text": "less", + "start": 72.23, + "end": 72.53 + }, + { + "text": "and", + "start": 72.53, + "end": 72.9 + }, + { + "text": "the", + "start": 72.9, + "end": 73.26 + }, + { + "text": "create", + "start": 73.38, + "end": 73.88 + }, + { + "text": "step", + "start": 74.04, + "end": 74.48 + }, + { + "text": "simply", + "start": 74.52, + "end": 75.24 + }, + { + "text": "fails.", + "start": 75.24, + "end": 76.12 + }, + { + "text": "Then", + "start": 76.15, + "end": 76.43 + }, + { + "text": "import", + "start": 76.43, + "end": 76.89 + }, + { + "text": "CSV", + "start": 76.89, + "end": 77.12 + }, + { + "text": "reads", + "start": 77.12, + "end": 77.5 + }, + { + "text": "your", + "start": 77.5, + "end": 77.79 + }, + { + "text": "spreadsheet", + "start": 77.88, + "end": 78.65 + }, + { + "text": "into", + "start": 78.72, + "end": 78.94 + }, + { + "text": "a", + "start": 78.99, + "end": 79.01 + }, + { + "text": "collection", + "start": 79.08, + "end": 79.81 + }, + { + "text": "of", + "start": 79.81, + "end": 79.96 + }, + { + "text": "objects,", + "start": 79.96, + "end": 80.65 + }, + { + "text": "one", + "start": 80.65, + "end": 80.84 + }, + { + "text": "for", + "start": 80.88, + "end": 81.11 + }, + { + "text": "every", + "start": 81.11, + "end": 81.49 + }, + { + "text": "new", + "start": 81.49, + "end": 81.78 + }, + { + "text": "hire.", + "start": 81.83, + "end": 82.58 + }, + { + "text": "Each", + "start": 82.58, + "end": 83.03 + }, + { + "text": "row", + "start": 83.03, + "end": 83.29 + }, + { + "text": "carries", + "start": 83.36, + "end": 84.15 + }, + { + "text": "the", + "start": 84.15, + "end": 84.48 + }, + { + "text": "same", + "start": 84.48, + "end": 84.87 + }, + { + "text": "fields", + "start": 84.94, + "end": 85.6 + }, + { + "text": "you", + "start": 85.6, + "end": 85.93 + }, + { + "text": "type", + "start": 85.93, + "end": 86.43 + }, + { + "text": "into", + "start": 86.43, + "end": 86.82 + }, + { + "text": "the", + "start": 86.82, + "end": 87.11 + }, + { + "text": "portal's", + "start": 87.11, + "end": 87.87 + }, + { + "text": "bulk", + "start": 88.25, + "end": 88.26 + }, + { + "text": "create", + "start": 88.26, + "end": 88.84 + }, + { + "text": "sheet.", + "start": 88.84, + "end": 89.64 + }, + { + "text": "A", + "start": 89.67, + "end": 89.75 + }, + { + "text": "display", + "start": 89.75, + "end": 90.53 + }, + { + "text": "name,", + "start": 90.53, + "end": 91.13 + }, + { + "text": "a", + "start": 91.2, + "end": 91.31 + }, + { + "text": "user", + "start": 91.31, + "end": 91.76 + }, + { + "text": "principal", + "start": 91.76, + "end": 92.7 + }, + { + "text": "name,", + "start": 92.78, + "end": 93.44 + }, + { + "text": "a", + "start": 93.44, + "end": 93.55 + }, + { + "text": "mail", + "start": 93.55, + "end": 93.97 + }, + { + "text": "nickname,", + "start": 94.09, + "end": 95.12 + }, + { + "text": "and", + "start": 95.12, + "end": 95.32 + }, + { + "text": "a", + "start": 95.32, + "end": 96.09 + }, + { + "text": "temporary", + "start": 96.09, + "end": 96.57 + }, + { + "text": "password.", + "start": 96.57, + "end": 97.74 + }, + { + "text": "Same", + "start": 97.9, + "end": 98.27 + }, + { + "text": "columns,", + "start": 98.27, + "end": 99.24 + }, + { + "text": "just", + "start": 99.27, + "end": 99.63 + }, + { + "text": "driven", + "start": 99.63, + "end": 100.22 + }, + { + "text": "from", + "start": 100.22, + "end": 100.61 + }, + { + "text": "a", + "start": 100.61, + "end": 100.7 + }, + { + "text": "file.", + "start": 100.72, + "end": 101.39 + }, + { + "text": "Now", + "start": 101.39, + "end": 101.68 + }, + { + "text": "the", + "start": 101.68, + "end": 101.97 + }, + { + "text": "loop", + "start": 101.97, + "end": 102.31 + }, + { + "text": "does", + "start": 102.38, + "end": 102.7 + }, + { + "text": "the", + "start": 102.75, + "end": 103.04 + }, + { + "text": "work.", + "start": 103.04, + "end": 103.72 + }, + { + "text": "A", + "start": 103.72, + "end": 103.82 + }, + { + "text": "for", + "start": 103.82, + "end": 103.96 + }, + { + "text": "each", + "start": 104.14, + "end": 104.49 + }, + { + "text": "walks", + "start": 104.5, + "end": 104.91 + }, + { + "text": "that", + "start": 104.91, + "end": 105.69 + }, + { + "text": "list", + "start": 105.69, + "end": 105.77 + }, + { + "text": "and", + "start": 105.77, + "end": 106.02 + }, + { + "text": "hands", + "start": 106.12, + "end": 106.72 + }, + { + "text": "each", + "start": 106.75, + "end": 106.93 + }, + { + "text": "row", + "start": 107.01, + "end": 107.14 + }, + { + "text": "to", + "start": 107.14, + "end": 107.25 + }, + { + "text": "new", + "start": 107.25, + "end": 107.43 + }, + { + "text": "men's", + "start": 107.44, + "end": 107.74 + }, + { + "text": "user", + "start": 107.74, + "end": 107.95 + }, + { + "text": "one", + "start": 108.04, + "end": 108.16 + }, + { + "text": "at", + "start": 108.16, + "end": 108.28 + }, + { + "text": "a", + "start": 108.28, + "end": 108.34 + }, + { + "text": "time.", + "start": 108.34, + "end": 108.76 + }, + { + "text": "That", + "start": 108.76, + "end": 108.98 + }, + { + "text": "single", + "start": 109.02, + "end": 109.37 + }, + { + "text": "Sambadlet", + "start": 109.37, + "end": 110.37 + }, + { + "text": "creates", + "start": 110.37, + "end": 111.44 + }, + { + "text": "the", + "start": 111.68, + "end": 112.16 + }, + { + "text": "account,", + "start": 112.16, + "end": 113.76 + }, + { + "text": "switches", + "start": 113.79, + "end": 114.43 + }, + { + "text": "it", + "start": 114.43, + "end": 114.57 + }, + { + "text": "on", + "start": 114.63, + "end": 114.75 + }, + { + "text": "and", + "start": 114.75, + "end": 114.99 + }, + { + "text": "forces", + "start": 115, + "end": 115.43 + }, + { + "text": "a", + "start": 115.52, + "end": 115.58 + }, + { + "text": "password", + "start": 115.58, + "end": 116.25 + }, + { + "text": "reset", + "start": 116.25, + "end": 116.65 + }, + { + "text": "at", + "start": 116.65, + "end": 116.82 + }, + { + "text": "first", + "start": 116.82, + "end": 117.22 + }, + { + "text": "sign-in.", + "start": 117.27, + "end": 118.1 + }, + { + "text": "30", + "start": 118.21, + "end": 118.48 + }, + { + "text": "rows", + "start": 118.65, + "end": 118.94 + }, + { + "text": "in,", + "start": 119.02, + "end": 119.31 + }, + { + "text": "30", + "start": 119.31, + "end": 119.47 + }, + { + "text": "accounts", + "start": 120.21, + "end": 120.52 + }, + { + "text": "out.", + "start": 120.55, + "end": 121.52 + }, + { + "text": "Here's", + "start": 121.52, + "end": 121.89 + }, + { + "text": "why", + "start": 121.89, + "end": 122.01 + }, + { + "text": "that", + "start": 122.08, + "end": 122.32 + }, + { + "text": "beats", + "start": 122.32, + "end": 122.63 + }, + { + "text": "clicking", + "start": 122.63, + "end": 123.05 + }, + { + "text": "through", + "start": 123.13, + "end": 123.56 + }, + { + "text": "a", + "start": 123.56, + "end": 123.59 + }, + { + "text": "browser.", + "start": 123.66, + "end": 124.28 + }, + { + "text": "A", + "start": 124.28, + "end": 124.37 + }, + { + "text": "script", + "start": 124.37, + "end": 124.85 + }, + { + "text": "is", + "start": 124.98, + "end": 125.09 + }, + { + "text": "repeatable.", + "start": 125.09, + "end": 126.19 + }, + { + "text": "Run", + "start": 126.19, + "end": 126.53 + }, + { + "text": "it", + "start": 126.53, + "end": 126.64 + }, + { + "text": "again", + "start": 126.75, + "end": 127.06 + }, + { + "text": "next", + "start": 127.06, + "end": 127.33 + }, + { + "text": "quarter", + "start": 127.33, + "end": 127.8 + }, + { + "text": "when", + "start": 127.8, + "end": 128.07 + }, + { + "text": "the", + "start": 128.07, + "end": 128.21 + }, + { + "text": "next", + "start": 128.28, + "end": 128.54 + }, + { + "text": "wave", + "start": 128.54, + "end": 128.81 + }, + { + "text": "of", + "start": 128.81, + "end": 128.94 + }, + { + "text": "hires", + "start": 128.94, + "end": 129.25 + }, + { + "text": "arrives", + "start": 129.32, + "end": 129.75 + }, + { + "text": "and", + "start": 129.75, + "end": 129.95 + }, + { + "text": "you", + "start": 129.95, + "end": 130.15 + }, + { + "text": "don't", + "start": 130.15, + "end": 130.48 + }, + { + "text": "reopen", + "start": 130.48, + "end": 130.89 + }, + { + "text": "a", + "start": 130.89, + "end": 130.95 + }, + { + "text": "single", + "start": 130.95, + "end": 131.44 + }, + { + "text": "blade,", + "start": 131.44, + "end": 132.23 + }, + { + "text": "you", + "start": 132.27, + "end": 132.55 + }, + { + "text": "point", + "start": 132.55, + "end": 133.03 + }, + { + "text": "it", + "start": 133.11, + "end": 133.27 + }, + { + "text": "at", + "start": 133.27, + "end": 133.47 + }, + { + "text": "a", + "start": 133.47, + "end": 133.57 + }, + { + "text": "new", + "start": 133.57, + "end": 133.88 + }, + { + "text": "file", + "start": 133.88, + "end": 134.29 + }, + { + "text": "and", + "start": 134.29, + "end": 134.6 + }, + { + "text": "go.", + "start": 134.6, + "end": 135.13 + }, + { + "text": "Now", + "start": 135.2, + "end": 135.31 + }, + { + "text": "one", + "start": 135.38, + "end": 135.5 + }, + { + "text": "small", + "start": 135.5, + "end": 135.79 + }, + { + "text": "detail", + "start": 135.79, + "end": 136.14 + }, + { + "text": "is", + "start": 136.14, + "end": 136.23 + }, + { + "text": "doing", + "start": 136.28, + "end": 136.54 + }, + { + "text": "more", + "start": 136.54, + "end": 136.77 + }, + { + "text": "than", + "start": 136.77, + "end": 136.96 + }, + { + "text": "it", + "start": 137, + "end": 137.15 + }, + { + "text": "looks.", + "start": 137.2, + "end": 137.97 + }, + { + "text": "Why", + "start": 138.39, + "end": 138.57 + }, + { + "text": "user", + "start": 138.65, + "end": 139.03 + }, + { + "text": "read", + "start": 139.03, + "end": 139.41 + }, + { + "text": "write?", + "start": 139.41, + "end": 140.17 + }, + { + "text": "All.", + "start": 140.17, + "end": 140.74 + }, + { + "text": "And", + "start": 140.74, + "end": 141.03 + }, + { + "text": "not", + "start": 141.03, + "end": 141.25 + }, + { + "text": "the", + "start": 141.32, + "end": 141.61 + }, + { + "text": "broader", + "start": 141.61, + "end": 142.28 + }, + { + "text": "directory.", + "start": 142.28, + "end": 143.43 + }, + { + "text": "Read", + "start": 143.49, + "end": 143.81 + }, + { + "text": "write?", + "start": 143.81, + "end": 144.48 + }, + { + "text": "All.", + "start": 144.81, + "end": 145.14 + }, + { + "text": "Both", + "start": 145.14, + "end": 145.49 + }, + { + "text": "of", + "start": 145.52, + "end": 145.71 + }, + { + "text": "them", + "start": 145.71, + "end": 146.2 + }, + { + "text": "would", + "start": 146.2, + "end": 146.36 + }, + { + "text": "work", + "start": 146.43, + "end": 146.7 + }, + { + "text": "but", + "start": 146.7, + "end": 146.89 + }, + { + "text": "the", + "start": 146.91, + "end": 147.13 + }, + { + "text": "broad", + "start": 147.14, + "end": 147.49 + }, + { + "text": "one", + "start": 147.52, + "end": 147.73 + }, + { + "text": "grants", + "start": 147.73, + "end": 148.18 + }, + { + "text": "far", + "start": 148.18, + "end": 148.4 + }, + { + "text": "more", + "start": 148.4, + "end": 148.66 + }, + { + "text": "than", + "start": 148.7, + "end": 148.93 + }, + { + "text": "user", + "start": 149, + "end": 149.29 + }, + { + "text": "management", + "start": 149.36, + "end": 150.05 + }, + { + "text": "alone", + "start": 150.05, + "end": 150.39 + }, + { + "text": "and", + "start": 150.44, + "end": 150.64 + }, + { + "text": "that's", + "start": 150.64, + "end": 151.03 + }, + { + "text": "the", + "start": 151.08, + "end": 151.3 + }, + { + "text": "decision", + "start": 151.36, + "end": 152.02 + }, + { + "text": "actually", + "start": 152.05, + "end": 152.63 + }, + { + "text": "being", + "start": 152.63, + "end": 153.01 + }, + { + "text": "tested.", + "start": 153.01, + "end": 153.69 + }, + { + "text": "You", + "start": 153.78, + "end": 153.9 + }, + { + "text": "match", + "start": 153.94, + "end": 154.28 + }, + { + "text": "the", + "start": 154.32, + "end": 154.53 + }, + { + "text": "scope", + "start": 154.53, + "end": 154.91 + }, + { + "text": "to", + "start": 154.91, + "end": 155.07 + }, + { + "text": "the", + "start": 155.07, + "end": 155.3 + }, + { + "text": "task", + "start": 155.3, + "end": 155.61 + }, + { + "text": "not", + "start": 155.61, + "end": 155.84 + }, + { + "text": "to", + "start": 155.84, + "end": 155.99 + }, + { + "text": "whatever", + "start": 155.99, + "end": 156.6 + }, + { + "text": "also", + "start": 156.6, + "end": 156.74 + }, + { + "text": "happens", + "start": 156.98, + "end": 157.45 + }, + { + "text": "to", + "start": 157.45, + "end": 157.68 + }, + { + "text": "work.", + "start": 157.71, + "end": 158.39 + }, + { + "text": "And", + "start": 158.4, + "end": 158.71 + }, + { + "text": "that", + "start": 158.71, + "end": 159.09 + }, + { + "text": "same", + "start": 159.16, + "end": 159.53 + }, + { + "text": "rule", + "start": 159.53, + "end": 159.94 + }, + { + "text": "scales", + "start": 159.94, + "end": 160.46 + }, + { + "text": "to", + "start": 160.54, + "end": 160.75 + }, + { + "text": "every", + "start": 160.82, + "end": 161.28 + }, + { + "text": "bulk", + "start": 161.28, + "end": 161.67 + }, + { + "text": "job.", + "start": 161.7, + "end": 162.38 + }, + { + "text": "Reading", + "start": 162.38, + "end": 162.96 + }, + { + "text": "users", + "start": 162.96, + "end": 163.35 + }, + { + "text": "for", + "start": 163.35, + "end": 163.41 + }, + { + "text": "an", + "start": 163.64, + "end": 163.77 + }, + { + "text": "audit,", + "start": 164.13, + "end": 164.25 + }, + { + "text": "that's", + "start": 164.34, + "end": 164.81 + }, + { + "text": "user.", + "start": 164.82, + "end": 165.52 + }, + { + "text": "Read", + "start": 165.55, + "end": 166.05 + }, + { + "text": "all,", + "start": 166.05, + "end": 166.73 + }, + { + "text": "read", + "start": 166.73, + "end": 167.19 + }, + { + "text": "only,", + "start": 167.28, + "end": 168.05 + }, + { + "text": "no", + "start": 168.12, + "end": 168.34 + }, + { + "text": "changes.", + "start": 168.39, + "end": 169.72 + }, + { + "text": "Adding", + "start": 169.72, + "end": 170.24 + }, + { + "text": "people", + "start": 170.48, + "end": 170.96 + }, + { + "text": "to", + "start": 170.96, + "end": 171.15 + }, + { + "text": "a", + "start": 171.15, + "end": 171.23 + }, + { + "text": "group?", + "start": 171.78, + "end": 172.09 + }, + { + "text": "Group", + "start": 172.18, + "end": 172.75 + }, + { + "text": "member?", + "start": 172.87, + "end": 174 + }, + { + "text": "Read", + "start": 174, + "end": 174.44 + }, + { + "text": "write?", + "start": 174.54, + "end": 175.6 + }, + { + "text": "All.", + "start": 175.61, + "end": 176.39 + }, + { + "text": "Using", + "start": 176.47, + "end": 176.89 + }, + { + "text": "an", + "start": 176.89, + "end": 177.07 + }, + { + "text": "administrative", + "start": 177.07, + "end": 178.32 + }, + { + "text": "unit?", + "start": 178.36, + "end": 178.96 + }, + { + "text": "Administrative", + "start": 178.97, + "end": 180.24 + }, + { + "text": "unit?", + "start": 180.24, + "end": 180.77 + }, + { + "text": "Read", + "start": 180.89, + "end": 181.16 + }, + { + "text": "write?", + "start": 181.33, + "end": 181.95 + }, + { + "text": "All.", + "start": 181.95, + "end": 182.56 + }, + { + "text": "None", + "start": 182.56, + "end": 182.725 + }, + { + "text": "of", + "start": 182.725, + "end": 182.89 + }, + { + "text": "them", + "start": 182.89, + "end": 182.94 + }, + { + "text": "stand", + "start": 182.94, + "end": 183.16 + }, + { + "text": "in", + "start": 183.19, + "end": 183.33 + }, + { + "text": "for", + "start": 183.33, + "end": 183.58 + }, + { + "text": "each", + "start": 183.58, + "end": 183.92 + }, + { + "text": "other.", + "start": 183.92, + "end": 184.6 + }, + { + "text": "Each", + "start": 184.64, + "end": 184.94 + }, + { + "text": "scope", + "start": 184.94, + "end": 185.37 + }, + { + "text": "tells", + "start": 185.37, + "end": 185.8 + }, + { + "text": "Enter", + "start": 185.8, + "end": 186.23 + }, + { + "text": "ID", + "start": 186.3, + "end": 186.4 + }, + { + "text": "exactly", + "start": 186.4, + "end": 187 + }, + { + "text": "what", + "start": 187, + "end": 187.34 + }, + { + "text": "your", + "start": 187.34, + "end": 187.68 + }, + { + "text": "script", + "start": 187.68, + "end": 188.19 + }, + { + "text": "may", + "start": 188.19, + "end": 188.44 + }, + { + "text": "touch.", + "start": 188.44, + "end": 188.89 + }, + { + "text": "Creating", + "start": 189.19, + "end": 189.2 + }, + { + "text": "accounts", + "start": 189.23, + "end": 189.82 + }, + { + "text": "isn't", + "start": 189.82, + "end": 190.2 + }, + { + "text": "the", + "start": 190.2, + "end": 190.43 + }, + { + "text": "only", + "start": 190.43, + "end": 190.68 + }, + { + "text": "bulk", + "start": 190.76, + "end": 191.05 + }, + { + "text": "task", + "start": 191.05, + "end": 191.36 + }, + { + "text": "either.", + "start": 191.36, + "end": 192.06 + }, + { + "text": "A", + "start": 192.07, + "end": 192.09 + }, + { + "text": "department", + "start": 192.16, + "end": 192.91 + }, + { + "text": "change,", + "start": 192.91, + "end": 193.53 + }, + { + "text": "a", + "start": 193.53, + "end": 193.65 + }, + { + "text": "manager", + "start": 193.65, + "end": 193.92 + }, + { + "text": "swap,", + "start": 194.16, + "end": 194.6 + }, + { + "text": "update", + "start": 194.6, + "end": 194.88 + }, + { + "text": "MG", + "start": 195.19, + "end": 195.35 + }, + { + "text": "user", + "start": 195.35, + "end": 195.71 + }, + { + "text": "runs", + "start": 195.74, + "end": 196.13 + }, + { + "text": "the", + "start": 196.13, + "end": 196.39 + }, + { + "text": "very", + "start": 196.48, + "end": 196.81 + }, + { + "text": "same", + "start": 196.81, + "end": 197.2 + }, + { + "text": "CSV", + "start": 197.2, + "end": 197.49 + }, + { + "text": "and", + "start": 197.49, + "end": 197.77 + }, + { + "text": "loop", + "start": 197.77, + "end": 198.17 + }, + { + "text": "pattern", + "start": 198.17, + "end": 198.86 + }, + { + "text": "under", + "start": 198.86, + "end": 199.35 + }, + { + "text": "that", + "start": 199.35, + "end": 199.74 + }, + { + "text": "same", + "start": 199.74, + "end": 200.13 + }, + { + "text": "user,", + "start": 200.13, + "end": 200.71 + }, + { + "text": "read", + "start": 200.71, + "end": 200.86 + }, + { + "text": "write,", + "start": 201.59, + "end": 201.73 + }, + { + "text": "all", + "start": 201.82, + "end": 202.07 + }, + { + "text": "scope", + "start": 202.07, + "end": 202.64 + }, + { + "text": "and", + "start": 202.71, + "end": 202.89 + }, + { + "text": "when", + "start": 202.97, + "end": 203.26 + }, + { + "text": "an", + "start": 203.27, + "end": 203.44 + }, + { + "text": "account", + "start": 203.44, + "end": 204.04 + }, + { + "text": "has", + "start": 204.04, + "end": 204.29 + }, + { + "text": "to", + "start": 204.29, + "end": 204.46 + }, + { + "text": "go", + "start": 204.46, + "end": 204.63 + }, + { + "text": "remove", + "start": 204.64, + "end": 205.14 + }, + { + "text": "MG", + "start": 205.14, + "end": 205.31 + }, + { + "text": "user", + "start": 205.31, + "end": 205.65 + }, + { + "text": "follows", + "start": 205.65, + "end": 206.25 + }, + { + "text": "the", + "start": 206.25, + "end": 206.5 + }, + { + "text": "identical", + "start": 206.5, + "end": 207.27 + }, + { + "text": "shape.", + "start": 207.27, + "end": 208.04 + }, + { + "text": "Learn", + "start": 208.04, + "end": 208.18 + }, + { + "text": "the", + "start": 208.18, + "end": 208.26 + }, + { + "text": "pattern", + "start": 208.26, + "end": 208.38 + }, + { + "text": "once,", + "start": 208.51, + "end": 209.19 + }, + { + "text": "reuse", + "start": 209.19, + "end": 209.71 + }, + { + "text": "it", + "start": 209.8, + "end": 209.97 + }, + { + "text": "everywhere.", + "start": 210.04, + "end": 211.55 + }, + { + "text": "One", + "start": 211.62, + "end": 211.75 + }, + { + "text": "trap", + "start": 211.75, + "end": 211.93 + }, + { + "text": "though", + "start": 211.93, + "end": 212.2 + }, + { + "text": "before", + "start": 212.2, + "end": 212.47 + }, + { + "text": "you", + "start": 212.47, + "end": 212.6 + }, + { + "text": "reach", + "start": 212.6, + "end": 212.82 + }, + { + "text": "for", + "start": 212.94, + "end": 212.96 + }, + { + "text": "this", + "start": 212.96, + "end": 213.2 + }, + { + "text": "out", + "start": 213.2, + "end": 213.48 + }, + { + "text": "of", + "start": 213.48, + "end": 213.66 + }, + { + "text": "habit,", + "start": 213.74, + "end": 214.19 + }, + { + "text": "Microsoft", + "start": 214.93, + "end": 215.16 + }, + { + "text": "Graph", + "start": 215.19, + "end": 215.54 + }, + { + "text": "doesn't", + "start": 215.54, + "end": 216.07 + }, + { + "text": "manage", + "start": 216.07, + "end": 216.53 + }, + { + "text": "mail", + "start": 216.53, + "end": 216.83 + }, + { + "text": "contacts", + "start": 216.92, + "end": 217.43 + }, + { + "text": "at", + "start": 217.46, + "end": 217.61 + }, + { + "text": "all.", + "start": 217.61, + "end": 218.05 + }, + { + "text": "Scripting", + "start": 218.12, + "end": 218.76 + }, + { + "text": "a", + "start": 218.76, + "end": 218.83 + }, + { + "text": "vendor", + "start": 218.83, + "end": 219.29 + }, + { + "text": "contact", + "start": 219.29, + "end": 219.79 + }, + { + "text": "with", + "start": 219.8, + "end": 220.14 + }, + { + "text": "new", + "start": 220.14, + "end": 220.34 + }, + { + "text": "MG", + "start": 220.42, + "end": 220.52 + }, + { + "text": "user", + "start": 220.52, + "end": 220.83 + }, + { + "text": "just", + "start": 220.95, + "end": 221.25 + }, + { + "text": "won't", + "start": 221.25, + "end": 221.65 + }, + { + "text": "work", + "start": 221.65, + "end": 221.98 + }, + { + "text": "because", + "start": 221.98, + "end": 222.56 + }, + { + "text": "that", + "start": 222.56, + "end": 222.89 + }, + { + "text": "contact", + "start": 222.89, + "end": 223.45 + }, + { + "text": "was", + "start": 223.52, + "end": 223.71 + }, + { + "text": "never", + "start": 223.71, + "end": 224.12 + }, + { + "text": "a", + "start": 224.12, + "end": 224.2 + }, + { + "text": "user", + "start": 224.2, + "end": 224.53 + }, + { + "text": "object.", + "start": 224.53, + "end": 225.25 + }, + { + "text": "That", + "start": 225.37, + "end": 225.64 + }, + { + "text": "job", + "start": 225.69, + "end": 225.96 + }, + { + "text": "belongs", + "start": 225.96, + "end": 226.59 + }, + { + "text": "to", + "start": 226.59, + "end": 226.64 + }, + { + "text": "new", + "start": 226.89, + "end": 226.99 + }, + { + "text": "mail", + "start": 226.99, + "end": 227.35 + }, + { + "text": "contact", + "start": 227.35, + "end": 228 + }, + { + "text": "over", + "start": 228, + "end": 228.39 + }, + { + "text": "in", + "start": 228.39, + "end": 228.55 + }, + { + "text": "Exchange", + "start": 228.64, + "end": 229.35 + }, + { + "text": "Online", + "start": 229.35, + "end": 229.85 + }, + { + "text": "PowerShell,", + "start": 229.93, + "end": 231.09 + }, + { + "text": "not", + "start": 231.09, + "end": 231.38 + }, + { + "text": "Graph.", + "start": 231.38, + "end": 232.04 + }, + { + "text": "So", + "start": 232.21, + "end": 232.34 + }, + { + "text": "the", + "start": 232.34, + "end": 232.63 + }, + { + "text": "overseas", + "start": 232.63, + "end": 233.02 + }, + { + "text": "office", + "start": 233.77, + "end": 233.91 + }, + { + "text": "is", + "start": 233.98, + "end": 234.1 + }, + { + "text": "covered,", + "start": 234.2, + "end": 235.04 + }, + { + "text": "you", + "start": 235.07, + "end": 235.25 + }, + { + "text": "connected", + "start": 235.33, + "end": 236 + }, + { + "text": "with", + "start": 236, + "end": 236.27 + }, + { + "text": "a", + "start": 236.36, + "end": 236.4 + }, + { + "text": "scope,", + "start": 236.4, + "end": 236.92 + }, + { + "text": "imported", + "start": 236.96, + "end": 237.57 + }, + { + "text": "a", + "start": 237.65, + "end": 237.68 + }, + { + "text": "CSV", + "start": 237.68, + "end": 237.92 + }, + { + "text": "and", + "start": 237.92, + "end": 238.11 + }, + { + "text": "let", + "start": 238.18, + "end": 238.4 + }, + { + "text": "new", + "start": 238.4, + "end": 238.64 + }, + { + "text": "MG", + "start": 238.64, + "end": 238.8 + }, + { + "text": "user", + "start": 238.8, + "end": 239.12 + }, + { + "text": "build", + "start": 239.12, + "end": 239.52 + }, + { + "text": "the", + "start": 239.52, + "end": 239.76 + }, + { + "text": "whole", + "start": 239.76, + "end": 240.11 + }, + { + "text": "roster", + "start": 240.17, + "end": 240.71 + }, + { + "text": "in", + "start": 240.75, + "end": 240.89 + }, + { + "text": "one", + "start": 240.89, + "end": 241.14 + }, + { + "text": "pass.", + "start": 241.14, + "end": 241.73 + }, + { + "text": "Then", + "start": 241.73, + "end": 242.07 + }, + { + "text": "you", + "start": 242.07, + "end": 242.32 + }, + { + "text": "reuse", + "start": 242.32, + "end": 242.74 + }, + { + "text": "that", + "start": 242.74, + "end": 243.08 + }, + { + "text": "same", + "start": 243.08, + "end": 243.42 + }, + { + "text": "loop", + "start": 243.42, + "end": 243.76 + }, + { + "text": "to", + "start": 243.76, + "end": 243.93 + }, + { + "text": "update", + "start": 243.93, + "end": 244.44 + }, + { + "text": "and", + "start": 244.44, + "end": 244.69 + }, + { + "text": "to", + "start": 244.69, + "end": 244.86 + }, + { + "text": "delete,", + "start": 244.86, + "end": 245.5 + }, + { + "text": "matching", + "start": 245.68, + "end": 246.22 + }, + { + "text": "every", + "start": 246.22, + "end": 246.42 + }, + { + "text": "scope", + "start": 246.42, + "end": 247.19 + }, + { + "text": "to", + "start": 247.19, + "end": 247.36 + }, + { + "text": "its", + "start": 247.36, + "end": 247.64 + }, + { + "text": "task", + "start": 247.67, + "end": 248.06 + }, + { + "text": "along", + "start": 248.06, + "end": 248.56 + }, + { + "text": "the", + "start": 248.56, + "end": 248.83 + }, + { + "text": "way.", + "start": 248.92, + "end": 249.42 + }, + { + "text": "One", + "start": 249.46, + "end": 249.69 + }, + { + "text": "pattern", + "start": 249.76, + "end": 250.46 + }, + { + "text": "for", + "start": 250.46, + "end": 250.76 + }, + { + "text": "the", + "start": 250.76, + "end": 251.06 + }, + { + "text": "entire", + "start": 251.06, + "end": 251.66 + }, + { + "text": "directory.", + "start": 251.66, + "end": 252.82 + }, + { + "text": "Ready", + "start": 252.82, + "end": 252.89 + }, + { + "text": "to", + "start": 252.89, + "end": 253.61 + }, + { + "text": "run", + "start": 253.61, + "end": 253.86 + }, + { + "text": "it", + "start": 253.86, + "end": 254.06 + }, + { + "text": "yourself?", + "start": 254.06, + "end": 255.16 + }, + { + "text": "The", + "start": 255.23, + "end": 255.41 + }, + { + "text": "next", + "start": 255.49, + "end": 255.79 + }, + { + "text": "exercise", + "start": 255.8, + "end": 256.43 + }, + { + "text": "takes", + "start": 256.52, + "end": 256.87 + }, + { + "text": "you", + "start": 256.96, + "end": 257.18 + }, + { + "text": "through", + "start": 257.18, + "end": 257.73 + }, + { + "text": "bulk", + "start": 257.8, + "end": 258.09 + }, + { + "text": "provisioning", + "start": 258.16, + "end": 259.16 + }, + { + "text": "with", + "start": 259.16, + "end": 259.5 + }, + { + "text": "Graph", + "start": 259.5, + "end": 259.92 + }, + { + "text": "PowerShell", + "start": 260.16, + "end": 260.79 + }, + { + "text": "hands", + "start": 260.79, + "end": 260.91 + }, + { + "text": "on.", + "start": 261.21, + "end": 261.72 + }, + { + "text": "For", + "start": 261.72, + "end": 261.98 + }, + { + "text": "the", + "start": 262.09, + "end": 262.32 + }, + { + "text": "parameters", + "start": 262.32, + "end": 263.3 + }, + { + "text": "open", + "start": 263.39, + "end": 263.73 + }, + { + "text": "the", + "start": 263.73, + "end": 264 + }, + { + "text": "new", + "start": 264, + "end": 264.27 + }, + { + "text": "MG", + "start": 264.27, + "end": 264.45 + }, + { + "text": "user", + "start": 264.45, + "end": 264.8 + }, + { + "text": "reference", + "start": 264.92, + "end": 265.63 + }, + { + "text": "on", + "start": 265.66, + "end": 265.83 + }, + { + "text": "Microsoft", + "start": 265.83, + "end": 266.66 + }, + { + "text": "Learn.", + "start": 266.66, + "end": 267.16 + } +] \ No newline at end of file diff --git a/learn/templates/blocks/title-hero.html b/learn/templates/blocks/title-hero.html index 2064e438d4..3acf2ff2e8 100644 --- a/learn/templates/blocks/title-hero.html +++ b/learn/templates/blocks/title-hero.html @@ -111,9 +111,15 @@ } #mk-th-title { font-size: var(--fs-h1); /* title-card headline — up to the h1 tier */ + /* .ilt-title's 1.08 leading is tighter than the face's own ascent+descent, so a + two-line lock-up collides with itself at h1 size. Give the stack enough leading + to clear its own descenders. */ + line-height: 1.16; margin-top: 2.4cqw; } - #mk-th-line { + /* the two title lines are CLASSED spans — an id selector here never matched them, + so the headline ran inline and wrapped instead of breaking on the authored lines. */ + .mk-th-line { display: block; } #mk-th-rule { @@ -157,9 +163,12 @@ kicker: "MICROSOFT LEARN", titleLine1: "Manage Windows devices", titleLine2: "with Microsoft Intune", + // on-screen length of this scene (its slot data-duration) — drives the camera push + pushSeconds: 12, subtitle: "A practical guide to enrolling, configuring, and securing your endpoints.", }; + var group = document.getElementById("mk-th-group"); var kicker = document.getElementById("mk-th-kicker"); var line1 = document.getElementById("mk-th-line1"); var line2 = document.getElementById("mk-th-line2"); @@ -206,6 +215,21 @@ 1.95, ); + // 5) a slow camera push carries the hold. A title card sits under a long line of + // narration, and without a carrier the shot freezes for the rest of the scene. + // `pushSeconds` is the scene's on-screen length (its slot data-duration); the + // push runs from the end of the waterfall to the cut, at a constant ~4px/s. + var push = Math.max(0, (CONFIG.pushSeconds || 12) - 2.75); + if (push > 0.5) { + gsap.set(group, { transformOrigin: "left center" }); + tl.fromTo( + group, + { scale: 1 }, + { scale: 1 + Math.min(0.07, push * 0.0032), duration: push, ease: "none" }, + 2.75, + ); + } + window.__timelines["title-hero"] = tl; })(); diff --git a/learn/tools/assemble_scenes.py b/learn/tools/assemble_scenes.py index 461a02e882..5fd456d0e6 100644 --- a/learn/tools/assemble_scenes.py +++ b/learn/tools/assemble_scenes.py @@ -131,12 +131,12 @@ def build_html(manifest: dict[str, Any], scenes_dir_name: str) -> tuple[str, dic seam_lines.append(f' // SEAM {prev["id"]} -> {cur["id"]} : {seam} (cut @{cut})') seam_lines.append( f' tl.to("#slot-{prev["id"]}", {{ {prop}: {12 * direction}, autoAlpha: 0, ' - f'duration: 0.34, ease: "power3.in" }}, {exit_at});' + f'duration: 0.34, ease: "power3.in" }}, {exit_at}); // anchor-exempt: seam mechanics stamped from an anchored scene boundary' ) - seam_lines.append(f' tl.set("#slot-{prev["id"]}", {{ autoAlpha: 0 }}, {cut});') + seam_lines.append(f' tl.set("#slot-{prev["id"]}", {{ autoAlpha: 0 }}, {cut}); // anchor-exempt: seam mechanics stamped from an anchored scene boundary') seam_lines.append( f' tl.fromTo("#slot-{cur["id"]}", {{ {prop}: {-10 * direction}, autoAlpha: 0.35 }}, ' - f'{{ {prop}: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }}, {cut});' + f'{{ {prop}: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }}, {cut}); // anchor-exempt: seam mechanics stamped from an anchored scene boundary' ) narration = manifest.get("narration") @@ -163,12 +163,12 @@ def build_html(manifest: dict[str, Any], scenes_dir_name: str) -> tuple[str, dic if intro_fade > 0: bookend_lines.append(' gsap.set("#fade-in", { autoAlpha: 1 });') bookend_lines.append( - f' tl.to("#fade-in", {{ autoAlpha: 0, duration: {intro_fade}, ease: "power2.out" }}, 0);' + f' tl.to("#fade-in", {{ autoAlpha: 0, duration: {intro_fade}, ease: "power2.out" }}, 0); // anchor-exempt: bookend fade, relative to the composition boundary' ) if outro_start is not None: bookend_lines.append( f' tl.fromTo("#fade-out", {{ autoAlpha: 0 }}, ' - f'{{ autoAlpha: 1, duration: {outro_fade}, ease: "power2.in", immediateRender: false }}, {outro_start});' + f'{{ autoAlpha: 1, duration: {outro_fade}, ease: "power2.in", immediateRender: false }}, {outro_start}); // anchor-exempt: bookend fade, relative to the composition boundary' ) # ---- head ---- diff --git a/packages/producer/tests/spanish-empire-cdn-inline/output/compiled.html b/packages/producer/tests/spanish-empire-cdn-inline/output/compiled.html index 5dc8f51004..51c6f24c7e 100644 --- a/packages/producer/tests/spanish-empire-cdn-inline/output/compiled.html +++ b/packages/producer/tests/spanish-empire-cdn-inline/output/compiled.html @@ -1,1644 +1,3 @@ - - - - - -The Rise and Reach of the Spanish Empire - - -
- - -
- - -
-
-
- - - - - -
-
-

CIRCA 1492 — 1821

-

At one point in history…

-

one empire connected almost the entire world.

-
-
-
- - -
-
-
-
1492
- - -
- -
ATLANTIC CROSSING
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -

CRUZ DE BORGOÑA

-
- - -
-
SPAIN
-
CARIBBEAN
-
AMERICAS
-
- -
-

THE DISCOVERY ERA

-

It began in the late 15th century,

-

when Spain funded voyages across unknown oceans.

-
-
-
- - -
-
-
EXPANSIÓN
- - -
-
South America
-
Central America
-
Philippines
-
Parts of Europe
-
& Beyond
-
-
-

RAPID EXPANSION

-

Within decades, Spain controlled

-

vast lands across the Americas, Europe, Asia, and beyond.

-
-
-
- - -
-
-
-
ORO
- - -
- - - - - - - - - - - - - - - - - - -
- - -
-
-
-
-
-
-
-
-
-
- - -
-
GOLD RESERVES
91%
-
SILVER OUTPUT
84%
-
GLOBAL TRADE
76%
-
- -
-

POWER & WEALTH

-

Gold and silver flowed into Spain,

-

making it one of the richest and most powerful empires in history.

-
-
-
- - -
-
-
CULTURA
-
-
-
- -
-

Architecture

-

Baroque cathedrals and colonial cities rose across two continents

-
-
-
- Aa -
-

Language

-

Spanish became one of Earth's most spoken languages — 500M+ today

-
-
-
- -
-

Religion

-

Catholic faith spread through missions across the Americas and Asia

-
-
-
-

CULTURAL LEGACY

-

Its influence shaped languages,

-

cultures, and religions across continents.

-
-
-
- - -
-
-
-
CRISIS
-
-
-
- - - - - - - - - -
-
Armed Conflicts
-
Colonial Resistance
-
Economic Strain
-
-
-

THE CHALLENGES

-

But power came at a cost—

-

conflicts, resistance, and economic strain began to weaken its dominance.

-
-
-
- - -
-
-
DECLIVE
- -
- -
-
-
-
1810Mexico rises
-
1816Argentina free
-
1821Peru & Central America
-
1898Cuba, Philippines lost
-
-
-

THE LONG DECLINE

-

Over time, colonies gained independence,

-

and the empire slowly dissolved.

-
-
-
- - -
-
- - - - -
- -
-
-
-

LASTING LEGACY

-

But its legacy…

-

still shapes the world today.

-
-
-
-
- - -
-
-
-
- - - - - - -
-
-

THE STORY OF

-

THE SPANISH
EMPIRE

-
-

1492 – 1898

-
-
-
-
- -
- - - - - - - - - - - - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:2c73953f6b8e45580e7fcad6e14655fa1392f13dc7df9fbaf16e294ce7231093 +size 2014653 diff --git a/packages/producer/tests/style-1-prod/output/compiled.html b/packages/producer/tests/style-1-prod/output/compiled.html index eb92470e17..5c0d03c02b 100644 --- a/packages/producer/tests/style-1-prod/output/compiled.html +++ b/packages/producer/tests/style-1-prod/output/compiled.html @@ -1,1263 +1,3 @@ - - - - - - Geometric Bold - Ikko Tanaka Style - - - - -
- - - -
- -
- - -
- -
-
-
ASKED & ANSWERED
-
- - -
-
-
47%
-
NEED MOTION
-
- - -
-
-
62%
-
INEFFECTIVE
-
-
- - -
-
-
75%
-
LACK SKILLS
-
- - -
-
-
EDITOR AGENT
-
- - - - -
- - -
-
- - - - -
- - - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:65fc299ed8210a04e340de40ca721bb495cc8cf4700c6c71444cd0cfc2bb704c +size 338867 diff --git a/packages/producer/tests/style-10-prod/output/compiled.html b/packages/producer/tests/style-10-prod/output/compiled.html index 1f74cc85f3..455406c665 100644 --- a/packages/producer/tests/style-10-prod/output/compiled.html +++ b/packages/producer/tests/style-10-prod/output/compiled.html @@ -1,896 +1,3 @@ - - - - - - - Ahn Sang-soo Play Mode Video - - - - - - - -
- -
- -
-
- - -
- -
- - - - - - -
- - -
- -
-
-
-
47%
-
NEEDED
MOTION
GRAPHICS
-
-
-
- - -
-
-
-
62%
-
-
ATTENTION LOSS
-
-
-
-
- - -
-
-
-
75%
-
SKILL
GAP
-
-
-
- - -
-
-
-
EDITOR AGENT
-
-
-
- - - - - - -
- - -
-
-
-
- - - - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:144019900e1c02039542aac16c21f0d9631a8f722256d6566584be0818fffd1a +size 96072 diff --git a/packages/producer/tests/style-11-prod/output/compiled.html b/packages/producer/tests/style-11-prod/output/compiled.html index 624db690e3..b4f5154d50 100644 --- a/packages/producer/tests/style-11-prod/output/compiled.html +++ b/packages/producer/tests/style-11-prod/output/compiled.html @@ -1,2083 +1,3 @@ - - - - - - Editor Agent - Sol LeWitt Style - - - - -
-
-
-
-
- - - - -
- -
-
- Editor Agent - Portrait System -
- -
- Survey Cut - 13.88s -
-
- -
-
-
Editor Agent / Survey System
- - - - - - - - - - - - - - - - - - - - - - - - - - -
-
Need motion
-
47%
-
Asked for motion graphics
-
Sharper pacing, clearer transitions, more visual energy.
-
- -
-
Attention drop
-
62%
-
Were stuck with static content
-
The message was right. The cut was not landing.
-
- -
-
Execution gap
-
75%
-
Knew the look, needed the edit
-
- The direction was clear. The hands-on workflow was the bottleneck. -
-
-
- - - - -
- -
-
-
Narration
-
-
- - - - -
- - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:8b7ab3a2dd0adbcdfe61b5548980f533494058bafcb6d8628706dc0c1198e212 +size 679957 diff --git a/packages/producer/tests/style-12-prod/output/compiled.html b/packages/producer/tests/style-12-prod/output/compiled.html index aa64d9f9f4..a36d09ce30 100644 --- a/packages/producer/tests/style-12-prod/output/compiled.html +++ b/packages/producer/tests/style-12-prod/output/compiled.html @@ -1,1568 +1,3 @@ - - - - - - Editor Agent - De Stijl Edition - - - - -
- -
-
-
-
-
-
-
-
- -
-
-
-
-
- - - - -
- - -
- -
- - -
-
-
-
-
47%
-
-
-
-
- -
-
-
62%
-
-
-
-
-
- -
-
-
3/4
-
-
-
-
-
- - - - -
- - -
-
-
Editor Agent
-
-
- - - - -
- - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:64f7d70c1adf6e7fa985962c8ebec4f94a36134b3d3efea59be39e709787fbe5 +size 415598 diff --git a/packages/producer/tests/style-13-prod/output/compiled.html b/packages/producer/tests/style-13-prod/output/compiled.html index 8ac715c9a8..138b430299 100644 --- a/packages/producer/tests/style-13-prod/output/compiled.html +++ b/packages/producer/tests/style-13-prod/output/compiled.html @@ -1,1557 +1,3 @@ - - - - - - Editor Agent - Wim Crouwel Style - - - - -
- -
-
- -
- - -
-
- - -
-
- - - - -
- - - - - -
-
- -
-
-
-
Need Motion Graphics
-
-
-
- - -
-
-
-
Static content reduces engagement
-
-
-
- - -
-
-
-
LACK TECHNICAL SKILLS
-
-
-
-
- - - - -
- - -
-
- - - - -
- - -
-
-
-
-
-
-
-
-
-
-
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:9a2c111d5c8e3bfd998e10dfc40e28d305638f032ae6d85248d6132d133fdacf +size 197335 diff --git a/packages/producer/tests/style-15-prod/output/compiled.html b/packages/producer/tests/style-15-prod/output/compiled.html index 7926829bc4..3fdeae1a1c 100644 --- a/packages/producer/tests/style-15-prod/output/compiled.html +++ b/packages/producer/tests/style-15-prod/output/compiled.html @@ -1,2957 +1,3 @@ - - - - - - Jan Tschichold Typography Video - - - - -
- -
-
- - -
- -
-
-
- - -
-
-
-
- - -
- - - - -
- - -
- -
-
-
-
-
-
-
-
-
-
- - -
-
- -
- -
-
-
- - - - -
- - -
-
-
-
-
-
- -
-
-
75%
-
(3 out of 4)
-
- -
-
LACK
-
THE ESSENTIAL
-
SKILLS
-
- -
-
-
-
-
-
- - - - -
- - -
-
- -
-
-
-
-
-
- - -
-
-
- - - - -
- - -
-
- -
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:1c4b525bacb707b8eeeed1e92ce222ef2f8b05240541b825b1f682814616d11e +size 586589 diff --git a/packages/producer/tests/style-16-prod/output/compiled.html b/packages/producer/tests/style-16-prod/output/compiled.html index cfad1e3ad8..365071c43c 100644 --- a/packages/producer/tests/style-16-prod/output/compiled.html +++ b/packages/producer/tests/style-16-prod/output/compiled.html @@ -1,1477 +1,3 @@ - - - - - - Editor Agent Video - - - - -
- -
- -
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
-
-
Survey signal
-
47%
-
OF YOU NEED
MOTION GRAPHICS
-
-
- - -
-
-
-
-
-
Engagement drop
-
62%
-
SAID STATIC CONTENT
REDUCES ENGAGEMENT
-
-
- - - - -
- - -
- -
- - -
-
-
Narration
-
-
- - - - -
- - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:f68e0405c67beba4f294fc35059cbb87e303df6877de3afca0942dfaf23ed92b +size 354093 diff --git a/packages/producer/tests/style-17-prod/output/compiled.html b/packages/producer/tests/style-17-prod/output/compiled.html index eea3c61d86..f5cbb6280e 100644 --- a/packages/producer/tests/style-17-prod/output/compiled.html +++ b/packages/producer/tests/style-17-prod/output/compiled.html @@ -1,1625 +1,3 @@ - - - - - - Editor Agent - Saul Bass Style - - - - -
- -
-
- -
-
-
- - -
- - - - - -
- - -
-
E
-
D
-
I
-
T
-
O
-
R
-
-
A
-
G
-
E
-
N
-
T
-
- - -
- - - -
-
- - - -
-
- - - - - - - - - - - -
- - - - - -
-
-
-
- -
-
-
-
6
-
2
-
%
-
-
-
STATIC CONTENT
-
COSTING YOU ATTENTION
-
-
-
- -
-
- - - - -
- - -
-
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:2e67a41fe4a0e9c9f7b7a33441046d5da6452a2ee69dcdea6789be0395d8b393 +size 143501 diff --git a/packages/producer/tests/style-18-prod/output/compiled.html b/packages/producer/tests/style-18-prod/output/compiled.html index af501279fe..d774975f4a 100644 --- a/packages/producer/tests/style-18-prod/output/compiled.html +++ b/packages/producer/tests/style-18-prod/output/compiled.html @@ -1,1994 +1,3 @@ - - - - - Editor Agent - Agnes Martin Style - - - - -
- -
-
- -
-
- - -
- -
- - -
- -
-
- - - - -
- - - -
- -
- - -
-
- -
-
-
-
-
-
- - -
-
47%
-
needed motion graphics
-
- - -
-
62%
-
static content reduces engagement
-
- - -
-
75%
-
lack technical skills
-
-
- - - - -
- - -
-
- -
- - - - -
- - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:52ce70637c3af64665191c72584b525f0acc79ae24a46b7d0b4c541277dd790a +size 2223522 diff --git a/packages/producer/tests/style-2-prod/output/compiled.html b/packages/producer/tests/style-2-prod/output/compiled.html index bc9f12615b..4fe4b7a2fa 100644 --- a/packages/producer/tests/style-2-prod/output/compiled.html +++ b/packages/producer/tests/style-2-prod/output/compiled.html @@ -1,1585 +1,3 @@ - - - - - - Swiss Grid Video - - - - -
-
2026
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - -
- -
- - -
-
-
-
-

SURVEY FINDINGS

-

CONTENT CREATION 2026

-
-
- - - - - - -
- -
- -
-
47%
-
-
MOTION GRAPHICS
-
- - -
-
62%
-
-
STATIC CONTENT
-
- - -
-
75%
-
-
EDITING SKILLS
-
- - - - - - - - - -
- -
-
-
- -
-
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:d0ccea5e8ec0b3b8d9a57aa128d1c0a03493d48fd344f54c52912378b1d0379e +size 550623 diff --git a/packages/producer/tests/style-3-prod/output/compiled.html b/packages/producer/tests/style-3-prod/output/compiled.html index b192df03a4..99e9d9ba70 100644 --- a/packages/producer/tests/style-3-prod/output/compiled.html +++ b/packages/producer/tests/style-3-prod/output/compiled.html @@ -1,1615 +1,3 @@ - - - - - - Swiss Grid - Editor Agent - - - - -
- - Grid - - -
- -
- - -
-
-
-
-

EDITOR AGENT

-

THE SURVEY FINDINGS

-
-
- - - - -
- - -
-
- -
-
47%
-
NEED MOTION GRAPHICS
-
- - -
-
62%
-
LOSING ATTENTION
-
-
-
-
- - -
-
3 OF 4
-
LACK EDITING SKILLS
-
-
-
-
- -
-
-
- - - - - -
- - -
-
- - - - -
- - - - - - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:a045c5849bbd56c5d0c36ebde9f725ec5d8ac7c8cae9eb1329736cef1cf8f651 +size 540633 diff --git a/packages/producer/tests/style-4-prod/output/compiled.html b/packages/producer/tests/style-4-prod/output/compiled.html index 49bc500d21..c8ad91114c 100644 --- a/packages/producer/tests/style-4-prod/output/compiled.html +++ b/packages/producer/tests/style-4-prod/output/compiled.html @@ -1,1824 +1,3 @@ - - - - - - Warm Grain - Editor Agent - - - - -
- -
-
- -
- - - - - -
-
-
-

Editor Agent

-

Design simplified.

-
-
- - - - -
- -
- -
-
-
47%
-
Need Motion Graphics
-
-
- - -
-
62%
-
- - -
-
- - - -
-
Editing Skills
-
- - - - -
- -
-
-
- -
-
- - - - -
- - - - - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:0095619faa1b1cb509fa06b6a51635eb3431e0a4235b421de816ae5e9aaab945 +size 1624099 diff --git a/packages/producer/tests/style-5-prod/output/compiled.html b/packages/producer/tests/style-5-prod/output/compiled.html index 06b75d5453..f33d475344 100644 --- a/packages/producer/tests/style-5-prod/output/compiled.html +++ b/packages/producer/tests/style-5-prod/output/compiled.html @@ -1,2098 +1,3 @@ - - - - - - Digital Grid — Wim Crouwel Style - - - - -
- -
-
-
-
-
- - - - -
- - -
-
-
-
-
- - - - -
- - -
-
- -
-
47% NEED MOTION GRAPHICS
-
-
-
-
-
00%
-
- - -
-
62% LOSE ATTENTION
-
-
-
STATIC
-
-
-
-
MOTION
-
00%
-
-
-
-
- - -
-
75% LACK SKILLS
-
-
- - - - -
-
00%
-
-
-
- - - - -
- - - - - -
-
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:5c3e2515a24714b2fc5ba5aae6b862b56d9984fb49ac38c98a400c3920c95e28 +size 304747 diff --git a/packages/producer/tests/style-6-prod/output/compiled.html b/packages/producer/tests/style-6-prod/output/compiled.html index a55472032c..5aab67e26e 100644 --- a/packages/producer/tests/style-6-prod/output/compiled.html +++ b/packages/producer/tests/style-6-prod/output/compiled.html @@ -1,827 +1,3 @@ - - - - - - - Athletic Bold — Sport Broadcast - - - - - - -
- - - - -
-
- -
- - -
-
WE ASKED
-
WHAT YOU
-
NEEDED.
-
-
-
- - -
- -
-
-
-
-
- - -
-
-
-
- - -
-
47%
-
NEED MOTION GRAPHICS
-
-
- - -
-
62%
-
STATIC LOSES ATTENTION
-
-
- - -
-
- 3 - OUT OF - 4 -
-
LACK SKILLS
-
-
- - -
-
-
-
EDITOR
-
AGENT
-
-
-
-
- - -
-
-
-
-
- - - -
- - - +version https://git-lfs.github.com/spec/v1 +oid sha256:30dd2560ce2521d7f66ae8113389ed4152190392f79ec4a3757d610045008e74 +size 71112 diff --git a/packages/producer/tests/style-7-prod/output/compiled.html b/packages/producer/tests/style-7-prod/output/compiled.html index 14ab26c7c7..7eed5bef27 100644 --- a/packages/producer/tests/style-7-prod/output/compiled.html +++ b/packages/producer/tests/style-7-prod/output/compiled.html @@ -1,2110 +1,3 @@ - - - - - - Editor Agent - Velvet Standard - - - - -
- -
-
-
EDITOR AGENT
-
-
- - - - -
- - -
- - - - -
-
-
-
-
47%
-
MOTION GRAPHICS
-
-
-
-
-
-
62%
-
STATIC CONTENT
-
-
-
-
-
-
75%
-
LACK SKILLS
-
-
-
- - - - -
- - -
-
-
-
-
-
-
- - - - -
- - - -
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:b5a2d2f72081ddd2e650a49427d55cb47b142101903bf13f29fba381ca10ffdb +size 3318885 diff --git a/packages/producer/tests/style-8-prod/output/compiled.html b/packages/producer/tests/style-8-prod/output/compiled.html index eb59570bd3..bd55c8d535 100644 --- a/packages/producer/tests/style-8-prod/output/compiled.html +++ b/packages/producer/tests/style-8-prod/output/compiled.html @@ -1,1706 +1,3 @@ - - - - - - Editor Agent - Henryk Tomaszewski Style - - - - - -
- -
- -
-
-
-
-
- - -
- -
- - -
-
47%
-
62%
-
75%
-
- - - - -
- - -
-
-
-
-

EDITOR AGENT

-
- - - - -
- - -
-
-
WE ASKED WHAT YOU NEEDED.
-
FORTY-SEVEN PERCENT OF YOU SAID
-
MOTION GRAPHICS.
-
SIXTY-TWO PERCENT SAID STATIC
-
CONTENT WAS COSTING YOU ATTENTION,
-
AND THREE OUT OF FOUR
-
SAID YOU KNOW THE LOOK
-
YOU WANT BUT DON'T HAVE
-
THE EDITING SKILLS TO GET
-
THERE.
-
SO WE BUILT
-
EDITOR AGENT
-
- - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:5274f601aa8c0e4692651b834d9a8937d57a0615381793a2c9f057e355c061de +size 1268028 diff --git a/packages/producer/tests/style-9-prod/output/compiled.html b/packages/producer/tests/style-9-prod/output/compiled.html index f0482cbda7..6e662da1b6 100644 --- a/packages/producer/tests/style-9-prod/output/compiled.html +++ b/packages/producer/tests/style-9-prod/output/compiled.html @@ -1,1658 +1,3 @@ - - - - - - Editor Agent - Play Mode - - - - - -
- -
-
- - -
- - -
-
- -
- - -
- - -
-
-

EDITOR AGENT

-
- - - - -
-
-
- - - - -
-
-
- -
-
-
-
-
47%
-
NEED MOTION GRAPHICS
-
-
- -
-
-
- - -
-
-
-
-
62%
-
STRUGGLE WITH STATIC CONTENT
-
-
- -
-
-
- - -
-
-
-
-
75%
-
LACK EDITING SKILLS
-
-
- -
-
-
-
- - - - -
- - - - - - - - - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:a2a3b624c8a32c0f7e1a3bcbea2659e8b0746c5d9d7350389ea757f45c8dc42a +size 198420 diff --git a/packages/producer/tests/sub-comp-class-selector/output/compiled.html b/packages/producer/tests/sub-comp-class-selector/output/compiled.html index 00d8970b2c..26f1e326eb 100644 --- a/packages/producer/tests/sub-comp-class-selector/output/compiled.html +++ b/packages/producer/tests/sub-comp-class-selector/output/compiled.html @@ -1,380 +1,3 @@ - - - - - - - - -
-
-
ISSUE 1847 REPRO
- - - - - -
-
- - - +version https://git-lfs.github.com/spec/v1 +oid sha256:63c24baa7a64c36982d724fc9ff2534a5ab7a565f3c71dfcc074248c568aa375 +size 169109 diff --git a/packages/producer/tests/sub-comp-height-percent/output/compiled.html b/packages/producer/tests/sub-comp-height-percent/output/compiled.html index e46ba029aa..c162b49c2d 100644 --- a/packages/producer/tests/sub-comp-height-percent/output/compiled.html +++ b/packages/producer/tests/sub-comp-height-percent/output/compiled.html @@ -1,368 +1,3 @@ - - - - - - - - -
-
- - -
-
-
- Centered -
-
-
- - - -
-
- - - +version https://git-lfs.github.com/spec/v1 +oid sha256:34960ab8bae7104cdff36d8c576c812401bc6310d287dedf236518dc88fefc03 +size 86426 diff --git a/packages/producer/tests/sub-comp-id-selector/output/compiled.html b/packages/producer/tests/sub-comp-id-selector/output/compiled.html index 3e08c487cf..7dff85de9e 100644 --- a/packages/producer/tests/sub-comp-id-selector/output/compiled.html +++ b/packages/producer/tests/sub-comp-id-selector/output/compiled.html @@ -1,389 +1,3 @@ - - - - - - - - -
-
-
- HELLO WORLD -
- - - -
-
- - - +version https://git-lfs.github.com/spec/v1 +oid sha256:5ce74947905322a2b3ffb1041067666bd93173d4e074f8f5323bc97c4521e7fb +size 174004 diff --git a/packages/producer/tests/sub-comp-t0/output/compiled.html b/packages/producer/tests/sub-comp-t0/output/compiled.html index 4e042ff02f..5594e3c636 100644 --- a/packages/producer/tests/sub-comp-t0/output/compiled.html +++ b/packages/producer/tests/sub-comp-t0/output/compiled.html @@ -1,805 +1,3 @@ - - - - - - - - - -
- -
-
-
BREAKING
-
Transfer confirmed
- - - - - -
- - -
-
-
Second Scene
- - - - - -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:74854a44116e6d0869888793b19cf3843eca78853649dfaf47efc57a8b346ba0 +size 284855 diff --git a/packages/producer/tests/sub-composition-video/output/compiled.html b/packages/producer/tests/sub-composition-video/output/compiled.html index 8702b32eea..d3a2d96045 100644 --- a/packages/producer/tests/sub-composition-video/output/compiled.html +++ b/packages/producer/tests/sub-composition-video/output/compiled.html @@ -1,687 +1,3 @@ - - - - - - Polaroid Speaker - - - - -
- - - - -
- -
- -
- -
- -
- -
-
-
-
-
- - - - -
- - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:54940f7e4f70f0e678127fd1824821c21ea2c28abb56879674cdd36b795b2327 +size 1084645 diff --git a/packages/producer/tests/timed-descendant-visibility/output/compiled.html b/packages/producer/tests/timed-descendant-visibility/output/compiled.html index fdb726ec35..3ef2f2e196 100644 --- a/packages/producer/tests/timed-descendant-visibility/output/compiled.html +++ b/packages/producer/tests/timed-descendant-visibility/output/compiled.html @@ -1,109 +1,3 @@ - - - - - - - - -
-
-
-
-
-
-
-
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:93e349ab3cf09c15b5289d73bf5276a223e45a00463cafc634e3be1cca116377 +size 2515 diff --git a/packages/producer/tests/typegpu-adapter/output/compiled.html b/packages/producer/tests/typegpu-adapter/output/compiled.html index 51a752fa3c..6fb717700e 100644 --- a/packages/producer/tests/typegpu-adapter/output/compiled.html +++ b/packages/producer/tests/typegpu-adapter/output/compiled.html @@ -1,659 +1,3 @@ - - - - - - -
- - -
TypeGPU adapter test
-
WebGPU is seekable.
-
GPU rendering works.
- - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:e834e9b27dc50157bb96bf90bbe7b8d29e344c2104462ba2d45d5595e0ff30b8 +size 2565576 diff --git a/packages/producer/tests/variables-prod/output/compiled.html b/packages/producer/tests/variables-prod/output/compiled.html index 6d7acf5b2c..e3001110a1 100644 --- a/packages/producer/tests/variables-prod/output/compiled.html +++ b/packages/producer/tests/variables-prod/output/compiled.html @@ -1,137 +1,3 @@ - - - - - - - - - -
- -

-

-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:5ebed76383e8c88a0b7c0c5528514247ccab3b4b65c71b1b560348aafa957604 +size 268563 diff --git a/packages/producer/tests/vfr-screen-recording/output/compiled.html b/packages/producer/tests/vfr-screen-recording/output/compiled.html index b65d17e535..9f3df193fc 100644 --- a/packages/producer/tests/vfr-screen-recording/output/compiled.html +++ b/packages/producer/tests/vfr-screen-recording/output/compiled.html @@ -1,72 +1,3 @@ - - - - - VFR Screen Recording Regression - - - -
- - -
VFR
-
- - - +version https://git-lfs.github.com/spec/v1 +oid sha256:29936b277efcbd6cd934e5911801e63403cb10a6da5404b2be5c5e7ce5d322f0 +size 89971 diff --git a/packages/producer/tests/video-hfid-no-id/output/compiled.html b/packages/producer/tests/video-hfid-no-id/output/compiled.html index d5dfc46901..a135ad97c2 100644 --- a/packages/producer/tests/video-hfid-no-id/output/compiled.html +++ b/packages/producer/tests/video-hfid-no-id/output/compiled.html @@ -1,61 +1,3 @@ - - - - - - - - - -
- - - -
- FOOTAGE -
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:d521b87458369854de7f54f5a7cc20c58797f8bb88e1247e30091fbab97de3d2 +size 75060 diff --git a/packages/producer/tests/vignelli-stacking/output/compiled.html b/packages/producer/tests/vignelli-stacking/output/compiled.html index 61337f2214..9361aff858 100644 --- a/packages/producer/tests/vignelli-stacking/output/compiled.html +++ b/packages/producer/tests/vignelli-stacking/output/compiled.html @@ -1,487 +1,3 @@ - - - - - - - Vignelli Style Video - - - - - -
-
- -
- -
-
-
-
PRUEBA
-
-
- -
-
-
GRABAR
CONTENIDO
-
-
- -
-
-
-
SER YO
MISMA
-
-
-
- -
-
-
-
- - - - +version https://git-lfs.github.com/spec/v1 +oid sha256:2b211f4cb757ba7c392c16eb1bfa58d8aebd7d704ffacc5a43fe36e021e7006e +size 301676 diff --git a/packages/producer/tests/webgl-video-texture-render-compat/output/compiled.html b/packages/producer/tests/webgl-video-texture-render-compat/output/compiled.html index e2d424c515..d008bcd9eb 100644 --- a/packages/producer/tests/webgl-video-texture-render-compat/output/compiled.html +++ b/packages/producer/tests/webgl-video-texture-render-compat/output/compiled.html @@ -1,106 +1,3 @@ - - - - - - -
- - - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:253e2b94f1babe8290f5f1c20e51c0d79d8b21cf1af4fecfa6a0d22733d9298d +size 4110 diff --git a/packages/producer/tests/webm-transparency/output/compiled.html b/packages/producer/tests/webm-transparency/output/compiled.html index e44e07d656..d64460622d 100644 --- a/packages/producer/tests/webm-transparency/output/compiled.html +++ b/packages/producer/tests/webm-transparency/output/compiled.html @@ -1,578 +1,3 @@ - - - - - - - -
- -
- - -
Overlay Test
- - - -
- - +version https://git-lfs.github.com/spec/v1 +oid sha256:0a58f6769219ee42b16805f01f00fb0958f4d1402e3c2fd82b19273eed14c4e5 +size 2562420