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_lgpo.py
r""" Manage Windows Local Group Policy ================================= .. versionadded:: 2016.11.0 This state module allows you to configure local Group Policy on Windows. You can ensure the setting of a single policy or multiple policies in one pass. Single policies must specify the policy name, the setting, and the policy class (Machine/User/Both). Here are some examples for setting a single policy setting. Example single policy configuration: .. code-block:: yaml Ensure Account Lockout Duration: lgpo.set: - name: Account lockout duration - setting: 90 - policy_class: Machine Example using abbreviated form: .. code-block:: yaml Account lockout duration: lgpo.set: - setting: 120 - policy_class: Machine It is also possible to set multiple policies in a single state. This is done by setting the settings under either `computer_policy` or `user_policy`. Here are some examples for setting multiple policy settings in a single state. Multiple policy configuration .. code-block:: yaml Company Local Group Policy: lgpo.set: - computer_policy: Deny log on locally: - Guest Account lockout duration: 120 Account lockout threshold: 10 Reset account lockout counter after: 120 Enforce password history: 24 Maximum password age: 60 Minimum password age: 1 Minimum password length: 14 Password must meet complexity requirements: Enabled Store passwords using reversible encryption: Disabled Configure Automatic Updates: Configure automatic updating: 4 - Auto download and schedule the intsall Scheduled install day: 7 - Every Saturday Scheduled install time: 17:00 Specify intranet Microsoft update service location: Set the intranet update service for detecting updates: http://mywsus Set the intranet statistics server: http://mywsus - user_policy: Do not process the legacy run list: Enabled .. code-block:: text server_policy: lgpo.set: - computer_policy: Maximum password age: 60 Minimum password age: 1 Minimum password length: 14 Account lockout duration: 120 Account lockout threshold: 10 Reset account lockout counter after: 120 Manage auditing and security log: - "BUILTIN\\Administrators" Replace a process level token: - "NT AUTHORITY\\NETWORK SERVICE" - "NT AUTHORITY\\LOCAL SERVICE" "Accounts: Guest account status": Disabled "Accounts: Rename guest account": Not_4_U "Audit: Audit the use of Backup and Restore privilege": Enabled "Interactive logon: Do not display last user name": Enabled "Network\\DNS Client\\Dynamic update": Disabled "System\\Logon\\Do not display the Getting Started welcome screen at logon": Enabled "Windows Components\\Remote Desktop Services\\Remote Desktop Session Host\\Connections\\Select RDP transport protocols": "Select Transport Type": "Use both UDP and TCP" "Windows Components\\Windows Update\\Allow Automatic Updates immediate installation": Enabled "Windows Components\\Windows Update\\Allow non-administrators to receive update notifications": Disabled "Windows Components\\Windows Update\\Always automatically restart at the scheduled time": "The restart timer will give users this much time to save their work (minutes)": 15 "Windows Components\\Windows Update\\Automatic Updates detection frequency": "Check for updates at the following interval (hours)": 1 "Windows Components\\Windows Update\\Configure Automatic Updates": "Configure automatic updating": 4 - Auto download and schedule the install "Install during automatic maintenance": False "Scheduled install day": 7 - Every Saturday "Scheduled install time": "17:00" "Windows Components\\Windows Update\\Delay Restart for scheduled installations": "Wait the following period before proceeding with a scheduled restart (minutes)": 1 "Windows Components\\Windows Update\\No auto-restart with logged on users for scheduled automatic updates installations": Disabled "Windows Components\\Windows Update\\Re-prompt for restart with scheduled installations": "Wait the following period before prompting again with a scheduled restart (minutes)": 30 "Windows Components\\Windows Update\\Reschedule Automatic Updates scheduled installations": Disabled "Windows Components\\Windows Update\\Specify intranet Microsoft update service location": "Set the intranet update service for detecting updates": http://mywsus "Set the intranet statistics server": http://mywsus - cumulative_rights_assignments: True Some policy settings can't be set on their own an require that other policy settings are set at the same time. It can be difficult to figure out what additional settings need to be applied. The easiest way to do this is to modify the setting manually using the Group Policy Editor (`gpedit.msc`) on the machine. Then `get` the policy settings configured on that machine. Use the following command: .. code-block:: bash salt-call --local lgpo.get machine For example, if I want to set the Windows Update settings for a Windows Server 2016 machine I would go into the Group Policy Editor (`gpedit.msc`) and configure the group policy. That policy can be found at: Computer Configuration -> Administrative Templates -> Windows Components -> Windows Update -> Configure Automatic Updates. You have the option to "Enable" the policy and set some configuration options. In this example, just click "Enable" and accept the default configuration options. Click "OK" to apply the setting. Now run the `get` command as shown above. You will find the following in the minion return: .. code-block:: bash Windows Components\Windows Update\Configure Automatic Updates: ---------- Configure automatic updating: 3 - Auto download and notify for install Install during automatic maintenance: False Install updates for other Microsoft products: False Scheduled install day: 0 - Every day Scheduled install time: 03:00 This shows you that to enable the "Configure Automatic Updates" policy you also have to configure the following settings: - Configure automatic updating - Install during automatic maintenance - Install updates for other Microsoft products - Scheduled install day - Scheduled install time So, if you were writing a state for the above policy, it would look like this: .. code-block:: bash configure_windows_update_settings: lgpo.set: - computer_policy: Configure Automatic Updates: Configure automatic updating: 3 - Auto download and notify for install Install during automatic maintenance: False Install updates for other Microsoft products: False Scheduled install day: 0 - Every day Scheduled install time: 03:00 .. note:: It is important that you put names of policies and settings exactly as they are displayed in the return. That includes capitalization and punctuation such as periods, dashes, etc. This rule applies to both the setting name and the setting value. .. warning:: From time to time Microsoft updates the Administrative templates on the machine. This can cause the policy name to change or the list of settings that must be applied at the same time. These settings often change between versions of Windows as well. For example, Windows Server 2019 allows you to also specify a specific week of the month to apply the update. Another thing note is the long policy name returned by the `get` function: .. code-block:: bash Windows Components\Windows Update\Configure Automatic Updates: When we wrote the state for this policy we only used the final portion of the policy name, `Configure Automatic Updates`. This usually works fine, but if you are having problems, you may try the long policy name. When writing the long name in a state file either wrap the name in single quotes to make yaml see it as raw data, or escape the back slashes. .. code-block:: bash 'Windows Components\Windows Update\Configure Automatic Updates:' or Windows Components\\Windows Update\\Configure Automatic Updates: """ import logging import salt.utils.data import salt.utils.dictdiffer import salt.utils.json import salt.utils.stringutils import salt.utils.versions import salt.utils.win_functions log = logging.getLogger(__name__) __virtualname__ = "lgpo" __func_alias__ = {"set_": "set"} def __virtual__(): """ load this state if the win_lgpo module exists """ if "lgpo.set" in __salt__: return __virtualname__ return False, "lgpo module could not be loaded" def _compare_policies(new_policy, current_policy): """ Helper function that returns ``True`` if the policies are the same, otherwise ``False`` """ # Compared dicts, lists, and strings if isinstance(new_policy, (str, int)): return new_policy == current_policy elif isinstance(new_policy, list): if isinstance(current_policy, list): return salt.utils.data.compare_lists(new_policy, current_policy) == {} else: return False elif isinstance(new_policy, dict): if isinstance(current_policy, dict): return salt.utils.data.compare_dicts(new_policy, current_policy) == {} else: return False def _convert_to_unicode(data): """ Helper function that makes sure all items in the dictionary are unicode for comparing the existing state with the desired state. This function is only needed for Python 2 and can be removed once we've migrated to Python 3. The data returned by the current settings sometimes has a mix of unicode and string values (these don't matter in Py3). This causes the comparison to say it's not in the correct state even though it is. They basically compares apples to apples, etc. Also, in Python 2, the utf-16 encoded strings remain utf-16 encoded (each character separated by `/x00`) In Python 3 it returns a utf-8 string. This will just remove all the null bytes (`/x00`), again comparing apples to apples. """ if isinstance(data, str): data = data.replace("\x00", "") return salt.utils.stringutils.to_unicode(data) elif isinstance(data, dict): return {_convert_to_unicode(k): _convert_to_unicode(v) for k, v in data.items()} elif isinstance(data, list): return list(_convert_to_unicode(v) for v in data) else: return data def set_( name, setting=None, policy_class=None, computer_policy=None, user_policy=None, cumulative_rights_assignments=True, adml_language="en-US", refresh_cache=False, ): """ Ensure the specified policy is set. .. warning:: The ``setting`` argument cannot be used in conjunction with the ``computer_policy`` or ``user_policy`` arguments Args: name (str): The name of a single policy to configure setting (str, dict, list): The configuration setting for the single named policy. If this argument is used the ``computer_policy`` / ``user_policy`` arguments will be ignored policy_class (str): The policy class of the single named policy to configure. This can ``machine``, ``user``, or ``both`` computer_policy (dict): A dictionary of containing the policy name and key/value pairs of a set of computer policies to configure. If this argument is used, the ``name`` / ``policy_class`` arguments will be ignored user_policy (dict): A dictionary of containing the policy name and key/value pairs of a set of user policies to configure. If this argument is used, the ``name`` / ``policy_class`` arguments will be ignored cumulative_rights_assignments (bool): If user rights assignments are being configured, determines if any user right assignment policies specified will be cumulative or explicit adml_language (str): The adml language to use for AMDX policy data/display conversions. Default is ``en-US`` refresh_cache (bool): Clear the cached policy definitions before applying the state. This is useful when the underlying policy files (ADMX/ADML) have been added/modified in the same state. This will allow those new policies to be picked up. This adds time to the state run when applied to multiple states within the same run. Therefore, it is best to only apply this to the first policy that is applied. For individual runs this will have no effect. Default is ``False`` .. versionadded:: 3006.8 .. versionadded:: 3007.1 """ ret = {"name": name, "result": True, "changes": {}, "comment": ""} policy_classes = ["machine", "computer", "user", "both"] class_map = { "computer": "Computer Configuration", "machine": "Computer Configuration", "user": "User Configuration", } if not setting and not computer_policy and not user_policy: msg = ( "At least one of the parameters setting, computer_policy, or " "user_policy must be specified." ) ret["result"] = False ret["comment"] = msg return ret if setting and not policy_class: msg = ( "A single policy setting was specified but the policy_class " "was not specified." ) ret["result"] = False ret["comment"] = msg return ret if setting and (computer_policy or user_policy): msg = ( "The setting and computer_policy/user_policy parameters are " "mutually exclusive. Please specify either a policy name and " "setting or a computer_policy and/or user_policy dict" ) ret["result"] = False ret["comment"] = msg return ret if policy_class and policy_class.lower() not in policy_classes: msg = "The policy_class parameter must be one of the following: {}" ret["result"] = False ret["comment"] = msg return ret if not setting: if computer_policy and not isinstance(computer_policy, dict): msg = "The computer_policy must be specified as a dict." ret["result"] = False ret["comment"] = msg return ret if user_policy and not isinstance(user_policy, dict): msg = "The user_policy must be specified as a dict." ret["result"] = False ret["comment"] = msg return ret else: user_policy = {} computer_policy = {} if policy_class.lower() == "both": user_policy[name] = setting computer_policy[name] = setting elif policy_class.lower() == "user": user_policy[name] = setting elif policy_class.lower() in ["machine", "computer"]: computer_policy[name] = setting pol_data = { "user": {"requested_policy": user_policy, "policy_lookup": {}}, "machine": {"requested_policy": computer_policy, "policy_lookup": {}}, } if refresh_cache: # Remove cached policies so new policies can be picked up __salt__["lgpo.clear_policy_cache"]() current_policy = {} deprecation_comments = [] for p_class, p_data in pol_data.items(): if p_data["requested_policy"]: for p_name, _ in p_data["requested_policy"].items(): lookup = __salt__["lgpo.get_policy_info"]( policy_name=p_name, policy_class=p_class, adml_language=adml_language, ) if lookup["policy_found"]: pol_data[p_class]["policy_lookup"][p_name] = lookup # Since we found the policy, let's get the current setting # as well current_policy.setdefault(class_map[p_class], {}) current_policy[class_map[p_class]][p_name] = __salt__[ "lgpo.get_policy" ]( policy_name=p_name, policy_class=p_class, adml_language=adml_language, return_value_only=True, ) # Validate element names if isinstance(p_data["requested_policy"][p_name], dict): valid_names = [] for element in lookup["policy_elements"]: valid_names.extend(element["element_aliases"]) for e_name in p_data["requested_policy"][p_name]: if e_name not in valid_names: new_e_name = e_name.split(":")[-1].strip() # If we find an invalid name, test the new # format. If found, add to deprecation comments # and bail if new_e_name in valid_names: msg = ( '"{}" is no longer valid.\n' 'Please use "{}" instead.' "".format(e_name, new_e_name) ) deprecation_comments.append(msg) else: msg = f"Invalid element name: {e_name}" ret["comment"] = "\n".join( [ret["comment"], msg] ).strip() ret["result"] = False else: ret["comment"] = "\n".join( [ret["comment"], lookup["message"]] ).strip() ret["result"] = False if not ret["result"]: if deprecation_comments: deprecation_comments.insert( 0, "The LGPO module changed the way it gets policy element names." ) deprecation_comments.append(ret["comment"]) ret["comment"] = "\n".join(deprecation_comments).strip() return ret log.debug("pol_data == %s", pol_data) log.debug("current policy == %s", current_policy) # compare policies policy_changes = [] for p_class, p_data in pol_data.items(): requested_policy = p_data.get("requested_policy") if requested_policy: for p_name, p_setting in requested_policy.items(): if p_name in current_policy[class_map[p_class]]: # compare the requested and current policies log.debug( "need to compare %s from current/requested policy", p_name ) # resolve user names in the requested policy and the current # policy so that we are comparing apples to apples if p_data["policy_lookup"][p_name]["rights_assignment"]: resolved_names = [] for name in p_data["requested_policy"][p_name]: resolved_names.append( salt.utils.win_functions.get_sam_name(name) ) p_data["requested_policy"][p_name] = resolved_names resolved_names = [] for name in current_policy[class_map[p_class]][p_name]: resolved_names.append( salt.utils.win_functions.get_sam_name(name) ) current_policy[class_map[p_class]][p_name] = resolved_names changes = False requested_policy_json = salt.utils.json.dumps( p_data["requested_policy"][p_name], sort_keys=True ) current_policy_json = salt.utils.json.dumps( current_policy[class_map[p_class]][p_name], sort_keys=True ) requested_policy_check = salt.utils.json.loads( requested_policy_json ) current_policy_check = salt.utils.json.loads(current_policy_json) # Are the requested and current policies identical policies_are_equal = _compare_policies( requested_policy_check, current_policy_check ) if not policies_are_equal: if ( p_data["policy_lookup"][p_name]["rights_assignment"] and cumulative_rights_assignments ): for user in p_data["requested_policy"][p_name]: if ( user not in current_policy[class_map[p_class]][p_name] ): user = salt.utils.win_functions.get_sam_name(user) if ( user not in current_policy[class_map[p_class]][ p_name ] ): changes = True else: changes = True if changes: log.debug("%s current policy != requested policy", p_name) log.debug( "We compared %s to %s", requested_policy_json, current_policy_json, ) policy_changes.append(p_name) else: msg = f'"{p_name}" is already set' log.debug(msg) else: policy_changes.append(p_name) log.debug("policy %s is not set, we will configure it", p_name) if __opts__["test"]: if policy_changes: msg = "The following policies are set to change:\n{}".format( "\n".join(policy_changes) ) ret["result"] = None else: msg = "All specified policies are properly configured" deprecation_comments.append(msg) ret["comment"] = "\n".join(deprecation_comments).strip() else: if policy_changes: _ret = __salt__["lgpo.set"]( computer_policy=pol_data["machine"]["requested_policy"], user_policy=pol_data["user"]["requested_policy"], cumulative_rights_assignments=cumulative_rights_assignments, adml_language=adml_language, ) if _ret: ret["result"] = _ret new_policy = {} for p_class, p_data in pol_data.items(): if p_data["requested_policy"]: for p_name, p_setting in p_data["requested_policy"].items(): new_policy.setdefault(class_map[p_class], {}) new_policy[class_map[p_class]][p_name] = __salt__[ "lgpo.get_policy" ]( policy_name=p_name, policy_class=p_class, adml_language=adml_language, return_value_only=True, ) ret["changes"] = salt.utils.dictdiffer.deep_diff( old=current_policy, new=new_policy ) if ret["changes"]: msg = "The following policies changed:\n{}".format( "\n".join(policy_changes) ) else: msg = "Failed to set the following policies:\n{}".format( "\n".join(policy_changes) ) ret["result"] = False else: msg = ( "Errors occurred while attempting to configure policies: {}".format( _ret ) ) ret["result"] = False deprecation_comments.append(msg) ret["comment"] = "\n".join(deprecation_comments).strip() else: msg = "All specified policies are properly configured" deprecation_comments.append(msg) ret["comment"] = "\n".join(deprecation_comments).strip() return ret