PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/saltstack/salt/lib/python3.10/site-packages/salt/states
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/salt/states/win_wua.py
""" Installation of Windows Updates using the Windows Update Agent .. versionadded:: 2017.7.0 Salt can manage Windows updates via the "wua" state module. Updates can be installed and removed. Update management declarations are as follows: For installation: .. code-block:: yaml # Install a single update using the KB KB3194343: wua.installed # Install a single update using the name parameter install_update: wua.installed: - name: KB3194343 # Install multiple updates using the updates parameter and a combination of # KB number and GUID install_updates: wua.installed: - updates: - KB3194343 - bb1dbb26-3fb6-45fd-bb05-e3c8e379195c For removal: .. code-block:: yaml # Remove a single update using the KB KB3194343: wua.removed # Remove a single update using the name parameter remove_update: wua.removed: - name: KB3194343 # Remove multiple updates using the updates parameter and a combination of # KB number and GUID remove_updates: wua.removed: - updates: - KB3194343 - bb1dbb26-3fb6-45fd-bb05-e3c8e379195c """ import logging import salt.utils.data import salt.utils.platform import salt.utils.win_update log = logging.getLogger(__name__) __virtualname__ = "wua" def __virtual__(): """ Only valid on Windows machines """ if not salt.utils.platform.is_windows(): return False, "WUA: Only available on Window systems" if not salt.utils.win_update.HAS_PYWIN32: return False, "WUA: Requires PyWin32 libraries" return __virtualname__ def installed(name, updates=None): """ Ensure Microsoft Updates are installed. Updates will be downloaded if needed. Args: name (str): The identifier of a single update to install. updates (list): A list of identifiers for updates to be installed. Overrides ``name``. Default is None. .. note:: Identifiers can be the GUID, the KB number, or any part of the Title of the Microsoft update. GUIDs and KBs are the preferred method to ensure you're installing the correct update. .. warning:: Using a partial KB number or a partial Title could result in more than one update being installed. Returns: dict: A dictionary containing the results of the update. There are three keys under changes. `installed` is a list of updates that were successfully installed. `failed` is a list of updates that failed to install. `superseded` is a list of updates that were not installed because they were superseded by another update. CLI Example: .. code-block:: yaml # using a GUID install_update: wua.installed: - name: 28cf1b09-2b1a-458c-9bd1-971d1b26b211 # using a KB install_update: wua.installed: - name: KB3194343 # using the full Title install_update: wua.installed: - name: Security Update for Adobe Flash Player for Windows 10 Version 1607 (for x64-based Systems) (KB3194343) # Install multiple updates install_updates: wua.installed: - updates: - KB3194343 - 28cf1b09-2b1a-458c-9bd1-971d1b26b211 """ if isinstance(updates, str): updates = [updates] if not updates: updates = name ret = {"name": name, "changes": {}, "result": True, "comment": ""} wua = salt.utils.win_update.WindowsUpdateAgent() # Search for updates install_list = wua.search(updates) # No updates found if install_list.count() == 0: ret["comment"] = "No updates found" return ret # List of updates to download download = salt.utils.win_update.Updates() for item in install_list.updates: if not salt.utils.data.is_true(item.IsDownloaded): download.updates.Add(item) # List of updates to install install = salt.utils.win_update.Updates() installed_updates = [] for item in install_list.updates: if not salt.utils.data.is_true(item.IsInstalled): install.updates.Add(item) else: installed_updates.extend("KB" + kb for kb in item.KBArticleIDs) if install.count() == 0: ret["comment"] = "Updates already installed: " ret["comment"] += "\n - ".join(installed_updates) return ret # Return comment of changes if test. if __opts__["test"]: ret["result"] = None ret["comment"] = "Updates will be installed:" for update in install.updates: ret["comment"] += "\n" ret["comment"] += ": ".join([update.Identity.UpdateID, update.Title]) return ret # Download updates wua.download(download) # Install updates wua.install(install) # Refresh windows update info wua.refresh() post_info = wua.updates().list() # superseded_updates is a list of updates that the WUA first requested to be # installed but became ineligible for installation because they were # superseded superseded_updates = {} failed_updates = {} installed_updates = {} # Verify the installation installed_items = install.list() for item in installed_items: if item not in post_info: # Update (item) was not installed for valid reason superseded_updates[item] = { "Title": installed_items[item]["Title"], "KBs": installed_items[item]["KBs"], } else: if not salt.utils.data.is_true(post_info[item]["Installed"]): failed_updates[item] = { "Title": post_info[item]["Title"], "KBs": post_info[item]["KBs"], } else: installed_updates[item] = { "Title": post_info[item]["Title"], "NeedsReboot": post_info[item]["NeedsReboot"], "KBs": post_info[item]["KBs"], } comments = [] if installed_updates: comments.append("Updates installed successfully") ret["changes"]["installed"] = installed_updates if failed_updates: comments.append("Some updates failed to install") ret["changes"]["failed"] = failed_updates ret["result"] = False # Add the list of updates not installed to the return if superseded_updates: comments.append("Some updates were superseded") ret["changes"]["superseded"] = superseded_updates ret["comment"] = "\n".join(comments) return ret def removed(name, updates=None): """ Ensure Microsoft Updates are uninstalled. Args: name (str): The identifier of a single update to uninstall. updates (list): A list of identifiers for updates to be removed. Overrides ``name``. Default is None. .. note:: Identifiers can be the GUID, the KB number, or any part of the Title of the Microsoft update. GUIDs and KBs are the preferred method to ensure you're uninstalling the correct update. .. warning:: Using a partial KB number or a partial Title could result in more than one update being removed. Returns: dict: A dictionary containing the results of the removal. There are three keys under changes. `removed` is a list of updates that were successfully removed. `failed` is a list of updates that failed to be removed. CLI Example: .. code-block:: yaml # using a GUID uninstall_update: wua.removed: - name: 28cf1b09-2b1a-458c-9bd1-971d1b26b211 # using a KB uninstall_update: wua.removed: - name: KB3194343 # using the full Title uninstall_update: wua.removed: - name: Security Update for Adobe Flash Player for Windows 10 Version 1607 (for x64-based Systems) (KB3194343) # Install multiple updates uninstall_updates: wua.removed: - updates: - KB3194343 - 28cf1b09-2b1a-458c-9bd1-971d1b26b211 """ if isinstance(updates, str): updates = [updates] if not updates: updates = name ret = {"name": name, "changes": {}, "result": True, "comment": ""} wua = salt.utils.win_update.WindowsUpdateAgent() # Search for updates updates = wua.search(updates) # No updates found if updates.count() == 0: ret["comment"] = "No updates found" return ret # List of updates to uninstall uninstall = salt.utils.win_update.Updates() removed_updates = [] for item in updates.updates: if salt.utils.data.is_true(item.IsInstalled): uninstall.updates.Add(item) else: removed_updates.extend("KB" + kb for kb in item.KBArticleIDs) if uninstall.count() == 0: ret["comment"] = "Updates already removed: " ret["comment"] += "\n - ".join(removed_updates) return ret # Return comment of changes if test. if __opts__["test"]: ret["result"] = None ret["comment"] = "Updates will be removed:" for update in uninstall.updates: ret["comment"] += "\n" ret["comment"] += ": ".join([update.Identity.UpdateID, update.Title]) return ret # Install updates wua.uninstall(uninstall) # Refresh windows update info wua.refresh() post_info = wua.updates().list() failed_updates = {} removed_updates = {} # Verify the installation for item in uninstall.list(): if salt.utils.data.is_true(post_info[item]["Installed"]): failed_updates[item] = { "Title": post_info[item]["Title"], "KBs": post_info[item]["KBs"], } else: removed_updates[item] = { "Title": post_info[item]["Title"], "NeedsReboot": post_info[item]["NeedsReboot"], "KBs": post_info[item]["KBs"], } if removed_updates: ret["comment"] = "Updates removed successfully" ret["changes"]["removed"] = removed_updates if failed_updates: ret["comment"] = "Some updates failed to uninstall" ret["changes"]["failed"] = failed_updates ret["result"] = False return ret def uptodate( name, software=True, drivers=False, skip_hidden=False, skip_mandatory=False, skip_reboot=True, categories=None, severities=None, ): """ Ensure Microsoft Updates that match the passed criteria are installed. Updates will be downloaded if needed. This state allows you to update a system without specifying a specific update to apply. All matching updates will be installed. Args: name (str): The name has no functional value and is only used as a tracking reference software (bool): Include software updates in the results (default is True) drivers (bool): Include driver updates in the results (default is False) skip_hidden (bool): Skip updates that have been hidden. Default is False. skip_mandatory (bool): Skip mandatory updates. Default is False. skip_reboot (bool): Skip updates that require a reboot. Default is True. categories (list): Specify the categories to list. Must be passed as a list. All categories returned by default. Categories include the following: * Critical Updates * Definition Updates * Drivers (make sure you set drivers=True) * Feature Packs * Security Updates * Update Rollups * Updates * Update Rollups * Windows 7 * Windows 8.1 * Windows 8.1 drivers * Windows 8.1 and later drivers * Windows Defender severities (list): Specify the severities to include. Must be passed as a list. All severities returned by default. Severities include the following: * Critical * Important Returns: dict: A dictionary containing the results of the update. There are three keys under changes. `installed` is a list of updates that were successfully installed. `failed` is a list of updates that failed to install. `superseded` is a list of updates that were not installed because they were superseded by another update. CLI Example: .. code-block:: yaml # Update the system using the state defaults update_system: wua.uptodate # Update the drivers update_drivers: wua.uptodate: - software: False - drivers: True - skip_reboot: False # Apply all critical updates update_critical: wua.uptodate: - severities: - Critical """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} wua = salt.utils.win_update.WindowsUpdateAgent() available_updates = wua.available( skip_hidden=skip_hidden, skip_installed=True, skip_mandatory=skip_mandatory, skip_reboot=skip_reboot, software=software, drivers=drivers, categories=categories, severities=severities, ) # No updates found if available_updates.count() == 0: ret["comment"] = "No updates found" return ret updates = list(available_updates.list().keys()) # Search for updates install_list = wua.search(updates) # List of updates to download download = salt.utils.win_update.Updates() for item in install_list.updates: if not salt.utils.data.is_true(item.IsDownloaded): download.updates.Add(item) # List of updates to install install = salt.utils.win_update.Updates() for item in install_list.updates: if not salt.utils.data.is_true(item.IsInstalled): install.updates.Add(item) # Return comment of changes if test. if __opts__["test"]: ret["result"] = None ret["comment"] = "Updates will be installed:" for update in install.updates: ret["comment"] += "\n" ret["comment"] += ": ".join([update.Identity.UpdateID, update.Title]) return ret # Download updates wua.download(download) # Install updates wua.install(install) # Refresh windows update info wua.refresh() post_info = wua.updates().list() # superseded_updates is a list of updates that the WUA first requested to be # installed but became ineligible for installation because they were # superseded by other updates superseded_updates = {} failed_updates = {} installed_updates = {} # Verify the installation installed_items = install.list() for item in installed_items: if item not in post_info: # Update (item) was not installed for valid reason superseded_updates[item] = { "Title": installed_items[item]["Title"], "KBs": installed_items[item]["KBs"], } else: if not salt.utils.data.is_true(post_info[item]["Installed"]): failed_updates[item] = { "Title": post_info[item]["Title"], "KBs": post_info[item]["KBs"], } else: installed_updates[item] = { "Title": post_info[item]["Title"], "NeedsReboot": post_info[item]["NeedsReboot"], "KBs": post_info[item]["KBs"], } comments = [] if installed_updates: comments.append("Updates installed successfully") ret["changes"]["installed"] = installed_updates if failed_updates: comments.append("Some updates failed to install") ret["changes"]["failed"] = failed_updates ret["result"] = False # Add the list of updates not installed to the return if superseded_updates: comments.append("Some updates were superseded") ret["changes"]["superseded"] = superseded_updates ret["comment"] = "\n".join(comments) return ret