[{"data":1,"prerenderedAt":1614},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler":1581,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler":1590,"children:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler":1595,"related:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler":1596},{"id":4,"title":5,"body":6,"dateModified":1546,"datePublished":1546,"description":1547,"extension":1548,"faq":1549,"keyword":1558,"kind":1559,"meta":1560,"navigation":278,"path":1569,"seo":1570,"slug":1573,"stem":1574,"topics":1575,"type":1579,"__hash__":1580},"docs\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler\u002Findex.md","Run Excel COM Automation from Task Scheduler Without a Logged-In User",{"type":7,"value":8,"toc":1534},"minimark",[9,29,188,193,196,231,234,238,245,252,444,457,461,464,594,616,758,762,769,1104,1119,1123,1126,1307,1322,1404,1408,1411,1422,1426,1459,1463,1469,1473,1479,1485,1491,1497,1501,1530],[10,11,12,13,17,18,22,23,28],"p",{},"A script that opens Excel through pywin32 runs perfectly when you start it from a terminal. Scheduled with ",[14,15,16],"em",{},"Run whether user is logged on or not",", it fails with a cryptic COM error, writes nothing, or — worst — never finishes, leaving an invisible ",[19,20,21],"code",{},"EXCEL.EXE"," running until someone reboots the machine. Nothing is wrong with the code. Excel is an interactive desktop application, and a scheduled task running with nobody logged on does not give it the environment it expects. This guide, part of ",[24,25,27],"a",{"href":26},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002F","Automating Excel with COM and pywin32",", explains the causes, the configurations that work, and how to make the job robust — or remove Excel from it.",[30,31,39,40,39,44,39,48,39,56,39,66,39,77,39,84,39,91,39,97,39,104,39,108,39,113,39,117,39,122,39,126,39,131,39,136,39,143,39,148,39,152,39,156,39,162,39,165,39,170,39,173,39,178,39,181],"svg",{"viewBox":32,"role":33,"ariaLabelledBy":34,"xmlns":37,"style":38},"4 0 752 233","img",[35,36],"ts-sessions-t","ts-sessions-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[41,42,43],"title",{"id":35},"The same script in an interactive session and in a scheduled background session",[45,46,47],"desc",{"id":36},"Run by hand, the script executes in the user's interactive session with a desktop, a loaded profile and a place to show dialogs, and Excel works. Run by Task Scheduler with nobody logged on, it executes in a non-interactive session without a normal desktop or profile, where Excel can fail to open or save files and dialogs appear where nobody can see them.",[49,50],"rect",{"x":51,"y":52,"width":53,"height":54,"fill":55},"4","0","752","233","#ffffff",[49,57],{"x":58,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"20.0","16.0","351.0","201.0","14","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[67,68,70],"g",{"transform":69},"translate(182.5,29.0) scale(1.083)",[71,72],"path",{"d":73,"fill":74,"stroke":75,"style":76},"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M4 21c0-4 3.6-7 8-7s8 3 8 7","none","var(--teal-ink,#0b6157)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[78,79,83],"text",{"x":80,"y":81,"style":82},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Run by hand",[85,86],"line",{"x1":87,"y1":88,"x2":89,"y2":88,"stroke":64,"style":90},"36.0","91.0","355.0","stroke-width:1px",[78,92,96],{"x":93,"y":94,"style":95},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","interactive desktop",[67,98,100],{"transform":99},"translate(38.5,99.5) scale(0.625)",[71,101],{"d":102,"fill":74,"stroke":64,"style":103},"M5 12.5l4.5 4.5L19 7","stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[78,105,107],{"x":93,"y":106,"style":95},"137.0","user profile loaded",[67,109,111],{"transform":110},"translate(38.5,125.5) scale(0.625)",[71,112],{"d":102,"fill":74,"stroke":64,"style":103},[78,114,116],{"x":93,"y":115,"style":95},"163.0","dialogs can be answered",[67,118,120],{"transform":119},"translate(38.5,151.5) scale(0.625)",[71,121],{"d":102,"fill":74,"stroke":64,"style":103},[78,123,125],{"x":93,"y":124,"style":95},"189.0","Excel behaves normally",[67,127,129],{"transform":128},"translate(38.5,177.5) scale(0.625)",[71,130],{"d":102,"fill":74,"stroke":64,"style":103},[49,132],{"x":133,"y":59,"width":60,"height":61,"rx":62,"fill":134,"stroke":135,"style":65},"389.0","#fee8f2","var(--accent,#f43f8f)",[67,137,139],{"transform":138},"translate(551.5,29.0) scale(1.083)",[71,140],{"d":141,"fill":74,"stroke":142,"style":76},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2","var(--accent-ink,#be185d)",[78,144,147],{"x":145,"y":81,"style":146},"564.5","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Scheduled, nobody logged on",[85,149],{"x1":150,"y1":88,"x2":151,"y2":88,"stroke":135,"style":90},"405.0","724.0",[78,153,155],{"x":154,"y":94,"style":95},"429.0","non-interactive session",[67,157,159],{"transform":158},"translate(407.5,99.5) scale(0.625)",[71,160],{"d":161,"fill":74,"stroke":135,"style":103},"M6 6l12 12 M18 6L6 18",[78,163,164],{"x":154,"y":106,"style":95},"no normal desktop folder",[67,166,168],{"transform":167},"translate(407.5,125.5) scale(0.625)",[71,169],{"d":161,"fill":74,"stroke":135,"style":103},[78,171,172],{"x":154,"y":115,"style":95},"invisible dialogs block forever",[67,174,176],{"transform":175},"translate(407.5,151.5) scale(0.625)",[71,177],{"d":161,"fill":74,"stroke":135,"style":103},[78,179,180],{"x":154,"y":124,"style":95},"COM errors or silent hangs",[67,182,184],{"transform":183},"translate(407.5,177.5) scale(0.625)",[71,185],{"d":186,"fill":74,"stroke":187,"style":103},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)",[189,190,192],"h2",{"id":191},"what-actually-goes-wrong","What actually goes wrong",[10,194,195],{},"Three separate things break, and a failing job usually hits more than one:",[197,198,199,207,225],"ol",{},[200,201,202,206],"li",{},[203,204,205],"strong",{},"No interactive desktop."," A task set to run whether the user is logged on or not runs in a non-interactive session. Excel starts, but anything that assumes a visible desktop — dialogs, some add-ins, printing — misbehaves.",[200,208,209,212,213,216,217,220,221,224],{},[203,210,211],{},"Missing profile folders."," Under system or service-like accounts, Excel looks for a Desktop folder in the system profile that does not exist, and opening or saving files fails. The classic symptom is ",[19,214,215],{},"Workbooks.Open"," returning ",[19,218,219],{},"None"," or ",[19,222,223],{},"SaveAs"," raising a COM error that says the file cannot be accessed.",[200,226,227,230],{},[203,228,229],{},"Dialogs nobody can see."," A \"file is locked\", \"update links?\" or \"repair this file?\" prompt appears in a session with no screen. Excel waits for an answer that never comes, and the job hangs.",[10,232,233],{},"Microsoft's own guidance is that Office applications are not supported for unattended server-side automation, precisely because of issues like these. The configurations below make it work in practice; they do not make it supported.",[189,235,237],{"id":236},"option-1-run-the-task-only-when-the-user-is-logged-on","Option 1 — Run the task only when the user is logged on",[10,239,240,241,244],{},"The most reliable way to drive Excel on a schedule is to give it the environment it was designed for. In the task's properties, choose ",[203,242,243],{},"Run only when user is logged on",", and use an account that stays logged in on that machine — typically a dedicated automation account on a dedicated machine or virtual desktop, with the screen locked rather than signed out. Excel then runs in a real interactive session, exactly as when you tested by hand.",[10,246,247,248,251],{},"The task definition can be created from Python with ",[19,249,250],{},"schtasks",", which keeps the setup reproducible:",[253,254,259],"pre",{"className":255,"code":256,"language":257,"meta":258,"style":258},"language-python shiki shiki-themes github-light github-dark-high-contrast","import subprocess\n\nsubprocess.run([\n    \"schtasks\", \"\u002FCreate\", \"\u002FTN\", \"Reports\\\\RefreshSalesWorkbook\",\n    \"\u002FTR\", r'\"C:\\reports\\.venv\\Scripts\\python.exe\" \"C:\\reports\\refresh.py\"',\n    \"\u002FSC\", \"DAILY\", \"\u002FST\", \"06:00\",\n    \"\u002FIT\",                      # interactive: run only when the user is logged on\n    \"\u002FF\",\n], check=True)\n","python","",[19,260,261,273,280,286,319,381,404,417,425],{"__ignoreMap":258},[262,263,265,269],"span",{"class":85,"line":264},1,[262,266,268],{"class":267},"s-kum","import",[262,270,272],{"class":271},"skGVy"," subprocess\n",[262,274,276],{"class":85,"line":275},2,[262,277,279],{"emptyLinePlaceholder":278},true,"\n",[262,281,283],{"class":85,"line":282},3,[262,284,285],{"class":271},"subprocess.run([\n",[262,287,289,293,296,299,301,304,306,309,313,316],{"class":85,"line":288},4,[262,290,292],{"class":291},"srMev","    \"schtasks\"",[262,294,295],{"class":271},", ",[262,297,298],{"class":291},"\"\u002FCreate\"",[262,300,295],{"class":271},[262,302,303],{"class":291},"\"\u002FTN\"",[262,305,295],{"class":271},[262,307,308],{"class":291},"\"Reports",[262,310,312],{"class":311},"sSjpA","\\\\",[262,314,315],{"class":291},"RefreshSalesWorkbook\"",[262,317,318],{"class":271},",\n",[262,320,322,325,327,330,333,337,340,343,346,350,353,356,359,362,365,367,369,371,374,376,379],{"class":85,"line":321},5,[262,323,324],{"class":291},"    \"\u002FTR\"",[262,326,295],{"class":271},[262,328,329],{"class":267},"r",[262,331,332],{"class":291},"'\"C:",[262,334,336],{"class":335},"s_b0D","\\r",[262,338,339],{"class":291},"eports",[262,341,342],{"class":335},"\\.",[262,344,345],{"class":291},"venv",[262,347,349],{"class":348},"sP0c6","\\S",[262,351,352],{"class":291},"cripts",[262,354,355],{"class":335},"\\p",[262,357,358],{"class":291},"ython",[262,360,361],{"class":348},".",[262,363,364],{"class":291},"exe\" \"C:",[262,366,336],{"class":335},[262,368,339],{"class":291},[262,370,336],{"class":335},[262,372,373],{"class":291},"efresh",[262,375,361],{"class":348},[262,377,378],{"class":291},"py\"'",[262,380,318],{"class":271},[262,382,384,387,389,392,394,397,399,402],{"class":85,"line":383},6,[262,385,386],{"class":291},"    \"\u002FSC\"",[262,388,295],{"class":271},[262,390,391],{"class":291},"\"DAILY\"",[262,393,295],{"class":271},[262,395,396],{"class":291},"\"\u002FST\"",[262,398,295],{"class":271},[262,400,401],{"class":291},"\"06:00\"",[262,403,318],{"class":271},[262,405,407,410,413],{"class":85,"line":406},7,[262,408,409],{"class":291},"    \"\u002FIT\"",[262,411,412],{"class":271},",                      ",[262,414,416],{"class":415},"s-wDw","# interactive: run only when the user is logged on\n",[262,418,420,423],{"class":85,"line":419},8,[262,421,422],{"class":291},"    \"\u002FF\"",[262,424,318],{"class":271},[262,426,428,431,435,438,441],{"class":85,"line":427},9,[262,429,430],{"class":271},"], ",[262,432,434],{"class":433},"sa561","check",[262,436,437],{"class":267},"=",[262,439,440],{"class":348},"True",[262,442,443],{"class":271},")\n",[10,445,446,449,450,452,453,361],{},[19,447,448],{},"\u002FIT"," is the command-line form of ",[14,451,243],{},". The general Task Scheduler setup — working directory, virtual environment, logging — is covered in ",[24,454,456],{"href":455},"\u002Fautomating-reporting-workflows\u002Fscheduling-python-excel-scripts-with-cron\u002Frun-python-excel-script-on-windows-task-scheduler\u002F","Run a Python Excel Script on Windows Task Scheduler",[189,458,460],{"id":459},"option-2-the-systemprofile-desktop-folder-workaround","Option 2 — The systemprofile Desktop folder workaround",[10,462,463],{},"When the task must run with nobody logged on, the long-standing workaround is to create the Desktop folders Excel looks for in the system profile. On 64-bit Windows there are two, one for 64-bit and one for 32-bit Office:",[253,465,467],{"className":255,"code":466,"language":257,"meta":258,"style":258},"from pathlib import Path\n\nfor folder in (r\"C:\\Windows\\System32\\config\\systemprofile\\Desktop\",\n               r\"C:\\Windows\\SysWOW64\\config\\systemprofile\\Desktop\"):\n    Path(folder).mkdir(parents=True, exist_ok=True)   # needs an elevated prompt\n",[19,468,469,482,486,536,567],{"__ignoreMap":258},[262,470,471,474,477,479],{"class":85,"line":264},[262,472,473],{"class":267},"from",[262,475,476],{"class":271}," pathlib ",[262,478,268],{"class":267},[262,480,481],{"class":271}," Path\n",[262,483,484],{"class":85,"line":275},[262,485,279],{"emptyLinePlaceholder":278},[262,487,488,491,494,497,500,502,505,508,511,513,516,519,522,525,528,531,534],{"class":85,"line":282},[262,489,490],{"class":267},"for",[262,492,493],{"class":271}," folder ",[262,495,496],{"class":267},"in",[262,498,499],{"class":271}," (",[262,501,329],{"class":267},[262,503,504],{"class":291},"\"C:",[262,506,507],{"class":348},"\\W",[262,509,510],{"class":291},"indows",[262,512,349],{"class":348},[262,514,515],{"class":291},"ystem32",[262,517,518],{"class":335},"\\c",[262,520,521],{"class":291},"onfig",[262,523,524],{"class":348},"\\s",[262,526,527],{"class":291},"ystemprofile",[262,529,530],{"class":348},"\\D",[262,532,533],{"class":291},"esktop\"",[262,535,318],{"class":271},[262,537,538,541,543,545,547,549,552,554,556,558,560,562,564],{"class":85,"line":288},[262,539,540],{"class":267},"               r",[262,542,504],{"class":291},[262,544,507],{"class":348},[262,546,510],{"class":291},[262,548,349],{"class":348},[262,550,551],{"class":291},"ysWOW64",[262,553,518],{"class":335},[262,555,521],{"class":291},[262,557,524],{"class":348},[262,559,527],{"class":291},[262,561,530],{"class":348},[262,563,533],{"class":291},[262,565,566],{"class":271},"):\n",[262,568,569,572,575,577,579,581,584,586,588,591],{"class":85,"line":321},[262,570,571],{"class":271},"    Path(folder).mkdir(",[262,573,574],{"class":433},"parents",[262,576,437],{"class":267},[262,578,440],{"class":348},[262,580,295],{"class":271},[262,582,583],{"class":433},"exist_ok",[262,585,437],{"class":267},[262,587,440],{"class":348},[262,589,590],{"class":271},")   ",[262,592,593],{"class":415},"# needs an elevated prompt\n",[10,595,596,597,600,601,603,604,607,608,611,612,615],{},"Run it once, as administrator. With the folders present, ",[19,598,599],{},"Open"," and ",[19,602,223],{}," generally work in non-interactive sessions. Some environments also need the DCOM configuration for ",[14,605,606],{},"Microsoft Excel Application"," (in ",[19,609,610],{},"dcomcnfg",") set to run as a specific user rather than ",[14,613,614],{},"The launching user",". Treat both as fragile: an Office update or a policy change can undo them, which is why the robustness steps below matter even when the workaround succeeds.",[30,617,39,622,39,625,39,628,39,631,39,639,39,647,39,652,39,656,39,660,39,663,39,668,39,677,39,682,39,687,39,693,39,698,39,703,39,705,39,708,39,712,39,715,39,718,39,723,39,726,39,729,39,731,39,734,39,738,39,741,39,745,39,751,39,755],{"viewBox":618,"role":33,"ariaLabelledBy":619,"xmlns":37,"style":38},"4 0 752 272",[620,621],"ts-choose-t","ts-choose-d",[41,623,624],{"id":620},"Choosing how to schedule a job that uses Excel",[45,626,627],{"id":621},"If the job only reads and writes workbook files, remove Excel and use openpyxl, xlsxwriter or pandas. If it needs the Excel application and a logged-on session is possible, run the task only when the user is logged on. Otherwise use the systemprofile Desktop workaround with a watchdog and cleanup.",[49,629],{"x":51,"y":52,"width":53,"height":630,"fill":55},"272",[49,632],{"x":633,"y":59,"width":634,"height":635,"rx":636,"fill":637,"stroke":638,"style":65},"191.5","377.1","75.5","12","#f0f4ff","var(--brand,#5b5cf0)",[67,640,642],{"transform":641},"translate(368.0,29.0) scale(1.000)",[71,643],{"d":644,"fill":74,"stroke":645,"style":646},"M3 5.5l8-1.2v7.2H3z M13 4l8-1.2v8.7h-8z M3 13.5h8v7.2l-8-1.2z M13 13.5h8v8.7l-8-1.2z","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[78,648,651],{"x":649,"y":635,"style":650},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Does the job need the Excel application itself?",[85,653],{"x1":649,"y1":654,"x2":649,"y2":655,"stroke":638,"style":65},"91.5","111.5",[85,657],{"x1":658,"y1":655,"x2":659,"y2":655,"stroke":638,"style":65},"134.7","625.3",[85,661],{"x1":658,"y1":655,"x2":658,"y2":662,"stroke":638,"style":65},"157.5",[664,665],"polygon",{"points":666,"fill":667},"134.7,161.5 129.7,152.5 139.7,152.5","#5b5cf0",[49,669],{"x":670,"y":671,"width":672,"height":673,"rx":674,"fill":55,"stroke":675,"style":676},"118.2","121.5","32.9","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[78,678,681],{"x":658,"y":679,"style":680},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","no",[49,683],{"x":58,"y":684,"width":685,"height":686,"rx":636,"fill":63,"stroke":64,"style":65},"163.5","229.3","93.0",[67,688,690],{"transform":689},"translate(122.7,176.5) scale(1.000)",[71,691],{"d":692,"fill":74,"stroke":75,"style":646},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01",[78,694,697],{"x":658,"y":695,"style":696},"223.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Remove Excel",[78,699,702],{"x":658,"y":700,"style":701},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","openpyxl, xlsxwriter, pandas",[85,704],{"x1":649,"y1":655,"x2":649,"y2":662,"stroke":638,"style":65},[664,706],{"points":707,"fill":667},"380.0,161.5 375.0,152.5 385.0,152.5",[49,709],{"x":710,"y":671,"width":711,"height":673,"rx":674,"fill":55,"stroke":675,"style":676},"272.1","215.9",[78,713,714],{"x":649,"y":679,"style":680},"yes, a session can stay logged on",[49,716],{"x":717,"y":684,"width":685,"height":686,"rx":636,"fill":637,"stroke":638,"style":65},"265.3",[67,719,721],{"transform":720},"translate(368.0,176.5) scale(1.000)",[71,722],{"d":73,"fill":74,"stroke":645,"style":646},[78,724,725],{"x":649,"y":695,"style":650},"Interactive task",[78,727,728],{"x":649,"y":700,"style":701},"run only when logged on",[85,730],{"x1":659,"y1":655,"x2":659,"y2":662,"stroke":638,"style":65},[664,732],{"points":733,"fill":667},"625.3,161.5 620.3,152.5 630.3,152.5",[49,735],{"x":736,"y":671,"width":737,"height":673,"rx":674,"fill":55,"stroke":675,"style":676},"549.2","152.3",[78,739,740],{"x":659,"y":679,"style":680},"yes, nobody logged on",[49,742],{"x":743,"y":684,"width":685,"height":686,"rx":636,"fill":744,"stroke":187,"style":65},"510.7","#fdefd8",[67,746,748],{"transform":747},"translate(613.3,176.5) scale(1.000)",[71,749],{"d":186,"fill":74,"stroke":750,"style":646},"var(--gold-ink,#7a4e06)",[78,752,754],{"x":659,"y":695,"style":753},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Workaround + watchdog",[78,756,757],{"x":659,"y":700,"style":701},"Desktop folders",[189,759,761],{"id":760},"make-the-script-safe-to-run-unattended","Make the script safe to run unattended",[10,763,764,765,768],{},"Whichever option you choose, write the COM code so it cannot hang and cannot leave Excel behind. Turn off everything that can raise a dialog, open files in a way that never prompts, and quit in a ",[19,766,767],{},"finally"," block:",[253,770,772],{"className":255,"code":771,"language":257,"meta":258,"style":258},"import logging\n\nimport pythoncom\nimport win32com.client as win32\n\nlog = logging.getLogger(\"refresh\")\n\ndef refresh_workbook(path: str) -> None:\n    pythoncom.CoInitialize()\n    excel = win32.DispatchEx(\"Excel.Application\")\n    try:\n        excel.Visible = False\n        excel.DisplayAlerts = False\n        excel.AskToUpdateLinks = False\n        excel.EnableEvents = False\n        wb = excel.Workbooks.Open(path, UpdateLinks=0, ReadOnly=False, IgnoreReadOnlyRecommended=True)\n        if wb is None:\n            raise RuntimeError(f\"Excel could not open {path} (non-interactive session?)\")\n        try:\n            wb.RefreshAll()\n            excel.CalculateUntilAsyncQueriesDone()\n            wb.Save()\n            log.info(\"refreshed %s\", path)\n        finally:\n            wb.Close(SaveChanges=False)\n    finally:\n        excel.Quit()\n        del excel\n        pythoncom.CoUninitialize()\n",[19,773,774,781,785,792,805,809,824,828,851,856,872,880,891,901,911,921,960,977,1008,1016,1022,1028,1034,1052,1060,1075,1083,1089,1098],{"__ignoreMap":258},[262,775,776,778],{"class":85,"line":264},[262,777,268],{"class":267},[262,779,780],{"class":271}," logging\n",[262,782,783],{"class":85,"line":275},[262,784,279],{"emptyLinePlaceholder":278},[262,786,787,789],{"class":85,"line":282},[262,788,268],{"class":267},[262,790,791],{"class":271}," pythoncom\n",[262,793,794,796,799,802],{"class":85,"line":288},[262,795,268],{"class":267},[262,797,798],{"class":271}," win32com.client ",[262,800,801],{"class":267},"as",[262,803,804],{"class":271}," win32\n",[262,806,807],{"class":85,"line":321},[262,808,279],{"emptyLinePlaceholder":278},[262,810,811,814,816,819,822],{"class":85,"line":383},[262,812,813],{"class":271},"log ",[262,815,437],{"class":267},[262,817,818],{"class":271}," logging.getLogger(",[262,820,821],{"class":291},"\"refresh\"",[262,823,443],{"class":271},[262,825,826],{"class":85,"line":406},[262,827,279],{"emptyLinePlaceholder":278},[262,829,830,833,837,840,843,846,848],{"class":85,"line":419},[262,831,832],{"class":267},"def",[262,834,836],{"class":835},"s_Opv"," refresh_workbook",[262,838,839],{"class":271},"(path: ",[262,841,842],{"class":348},"str",[262,844,845],{"class":271},") -> ",[262,847,219],{"class":348},[262,849,850],{"class":271},":\n",[262,852,853],{"class":85,"line":427},[262,854,855],{"class":271},"    pythoncom.CoInitialize()\n",[262,857,859,862,864,867,870],{"class":85,"line":858},10,[262,860,861],{"class":271},"    excel ",[262,863,437],{"class":267},[262,865,866],{"class":271}," win32.DispatchEx(",[262,868,869],{"class":291},"\"Excel.Application\"",[262,871,443],{"class":271},[262,873,875,878],{"class":85,"line":874},11,[262,876,877],{"class":267},"    try",[262,879,850],{"class":271},[262,881,883,886,888],{"class":85,"line":882},12,[262,884,885],{"class":271},"        excel.Visible ",[262,887,437],{"class":267},[262,889,890],{"class":348}," False\n",[262,892,894,897,899],{"class":85,"line":893},13,[262,895,896],{"class":271},"        excel.DisplayAlerts ",[262,898,437],{"class":267},[262,900,890],{"class":348},[262,902,904,907,909],{"class":85,"line":903},14,[262,905,906],{"class":271},"        excel.AskToUpdateLinks ",[262,908,437],{"class":267},[262,910,890],{"class":348},[262,912,914,917,919],{"class":85,"line":913},15,[262,915,916],{"class":271},"        excel.EnableEvents ",[262,918,437],{"class":267},[262,920,890],{"class":348},[262,922,924,927,929,932,935,937,939,941,944,946,949,951,954,956,958],{"class":85,"line":923},16,[262,925,926],{"class":271},"        wb ",[262,928,437],{"class":267},[262,930,931],{"class":271}," excel.Workbooks.Open(path, ",[262,933,934],{"class":433},"UpdateLinks",[262,936,437],{"class":267},[262,938,52],{"class":348},[262,940,295],{"class":271},[262,942,943],{"class":433},"ReadOnly",[262,945,437],{"class":267},[262,947,948],{"class":348},"False",[262,950,295],{"class":271},[262,952,953],{"class":433},"IgnoreReadOnlyRecommended",[262,955,437],{"class":267},[262,957,440],{"class":348},[262,959,443],{"class":271},[262,961,963,966,969,972,975],{"class":85,"line":962},17,[262,964,965],{"class":267},"        if",[262,967,968],{"class":271}," wb ",[262,970,971],{"class":267},"is",[262,973,974],{"class":348}," None",[262,976,850],{"class":271},[262,978,980,983,986,989,992,995,998,1000,1003,1006],{"class":85,"line":979},18,[262,981,982],{"class":267},"            raise",[262,984,985],{"class":348}," RuntimeError",[262,987,988],{"class":271},"(",[262,990,991],{"class":267},"f",[262,993,994],{"class":291},"\"Excel could not open ",[262,996,997],{"class":311},"{",[262,999,71],{"class":271},[262,1001,1002],{"class":311},"}",[262,1004,1005],{"class":291}," (non-interactive session?)\"",[262,1007,443],{"class":271},[262,1009,1011,1014],{"class":85,"line":1010},19,[262,1012,1013],{"class":267},"        try",[262,1015,850],{"class":271},[262,1017,1019],{"class":85,"line":1018},20,[262,1020,1021],{"class":271},"            wb.RefreshAll()\n",[262,1023,1025],{"class":85,"line":1024},21,[262,1026,1027],{"class":271},"            excel.CalculateUntilAsyncQueriesDone()\n",[262,1029,1031],{"class":85,"line":1030},22,[262,1032,1033],{"class":271},"            wb.Save()\n",[262,1035,1037,1040,1043,1046,1049],{"class":85,"line":1036},23,[262,1038,1039],{"class":271},"            log.info(",[262,1041,1042],{"class":291},"\"refreshed ",[262,1044,1045],{"class":311},"%s",[262,1047,1048],{"class":291},"\"",[262,1050,1051],{"class":271},", path)\n",[262,1053,1055,1058],{"class":85,"line":1054},24,[262,1056,1057],{"class":267},"        finally",[262,1059,850],{"class":271},[262,1061,1063,1066,1069,1071,1073],{"class":85,"line":1062},25,[262,1064,1065],{"class":271},"            wb.Close(",[262,1067,1068],{"class":433},"SaveChanges",[262,1070,437],{"class":267},[262,1072,948],{"class":348},[262,1074,443],{"class":271},[262,1076,1078,1081],{"class":85,"line":1077},26,[262,1079,1080],{"class":267},"    finally",[262,1082,850],{"class":271},[262,1084,1086],{"class":85,"line":1085},27,[262,1087,1088],{"class":271},"        excel.Quit()\n",[262,1090,1092,1095],{"class":85,"line":1091},28,[262,1093,1094],{"class":267},"        del",[262,1096,1097],{"class":271}," excel\n",[262,1099,1101],{"class":85,"line":1100},29,[262,1102,1103],{"class":271},"        pythoncom.CoUninitialize()\n",[10,1105,1106,1107,1110,1111,1114,1115,361],{},"Checking ",[19,1108,1109],{},"wb is None"," turns the silent failure mode of a non-interactive session into a clear error in the log. ",[19,1112,1113],{},"CalculateUntilAsyncQueriesDone"," waits for background data connections before saving, which is the usual reason a scheduled refresh saves stale data. More on COM error handling in ",[24,1116,1118],{"href":1117},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fhandle-com-errors-and-excel-dialog-prompts-in-python\u002F","Handle COM Errors and Excel Dialog Prompts in Python",[189,1120,1122],{"id":1121},"add-a-watchdog-so-a-hang-cannot-block-tomorrows-run","Add a watchdog so a hang cannot block tomorrow's run",[10,1124,1125],{},"Even with alerts off, some prompts — a corrupt-file repair, a credential dialog from a data connection — can still stall Excel. Run the COM work in a child process with a time limit, and kill any Excel it leaves behind if the limit is exceeded:",[253,1127,1129],{"className":255,"code":1128,"language":257,"meta":258,"style":258},"import subprocess\nimport sys\n\ndef run_with_timeout(script: str, workbook: str, seconds: int = 900) -> int:\n    proc = subprocess.Popen([sys.executable, script, workbook])\n    try:\n        return proc.wait(timeout=seconds)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n        # Excel started by the killed process keeps running; clean it up.\n        subprocess.run([\"taskkill\", \"\u002FF\", \"\u002FIM\", \"EXCEL.EXE\", \"\u002FFI\", \"USERNAME eq %USERNAME%\"],\n                       capture_output=True)\n        log.error(\"timed out after %s s on %s\", seconds, workbook)\n        return 1\n",[19,1130,1131,1137,1144,1148,1183,1193,1199,1215,1223,1228,1233,1269,1280,1300],{"__ignoreMap":258},[262,1132,1133,1135],{"class":85,"line":264},[262,1134,268],{"class":267},[262,1136,272],{"class":271},[262,1138,1139,1141],{"class":85,"line":275},[262,1140,268],{"class":267},[262,1142,1143],{"class":271}," sys\n",[262,1145,1146],{"class":85,"line":282},[262,1147,279],{"emptyLinePlaceholder":278},[262,1149,1150,1152,1155,1158,1160,1163,1165,1168,1171,1174,1177,1179,1181],{"class":85,"line":288},[262,1151,832],{"class":267},[262,1153,1154],{"class":835}," run_with_timeout",[262,1156,1157],{"class":271},"(script: ",[262,1159,842],{"class":348},[262,1161,1162],{"class":271},", workbook: ",[262,1164,842],{"class":348},[262,1166,1167],{"class":271},", seconds: ",[262,1169,1170],{"class":348},"int",[262,1172,1173],{"class":267}," =",[262,1175,1176],{"class":348}," 900",[262,1178,845],{"class":271},[262,1180,1170],{"class":348},[262,1182,850],{"class":271},[262,1184,1185,1188,1190],{"class":85,"line":321},[262,1186,1187],{"class":271},"    proc ",[262,1189,437],{"class":267},[262,1191,1192],{"class":271}," subprocess.Popen([sys.executable, script, workbook])\n",[262,1194,1195,1197],{"class":85,"line":383},[262,1196,877],{"class":267},[262,1198,850],{"class":271},[262,1200,1201,1204,1207,1210,1212],{"class":85,"line":406},[262,1202,1203],{"class":267},"        return",[262,1205,1206],{"class":271}," proc.wait(",[262,1208,1209],{"class":433},"timeout",[262,1211,437],{"class":267},[262,1213,1214],{"class":271},"seconds)\n",[262,1216,1217,1220],{"class":85,"line":419},[262,1218,1219],{"class":267},"    except",[262,1221,1222],{"class":271}," subprocess.TimeoutExpired:\n",[262,1224,1225],{"class":85,"line":427},[262,1226,1227],{"class":271},"        proc.kill()\n",[262,1229,1230],{"class":85,"line":858},[262,1231,1232],{"class":415},"        # Excel started by the killed process keeps running; clean it up.\n",[262,1234,1235,1238,1241,1243,1246,1248,1251,1253,1256,1258,1261,1263,1266],{"class":85,"line":874},[262,1236,1237],{"class":271},"        subprocess.run([",[262,1239,1240],{"class":291},"\"taskkill\"",[262,1242,295],{"class":271},[262,1244,1245],{"class":291},"\"\u002FF\"",[262,1247,295],{"class":271},[262,1249,1250],{"class":291},"\"\u002FIM\"",[262,1252,295],{"class":271},[262,1254,1255],{"class":291},"\"EXCEL.EXE\"",[262,1257,295],{"class":271},[262,1259,1260],{"class":291},"\"\u002FFI\"",[262,1262,295],{"class":271},[262,1264,1265],{"class":291},"\"USERNAME eq %USERNAME%\"",[262,1267,1268],{"class":271},"],\n",[262,1270,1271,1274,1276,1278],{"class":85,"line":882},[262,1272,1273],{"class":433},"                       capture_output",[262,1275,437],{"class":267},[262,1277,440],{"class":348},[262,1279,443],{"class":271},[262,1281,1282,1285,1288,1290,1293,1295,1297],{"class":85,"line":893},[262,1283,1284],{"class":271},"        log.error(",[262,1286,1287],{"class":291},"\"timed out after ",[262,1289,1045],{"class":311},[262,1291,1292],{"class":291}," s on ",[262,1294,1045],{"class":311},[262,1296,1048],{"class":291},[262,1298,1299],{"class":271},", seconds, workbook)\n",[262,1301,1302,1304],{"class":85,"line":903},[262,1303,1203],{"class":267},[262,1305,1306],{"class":348}," 1\n",[10,1308,1309,1310,1313,1314,1317,1318,361],{},"Only kill Excel processes belonging to the automation account — on a shared machine, a blanket ",[19,1311,1312],{},"taskkill \u002FIM EXCEL.EXE"," closes other people's workbooks. Set Task Scheduler's ",[14,1315,1316],{},"Stop the task if it runs longer than"," as a second line of defence, and have the job report failure — an email or chat alert — rather than relying on someone to notice a missing file; see ",[24,1319,1321],{"href":1320},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fsend-an-alert-when-an-excel-report-job-fails\u002F","Send an Alert When an Excel Report Job Fails",[30,1323,39,1329,39,1332,39,1335,39,1340,39,1345,39,1350,39,1354,39,1358,39,1361,39,1364,39,1367,39,1373,39,1377,39,1381,39,1385,39,1388,39,1391,39,1396,39,1400],{"viewBox":1324,"role":33,"ariaLabelledBy":1325,"xmlns":37,"style":1328},"74 0 612 383",[1326,1327],"ts-layers-t","ts-layers-d","width:100%;max-width:612px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[41,1330,1331],{"id":1326},"Layers of protection for a scheduled Excel COM job",[45,1333,1334],{"id":1327},"The scheduled task starts a parent Python process, which runs the COM work in a child process with a timeout. The child turns off alerts, checks every call and quits Excel in a finally block. If the child hangs, the parent kills it and its Excel process and raises an alert, and Task Scheduler's own time limit backs this up.",[49,1336],{"x":1337,"y":52,"width":1338,"height":1339,"fill":55},"74","612","383",[49,1341],{"x":1342,"y":59,"width":1343,"height":686,"rx":636,"fill":1344,"stroke":675,"style":65},"90.0","580.0","#e7ebef",[67,1346,1347],{"transform":641},[71,1348],{"d":141,"fill":74,"stroke":1349,"style":646},"var(--text,#172033)",[78,1351,1353],{"x":649,"y":635,"style":1352},"font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Task Scheduler",[78,1355,1357],{"x":649,"y":1356,"style":701},"95.0","time limit, run as automation account",[85,1359],{"x1":649,"y1":1360,"x2":649,"y2":679,"stroke":638,"style":65},"114.0",[664,1362],{"points":1363,"fill":667},"380.0,140.0 375.0,131.0 385.0,131.0",[49,1365],{"x":1342,"y":1366,"width":1343,"height":686,"rx":636,"fill":744,"stroke":187,"style":65},"145.0",[67,1368,1370],{"transform":1369},"translate(368.0,158.0) scale(1.000)",[71,1371],{"d":1372,"fill":74,"stroke":750,"style":646},"M12 9a3 3 0 1 0 .01 0z M12 2.5v3 M12 18.5v3 M2.5 12h3 M18.5 12h3 M5.3 5.3l2.1 2.1 M16.6 16.6l2.1 2.1 M5.3 18.7l2.1-2.1 M16.6 7.4l2.1-2.1",[78,1374,1376],{"x":649,"y":1375,"style":753},"204.5","Parent process",[78,1378,1380],{"x":649,"y":1379,"style":701},"224.0","timeout, cleanup, alert on failure",[85,1382],{"x1":649,"y1":1383,"x2":649,"y2":1384,"stroke":638,"style":65},"243.0","265.0",[664,1386],{"points":1387,"fill":667},"380.0,269.0 375.0,260.0 385.0,260.0",[49,1389],{"x":1342,"y":1390,"width":1343,"height":686,"rx":636,"fill":637,"stroke":638,"style":65},"274.0",[67,1392,1394],{"transform":1393},"translate(368.0,287.0) scale(1.000)",[71,1395],{"d":644,"fill":74,"stroke":645,"style":646},[78,1397,1399],{"x":649,"y":1398,"style":650},"333.5","Child process",[78,1401,1403],{"x":649,"y":1402,"style":701},"353.0","alerts off, check every call, quit in finally",[189,1405,1407],{"id":1406},"the-better-fix-do-not-use-excel","The better fix: do not use Excel",[10,1409,1410],{},"Most scheduled jobs that drive Excel do not need the application. They open a workbook, write values, format some cells, save, and maybe export a PDF — all things Python libraries do without Excel, faster and without any of the problems above. openpyxl edits existing workbooks, xlsxwriter builds new formatted ones, pandas reads and writes data, and LibreOffice converts to PDF headlessly. Such jobs run on Windows, Linux or in containers, under any scheduler.",[10,1412,1413,1414,600,1418,361],{},"Keep Excel only for the few things that genuinely need it: refreshing Power Query or OLE DB connections that only Excel can run, recalculating workbooks that use functions no other engine supports, running existing VBA macros. Even then, consider moving the data refresh out of Excel — query the source from Python — so Excel is not needed at all. The comparison of routes is laid out in ",[24,1415,1417],{"href":1416},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fxlwings-vs-pywin32-for-excel-automation\u002F","xlwings vs pywin32 for Excel Automation",[24,1419,1421],{"href":1420},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002F","Choosing a Python Excel Library",[189,1423,1425],{"id":1424},"common-pitfalls","Common pitfalls",[1427,1428,1429,1435,1444,1453],"ul",{},[200,1430,1431,1434],{},[203,1432,1433],{},"Testing only by hand."," A job that works from your terminal proves nothing about the scheduled context. Test by triggering the task itself, with the same account and settings it will use.",[200,1436,1437,1440,1441,361],{},[203,1438,1439],{},"Mapped drives."," Drive letters mapped at logon do not exist in a background session. Use UNC paths such as ",[19,1442,1443],{},"\\\\server\\share\\reports",[200,1445,1446,1449,1450,1452],{},[203,1447,1448],{},"Blanket process kills."," Killing every ",[19,1451,21],{}," on a shared machine closes other users' work. Filter by user.",[200,1454,1455,1458],{},[203,1456,1457],{},"Assuming the workaround is permanent."," Office updates can change behaviour. Monitor the job and alert on failure.",[189,1460,1462],{"id":1461},"conclusion","Conclusion",[10,1464,1465,1466,1468],{},"Excel expects an interactive desktop, a user profile and someone to answer dialogs, and a task running with nobody logged on provides none of them. The dependable setup is a task that runs only when a dedicated account is logged on; the systemprofile Desktop folders make background runs work in many cases but remain an unsupported workaround. Either way, disable every prompt, check each COM call, quit Excel in ",[19,1467,767],{},", and wrap the job in a watchdog with alerts — and wherever the job only reads and writes files, replace Excel with Python libraries and the problem disappears.",[189,1470,1472],{"id":1471},"frequently-asked-questions","Frequently asked questions",[10,1474,1475,1478],{},[203,1476,1477],{},"Why does my Excel script work manually but not from Task Scheduler?","\nWhen a task runs whether the user is logged on or not, it runs in a non-interactive session without a normal user desktop and profile. Excel expects both, so Workbooks.Open or SaveAs can fail with a COM error, return None, or wait on an invisible dialog.",[10,1480,1481,1484],{},[203,1482,1483],{},"What is the Desktop folder fix?","\nCreating an empty Desktop folder inside C:\\Windows\\System32\\config\\systemprofile (and SysWOW64\\config\\systemprofile on 64-bit Windows) lets Excel open and save files when it runs under a system or non-interactive account. It is a long-standing workaround, not a supported configuration.",[10,1486,1487,1490],{},[203,1488,1489],{},"Does Microsoft support running Excel unattended on a server?","\nNo. Microsoft does not recommend or support server-side automation of Office applications, because they were designed for interactive use. Use an interactive session if you must drive Excel, or generate files without Excel.",[10,1492,1493,1496],{},[203,1494,1495],{},"What is the most reliable fix?","\nRemove Excel from the job. If the task only reads and writes workbooks, openpyxl, xlsxwriter and pandas do it without Excel and run happily in any scheduler. Keep COM only for things that genuinely need the application, such as refreshing data connections or running macros.",[189,1498,1500],{"id":1499},"related","Related",[1427,1502,1503,1509,1516,1523],{},[200,1504,1505,1506,1508],{},"Up one level: ",[24,1507,27],{"href":26}," — the COM basics.",[200,1510,1511,1515],{},[24,1512,1514],{"href":1513},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fclose-excel-cleanly-and-avoid-orphan-com-processes\u002F","Close Excel Cleanly and Avoid Orphan COM Processes"," — cleanup in depth.",[200,1517,1518,1522],{},[24,1519,1521],{"href":1520},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frefresh-excel-data-connections-and-recalculate-with-win32com\u002F","Refresh Excel Data Connections and Recalculate with win32com"," — the refresh itself.",[200,1524,1525,1529],{},[24,1526,1528],{"href":1527},"\u002Fautomating-reporting-workflows\u002Fscheduling-python-excel-scripts-with-cron\u002F","Scheduling Python Excel Scripts with Cron"," — schedulers for Excel-free jobs.",[1531,1532,1533],"style",{},"html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":258,"searchDepth":275,"depth":275,"links":1535},[1536,1537,1538,1539,1540,1541,1542,1543,1544,1545],{"id":191,"depth":275,"text":192},{"id":236,"depth":275,"text":237},{"id":459,"depth":275,"text":460},{"id":760,"depth":275,"text":761},{"id":1121,"depth":275,"text":1122},{"id":1406,"depth":275,"text":1407},{"id":1424,"depth":275,"text":1425},{"id":1461,"depth":275,"text":1462},{"id":1471,"depth":275,"text":1472},{"id":1499,"depth":275,"text":1500},"2026-09-23","Why a pywin32 script that drives Excel works when you run it by hand and fails or hangs from Task Scheduler — session 0, the missing systemprofile Desktop folder, DCOM identity, dialogs nobody can click — and the setups that work, plus how to avoid needing Excel at all.","md",[1550,1552,1554,1556],{"q":1477,"a":1551},"When a task runs whether the user is logged on or not, it runs in a non-interactive session without a normal user desktop and profile. Excel expects both, so Workbooks.Open or SaveAs can fail with a COM error, return None, or wait on an invisible dialog.",{"q":1483,"a":1553},"Creating an empty Desktop folder inside C:\\Windows\\System32\\config\\systemprofile (and SysWOW64\\config\\systemprofile on 64-bit Windows) lets Excel open and save files when it runs under a system or non-interactive account. It is a long-standing workaround, not a supported configuration.",{"q":1489,"a":1555},"No. Microsoft does not recommend or support server-side automation of Office applications, because they were designed for interactive use. Use an interactive session if you must drive Excel, or generate files without Excel.",{"q":1495,"a":1557},"Remove Excel from the job. If the task only reads and writes workbooks, openpyxl, xlsxwriter and pandas do it without Excel and run happily in any scheduler. Keep COM only for things that genuinely need the application, such as refreshing data connections or running macros.","run excel com automation from task scheduler without a logged-in user",null,{"breadcrumb":1561},[1562,1565,1568],{"name":1563,"item":1564},"Home","\u002F",{"name":1566,"item":1567},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":27,"item":26},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler",{"title":1571,"description":1572},"Excel COM (pywin32) Fails in Task Scheduler — Causes and Fixes","Fix Python Excel automation that fails under Windows Task Scheduler — run-whether-logged-on-or-not, the systemprofile Desktop folder fix, DCOM identity, hung dialogs, watchdogs and cleanup, and Excel-free alternatives.","run-excel-com-automation-from-task-scheduler","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-excel-com-automation-from-task-scheduler\u002Findex",[1576,1577,1578],"com-automation","scheduling","troubleshooting","how-to","daHB3A-QuyX-NIaw1HjVfvFV3TVbfSSu-utafri30Do",[1582,1586],{"title":1583,"path":1584,"stem":1585,"children":-1},"Run an Excel Macro from Python with win32com","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-an-excel-macro-from-python-with-win32com","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-an-excel-macro-from-python-with-win32com\u002Findex",{"title":1587,"path":1588,"stem":1589,"children":-1},"Save a Workbook in Another Format with win32com","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fsave-a-workbook-in-another-format-with-win32com","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fsave-a-workbook-in-another-format-with-win32com\u002Findex",[1591,1593],{"path":1592,"title":27},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32",{"path":1594,"title":1566},"\u002Fgetting-started-with-python-excel-automation",[],[1597,1600,1603,1606,1608,1611],{"path":1598,"title":1599,"kind":1579},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-win32com-and-xlwings-code-without-excel","Test win32com and xlwings Code Without Excel",{"path":1601,"title":1602,"kind":1579},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fexport-an-excel-chart-as-an-image","Export an Excel Chart as an Image with Python",{"path":1604,"title":1605,"kind":1579},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python","Automate Excel on macOS with Python",{"path":1607,"title":1514,"kind":1579},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fclose-excel-cleanly-and-avoid-orphan-com-processes",{"path":1609,"title":1118,"kind":1610},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fhandle-com-errors-and-excel-dialog-prompts-in-python","fix",{"path":1612,"title":1613,"kind":1579},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fprint-an-excel-workbook-from-python-with-win32com","Print an Excel Workbook from Python with win32com",1790972056864]