From 8f5d1f885a7c2387bdd83626c061d811929a2110 Mon Sep 17 00:00:00 2001 From: "Raghu Shantha [MSFT]" Date: Thu, 30 Jun 2016 12:08:06 -0700 Subject: [PATCH] Resurect accidentally deleted files for PowerShellGet The remove happened in eea998b4d --- src/Modules/PowerShellGet/PSGet.Format.ps1xml | 190 + src/Modules/PowerShellGet/PSGet.Resource.psd1 | Bin 0 -> 78998 bytes src/Modules/PowerShellGet/PSModule.psm1 | 14477 ++++++++++++++++ src/Modules/PowerShellGet/PowerShellGet.psd1 | Bin 0 -> 4318 bytes 4 files changed, 14667 insertions(+) create mode 100644 src/Modules/PowerShellGet/PSGet.Format.ps1xml create mode 100644 src/Modules/PowerShellGet/PSGet.Resource.psd1 create mode 100644 src/Modules/PowerShellGet/PSModule.psm1 create mode 100644 src/Modules/PowerShellGet/PowerShellGet.psd1 diff --git a/src/Modules/PowerShellGet/PSGet.Format.ps1xml b/src/Modules/PowerShellGet/PSGet.Format.ps1xml new file mode 100644 index 0000000000..2908458c05 --- /dev/null +++ b/src/Modules/PowerShellGet/PSGet.Format.ps1xml @@ -0,0 +1,190 @@ + + + + + PSRepositoryItemInfo + + Microsoft.PowerShell.Commands.PSRepositoryItemInfo + + + + + 10 + + + 35 + + + 20 + + + + + + + + Version + + + Name + + + Repository + + + Description + + + + + + + + PSRepository + + Microsoft.PowerShell.Commands.PSRepository + + + + + 25 + + + 20 + + + + + + + + Name + + + InstallationPolicy + + + SourceLocation + + + + + + + + PSScriptInfo + + Microsoft.PowerShell.Commands.PSScriptInfo + + + + + 10 + + + 25 + + + 20 + + + + + + + + Version + + + Name + + + Author + + + Description + + + + + + + + PSGetDscResourceInfo + + Microsoft.PowerShell.Commands.PSGetCommandInfo + Microsoft.PowerShell.Commands.PSGetDscResourceInfo + + + + + 35 + + + 10 + + + 35 + + + + + + + + Name + + + Version + + + ModuleName + + + Repository + + + + + + + + PSGetRoleCapabilityInfo + + Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo + + + + + 35 + + + 10 + + + 35 + + + + + + + + Name + + + Version + + + ModuleName + + + Repository + + + + + + + + diff --git a/src/Modules/PowerShellGet/PSGet.Resource.psd1 b/src/Modules/PowerShellGet/PSGet.Resource.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..6dfd08222a2a507b315dee74819f83970a894f7c GIT binary patch literal 78998 zcmeI5+ix97lHSj=0l%-`h#dp!0j&1U%+AYrwO+N<(h%FatjJblp9X4)t&v-zXp$PO zyx4!;cKqsNC?c}5>eM+r)TKvgG)10Ml^Ge=FCrtW{@?%o)#`Km??12plhLf7d#hWk z*Q=A&yVdFH#p?O$&#Uv*-s-E>)77u--+T7iQ~T!i>dgNCY50!oPwftVKCw?;*l)+H zukGratC#lQUK;6a`0L2-KC(~$Vn3hRm398_?Ea@V(n}lZ{|r~`tsbrpR(I|9bG!PH z{mblcY=o!w``0%2nT_+CGS25H1NZEBwriP-q>$PtG6a)B)4x8y*F_8%>I6E zzuj0pwx6eVpQO5H^ZmPV`akU7JsaUC`}r!3r0@T3_pi*z7yh*RlX3bxlf~oJx2BT^#=Qrt`}XOd7Vzf38Q`pwr&%I}N9$VDiGnv5ipn@y$ z&y@~r?!>M`&O}pZz?&(=`iO5tFnfrmyvqq#J0thVJfNDZVl&CAfOBjc3M_#yd=w+b6XyRoR3gP!vn zG7&}*b<(e~Ua?lm^qpM~u3RR|dH%?f?IILA5nRpDpmXX)F? z3$rEUgHLw~GIxj`M@A9X;K^9MXle0Wcr=aK^Lluou!p}4^S&8zf6sibTgq4lSSFqi z-XH__UCTXU-`?h|ec$N5JNOCEFW&3WX2*K(+0QBa56Sd+F*je03gYMUGQYS81;Nk$ zEYtL97GaA%Pxfv6ekK6!Ad=znu>)`fF-ra(q(Icd=Ek1=j(u}F#MNW-X3xwIqE&w9 zjr18SCmz9d`P;}frMJvW-dOz)JOLpyZqQ#fHf)(pMF@;sl&lhrjbHF_SoxcQ8!jbu6n$aNSn>So&~wEHm$2w*qchiuH|=V32KM7cOn+wl<~mmR zw?nq*aw4DaN%C*)N^x`A=j}Do1Il08YLS8CiBlULWZ<(qPw{g^G`tV|>7z|N@|peT z*`<4cJ^LJNgD=4{K`>QEzOv}V%+NH?|6gBJ7+R#WZ+C|lW!(FDTEUrVC_EyY{$d4R ztf2bXDJ!UWbnMm7%(LN#m!lbv@)0K=+5OWvavdhu_jB=1eo_?H^{P=~Ko;NEts3{!t!$)9P5tn8+RB=R2$Yfrj8w4}ri{#^_-h&v3z( zLW3^`4^E7N>oG?kpJY6YRJrGgjqq-$euU2^F7zvuwem8qPKNDg=x|CI zzod8Fs>n!`T6xbJ`ZCDza2GPj(J3QTxGj799A%KXw0jw_7ZCM?DutVaWl<@5GE_{d z)!#Jvg8Sm0jAX+%1u~xE{*%$@ft>$*A+a;FN3{6J=94wVH-SW|f1oy^JpC_rANd8I z0ljqGcr@f)jO&Q9u85h~r`WS`$P@8ST&wEk+rbL3)PAPGEYi2JKFVhxMXy9{XE~dA zuLE1{!6)FumUtw2v85hqdw;|XA*U*R>9b_Lgy!F0cwVkmtVY|eo5j4dpX43VzQ{YI zmywZREAqvCKe>stg-w1my(RDYc#*4D&Ci~!dYb(bt%!!3uVZX&yNJNOb!2&vgQ7`~ zjN8-rbKPn`o}3(EfK6I$4-4sO?54IV1Rc9ENVy^mBFiiLR7fYs6)3@jZ|5!1uE2=w zU}p&i27P5# z1+t-X&3+*k0O#`km1AHfkhfE^&N8^J=5tjVJ|0}4GKY0RMPR#neJ>l_yNE69se%*X zq%tq(X&pmYjy(=+z$=AyR_I|rRh8XdE~_f)f3+*{MSmFjXfoeCU+zmNTkSRy%J=VD zLfIzq*^>CQgzELJgxKXqV{!%Bvrazq%(xeqqdxv{K>dF)-5{2*TX{B$(05E`r?z(x zzIslRzZ&$c+64IXJW)#bTF+0e)B2zrUAxS#g?90&(R;ol&2G8;ZpfxSxBUw8vVR>c z-}$WC+An3dAoO6l{$|Urx}3kMHvf6+a`qo+#1}0dcUXPQJ+B9Rc*KWJU;c1U9A4LdFQt# z3(yiZVsSoegm)X?weP91fSA|^=-*lQ-K!UyucvtK|C5bRwK5PQXrE4U^uqTcH1Zs_ z=+l>ZxarEWAN!aq!$x!D=v95WCU+AHqsi}pG&0)bclsMDijI14-)@*8bMxa<1U^)b zk@YvzMKzq<<4wYl;|y(z4}Gk>M63H840@;dxQyO8y&Plv?djb&-bH5GR%LDvdAa;Y zNSIdf+GrvFI2GC$d0cxUp2UZ!<8T<7~Id0wPSd{ae*(flehb@o*H zJl9@Irpha1aL@Nk`qbq4Zzsygebn`H!$vr~s3G>U^H)Wq&}r5Grz?G;YMochmbe{d z)f%^#|%{;VNca#dqxQ{wW|!53hMRPoe% zyO~xnXT^sH6Z$@9MebdgyN(8W>e~&`!kD;{qdL3OZT`&*(IG> zw>RN$zOTys!|*rHzl6W}`aZo^!(UE@uy6455I>$@bXa7I$^IV?*WM9WB>PpYdpnHQ zjt}BczpnQLUY?>eTd|LpxxK`BAcN z*ZU`(bMSsvkAS|{6LAV(&52jlk)N8cQ=X!(TfYzK5ueDl@I`dwJ~0o&SsnH`V!Sh} zG>eOKxlPuo$HUy@MszV_*AdON2lx5$Yl=7Pb&9Oy+)zF^HTS_#bAr#pNTEyXu|*(; z!2gaM=?;&RiQ4mP_YS$XMr*}tbR+L&L?@1WRkWt=nNU|}2c)8(Uah!?0nv@X?^%a@ zFXPZ=tS22e;S{>9Rn^$(w(0BIoO?layLKNl^D5|o8r9RCqV*c&zUYzJ)pUQrQa#%Q z#a2yoUiPfly_v6mbBTxXe(RXuNN__Urd%ToPrU`|o>td(-s&N7Jq6W(`=x zS;?F3n}peKueiz)aab8uk62UYb#(of`~+=X zhud;R8{>0-KBDKwAuq@HenlN$d{QPk_V9g^Z-|3xRzgH|7PCYBn5st%xB?f-sl*ZN5w&fUCi z`i|&l;B-;kdEMd`o}QTc5AT0>-|&z2siX>4)hYO;G=*=}d1b2P%*1-o5oE=fXjir@ zJmK@fFD&tKoDkHRC+=$fM!VjBw)yC@tv;{n(&Z$nY@XA4K~?YUUCR?B_t>Z-BUsk0 zG1h|C1K>qei-}Cb&xUzy@}3-I(YMg7^PgG#Y8;%B`?n#75*~FQS96~J`2yt}8I?xoHBwM?_Yu+h{=Q6f8fs_3 zyRw7EEMp>8?i1Wpe*3oW+OIjr|M*97uF5g+?W^Rot0nDHg7`r=={(#-DzZs(82K>H zzA)YxwQMG*KEH1nKk`#C;9%6y?%Q|T^;OPJ=MJ^WQ}apj9X^qaKECxDF)PUE+Wj+> zE1TByHFB;LvCh^*XS{=#SEu!{ z`NgBvzYIUs;jyjWehA%+)h*Xa#s6$!JxT+kCeatkkoI|YZ$V-C5tTOc zM1G!J_!UpY2}Sw@^~tA#uCmXGwJQHrMTLHc+Lb7rADw|bfA-w`!yi`v-TotT(Lc{~ zU|H+)<})E=vVq3UTPP}Q(n4OwuGg~ILOr0sfqu; z3|sp$gDd(7fKSOjGI_wyp-z@^nc~gU25Crz3ZHe9?WQ z!N8zcdMw8J(a-MJ&C*JA{d{BTVSn|%o=)W|_5C5n+_9gE-Sbsu)fKTp5OeGx^;gW; z>?)jFrts&XQ_1Jx8+K~^yZ)|}c0I!9_o^|}=dd$o;QSXg5!LpnyhKJ`E3dvsOD!ZS z7@MsEp4C1l&v>w~552zHA+^c+?iio6BlgTHTCc5N4BJOCNA^3XBu<7;*rNd>W$n3P zQjNQj6zj%nj_rRvXVI&m{EKzAbG{D)DhciEq8zs zrug&7zNdzf&n?w`Dz12L{GtMaO`=)BJN|C(mz`=~CQj+AQpNS{XycuFt&MB7Q>fYT zw)o`!7=21&U(CI0m8m1K1LFaEF7$P_-4I#2NDLn_rb4ko8J9Bf%_x!`kPE1DM|(%= z?rB#X7D3)9?l_+4&&s~5U*Veby=g`}GCc|h!`^;Rs_`6^zO_B-Xan40$GSHgx&le_%e1GdM9(ZZfe|Kr&wqYJR_z>f7aM`{dsrVH<{z4 zYu(gdpKJM82C>&vsd2C4u~t^UTuLD4`kef+ZdA+fdCm0_dz$9)N(!j1)kEf5PW@Pi z_+(nr-nZzM;CQF{hOtKUDZ*mvj{TS(v_E$8gmdU5(tgi6zM*UCnBKeC(Vo*TjZUn@ ziWHCecf1Ebo;P--4^1Z8yMJ!?LMdZJA9;*g(bYC01 zP>vOIYrZ~o-~4103J+Yf5yXd9v%+_d<<{4jDXF(8VBaX0(dg??UtoqxAE!kLO$|&Em~9Gr~B0GJ$pEYSQ0TiupDC(oBXsvyp5x31>BYgZllfo z%zYk9=jp2o$+B})(bs`}e?B}*=#l-FH3qKoS?fn{ytk%LUCVmZJCY&00^7+t&)&ZU z24BuwVDfns?6CShVel5eMVBN|F~8^KY|spHv&+B5W#3j5{-d}0u$k`Foo^5EW|Y>}55Wou|1D=CB{K%Ul&` zX(Rr^@9^q5zVkViY}F}U7v@KdEP0x{ZUKtVEn4 z8S-->r)AyK$9#Hoo*y4q`pfCuMiZ8g{>##eyzaTW!KWkpIVvwJ`MI%|$ldou*L#Dp z-FqGJ?4ok-ZxFdUe~`WDJ@dnUf`+;*XJx@aRNEeyXX2Rx;my7=R7Pg=Y>iI_wN;Rno@7YO-2jlo$vxQ1W8$Bv&jLO7(?Z&8|3^EMj1Ze^}n zpIa2GyLWrtns{A%^=4I{cB{pCCOUpTloscC>)L-w8okLXKUeMU zZ;$sI_F@>Ti>_InxYK%kp9lKe(=0jbbSjo)Y0)J-&Th3A|g0=W1*<;KcXdR%hO?~uIYEy4w|x<0r}a+i`M$qeV`Gi-j7G#ew3R7u_Z<%^arOM_csGe^p`L_Kly>J#VjIW9PFh&m(mQ+~BWeqM3hK-~OK7DF8u#ifx|*N7 z5p?!yO6%vEvO34MRi5KYe1DAxrs4HH%^7QZ6;QQIbct>vmuPPt)#kl=MZMR%6h!Y* zYTD>|(`ewC?srWu<~iElIhH!Qti6%-+;1hFM-$rYuLy1EaTHA%^FCH|y<1c6M-JaZ zI<~o}RE*_a9ZAx_UY?pL;r$ZLGEY;O8Bq z@zgv=yO-MTO!K@jd;=&hccRSAQf1SklkuEAt6|?#yVtQlruEZ17!>uTHJ^9vjtlei ze0)BPwYK%%5!Vhc`apX6x5Oiiy^P1a^(b$OD#v$iWcD3JkTB1>qWh%h^Un+pk|A9oOu$NRAcL<1=z5koQ`*)z?<% zvW#@zsP6jIyr7RE>T``%-CJTiEiItLIP22R?D}@ixK%4i*DZ#62FAWJ*~d%EvvS69 zX1yN7MRg6ccQ|#zootT#rSa?6FR-*+4p!x?43+4x_zj8 zdG@6)E{`jfd*La18dcH!OPhmHB8OZTl`Ag~E_h0A*sfuUXXJZO@zQwZKFBp;Id$1@ zZNp(%$sEpye)4T9?=|C}TG`=6^dzoN25^!AZd1@o(VJdA5q z%#CVko6njp&2s~ne${hvP|pHzeP8z!A?32u+#pZ(%AJqNJA`$nfZV!$wn)v6r$??e zGxyguLz3MptIPaF!|=3TEA8b!yOeyc@~^`jWOAHzU{~~u9=OizP7gAFm*@e}1S+Ht z5tVM(IVti-x1~S|PV>pdomGl>Tw=agg>*(_+#M8W1p1yS<5)bQ=&Sya{Dxke>Lary zWZG2I$|$^N7g?7#n>Ta5&fA}dr=7D;j$g{FCEnzB7Cg1Rpc}(!h0IrK=J_hDX=>$h zCgE&&#=6gnzdW}4T%z^$T6}KvvSR22p1c?E{6Hv|m2NChqe$#Bi`EVZTEnAghibvY< zYL?0H@>0V#_lFgMx{y1(3=DFWvSdEE$P-Peos7AlPJ(qZ&AzDL6_LHs7rhTp)$0A& z_kNmse;Ik^dvBZeW$&*T@yqdJyO!s8y!C#pAGHI$uJ>W&9wuK z>v`DvCp@>b^^t{ltq584s)9tMSpPI-Jn2eLqT7GJW{tXxlHU*aI~u4+NvEV+JOvUV zZc@!qZXi79h^Dowd&W`k0vUTfN2FjIKQB<%PEGu_%?L_hACc@N>XCDj)@tHe>HR## zJFA$LexLQ!^6Un#_IHN1xV`0k;O?JnbagdRnen=dbWHJXz3#dfh-ZRLYlrJ?&lB$3 z3SwVZs~^h;EFK)0dismYe!Oxlvs!OdkaOjzt+He*b*}j=ATj#XLjy<$Z z);S(;Zk>8R*it#>tHaNHit@{p_VlyLEnmHEU1R>bZG8xNWxFE6BDt_f{GF<@2bS^a zZI|Rn%8}wTo`2(S`M}oLk*FgnL!GuAUvv1AYG3}m@$9Ago-|A1!>wpqim{@4&GHrT zUK?s6$HN}ai(yBKJe4kyvjGR?Ze3N@$1A_loJRLb!dOwdfwBJ`rSil|}~en$PX z><)vsz*bdCUzxTc3FL*;rsezVi6>md9qd;w)8%=K-bSyhC4SNCupjJbUb0mugu~U% zD(|k0p?$sv^}P0J803!RS=hL)*HdN`J95YG4}2OU*sIkQ`y~!zi{INd#DM2ByQ*y`e%9=^TelaV*Hw^ts*U2i(?WJe{zdl- zIfZ`f_v`o$XFi*Zt|=ZYxwGv@K>MUY$^mO0uU-3bLp=uz1c`G7 z_MQFozsJ1-wSNImd|)=msjBwcjKq30XkA#UsymfOu|lWya#W7xhOY=;Qzalz;uW_( zefe#1W52-aa@1jUpjNtp*zW?N>X{66=54hQum9lvda_QkPt6mqcpz61oi9k9lezYGiY6=`{}Ze6-i~;dayn*wK*<*7^E7EJ#&*7yhoqxJ%wZ z5v8|&{9HaKqa6vTscXldsG0`;*PG`-)8yMacjfqcDi7N9xj$s+@~^(C=-lv6K$MDV zsKs5oLw(;8ZIQGJ(;`$f=ke_qBjUKcd->rw3)`U%bLrY^DHKuj;i+9-0JG2}R zt(fNZI{!eH>Q7q~Lb)@1LbXxo#8EM`)pJO_IGrmgtdfcvI9+wAxu@xAbgt%lqV>z+ z-|;!B@w{^<(#NNB_2iGo)^mS*Kw69kPIgQNa%fLfumaIU4Ni#Sw??1Wa>>EST)j85 zjtM8I*HMS0_R9)|Kj7E*hW7Nnbt(<_Y<5Rm^*x3?y2Mw`zxf_cjOCy8?(41RcNbl~ zXaIFa&uc@3|l6{dj`3`bOdX*Cs7$D|Ey3aPhpvp^*E*WB4r2;-l+Jxils9{nmx6% zp_7aBp`My0aY})z7xviGd*4OK`AAewkIj0p;hM#$f~wtvmY z%wP{0?y7gB_KCp%N5+3u2kM(s2adiNB8YayOBhnmxqH@@bnx`py&zW zXwSas$y3vmH@0Tk`6c4Q5omxDwQ`~} z{OvxmqmjIZibYy}gH3|dee@v@Gv;FKU5G+x>iIo1H!zcY8*96qeoT#u4?t`FTD4`G zFS+uzOZ}Oiaa(D>HD*tRB2TM*tJef&9htWxNV62mU)*`^D^|Q#(H+ADYV)Aso>JARSg zGR|N`@2>X0es4MN-wl3oyWD$_n{pcJWTJOrUa8$3!l@y|ro@lFTC>mLJXY$j`sMdOYg`I=^mb!6m!z+jV=$$!H zpLf#oLe-AP#)+4<2C9X1^=~GsP0KjY_6+*^#_Nfi2o)vu(LfJ8dpu}0H8|%H@(XT_ zM+TK@IWtEgU>Ud^bDqElKc{vMdWh&SL6bsrcFJo8OEfIUms zs@d0|Y8{pIr8E1}-c=<(A9z=}JYA=(sIBEM{sx+sc_^+%?vk0;O5<#of6I9CR>+(R z3sg`C4oORn{kJz@5%rCmd#k_Mo03cGzy8bKa?R-J!!4tgC-i9FQfEQfA^g^4%}%AH z=sPF7)Q6=rf3EuQo52U{N*|VT>$3WQmF6cM!n;hgH>aQ2IQ4A)Vh5l64G&8$ zHg&G3T~S?u@5oKBvDIhq&X|uE;su^1x*zn}X~SWy1RS<4m&S1h93j3aev!e=tq>F- zUzlZIIn_r1hZnk$uWe&LZ#x0EY#Z}?_$KtO=Osa2^KS-Hg@O(bY=dW7$SSabyq0fl zB&zA)Ha{iI{`#il=T0KW($kt8_$BL4bjZi988K`fZrO&~j2Pt|oNBL_%jV`O?dwcN zjjgWWH|b@;U(pYM=Q%TOKeylL;L25q7B2|73m-d`_zU(B*)_}~)2GwZ9ONG;Zgb8( zHd_6S7>7fi1bW$ATQUNno6GYDRi&~vNdp{LJEjG@;4RhX|>(KAPg{?T+C4wCo z4_+Fd=={&xb-A959_B^=)E^?->8;PPX=D%5U*+4xj@Uug-sS#9gv_zAH~ZY2zZDs{fH8D=JCc5t%{lmKs+{LZ?07AObTM^Xqw+l7xFsxO8H^ zNu6axVzN)h(FryzQ1RK%Uj&WWOLN!tAx^0RwyFHEqnpMjNsZ@Aj^AamZxWPOt8$F2 zky@PV$JI#?>+pP!yloSyAP4TxE9GxIZhgbSW^!83Z{h%&dt^wDstZ!hoNMto9X^?x zQEfmwypP8BH{@p-9ewlh&xV>@uS@TV`8;I~ikoO?JhNGO+2lo z_gA*eniUbb)_c9wu}gosqMPF^IEB53HKXep@wOZ%KGM^p-n1td86sIn?T@-%JlCB; zkJRTy{KYPjJr*yU@Mor-58pakcaKn|KBl3ETO4EKt>E`9(*XCro{RDcXo_pHe0VOL zbl-g)G=sQ^J$eF9<{C(f8bls1V=u=XbseFzef`Naj5TIGz17dRl8o8??S7I$pO&hv zEx)L$^tuz#>i#$2uQm!zQ;2>d0oR9m@Axg%S*JjQwf2jr~rwel%t}RcHBxe!MAF79M4aeklk8w`!ZEy>5 zi+7r)c~reYp94$eLrlr2ZfZu=0I^=WiB#8Zk!iMg`9)$UC<=MejgAK9*@&(cHG1`> z&a@;B^m!2H^s0{`Q*`_0cOqyWL3=|{S-5HTgH)7V<|?amW7j&SnJ%wO8mHE4u2R1a z%G*n_4fIh8^^cs9^kQk2jC`JFbpFJy`FEz&``a0OuLrbAjrV0ik<~wPr)ArInVUL#Y=p^J@5T{r5K}~#Dv7_%cZOUtPAd> z)9hP$qAaly#QlH)+d}q&J7QLw(s5!zbgW=lk2gtN9iWK z0x$n;vm8(0Vvuj(^6Xz78@lym`Soj>WCGCLlcD>7m^k>a3(1DF`Y80!t{)X-5^=9xK3Taim?RH%2WRB0_#w+7d^kFD2 zSNxP^n`>`93!1j|KyaXHJXc%!>s9aMr|=5$+|uo~QxKU&#Xi&Z?m|nsqDnsNm2*iF zryr!xW$du-*NPsm38QD)iNe#|w49gdiJ9hqj zwCFIX9vyD`zN+sxsE&kOUK)k;suG{cT*$W3IC;ge5kCcvrow+XF;#P}d~fkxE0^&* zlK(J7Y}t07+gW2Dnrpix94Lx6dZnm_ZkWYagK9Oapr^3%2KuPuOdIEXhW4brwEEw8{zjhp= zXzEwgG2OGsH+s!nx)|%?Nhmsvk}+Ax3EL-f=ZJ%!_D-{GIXP;prsg}~LL&7(jTs); zHA0p3CHBk8ZV!|>&)erdww1lgp(XOpUb%8%b9(zvlDuhJiC(I*pi>eLFC=_utCNLD zM${W}M0sl8%9dMeykVdFxK-Pb$@I$cZfI`ke&&Ej=l(zdv89vc%t_Oq| z#*Ei3ius(ZcRVXAcH8u5@RL!2c2sPjDD7E!d+qe-m*FRx=y~d)Y2ndOKgb!9Yu^J~ zC%h}?4;bwbpPdi*&;cliOI7sw^^Z3BpZ&c%lb6EZq{u7aI+W**# zo_~}hXwQHL`OaG1LPqpGSc?-!>5ecc{XnR*VB%D z8&8!v@K{ESz9TPbk^fS+#HW#WBTYqtT%)N7FiW-e!%2$1I%VNngQ9!hO((bK`n-qj zmP3B8-_fX`5h=A)dfmqFjaZjCCK-FpAvn|bUX^>d2A;5**T$i%<<7H^ehvym?6oR9xMu-v-Kxq>wj=tdsHFDhSmgS^b=9eF8IN9@r^GXmA&pUFU!v7( zIZ6f5vO`R68^4Ebw|=I2Q{Q`%r*Yk%T9H?D@g(?h@i5{Rzx85QpK{efg64f2bF7V7 zkJWXnYA~KV5LHhXJvI=x#UW*dnK$TStfq}Tm$6{i)UaUZZgiu#C2b<_9@m6$KPIQ9 zH3lt5yO373A)--#*0PZ*(E&1jdiPK zF7c{b%=~KOuAm?zx=M|&0Bq`Xw?2Xx3UYM0;l=!SUt@cZkDH@&f4x&O-M3jB6WlYN z3)Or|C?aqJd2^15&XsAsBUbq8#G_9UHG~bV*TBP}a-zID+lXrq67*hsw5R&$ij}I4 zj&VLHLLLFz*7G~oOXD&)xEJesu`RlMWg&InmM*W6bO?OV>+8rTg8TrvJWTVtCG?5Yy6K5F$e8J+*wc!9Ur=>5rUtp#gh z?}eH`wVu!rs=Z^6OCRm)VN{|WwgCe6{y2L5YIfPrFUOMfeV^cVTNMvq;-07?l3mGL z9>$|r(Br-|IOOr+)0O|>1>&oIqxBGV#kaknh(w_6CstGDE9ty*SMCZn#*~tb=;jP&XK}Li~7bo zP1Zh)-*@$B!mFwoP5A7+Q&vdXYpj0OeVbb0c(23}6&{oGvD;x|#l2tIDdb-bd#c~r SlUr{M6}W4we;WS9TK+!_A?%C* literal 0 HcmV?d00001 diff --git a/src/Modules/PowerShellGet/PSModule.psm1 b/src/Modules/PowerShellGet/PSModule.psm1 new file mode 100644 index 0000000000..6f53550ef0 --- /dev/null +++ b/src/Modules/PowerShellGet/PSModule.psm1 @@ -0,0 +1,14477 @@ + +######################################################################################### +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# PowerShellGet Module +# +######################################################################################### + +Microsoft.PowerShell.Core\Set-StrictMode -Version Latest + +#region script variables + +# Check if this is nano server. [System.Runtime.Loader.AssemblyLoadContext] is only available on NanoServer +$script:isNanoServer = $null -ne ('System.Runtime.Loader.AssemblyLoadContext' -as [Type]) + +try +{ + $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments") +} +catch +{ + $script:MyDocumentsFolderPath = $null +} + +$script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" + +$script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) + { + Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell" + } + else + { + Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell" + } + +$script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Modules" +$script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Modules" + +$script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Scripts" + +$script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Scripts" + +$script:TempPath = ([System.IO.DirectoryInfo]$env:TEMP).FullName +$script:PSGetItemInfoFileName = "PSGetModuleInfo.xml" +$script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' +$script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' +$script:PSGetModuleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PSRepositories.xml" +$script:PSGetModuleSources = $null +$script:PSGetInstalledModules = $null +$script:PSGetSettingsFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PowerShellGetSettings.xml" +$script:PSGetSettings = $null + +$script:MyDocumentsInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsScriptsPath -ChildPath 'InstalledScriptInfos' +$script:ProgramFilesInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesScriptsPath -ChildPath 'InstalledScriptInfos' + +$script:InstalledScriptInfoFileName = 'InstalledScriptInfo.xml' +$script:PSGetInstalledScripts = $null + +# Public PSGallery module source name and location +$Script:PSGalleryModuleSource="PSGallery" +$Script:PSGallerySourceUri = 'https://go.microsoft.com/fwlink/?LinkID=397631&clcid=0x409' +$Script:PSGalleryPublishUri = 'https://go.microsoft.com/fwlink/?LinkID=397527&clcid=0x409' +$Script:PSGalleryScriptSourceUri = 'https://go.microsoft.com/fwlink/?LinkID=622995&clcid=0x409' + +# PSGallery V3 Source +$Script:PSGalleryV3SourceUri = 'https://go.microsoft.com/fwlink/?LinkId=528403&clcid=0x409' + +$Script:PSGalleryV2ApiAvailable = $true +$Script:PSGalleryV3ApiAvailable = $false +$Script:PSGalleryApiChecked = $false + +$Script:ResponseUri = "ResponseUri" +$Script:StatusCode = "StatusCode" +$Script:Exception = "Exception" + +$script:PSModuleProviderName = 'PowerShellGet' +$script:PackageManagementProviderParam = "PackageManagementProvider" +$script:PublishLocation = "PublishLocation" +$script:ScriptSourceLocation = 'ScriptSourceLocation' +$script:ScriptPublishLocation = 'ScriptPublishLocation' +$script:Proxy = 'Proxy' +$script:ProxyCredential = 'ProxyCredential' +$script:Credential = 'Credential' +$script:VSTSAuthenticatedFeedsDocUrl = 'https://go.microsoft.com/fwlink/?LinkID=698608' + +$script:NuGetProviderName = "NuGet" +$script:NuGetProviderVersion = [Version]'2.8.5.201' + +$script:SupportsPSModulesFeatureName="supports-powershell-modules" +$script:FastPackRefHastable = @{} +$script:NuGetBinaryProgramDataPath="$env:ProgramFiles\PackageManagement\ProviderAssemblies" +$script:NuGetBinaryLocalAppDataPath="$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies" +# go fwlink for 'https://nuget.org/nuget.exe' +$script:NuGetClientSourceURL = 'http://go.microsoft.com/fwlink/?LinkID=690216&clcid=0x409' +$script:NuGetExeName = 'NuGet.exe' +$script:NuGetExePath = $null +$script:NuGetProvider = $null +# PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure. +# PowerShellGetFormatVersion is in the form of Major.Minor. +# Minor is incremented for the backward compatible format change. +# Major is incremented for the breaking change. +$script:CurrentPSGetFormatVersion = "1.0" +$script:PSGetFormatVersion = "PowerShellGetFormatVersion" +$script:SupportedPSGetFormatVersionMajors = @("1") +$script:ModuleReferences = 'Module References' +$script:AllVersions = "AllVersions" +$script:Filter = "Filter" +$script:IncludeValidSet = @('DscResource','Cmdlet','Function','Workflow','RoleCapability') +$script:DscResource = "PSDscResource" +$script:Command = "PSCommand" +$script:Cmdlet = "PSCmdlet" +$script:Function = "PSFunction" +$script:Workflow = "PSWorkflow" +$script:RoleCapability = 'PSRoleCapability' +$script:Includes = "PSIncludes" +$script:Tag = "Tag" +$script:NotSpecified= '_NotSpecified_' +$script:PSGetModuleName = 'PowerShellGet' +$script:FindByCanonicalId = 'FindByCanonicalId' +$script:InstalledLocation = 'InstalledLocation' +$script:PSArtifactType = 'Type' +$script:PSArtifactTypeModule = 'Module' +$script:PSArtifactTypeScript = 'Script' +$script:All = 'All' + +$script:Name = 'Name' +$script:Version = 'Version' +$script:Guid = 'Guid' +$script:Path = 'Path' +$script:ScriptBase = 'ScriptBase' +$script:Description = 'Description' +$script:Author = 'Author' +$script:CompanyName = 'CompanyName' +$script:Copyright = 'Copyright' +$script:Tags = 'Tags' +$script:LicenseUri = 'LicenseUri' +$script:ProjectUri = 'ProjectUri' +$script:IconUri = 'IconUri' +$script:RequiredModules = 'RequiredModules' +$script:ExternalModuleDependencies = 'ExternalModuleDependencies' +$script:ReleaseNotes = 'ReleaseNotes' +$script:RequiredScripts = 'RequiredScripts' +$script:ExternalScriptDependencies = 'ExternalScriptDependencies' +$script:DefinedCommands = 'DefinedCommands' +$script:DefinedFunctions = 'DefinedFunctions' +$script:DefinedWorkflows = 'DefinedWorkflows' +$script:TextInfo = (Get-Culture).TextInfo + +$script:PSScriptInfoProperties = @($script:Name + $script:Version, + $script:Guid, + $script:Path, + $script:ScriptBase, + $script:Description, + $script:Author, + $script:CompanyName, + $script:Copyright, + $script:Tags, + $script:ReleaseNotes, + $script:RequiredModules, + $script:ExternalModuleDependencies, + $script:RequiredScripts, + $script:ExternalScriptDependencies, + $script:LicenseUri, + $script:ProjectUri, + $script:IconUri, + $script:DefinedCommands, + $script:DefinedFunctions, + $script:DefinedWorkflows + ) + +$script:SystemEnvironmentKey = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' +$script:UserEnvironmentKey = 'HKCU:\Environment' +$script:SystemEnvironmentVariableMaximumLength = 1024 +$script:UserEnvironmentVariableMaximumLength = 255 +$script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } + +# Wildcard pattern matching configuration. +$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` + [System.Management.Automation.WildcardOptions]::IgnoreCase + +$script:DynamicOptionTypeMap = @{ + 0 = [string]; # String + 1 = [string[]]; # StringArray + 2 = [int]; # Int + 3 = [switch]; # Switch + 4 = [string]; # Folder + 5 = [string]; # File + 6 = [string]; # Path + 7 = [Uri]; # Uri + 8 = [SecureString]; #SecureString + } +#endregion script variables + +#region Module message resolvers +$script:PackageManagementMessageResolverScriptBlock = { + param($i, $Message) + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + +$script:PackageManagementSaveModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedPackage + + switch ($i) + { + 'ActionInstallPackage' { return "Save-Module" } + 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} + 'TargetPackage' { return $PackageTarget } + Default { + $Message = $Message -creplace "Install", "Download" + $Message = $Message -creplace "install", "download" + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementInstallModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + + switch ($i) + { + 'ActionInstallPackage' { return "Install-Module" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUnInstallModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + switch ($i) + { + 'ActionUninstallPackage' { return "Uninstall-Module" } + 'TargetPackageVersion' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUpdateModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = ($LocalizedData.UpdateModulewhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) + switch ($i) + { + 'ActionInstallPackage' { return "Update-Module" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +function PackageManagementMessageResolver($MsgID, $Message) { + $NoMatchFound = $LocalizedData.NoMatchFound + $SourceNotFound = $LocalizedData.SourceNotFound + $ModuleIsNotTrusted = $LocalizedData.ModuleIsNotTrusted + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage + + switch ($MsgID) + { + 'NoMatchFound' { return $NoMatchFound } + 'SourceNotFound' { return $SourceNotFound } + 'CaptionPackageNotTrusted' { return $ModuleIsNotTrusted } + 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } + 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} + Default { + if($Message) + { + $tempMessage = $Message -creplace "PackageSource", "PSRepository" + $tempMessage = $tempMessage -creplace "packagesource", "psrepository" + $tempMessage = $tempMessage -creplace "Package", "Module" + $tempMessage = $tempMessage -creplace "package", "module" + $tempMessage = $tempMessage -creplace "Sources", "Repositories" + $tempMessage = $tempMessage -creplace "sources", "repositories" + $tempMessage = $tempMessage -creplace "Source", "Repository" + $tempMessage = $tempMessage -creplace "source", "repository" + + return $tempMessage + } + } + } +} + +#endregion Module message resolvers + +#region Script message resolvers +$script:PackageManagementMessageResolverScriptBlockForScriptCmdlets = { + param($i, $Message) + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + +$script:PackageManagementSaveScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedScriptPackage + + switch ($i) + { + 'ActionInstallPackage' { return "Save-Script" } + 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} + 'TargetPackage' { return $PackageTarget } + Default { + $Message = $Message -creplace "Install", "Download" + $Message = $Message -creplace "install", "download" + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementInstallScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + + switch ($i) + { + 'ActionInstallPackage' { return "Install-Script" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUnInstallScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + switch ($i) + { + 'ActionUninstallPackage' { return "Uninstall-Script" } + 'TargetPackageVersion' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUpdateScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = ($LocalizedData.UpdateScriptwhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) + switch ($i) + { + 'ActionInstallPackage' { return "Update-Script" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +function PackageManagementMessageResolverForScripts($MsgID, $Message) { + $NoMatchFound = $LocalizedData.NoMatchFoundForScriptName + $SourceNotFound = $LocalizedData.SourceNotFound + $ScriptIsNotTrusted = $LocalizedData.ScriptIsNotTrusted + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage + + switch ($MsgID) + { + 'NoMatchFound' { return $NoMatchFound } + 'SourceNotFound' { return $SourceNotFound } + 'CaptionPackageNotTrusted' { return $ScriptIsNotTrusted } + 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } + 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} + Default { + if($Message) + { + $tempMessage = $Message -creplace "PackageSource", "PSRepository" + $tempMessage = $tempMessage -creplace "packagesource", "psrepository" + $tempMessage = $tempMessage -creplace "Package", "Script" + $tempMessage = $tempMessage -creplace "package", "script" + $tempMessage = $tempMessage -creplace "Sources", "Repositories" + $tempMessage = $tempMessage -creplace "sources", "repositories" + $tempMessage = $tempMessage -creplace "Source", "Repository" + $tempMessage = $tempMessage -creplace "source", "repository" + + return $tempMessage + } + } + } +} + +#endregion Script message resolvers + +Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSGet.Resource.psd1 + +#region Add .Net type for Telemetry APIs and WebProxy + +# This code is required to add a .Net type and call the Telemetry APIs +# This is required since PowerShell does not support generation of .Net Anonymous types +# +$requiredAssembly = @( "system.management.automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "$([System.Net.IWebProxy].AssemblyQualifiedName)".Substring('System.Net.IWebProxy'.Length+1).Trim(), + "$([System.Uri].AssemblyQualifiedName)".Substring('System.Uri'.Length+1).Trim() + ) + +$source = @" +using System; +using System.Net; +using System.Management.Automation; +using Microsoft.Win32.SafeHandles; +using System.Security.Cryptography; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell.Commands.PowerShellGet +{ + public static class Telemetry + { + public static void TraceMessageArtifactsNotFound(string[] artifactsNotFound, string operationName) + { + Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { ArtifactsNotFound = artifactsNotFound }); + } + + public static void TraceMessageNonPSGalleryRegistration(string sourceLocationType, string sourceLocationHash, string installationPolicy, string packageManagementProvider, string publishLocationHash, string scriptSourceLocationHash, string scriptPublishLocationHash, string operationName) + { + Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { SourceLocationType = sourceLocationType, SourceLocationHash = sourceLocationHash, InstallationPolicy = installationPolicy, PackageManagementProvider = packageManagementProvider, PublishLocationHash = publishLocationHash, ScriptSourceLocationHash = scriptSourceLocationHash, ScriptPublishLocationHash = scriptPublishLocationHash }); + } + + } + + /// + /// Used by Ping-Endpoint function to supply webproxy to HttpClient + /// We cannot use System.Net.WebProxy because this is not available on CoreClr + /// + public class InternalWebProxy : IWebProxy + { + Uri _proxyUri; + ICredentials _credentials; + + public InternalWebProxy(Uri uri, ICredentials credentials) + { + Credentials = credentials; + _proxyUri = uri; + } + + /// + /// Credentials used by WebProxy + /// + public ICredentials Credentials + { + get + { + return _credentials; + } + set + { + _credentials = value; + } + } + + public Uri GetProxy(Uri destination) + { + return _proxyUri; + } + + public bool IsBypassed(Uri host) + { + return false; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct CERT_CHAIN_POLICY_PARA { + public CERT_CHAIN_POLICY_PARA(int size) { + cbSize = (uint) size; + dwFlags = 0; + pvExtraPolicyPara = IntPtr.Zero; + } + public uint cbSize; + public uint dwFlags; + public IntPtr pvExtraPolicyPara; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct CERT_CHAIN_POLICY_STATUS { + public CERT_CHAIN_POLICY_STATUS(int size) { + cbSize = (uint) size; + dwError = 0; + lChainIndex = IntPtr.Zero; + lElementIndex = IntPtr.Zero; + pvExtraPolicyStatus = IntPtr.Zero; + } + public uint cbSize; + public uint dwError; + public IntPtr lChainIndex; + public IntPtr lElementIndex; + public IntPtr pvExtraPolicyStatus; + } + + public class Win32Helpers + { + [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] + public extern static + bool CertVerifyCertificateChainPolicy( + [In] IntPtr pszPolicyOID, + [In] SafeX509ChainHandle pChainContext, + [In] ref CERT_CHAIN_POLICY_PARA pPolicyPara, + [In,Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus); + + [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] + public static extern + SafeX509ChainHandle CertDuplicateCertificateChain( + [In] IntPtr pChainContext); + + public static bool IsMicrosoftCertificate([In] SafeX509ChainHandle pChainContext) + { + //------------------------------------------------------------------------- + // CERT_CHAIN_POLICY_MICROSOFT_ROOT + // + // Checks if the last element of the first simple chain contains a + // Microsoft root public key. If it doesn't contain a Microsoft root + // public key, dwError is set to CERT_E_UNTRUSTEDROOT. + // + // pPolicyPara is optional. However, + // MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG can be set in + // the dwFlags in pPolicyPara to also check for the Microsoft Test Roots. + // + // MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG can be set + // in the dwFlags in pPolicyPara to check for the Microsoft root for + // application signing instead of the Microsoft product root. This flag + // explicitly checks for the application root only and cannot be combined + // with the test root flag. + // + // MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG can be set + // in the dwFlags in pPolicyPara to always disable the Flight root. + // + // pvExtraPolicyPara and pvExtraPolicyStatus aren't used and must be set + // to NULL. + //-------------------------------------------------------------------------- + const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG = 0x00010000; + //const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG = 0x00020000; + //const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG = 0x00040000; + + CERT_CHAIN_POLICY_PARA PolicyPara = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA))); + CERT_CHAIN_POLICY_STATUS PolicyStatus = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS))); + int CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7; + + PolicyPara.dwFlags = (uint) MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG; + + if(!CertVerifyCertificateChainPolicy(new IntPtr(CERT_CHAIN_POLICY_MICROSOFT_ROOT), + pChainContext, + ref PolicyPara, + ref PolicyStatus)) + { + return false; + } + + return (PolicyStatus.dwError == 0); + } + } +} +"@ + +# Telemetry is turned off by default. +$script:TelemetryEnabled = $false + +try +{ + # If the telemetry namespace/methods are not found flow goes to the catch block where telemetry is disabled + $telemetryMethods = ([Microsoft.PowerShell.Get.Telemetry] | Get-Member -Static).Name + + if ($telemetryMethods.Contains("TraceMessageArtifactsNotFound") -and $telemetryMethods.Contains("TraceMessageNonPSGalleryRegistration")) + { + # Turn ON Telemetry if the infrastructure is present on the machine + $script:TelemetryEnabled = $true + } +} +catch +{ + # Ignore the error and try adding the type below +} + +if(-not $script:TelemetryEnabled) +{ + try + { + Add-Type -ReferencedAssemblies $requiredAssembly -TypeDefinition $source -Language CSharp -ErrorAction SilentlyContinue + + # If the telemetry namespace/methods are not found flow goes to the catch block where telemetry is disabled + $telemetryMethods = ([Microsoft.PowerShell.Get.Telemetry] | Get-Member -Static).Name + + if ($telemetryMethods.Contains("TraceMessageArtifactsNotFound") -and $telemetryMethods.Contains("TraceMessageNonPSGalleryRegistration")) + { + # Turn ON Telemetry if the infrastructure is present on the machine + $script:TelemetryEnabled = $true + } + } + catch + { + # Disable Telemetry if there are any issues finding/loading the Telemetry infrastructure + $script:TelemetryEnabled = $false + } +} + +#endregion + +#region *-Module cmdlets +function Publish-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398575', + DefaultParameterSetName="ModuleNameParameterSet")] + Param + ( + [Parameter(Mandatory=$true, + ParameterSetName="ModuleNameParameterSet", + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter(Mandatory=$true, + ParameterSetName="ModulePathParameterSet", + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(ParameterSetName="ModuleNameParameterSet")] + [ValidateNotNullOrEmpty()] + [Version] + $RequiredVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $NuGetApiKey, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Repository = $Script:PSGalleryModuleSource, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [ValidateSet("1.0")] + [Version] + $FormatVersion, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + if($script:isNanoServer) { + $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Module" + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishModuleIsNotSupportedOnNanoServer" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + Get-PSGalleryApiAvailability -Repository $Repository + + if($LicenseUri -and -not (Test-WebUri -uri $LicenseUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $LicenseUri + } + + if($IconUri -and -not (Test-WebUri -uri $IconUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $IconUri + } + + if($ProjectUri -and -not (Test-WebUri -uri $ProjectUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ProjectUri + } + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force + } + + Process + { + if($Repository -eq $Script:PSGalleryModuleSource) + { + $moduleSource = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + if(-not $moduleSource) + { + $message = $LocalizedData.PSGalleryNotFound -f ($Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'PSGalleryNotFound' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + return + } + } + else + { + $ev = $null + $moduleSource = Get-PSRepository -Name $Repository -ErrorVariable ev + if($ev) { return } + } + + $DestinationLocation = $moduleSource.PublishLocation + + if(-not $DestinationLocation -or + (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and + -not (Test-WebUri -uri $DestinationLocation))) + + { + $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PSGalleryPublishLocationIsMissing" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $message = $LocalizedData.PublishLocation -f ($DestinationLocation) + Write-Verbose -Message $message + + if(-not $NuGetApiKey.Trim()) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) + { + $NuGetApiKey = "$(Get-Random)" + } + else + { + $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $providerName = Get-ProviderName -PSCustomObject $moduleSource + if($providerName -ne $script:NuGetProviderName) + { + $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PublishModuleSupportsOnlyNuGetBasedPublishLocations" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $moduleName = $null + + if($Name) + { + $module = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | + Microsoft.PowerShell.Core\Where-Object {-not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} + + if(-not $module) + { + if($RequiredVersion) + { + $message = $LocalizedData.ModuleWithRequiredVersionNotAvailableLocally -f ($Name, $RequiredVersion) + } + else + { + $message = $LocalizedData.ModuleNotAvailableLocally -f ($Name) + } + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleNotAvailableLocallyToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + + } + elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") + { + $message = $LocalizedData.AmbiguousModuleName -f ($Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "AmbiguousModuleNameToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + + $moduleName = $module.Name + $Path = $module.ModuleBase + } + else + { + $resolvedPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $resolvedPath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $resolvedPath -PathType Container)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.PathIsNotADirectory -f ($Path)) ` + -ErrorId "PathIsNotADirectory" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + return + } + + $moduleName = Microsoft.PowerShell.Management\Split-Path -Path $resolvedPath -Leaf + $modulePathWithVersion = $false + + # if the Leaf of the $resolvedPath is a version, use its parent folder name as the module name + $ModuleVersion = New-Object System.Version + if([System.Version]::TryParse($moduleName, ([ref]$ModuleVersion))) + { + $moduleName = Microsoft.PowerShell.Management\Split-Path -Path (Microsoft.PowerShell.Management\Split-Path $resolvedPath -Parent) -Leaf + $modulePathWithVersion = $true + } + + $manifestPath = Join-Path -Path $resolvedPath -ChildPath "$moduleName.psd1" + $module = $null + + if(Microsoft.PowerShell.Management\Test-Path -Path $manifestPath -PathType Leaf) + { + $ev = $null + $module = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` + -ErrorVariable ev ` + -Verbose:$VerbosePreference + if($ev) + { + # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. + return + } + } + elseif(-not $modulePathWithVersion -and ($PSVersionTable.PSVersion -ge [Version]'5.0')) + { + $module = Microsoft.PowerShell.Core\Get-Module -Name $resolvedPath -ListAvailable -ErrorAction SilentlyContinue -Verbose:$false + } + + if(-not $module) + { + $message = $LocalizedData.InvalidModulePathToPublish -f ($Path) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidModulePathToPublish' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + } + elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") + { + $message = $LocalizedData.AmbiguousModulePath -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'AmbiguousModulePathToPublish' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + } + + if($module -and (-not $module.Path.EndsWith('.psd1', [System.StringComparison]::OrdinalIgnoreCase))) + { + $message = $LocalizedData.InvalidModuleToPublish -f ($module.Name) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $module.Name + } + + $moduleName = $module.Name + $Path = $module.ModuleBase + } + + $message = $LocalizedData.PublishModuleLocation -f ($moduleName, $Path) + Write-Verbose -Message $message + + #If users are providing tags using -Tags while running PS 5.0, will show warning messages + if($Tags) + { + $message = $LocalizedData.TagsShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($ReleaseNotes) + { + $message = $LocalizedData.ReleaseNotesShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($LicenseUri) + { + $message = $LocalizedData.LicenseUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($IconUri) + { + $message = $LocalizedData.IconUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($ProjectUri) + { + $message = $LocalizedData.ProjectUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + + # Copy the source module to temp location to publish + $tempModulePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath ` + -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$moduleName" + + if(-not $FormatVersion) + { + $tempModulePathForFormatVersion = $tempModulePath + } + elseif ($FormatVersion -eq "1.0") + { + $tempModulePathForFormatVersion = Microsoft.PowerShell.Management\Join-Path $tempModulePath "Content\Deployment\$script:ModuleReferences\$moduleName" + } + + $null = Microsoft.PowerShell.Management\New-Item -Path $tempModulePathForFormatVersion -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Copy-Item -Path "$Path\*" -Destination $tempModulePathForFormatVersion -Force -Recurse -Confirm:$false -WhatIf:$false + + try + { + $manifestPath = Microsoft.PowerShell.Management\Join-Path $tempModulePathForFormatVersion "$moduleName.psd1" + + if(-not (Microsoft.PowerShell.Management\Test-Path $manifestPath)) + { + $message = $LocalizedData.InvalidModuleToPublish -f ($moduleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + $ev = $null + $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` + -ErrorVariable ev ` + -Verbose:$VerbosePreference + if($ev) + { + # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. + return + } + + if(-not $moduleInfo -or + -not $moduleInfo.Author -or + -not $moduleInfo.Description) + { + $message = $LocalizedData.MissingRequiredManifestKeys -f ($moduleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "MissingRequiredModuleManifestKeys" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + $FindParameters = @{ + Name = $moduleName + Repository = $Repository + Tag = 'PSScript' + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($Credential) + { + $FindParameters[$script:Credential] = $Credential + } + + # Check if the specified module name is already used for a script on the specified repository + # Use Find-Script to check if that name is already used as scriptname + $scriptPSGetItemInfo = Find-Script @FindParameters | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + if($scriptPSGetItemInfo) + { + $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($moduleName, $Repository, 'Find-Script') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedNameIsAlearyUsed" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + $null = $FindParameters.Remove('Tag') + $currentPSGetItemInfo = Find-Module @FindParameters | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleInfo.Name} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if($currentPSGetItemInfo) + { + if($currentPSGetItemInfo.Version -eq $moduleInfo.Version) + { + $message = $LocalizedData.ModuleVersionIsAlreadyAvailableInTheGallery -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'ModuleVersionIsAlreadyAvailableInTheGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + elseif(-not $Force -and ($currentPSGetItemInfo.Version -gt $moduleInfo.Version)) + { + $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + } + + $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) + if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) + { + Publish-PSArtifactUtility -PSModuleInfo $moduleInfo ` + -ManifestPath $manifestPath ` + -NugetApiKey $NuGetApiKey ` + -Destination $DestinationLocation ` + -Repository $Repository ` + -NugetPackageRoot $tempModulePath ` + -FormatVersion $FormatVersion ` + -ReleaseNotes $($ReleaseNotes -join "`r`n") ` + -Tags $Tags ` + -LicenseUri $LicenseUri ` + -IconUri $IconUri ` + -ProjectUri $ProjectUri ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempModulePath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Find-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=398574')] + [outputtype("PSCustomObject[]")] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [switch] + $IncludeDependencies, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [ValidateSet('DscResource','Cmdlet','Function','RoleCapability')] + [string[]] + $Includes, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $DscResource, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $RoleCapability, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Command, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $modulesFoundInPSGallery = @() + + # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories + $isRepositoryNullOrPSGallerySpecified = $false + if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + elseif(-not $Repository) + { + $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($psgalleryRepo) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + } + + PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { + + $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule + + $psgetItemInfo + + if ($psgetItemInfo -and + $isRepositoryNullOrPSGallerySpecified -and + $script:TelemetryEnabled -and + ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) + { + $modulesFoundInPSGallery += $psgetItemInfo.Name + } + } + + # Perform Telemetry if Repository is not supplied or Repository contains PSGallery + # We are only interested in finding modules not in PSGallery + if ($isRepositoryNullOrPSGallerySpecified) + { + Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $modulesFoundInPSGallery -operationName 'PSGET_FIND_MODULE' + } + } +} + +function Save-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=531351', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(Mandatory=$true, ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndPathParameterSet')] + [string] + $Path, + + [Parameter(Mandatory=$true, ParameterSetName='NameAndLiteralPathParameterSet')] + [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [string] + $LiteralPath, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Module names already tried in the current pipeline for InputObject parameterset + $moduleNamesInPipeline = @() + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + # When -Force is specified, Path will be created if not available. + if(-not $Force) + { + if($Path) + { + $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['Path'] = $destinationPath + } + else + { + $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['LiteralPath'] = $destinationPath + } + } + + if($Name) + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $null = PackageManagement\Save-Package @PSBoundParameters + } + elseif($InputObject) + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + $psgetModuleInfo = $inputValue.PSGetModuleInfo + } + else + { + $psgetModuleInfo = $inputValue + } + + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetModuleInfo.Name + + if ($psgetModuleInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psgetModuleInfo.Name + $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version + $PSBoundParameters['Source'] = $psgetModuleInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) + + $null = PackageManagement\Save-Package @PSBoundParameters + } + } + } +} + +function Install-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398573', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [ValidateSet("CurrentUser","AllUsers")] + [string] + $Scope = "AllUsers", + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [switch] + $AllowClobber, + + [Parameter()] + [switch] + $SkipPublisherCheck, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) + { + # Throw an error when Install-Module is used as a non-admin user and '-Scope CurrentUser' is not specified + $message = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Module names already tried in the current pipeline for InputObject parameterset + $moduleNamesInPipeline = @() + $YesToAll = $false + $NoToAll = $false + $SourceSGrantedTrust = @() + $SourcesDeniedTrust = @() + } + + Process + { + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + $PSBoundParameters['Scope'] = $Scope + + if($PSCmdlet.ParameterSetName -eq "NameParameterSet") + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $null = PackageManagement\Install-Package @PSBoundParameters + } + elseif($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + $psgetModuleInfo = $inputValue.PSGetModuleInfo + } + else + { + $psgetModuleInfo = $inputValue + } + + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetModuleInfo.Name + + if ($psgetModuleInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psgetModuleInfo.Name + $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version + $PSBoundParameters['Source'] = $psgetModuleInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) + + #Check if module is already installed + $InstalledModuleInfo = Test-ModuleInstalled -Name $psgetModuleInfo.Name -RequiredVersion $psgetModuleInfo.Version + if(-not $Force -and $InstalledModuleInfo -ne $null) + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) + Write-Verbose -Message $message + } + else + { + $source = $psgetModuleInfo.Repository + $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy + $ShouldProcessMessage = $PackageTarget -f ($psgetModuleInfo.Name, $psgetModuleInfo.Version) + + if($psCmdlet.ShouldProcess($ShouldProcessMessage)) + { + if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) + { + if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) + { + $message = $QueryInstallUntrustedPackage -f ($psgetModuleInfo.Name, $psgetModuleInfo.RepositorySourceLocation) + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) + } + else + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) + } + + if($sourceTrusted) + { + $SourceSGrantedTrust+=$source + } + else + { + $SourcesDeniedTrust+=$source + } + } + } + + if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourceSGrantedTrust.Contains($source) -or $YesToAll -or $Force) + { + $PSBoundParameters["Force"] = $true + $null = PackageManagement\Install-Package @PSBoundParameters + } + } + } + } + } + } +} + +function Update-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398576')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [switch] + $SkipPublisherCheck, + + [Parameter()] + [Switch] + $Force + ) + + Begin + { + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Module names already tried in the current pipeline + $moduleNamesInPipeline = @() + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $GetPackageParameters = @{} + $GetPackageParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + $GetPackageParameters["Provider"] = $script:PSModuleProviderName + $GetPackageParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + $GetPackageParameters['ErrorAction'] = 'SilentlyContinue' + $GetPackageParameters['WarningAction'] = 'SilentlyContinue' + + $PSGetItemInfos = @() + + if($Name) + { + foreach($moduleName in $Name) + { + $GetPackageParameters['Name'] = $moduleName + $installedPackages = PackageManagement\Get-Package @GetPackageParameters + + if(-not $installedPackages -and -not (Test-WildcardPattern -Name $moduleName)) + { + $availableModules = Get-Module -ListAvailable $moduleName -Verbose:$false | Microsoft.PowerShell.Utility\Select-Object -Unique + + if(-not $availableModules) + { + $message = $LocalizedData.ModuleNotInstalledOnThisMachine -f ($moduleName) + Write-Error -Message $message -ErrorId 'ModuleNotInstalledOnThisMachine' -Category InvalidOperation -TargetObject $moduleName + } + else + { + $message = $LocalizedData.ModuleNotInstalledUsingPowerShellGet -f ($moduleName) + Write-Error -Message $message -ErrorId 'ModuleNotInstalledUsingInstallModuleCmdlet' -Category InvalidOperation -TargetObject $moduleName + } + + continue + } + + $installedPackages | + Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | + Microsoft.PowerShell.Core\ForEach-Object { + if(-not (Test-RunningAsElevated) -and $_.InstalledLocation.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-WildcardPattern -Name $moduleName)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForUpdate -f ($_.Name, $_.InstalledLocation) + Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $moduleName + } + continue + } + + $PSGetItemInfos += $_ + } + } + } + else + { + + $PSGetItemInfos = PackageManagement\Get-Package @GetPackageParameters | + Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | + Microsoft.PowerShell.Core\Where-Object { + (Test-RunningAsElevated) -or + $_.InstalledLocation.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase) + } + } + + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + foreach($psgetItemInfo in $PSGetItemInfos) + { + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetItemInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetItemInfo.Name + + $message = $LocalizedData.CheckingForModuleUpdate -f ($psgetItemInfo.Name) + Write-Verbose -Message $message + + $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo + if(-not $providerName) + { + $providerName = $script:NuGetProviderName + } + + $PSBoundParameters["Name"] = $psgetItemInfo.Name + $PSBoundParameters['Source'] = $psgetItemInfo.Repository + + Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) + + $PSBoundParameters["PackageManagementProvider"] = $providerName + $PSBoundParameters["InstallUpdate"] = $true + + if($psgetItemInfo.InstalledLocation.ToString().StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "CurrentUser" + } + else + { + $PSBoundParameters['Scope'] = 'AllUsers' + } + + $sid = PackageManagement\Install-Package @PSBoundParameters + } + } +} + +function Uninstall-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=526864')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [switch] + $AllVersions, + + [Parameter()] + [Switch] + $Force + ) + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + if($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $PSBoundParameters["Name"] = $inputValue.Name + $PSBoundParameters["RequiredVersion"] = $inputValue.Version + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } + else + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } +} + +function Get-InstalledModule +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=526863')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [switch] + $AllVersions + ) + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} + } +} + +#endregion *-Module cmdlets + +#region Find-DscResouce cmdlet + +function Find-DscResource +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=517196')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + $PSBoundParameters['Includes'] = 'DscResource' + + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['DscResource'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.DscResource | Microsoft.PowerShell.Core\ForEach-Object { + if($Name -and ($Name -notcontains $_)) + { + return + } + + $psgetDscResourceInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetDscResourceInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetDscResourceInfo') + $psgetDscResourceInfo + } + } + } +} + +#endregion Find-DscResouce cmdlet + +#region Find-Command cmdlet + +function Find-Command +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=733636')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['Command'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + else + { + $PSBoundParameters['Includes'] = @('Cmdlet','Function') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.Command | Microsoft.PowerShell.Core\ForEach-Object { + if(($_ -eq "*") -or ($Name -and ($Name -notcontains $_))) + { + return + } + + $psgetCommandInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetCommandInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetCommandInfo') + $psgetCommandInfo + } + } + } +} + +#endregion Find-Command cmdlet + +#region Find-RoleCapability cmdlet + +function Find-RoleCapability +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=718029')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + $PSBoundParameters['Includes'] = 'RoleCapability' + + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['RoleCapability'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.RoleCapability | Microsoft.PowerShell.Core\ForEach-Object { + if($Name -and ($Name -notcontains $_)) + { + return + } + + $psgetRoleCapabilityInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetRoleCapabilityInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo') + $psgetRoleCapabilityInfo + } + } + } +} + +#endregion Find-RoleCapability cmdlet + +#region *-Script cmdlets +function Publish-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619788')] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='PathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='LiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $NuGetApiKey, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Repository = $Script:PSGalleryModuleSource, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + if($script:isNanoServer) { + $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Script" + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishScriptIsNotSupportedOnNanoServer" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force + } + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + if($Repository -eq $Script:PSGalleryModuleSource) + { + $repo = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + if(-not $repo) + { + $message = $LocalizedData.PSGalleryNotFound -f ($Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'PSGalleryNotFound' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + return + } + } + else + { + $ev = $null + $repo = Get-PSRepository -Name $Repository -ErrorVariable ev + if($ev) { return } + } + + $DestinationLocation = $null + + if(Get-Member -InputObject $repo -Name $script:ScriptPublishLocation) + { + $DestinationLocation = $repo.ScriptPublishLocation + } + + if(-not $DestinationLocation -or + (-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) -and + -not (Test-WebUri -uri $DestinationLocation))) + + { + $message = $LocalizedData.PSRepositoryScriptPublishLocationIsMissing -f ($Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PSRepositoryScriptPublishLocationIsMissing" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $message = $LocalizedData.PublishLocation -f ($DestinationLocation) + Write-Verbose -Message $message + + if(-not $NuGetApiKey.Trim()) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) + { + $NuGetApiKey = "$(Get-Random)" + } + else + { + $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $providerName = Get-ProviderName -PSCustomObject $repo + if($providerName -ne $script:NuGetProviderName) + { + $message = $LocalizedData.PublishScriptSupportsOnlyNuGetBasedPublishLocations -f ($DestinationLocation, $Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PublishScriptSupportsOnlyNuGetBasedPublishLocations" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + if($Path) + { + $PSScriptInfo = Test-ScriptFileInfo -Path $scriptFilePath + } + else + { + $PSScriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath + } + + if(-not $PSScriptInfo) + { + # Test-ScriptFileInfo throws the actual error + return + } + + $scriptName = $PSScriptInfo.Name + + # Copy the source script file to temp location to publish + $tempScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath ` + -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$scriptName" + + $null = Microsoft.PowerShell.Management\New-Item -Path $tempScriptPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + if($Path) + { + Microsoft.PowerShell.Management\Copy-Item -Path $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false + } + else + { + Microsoft.PowerShell.Management\Copy-Item -LiteralPath $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false + } + + try + { + $FindParameters = @{ + Name = $scriptName + Repository = $Repository + Tag = 'PSModule' + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($Credential) + { + $FindParameters[$script:Credential] = $Credential + } + + # Check if the specified script name is already used for a module on the specified repository + # Use Find-Module to check if that name is already used as module name + $modulePSGetItemInfo = Find-Module @FindParameters | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + if($modulePSGetItemInfo) + { + $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($scriptName, $Repository, 'Find-Module') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedNameIsAlearyUsed" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $scriptName + } + + $null = $FindParameters.Remove('Tag') + + $currentPSGetItemInfo = $null + $currentPSGetItemInfo = Find-Script @FindParameters | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if($currentPSGetItemInfo) + { + if($currentPSGetItemInfo.Version -eq $PSScriptInfo.Version) + { + $message = $LocalizedData.ScriptVersionIsAlreadyAvailableInTheGallery -f ($scriptName, + $PSScriptInfo.Version, + $currentPSGetItemInfo.Version, + $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId 'ScriptVersionIsAlreadyAvailableInTheGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + elseif(-not $Force -and ($currentPSGetItemInfo.Version -gt $PSScriptInfo.Version)) + { + $message = $LocalizedData.ScriptVersionShouldBeGreaterThanGalleryVersion -f ($scriptName, + $PSScriptInfo.Version, + $currentPSGetItemInfo.Version, + $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ScriptVersionShouldBeGreaterThanGalleryVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + } + + $shouldProcessMessage = $LocalizedData.PublishScriptwhatIfMessage -f ($PSScriptInfo.Version, $scriptName) + if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script")) + { + Publish-PSArtifactUtility -PSScriptInfo $PSScriptInfo ` + -NugetApiKey $NuGetApiKey ` + -Destination $DestinationLocation ` + -Repository $Repository ` + -NugetPackageRoot $tempScriptPath ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempScriptPath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Find-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619785')] + [outputtype("PSCustomObject[]")] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [switch] + $IncludeDependencies, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [ValidateSet('Function','Workflow')] + [string[]] + $Includes, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Command, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters['Provider'] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets + + $scriptsFoundInPSGallery = @() + + # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories + $isRepositoryNullOrPSGallerySpecified = $false + if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + elseif(-not $Repository) + { + $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + # And check for IsDeafult? + if($psgalleryRepo) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + } + + PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { + $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript + + $psgetItemInfo + + if ($psgetItemInfo -and + $isRepositoryNullOrPSGallerySpecified -and + $script:TelemetryEnabled -and + ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) + { + $scriptsFoundInPSGallery += $psgetItemInfo.Name + } + } + + # Perform Telemetry if Repository is not supplied or Repository contains PSGallery + # We are only interested in finding artifacts not in PSGallery + if ($isRepositoryNullOrPSGallerySpecified) + { + Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $scriptsFoundInPSGallery -operationName PSGET_FIND_SCRIPT + } + } +} + +function Save-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619786', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='InputOjectAndPathParameterSet')] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [string] + $LiteralPath, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Script names already tried in the current pipeline for InputObject parameterset + $scriptNamesInPipeline = @() + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + # When -Force is specified, Path will be created if not available. + if(-not $Force) + { + if($Path) + { + $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['Path'] = $destinationPath + } + else + { + $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['LiteralPath'] = $destinationPath + } + } + + if($Name) + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + $null = PackageManagement\Save-Package @PSBoundParameters + } + elseif($InputObject) + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $psRepositoryItemInfo = $inputValue + + # Skip the script name if it is already tried in the current pipeline + if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) + { + continue + } + + $scriptNamesInPipeline += $psRepositoryItemInfo.Name + + if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name + $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version + $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) + + $null = PackageManagement\Save-Package @PSBoundParameters + } + } + } +} + +function Install-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619784', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter()] + [ValidateSet("CurrentUser","AllUsers")] + [string] + $Scope = 'AllUsers', + + [Parameter()] + [Switch] + $NoPathUpdate, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) + { + # Throw an error when Install-Script is used as a non-admin user and '-Scope CurrentUser' is not specified + $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + # Check and add the scope path to PATH environment variable + if($Scope -eq 'AllUsers') + { + $scopePath = $script:ProgramFilesScriptsPath + } + else + { + $scopePath = $script:MyDocumentsScriptsPath + } + + ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` + -ScopePath $scopePath ` + -NoPathUpdate:$NoPathUpdate ` + -Force:$Force + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Script names already tried in the current pipeline for InputObject parameterset + $scriptNamesInPipeline = @() + + $YesToAll = $false + $NoToAll = $false + $SourceSGrantedTrust = @() + $SourcesDeniedTrust = @() + } + + Process + { + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + $PSBoundParameters['Scope'] = $Scope + + if($PSCmdlet.ParameterSetName -eq "NameParameterSet") + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + if(-not $Force) + { + foreach($scriptName in $Name) + { + # Throw an error if there is a command with the same name and -force is not specified. + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $scriptName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + # Check if this script was already installed, may be with -Force + $InstalledScriptInfo = Test-ScriptInstalled -Name $scriptName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if(-not $InstalledScriptInfo) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($scriptName) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + + # return if only single name is specified + if($scriptName -eq $Name) + { + return + } + } + } + } + } + + $null = PackageManagement\Install-Package @PSBoundParameters + } + elseif($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $psRepositoryItemInfo = $inputValue + + # Skip the script name if it is already tried in the current pipeline + if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) + { + continue + } + + $scriptNamesInPipeline += $psRepositoryItemInfo.Name + + if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name + $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version + $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) + + $InstalledScriptInfo = Test-ScriptInstalled -Name $psRepositoryItemInfo.Name + if(-not $Force -and $InstalledScriptInfo) + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) + Write-Verbose -Message $message + } + else + { + # Throw an error if there is a command with the same name and -force is not specified. + if(-not $Force) + { + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $psRepositoryItemInfo.Name ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + + continue + } + } + + $source = $psRepositoryItemInfo.Repository + $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy + $ShouldProcessMessage = $PackageTarget -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.Version) + + if($psCmdlet.ShouldProcess($ShouldProcessMessage)) + { + if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) + { + if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) + { + $message = $QueryInstallUntrustedPackage -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.RepositorySourceLocation) + + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) + } + else + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) + } + + if($sourceTrusted) + { + $SourcesGrantedTrust+=$source + } + else + { + $SourcesDeniedTrust+=$source + } + } + } + } + if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourcesGrantedTrust.Contains($source) -or $YesToAll -or $Force) + { + $PSBoundParameters["Force"] = $true + $null = PackageManagement\Install-Package @PSBoundParameters + } + } + } + } + } +} + +function Update-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619787')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [Switch] + $Force + ) + + Begin + { + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + # Script names already tried in the current pipeline + $scriptNamesInPipeline = @() + } + + Process + { + $scriptFilePathsToUpdate = @() + + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($Name) + { + foreach($scriptName in $Name) + { + $availableScriptPaths = Get-AvailableScriptFilePath -Name $scriptName -Verbose:$false + + if(-not $availableScriptPaths -and -not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.ScriptNotInstalledOnThisMachine -f ($scriptName, $script:MyDocumentsScriptsPath, $script:ProgramFilesScriptsPath) + Write-Error -Message $message -ErrorId "ScriptNotInstalledOnThisMachine" -Category InvalidOperation -TargetObject $scriptName + continue + } + + foreach($scriptFilePath in $availableScriptPaths) + { + $installedScriptFilePath = Get-InstalledScriptFilePath -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) | + Microsoft.PowerShell.Core\Where-Object {$_ -eq $scriptFilePath } + + # Check if this script got installed with PowerShellGet and user has required permissions + if ($installedScriptFilePath) + { + if(-not (Test-RunningAsElevated) -and $installedScriptFilePath.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForScriptUpdate -f ($scriptName, $installedScriptFilePath) + Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $scriptName + } + continue + } + + $scriptFilePathsToUpdate += $installedScriptFilePath + } + else + { + if(-not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.ScriptNotInstalledUsingPowerShellGet -f ($scriptName) + Write-Error -Message $message -ErrorId "ScriptNotInstalledUsingPowerShellGet" -Category InvalidOperation -TargetObject $scriptName + } + continue + } + } + } + } + else + { + $isRunningAsElevated = Test-RunningAsElevated + $installedScriptFilePaths = Get-InstalledScriptFilePath + + if($isRunningAsElevated) + { + $scriptFilePathsToUpdate = $installedScriptFilePaths + } + else + { + # Update the scripts installed under + $scriptFilePathsToUpdate = $installedScriptFilePaths | Microsoft.PowerShell.Core\Where-Object { + $_.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)} + } + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateScriptMessageResolverScriptBlock + $PSBoundParameters["InstallUpdate"] = $true + + foreach($scriptFilePath in $scriptFilePathsToUpdate) + { + $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath) + + $installedScriptInfoFilePath = $null + $installedScriptInfoFileName = "$($scriptName)_$script:InstalledScriptInfoFileName" + + if($scriptFilePath.ToString().StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "CurrentUser" + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + elseif($scriptFilePath.ToString().StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "AllUsers" + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + + } + + $psgetItemInfo = $null + if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) + { + $psgetItemInfo = DeSerialize-PSObject -Path $installedScriptInfoFilePath + } + + # Skip the script name if it is already tried in the current pipeline + if(-not $psgetItemInfo -or ($scriptNamesInPipeline -contains $psgetItemInfo.Name)) + { + continue + } + + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` + -ChildPath "$($psgetItemInfo.Name).ps1" + + # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $installedScriptInfoFilePath -Force -ErrorAction SilentlyContinue + + continue + } + + $scriptNamesInPipeline += $psgetItemInfo.Name + + $message = $LocalizedData.CheckingForScriptUpdate -f ($psgetItemInfo.Name) + Write-Verbose -Message $message + + $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo + if(-not $providerName) + { + $providerName = $script:NuGetProviderName + } + + $PSBoundParameters["PackageManagementProvider"] = $providerName + $PSBoundParameters["Name"] = $psgetItemInfo.Name + $PSBoundParameters['Source'] = $psgetItemInfo.Repository + + Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) + + $sid = PackageManagement\Install-Package @PSBoundParameters + } + } +} + +function Uninstall-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619789')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $Force + ) + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + if($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $PSBoundParameters["Name"] = $inputValue.Name + $PSBoundParameters["RequiredVersion"] = $inputValue.Version + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } + else + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } +} + +function Get-InstalledScript +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619790')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion + ) + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript} + } +} + +#endregion *-Script cmdlets + +#region *-PSRepository cmdlets + +function Register-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkID=517129')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter(Mandatory=$true, + Position=1, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [Uri] + $SourceLocation, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [Uri] + $PublishLocation, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptSourceLocation, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptPublishLocation, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [PSCredential] + $Credential, + + [Parameter(Mandatory=$true, + ParameterSetName='PSGalleryParameterSet')] + [Switch] + $Default, + + [Parameter()] + [ValidateSet('Trusted','Untrusted')] + [string] + $InstallationPolicy = 'Untrusted', + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $PackageManagementProvider + ) + + DynamicParam + { + if (Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) + { + Set-Variable -Name selctedProviderName -value $null -Scope 1 + + if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) + { + $selctedProviderName = $PackageManagementProvider + $null = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName) + } + else + { + $dynamicParameters = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName) + Set-Variable -Name PackageManagementProvider -Value $selctedProviderName -Scope 1 + $null = $dynamicParameters + } + } + } + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + if($PackageManagementProvider) + { + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) + { + $possibleProviderNames = $script:NuGetProviderName + + if($providers) + { + $possibleProviderNames = ($providers.Name -join ',') + } + + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PackageManagementProvider + return + } + } + } + + Process + { + if($PSCmdlet.ParameterSetName -eq 'PSGalleryParameterSet') + { + if(-not $Default) + { + return + } + + $PSBoundParameters['Name'] = $Script:PSGalleryModuleSource + $null = $PSBoundParameters.Remove('Default') + } + else + { + if($Name -eq $Script:PSGalleryModuleSource) + { + $message = $LocalizedData.UseDefaultParameterSetOnRegisterPSRepository + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'UseDefaultParameterSetOnRegisterPSRepository' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + return + } + + # Ping and resolve the specified location + $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` + -LocationParameterName 'SourceLocation' ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -CallerPSCmdlet $PSCmdlet + if(-not $SourceLocation) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + + $providerName = $null + + if($PackageManagementProvider) + { + $providerName = $PackageManagementProvider + } + elseif($selctedProviderName) + { + $providerName = $selctedProviderName + } + else + { + $providerName = Get-PackageManagementProviderName -Location $SourceLocation + } + + if($providerName) + { + $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName + } + + if($PublishLocation) + { + $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation + } + + if($ScriptPublishLocation) + { + $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation + } + + if($ScriptSourceLocation) + { + $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation + } + + $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation + $null = $PSBoundParameters.Remove("SourceLocation") + } + + if($InstallationPolicy -eq "Trusted") + { + $PSBoundParameters['Trusted'] = $true + } + $null = $PSBoundParameters.Remove("InstallationPolicy") + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = PackageManagement\Register-PackageSource @PSBoundParameters + } +} + +function Set-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=517128')] + Param + ( + [Parameter(Mandatory=$true, Position=0)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter(Position=1)] + [ValidateNotNullOrEmpty()] + [Uri] + $SourceLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $PublishLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptSourceLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptPublishLocation, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $Credential, + + [Parameter()] + [ValidateSet('Trusted','Untrusted')] + [string] + $InstallationPolicy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Proxy, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [PSCredential] + $ProxyCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PackageManagementProvider + ) + + DynamicParam + { + if (Get-Variable -Name Name -ErrorAction SilentlyContinue) + { + $moduleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if($moduleSource) + { + $providerName = (Get-ProviderName -PSCustomObject $moduleSource) + + $loc = $moduleSource.SourceLocation + + if(Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) + { + $loc = $SourceLocation + } + + if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) + { + $providerName = $PackageManagementProvider + } + + $null = Get-DynamicParameters -Location $loc -PackageManagementProvider ([REF]$providerName) + } + } + } + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + + if($PackageManagementProvider) + { + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) + { + $possibleProviderNames = $script:NuGetProviderName + + if($providers) + { + $possibleProviderNames = ($providers.Name -join ',') + } + + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PackageManagementProvider + return + } + } + } + + Process + { + # Ping and resolve the specified location + if($SourceLocation) + { + # Ping and resolve the specified location + $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` + -LocationParameterName 'SourceLocation' ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -CallerPSCmdlet $PSCmdlet + if(-not $SourceLocation) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + } + + $ModuleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if(-not $ModuleSource) + { + $message = $LocalizedData.RepositoryNotFound -f ($Name) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Name + } + + if (-not $PackageManagementProvider) + { + $PackageManagementProvider = (Get-ProviderName -PSCustomObject $ModuleSource) + } + + $Trusted = $ModuleSource.Trusted + if($InstallationPolicy) + { + if($InstallationPolicy -eq "Trusted") + { + $Trusted = $true + } + else + { + $Trusted = $false + } + + $null = $PSBoundParameters.Remove("InstallationPolicy") + } + + if($PublishLocation) + { + $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation + } + + if($ScriptPublishLocation) + { + $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation + } + + if($ScriptSourceLocation) + { + $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation + } + + if($SourceLocation) + { + $PSBoundParameters["NewLocation"] = Get-LocationString -LocationUri $SourceLocation + + $null = $PSBoundParameters.Remove("SourceLocation") + } + + $PSBoundParameters[$script:PackageManagementProviderParam] = $PackageManagementProvider + $PSBoundParameters.Add("Trusted", $Trusted) + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = PackageManagement\Set-PackageSource @PSBoundParameters + } +} + +function Unregister-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517130')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = $PSBoundParameters.Remove("Name") + + foreach ($moduleSourceName in $Name) + { + # Check if $moduleSourceName contains any wildcards + if(Test-WildcardPattern $moduleSourceName) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation + continue + } + + $PSBoundParameters["Source"] = $moduleSourceName + + $null = PackageManagement\Unregister-PackageSource @PSBoundParameters + } + } +} + +function Get-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517127')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + if($Name) + { + foreach($sourceName in $Name) + { + $PSBoundParameters["Name"] = $sourceName + + $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters + + $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } + } + } + else + { + $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters + + $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } + } + } +} + +#endregion *-PSRepository cmdlets + +#region *-ScriptFileInfo cmdlets + +# Below is the sample PSScriptInfo in a script file. +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 544238e3-1751-4065-9227-be105ff11636 + +.AUTHOR manikb + +.COMPANYNAME Microsoft Corporation + +.COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. + +.TAGS Tag1 Tag2 Tag3 + +.LICENSEURI https://contoso.com/License + +.PROJECTURI https://contoso.com/ + +.ICONURI https://contoso.com/Icon + +.EXTERNALMODULEDEPENDENCIES ExternalModule1 + +.REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript + +.EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript + +.RELEASENOTES +contoso script now supports following features +Feature 1 +Feature 2 +Feature 3 +Feature 4 +Feature 5 + +#> + +<# #Requires -Module statements #> + +<# + +.DESCRIPTION + Description goes here. + +#> + + +# +function Test-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619791')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='PathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='LiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath + ) + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + return + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + $PSScriptInfo = New-PSScriptInfoObject -Path $scriptFilePath + + [System.Management.Automation.Language.Token[]]$tokens = $null; + [System.Management.Automation.Language.ParseError[]]$errors = $null; + $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) + + + $notSupportedOnNanoErrorIds = @('WorkflowNotSupportedInPowerShellCore', + 'ConfigurationNotSupportedInPowerShellCore') + $errosAfterSkippingOneCoreErrors = $errors | Microsoft.PowerShell.Core\Where-Object { $notSupportedOnNanoErrorIds -notcontains $_.ErrorId} + + if($errosAfterSkippingOneCoreErrors) + { + $errorMessage = ($LocalizedData.ScriptParseError -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "ScriptParseError" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $errosAfterSkippingOneCoreErrors ` + -ErrorCategory InvalidArgument + return + } + + if($ast) + { + # Get the block/group comment begining with <#PSScriptInfo + $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} + + $psscriptInfoComments = $CommentTokens | + Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $psscriptInfoComments) + { + $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingPSScriptInfo" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + # $psscriptInfoComments.Text will have the multiline PSScriptInfo comment, + # split them into multiple lines to parse for the PSScriptInfo metadata properties. + $commentLines = $psscriptInfoComments.Text -split "`r`n" + + $KeyName = $null + $Value = "" + + # PSScriptInfo comment will be in following format: + <#PSScriptInfo + + .VERSION 1.0 + + .GUID 544238e3-1751-4065-9227-be105ff11636 + + .AUTHOR manikb + + .COMPANYNAME Microsoft Corporation + + .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. + + .TAGS Tag1 Tag2 Tag3 + + .LICENSEURI https://contoso.com/License + + .PROJECTURI https://contoso.com/ + + .ICONURI https://contoso.com/Icon + + .EXTERNALMODULEDEPENDENCIES ExternalModule1 + + .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript + + .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript + + .RELEASENOTES + contoso script now supports following features + Feature 1 + Feature 2 + Feature 3 + Feature 4 + Feature 5 + + #> + # If comment line count is not more than two, it doesn't have the any metadata property + # First line is <#PSScriptInfo + # Last line #> + # + if($commentLines.Count -gt 2) + { + for($i = 1; $i -lt ($commentLines.count - 1); $i++) + { + $line = $commentLines[$i] + + if(-not $line) + { + continue + } + + # A line is starting with . conveys a new metadata property + # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object + # + if($line.trim().StartsWith('.')) + { + $parts = $line.trim() -split '[.\s+]',3 | Microsoft.PowerShell.Core\Where-Object {$_} + + if($KeyName -and $Value) + { + if($keyName -eq $script:ReleaseNotes) + { + $Value = $Value.Trim() -split '__NEWLINE__' + } + elseif($keyName -eq $script:DESCRIPTION) + { + $Value = $Value -split '__NEWLINE__' + $Value = ($Value -join "`r`n").Trim() + } + else + { + $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } + + if($Value -and $Value.GetType().ToString() -eq "System.String") + { + $Value = $Value.Trim() + } + } + + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $KeyName ` + -PropertyValue $Value ` + -CallerPSCmdlet $PSCmdlet + } + + $KeyName = $null + $Value = "" + + if($parts.GetType().ToString() -eq "System.String") + { + $KeyName = $parts + } + else + { + $KeyName = $parts[0]; + $Value = $parts[1] + } + } + else + { + if($Value) + { + # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object + $Value += '__NEWLINE__' + } + + $Value += $line + } + } + + if($KeyName -and $Value) + { + if($keyName -eq $script:ReleaseNotes) + { + $Value = $Value.Trim() -split '__NEWLINE__' + } + elseif($keyName -eq $script:DESCRIPTION) + { + $Value = $Value -split '__NEWLINE__' + $Value = ($Value -join "`r`n").Trim() + } + else + { + $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } + + if($Value -and $Value.GetType().ToString() -eq "System.String") + { + $Value = $Value.Trim() + } + } + + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $KeyName ` + -PropertyValue $Value ` + -CallerPSCmdlet $PSCmdlet + + $KeyName = $null + $Value = "" + } + } + + $helpContent = $ast.GetHelpContent() + if($helpContent -and $helpContent.Description) + { + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DESCRIPTION ` + -PropertyValue $helpContent.Description.Trim() ` + -CallerPSCmdlet $PSCmdlet + + } + + # Handle RequiredModules + if((Microsoft.PowerShell.Utility\Get-Member -InputObject $ast -Name 'ScriptRequirements') -and + $ast.ScriptRequirements -and + (Microsoft.PowerShell.Utility\Get-Member -InputObject $ast.ScriptRequirements -Name 'RequiredModules') -and + $ast.ScriptRequirements.RequiredModules) + { + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:RequiredModules ` + -PropertyValue $ast.ScriptRequirements.RequiredModules ` + -CallerPSCmdlet $PSCmdlet + } + + # Get all defined functions and populate DefinedCommands, DefinedFunctions and DefinedWorkflows + $allCommands = $ast.FindAll({param($i) return ($i.GetType().Name -eq 'FunctionDefinitionAst')}, $true) + + if($allCommands) + { + $allCommandNames = $allCommands | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedCommands ` + -PropertyValue $allCommandNames ` + -CallerPSCmdlet $PSCmdlet + + $allFunctionNames = $allCommands | Where-Object {-not $_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedFunctions ` + -PropertyValue $allFunctionNames ` + -CallerPSCmdlet $PSCmdlet + + + $allWorkflowNames = $allCommands | Where-Object {$_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedWorkflows ` + -PropertyValue $allWorkflowNames ` + -CallerPSCmdlet $PSCmdlet + } + } + + # Ensure that the script file has the required metadata properties. + if(-not $PSScriptInfo.Version -or -not $PSScriptInfo.Guid -or -not $PSScriptInfo.Author -or -not $PSScriptInfo.Description) + { + $errorMessage = ($LocalizedData.MissingRequiredPSScriptInfoProperties -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingRequiredPSScriptInfoProperties" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + + $PSScriptInfo = Get-OrderedPSScriptInfoObject -PSScriptInfo $PSScriptInfo + + return $PSScriptInfo + } +} + +function New-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619792')] + Param + ( + [Parameter(Mandatory=$false, + Position=0, + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredScripts, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [switch] + $Force + ) + + Process + { + if($Path) + { + if(-not $Path.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $Path) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'InvalidScriptFilePath' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Force -and (Microsoft.PowerShell.Management\Test-Path -Path $Path)) + { + $errorMessage = ($LocalizedData.ScriptFileExist -f $Path) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'ScriptFileExist' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + } + elseif(-not $PassThru) + { + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $LocalizedData.MissingTheRequiredPathOrPassThruParameter ` + -ErrorId 'MissingTheRequiredPathOrPassThruParameter' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Version) + { + $Version = [Version]'1.0' + } + + if(-not $Author) + { + $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) + } + + if(-not $Guid) + { + $Guid = [System.Guid]::NewGuid() + } + + $params = @{ + Version = $Version + Author = $Author + Guid = $Guid + CompanyName = $CompanyName + Copyright = $Copyright + ExternalModuleDependencies = $ExternalModuleDependencies + RequiredScripts = $RequiredScripts + ExternalScriptDependencies = $ExternalScriptDependencies + Tags = $Tags + ProjectUri = $ProjectUri + LicenseUri = $LicenseUri + IconUri = $IconUri + ReleaseNotes = $ReleaseNotes + } + + if(-not (Validate-ScriptFileInfoParameters -parameters $params)) + { + return + } + + if("$Description" -match '<#' -or "$Description" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + return + } + + $PSScriptInfoString = Get-PSScriptInfoString @params + + $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules + + $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $Description + + $ScriptMetadataString = $PSScriptInfoString + $ScriptMetadataString += "`r`n" + + if("$requiresStrings".Trim()) + { + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $requiresStrings -join "`r`n" + $ScriptMetadataString += "`r`n" + } + + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $ScriptCommentHelpInfoString + $ScriptMetadataString += "Param()`r`n`r`n" + + $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1" + + try + { + Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the errors + return + } + + if($Path -and ($Force -or $PSCmdlet.ShouldProcess($Path, ($LocalizedData.NewScriptFileInfowhatIfMessage -f $Path) ))) + { + Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $Path -Force -WhatIf:$false -Confirm:$false + } + + if($PassThru) + { + Write-Output -InputObject $ScriptMetadataString + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + } +} + +function Update-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619793')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName='PathParameterSet', + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName='LiteralPathParameterSet', + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredScripts, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [switch] + $Force + ) + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + $psscriptInfo = $null + try + { + $psscriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath + } + catch + { + if(-not $Force) + { + throw $_ + return + } + } + + if(-not $psscriptInfo) + { + if(-not $Description) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.DescriptionParameterIsMissingForAddingTheScriptFileInfo ` + -ErrorId 'DescriptionParameterIsMissingForAddingTheScriptFileInfo' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Version) + { + $Version = [Version]'1.0' + } + + if(-not $Author) + { + $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) + } + + if(-not $Guid) + { + $Guid = [System.Guid]::NewGuid() + } + } + else + { + # Use existing values if any of the parameters are not specified during Update-ScriptFileInfo + if(-not $Version -and $psscriptInfo.Version) + { + $Version = $psscriptInfo.Version + } + + if(-not $Guid -and $psscriptInfo.Guid) + { + $Guid = $psscriptInfo.Guid + } + + if(-not $Author -and $psscriptInfo.Author) + { + $Author = $psscriptInfo.Author + } + + if(-not $CompanyName -and $psscriptInfo.CompanyName) + { + $CompanyName = $psscriptInfo.CompanyName + } + + if(-not $Copyright -and $psscriptInfo.Copyright) + { + $Copyright = $psscriptInfo.Copyright + } + + if(-not $RequiredModules -and $psscriptInfo.RequiredModules) + { + $RequiredModules = $psscriptInfo.RequiredModules + } + + if(-not $ExternalModuleDependencies -and $psscriptInfo.ExternalModuleDependencies) + { + $ExternalModuleDependencies = $psscriptInfo.ExternalModuleDependencies + } + + if(-not $RequiredScripts -and $psscriptInfo.RequiredScripts) + { + $RequiredScripts = $psscriptInfo.RequiredScripts + } + + if(-not $ExternalScriptDependencies -and $psscriptInfo.ExternalScriptDependencies) + { + $ExternalScriptDependencies = $psscriptInfo.ExternalScriptDependencies + } + + if(-not $Tags -and $psscriptInfo.Tags) + { + $Tags = $psscriptInfo.Tags + } + + if(-not $ProjectUri -and $psscriptInfo.ProjectUri) + { + $ProjectUri = $psscriptInfo.ProjectUri + } + + if(-not $LicenseUri -and $psscriptInfo.LicenseUri) + { + $LicenseUri = $psscriptInfo.LicenseUri + } + + if(-not $IconUri -and $psscriptInfo.IconUri) + { + $IconUri = $psscriptInfo.IconUri + } + + if(-not $ReleaseNotes -and $psscriptInfo.ReleaseNotes) + { + $ReleaseNotes = $psscriptInfo.ReleaseNotes + } + } + + $params = @{ + Version = $Version + Author = $Author + Guid = $Guid + CompanyName = $CompanyName + Copyright = $Copyright + ExternalModuleDependencies = $ExternalModuleDependencies + RequiredScripts = $RequiredScripts + ExternalScriptDependencies = $ExternalScriptDependencies + Tags = $Tags + ProjectUri = $ProjectUri + LicenseUri = $LicenseUri + IconUri = $IconUri + ReleaseNotes = $ReleaseNotes + } + + if(-not (Validate-ScriptFileInfoParameters -parameters $params)) + { + return + } + + if("$Description" -match '<#' -or "$Description" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + return + } + + $PSScriptInfoString = Get-PSScriptInfoString @params + + $requiresStrings = "" + $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules + + $DescriptionValue = if($Description) {$Description} else {$psscriptInfo.Description} + $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $DescriptionValue + + $ScriptMetadataString = $PSScriptInfoString + $ScriptMetadataString += "`r`n" + + if("$requiresStrings".Trim()) + { + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $requiresStrings -join "`r`n" + $ScriptMetadataString += "`r`n" + } + + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $ScriptCommentHelpInfoString + $ScriptMetadataString += "`r`nParam()`r`n`r`n" + if(-not $ScriptMetadataString) + { + return + } + + $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1" + + try + { + # First create a new script file with new script metadata to ensure that updated values are valid. + Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + + $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -LiteralPath $scriptFilePath + + # If -Force is specified and script file doesnt have a valid PSScriptInfo + # Prepend the PSScriptInfo and Check if the Test-ScriptFileInfo returns a valid script info without any errors + if($Force -and -not $psscriptInfo) + { + # Add the script file contents to the temp file with script metadata + Microsoft.PowerShell.Management\Set-Content -LiteralPath $tempScriptFilePath ` + -Value $ScriptMetadataString,$scriptFileContents ` + -Force ` + -WhatIf:$false ` + -Confirm:$false + + $tempScriptInfo = $null + try + { + $tempScriptInfo = Test-ScriptFileInfo -LiteralPath $tempScriptFilePath + } + catch + { + $errorMessage = ($LocalizedData.UnableToAddPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'UnableToAddPSScriptInfo' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidOperation + return + } + } + else + { + [System.Management.Automation.Language.Token[]]$tokens = $null; + [System.Management.Automation.Language.ParseError[]]$errors = $null; + $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) + + # Update PSScriptInfo and #Requires + $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} + + $psscriptInfoComments = $CommentTokens | + Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $psscriptInfoComments) + { + $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingPSScriptInfo" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + # Ensure that metadata is replaced at the correct location and should not corrupt the existing script file. + + # Remove the lines between below lines and add the new PSScriptInfo and new #Requires statements + # ($psscriptInfoComments.Extent.StartLineNumber - 1) + # ($psscriptInfoComments.Extent.EndLineNumber - 1) + $tempContents = @() + $IsNewPScriptInfoAdded = $false + + for($i = 0; $i -lt $scriptFileContents.Count; $i++) + { + $line = $scriptFileContents[$i] + if(($i -ge ($psscriptInfoComments.Extent.StartLineNumber - 1)) -and + ($i -le ($psscriptInfoComments.Extent.EndLineNumber - 1))) + { + if(-not $IsNewPScriptInfoAdded) + { + $PSScriptInfoString = $PSScriptInfoString.TrimStart() + $requiresStrings = $requiresStrings.TrimEnd() + + $tempContents += "$PSScriptInfoString `r`n`r`n$($requiresStrings -join "`r`n")" + $IsNewPScriptInfoAdded = $true + } + } + elseif($line -notmatch "\s*#Requires\s+-Module") + { + # Add the existing lines if they are not part of PSScriptInfo comment or not containing #Requires -Module statements. + $tempContents += $line + } + } + + Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + + # Now update the Description value if a new is specified. + if($Description) + { + $tempContents = @() + $IsDescriptionAdded = $false + + $IsDescriptionBeginFound = $false + $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -Path $tempScriptFilePath + + for($i = 0; $i -lt $scriptFileContents.Count; $i++) + { + $line = $scriptFileContents[$i] + + if(-not $IsDescriptionAdded) + { + if(-not $IsDescriptionBeginFound) + { + if($line.Trim().StartsWith(".DESCRIPTION", [System.StringComparison]::OrdinalIgnoreCase)) + { + $IsDescriptionBeginFound = $true + } + else + { + $tempContents += $line + } + } + else + { + # Description begin has found + # Skip the old description lines until description end is found + + if($line.Trim().StartsWith("#>", [System.StringComparison]::OrdinalIgnoreCase) -or + $line.Trim().StartsWith(".", [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempContents += ".DESCRIPTION `r`n$($Description -join "`r`n")`r`n" + $IsDescriptionAdded = $true + $tempContents += $line + } + } + } + else + { + $tempContents += $line + } + } + + Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + } + } + + if($Force -or $PSCmdlet.ShouldProcess($scriptFilePath, ($LocalizedData.UpdateScriptFileInfowhatIfMessage -f $Path) )) + { + Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $scriptFilePath -Force -WhatIf:$false -Confirm:$false + + if($PassThru) + { + $ScriptMetadataString + } + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + } +} + +function Get-RequiresString +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [Object[]] + $RequiredModules + ) + + Process + { + if($RequiredModules) + { + $RequiredModuleStrings = @() + + foreach($requiredModuleObject in $RequiredModules) + { + if($requiredModuleObject.GetType().ToString() -eq 'System.Collections.Hashtable') + { + if(($requiredModuleObject.Keys.Count -eq 1) -and + (Microsoft.PowerShell.Utility\Get-Member -InputObject $requiredModuleObject -Name 'ModuleName')) + { + $RequiredModuleStrings += $requiredModuleObject['ModuleName'].ToString() + } + else + { + $moduleSpec = New-Object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList $requiredModuleObject + if (-not (Microsoft.PowerShell.Utility\Get-Variable -Name moduleSpec -ErrorAction SilentlyContinue)) + { + return + } + + $keyvalueStrings = $requiredModuleObject.Keys | Microsoft.PowerShell.Core\ForEach-Object {"$_ = '$( $requiredModuleObject[$_])'"} + $RequiredModuleStrings += "@{$($keyvalueStrings -join '; ')}" + } + } + elseif(($PSVersionTable.PSVersion -eq [Version]'3.0') -and + ($requiredModuleObject.GetType().ToString() -eq 'Microsoft.PowerShell.Commands.ModuleSpecification')) + { + # ModuleSpecification.ToString() is not implemented on PowerShell 3.0. + + $optionalString = " " + + if($requiredModuleObject.Version) + { + $optionalString += "ModuleVersion = '$($requiredModuleObject.Version.ToString())'; " + } + + if($requiredModuleObject.Guid) + { + $optionalString += "Guid = '$($requiredModuleObject.Guid.ToString())'; " + } + + if($optionalString.Trim()) + { + $moduleSpecString = "@{ ModuleName = '$($requiredModuleObject.Name.ToString())';$optionalString}" + } + else + { + $moduleSpecString = $requiredModuleObject.Name.ToString() + } + + $RequiredModuleStrings += $moduleSpecString + } + else + { + $RequiredModuleStrings += $requiredModuleObject.ToString() + } + } + + $hashRequiresStrings = $RequiredModuleStrings | + Microsoft.PowerShell.Core\ForEach-Object { "#Requires -Module $_" } + + return $hashRequiresStrings + } + else + { + return "" + } + } +} + +function Get-PSScriptInfoString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [String] + $CompanyName, + + [Parameter()] + [string] + $Copyright, + + [Parameter()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [string[]] + $RequiredScripts, + + [Parameter()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [string[]] + $Tags, + + [Parameter()] + [Uri] + $ProjectUri, + + [Parameter()] + [Uri] + $LicenseUri, + + [Parameter()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes + ) + + Process + { + $PSScriptInfoString = @" + +<#PSScriptInfo + +.VERSION $Version + +.GUID $Guid + +.AUTHOR $Author + +.COMPANYNAME $CompanyName + +.COPYRIGHT $Copyright + +.TAGS $Tags + +.LICENSEURI $LicenseUri + +.PROJECTURI $ProjectUri + +.ICONURI $IconUri + +.EXTERNALMODULEDEPENDENCIES $($ExternalModuleDependencies -join ',') + +.REQUIREDSCRIPTS $($RequiredScripts -join ',') + +.EXTERNALSCRIPTDEPENDENCIES $($ExternalScriptDependencies -join ',') + +.RELEASENOTES +$($ReleaseNotes -join "`r`n") + +#> +"@ + return $PSScriptInfoString + } +} + +function Validate-ScriptFileInfoParameters +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $Parameters + ) + + $hasErrors = $false + + $Parameters.Keys | ForEach-Object { + + $parameterName = $_ + + $parameterValue = $($Parameters[$parameterName]) + + if("$parameterValue" -match '<#' -or "$parameterValue" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($parameterValue, $parameterName) + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + $hasErrors = $true + } + } + + return (-not $hasErrors) +} + +function Get-ScriptCommentHelpInfoString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [string] + $Synopsis, + + [Parameter()] + [string[]] + $Example, + + [Parameter()] + [string[]] + $Inputs, + + [Parameter()] + [string[]] + $Outputs, + + [Parameter()] + [string[]] + $Notes, + + [Parameter()] + [string[]] + $Link, + + [Parameter()] + [string] + $Component, + + [Parameter()] + [string] + $Role, + + [Parameter()] + [string] + $Functionality + ) + + Process + { + $ScriptCommentHelpInfoString = "<# `r`n`r`n.DESCRIPTION `r`n $Description `r`n`r`n" + + if("$Synopsis".Trim()) + { + $ScriptCommentHelpInfoString += ".SYNOPSIS `r`n$Synopsis `r`n`r`n" + } + + if("$Example".Trim()) + { + $Example | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".EXAMPLE `r`n$_ `r`n`r`n" + } + } + } + + if("$Inputs".Trim()) + { + $Inputs | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".INPUTS `r`n$_ `r`n`r`n" + } + } + } + + if("$Outputs".Trim()) + { + $Outputs | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".OUTPUTS `r`n$_ `r`n`r`n" + } + } + } + + if("$Notes".Trim()) + { + $ScriptCommentHelpInfoString += ".NOTES `r`n$($Notes -join "`r`n") `r`n`r`n" + } + + if("$Link".Trim()) + { + $Link | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".LINK `r`n$_ `r`n`r`n" + } + } + } + + if("$Component".Trim()) + { + $ScriptCommentHelpInfoString += ".COMPONENT `r`n$($Component -join "`r`n") `r`n`r`n" + } + + if("$Role".Trim()) + { + $ScriptCommentHelpInfoString += ".ROLE `r`n$($Role -join "`r`n") `r`n`r`n" + } + + if("$Functionality".Trim()) + { + $ScriptCommentHelpInfoString += ".FUNCTIONALITY `r`n$($Functionality -join "`r`n") `r`n`r`n" + } + + $ScriptCommentHelpInfoString += "#> `r`n" + + return $ScriptCommentHelpInfoString + } +} + +#endregion *-ScriptFileInfo cmdlets + +#region Utility functions + +function Get-ManifestHashTable +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $Lines = $null + + try + { + $Lines = Get-Content -Path $Path -Force + } + catch + { + if($CallerPSCmdlet) + { + $CallerPSCmdlet.ThrowTerminatingError($_.Exception.ErrorRecord) + } + } + + if(-not $Lines) + { + return + } + + $scriptBlock = [ScriptBlock]::Create( $Lines -join "`n" ) + + $allowedVariables = [System.Collections.Generic.List[String]] @('PSEdition', 'PSScriptRoot') + $allowedCommands = [System.Collections.Generic.List[String]] @() + $allowEnvironmentVariables = $false + + try + { + $scriptBlock.CheckRestrictedLanguage($allowedCommands, $allowedVariables, $allowEnvironmentVariables) + } + catch + { + if($CallerPSCmdlet) + { + $CallerPSCmdlet.ThrowTerminatingError($_.Exception.ErrorRecord) + } + + return + } + + return $scriptBlock.InvokeReturnAsIs() +} + +function Get-ParametersHashtable +{ + param( + $Proxy, + $ProxyCredential + ) + + $ParametersHashtable = @{} + if($Proxy) + { + $ParametersHashtable[$script:Proxy] = $Proxy + } + + if($ProxyCredential) + { + $ParametersHashtable[$script:ProxyCredential] = $ProxyCredential + } + + return $ParametersHashtable +} + +function ToUpper +{ + param([string]$str) + return $script:TextInfo.ToUpper($str) +} + +function Resolve-PathHelper +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $path, + + [Parameter()] + [switch] + $isLiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $callerPSCmdlet + ) + + $resolvedPaths =@() + + foreach($currentPath in $path) + { + try + { + if($isLiteralPath) + { + $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $currentPath -ErrorAction Stop + } + else + { + $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -Path $currentPath -ErrorAction Stop + } + } + catch + { + $errorMessage = ($LocalizedData.PathNotFound -f $currentPath) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $callerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + foreach($currentResolvedPath in $currentResolvedPaths) + { + $resolvedPaths += $currentResolvedPath.ProviderPath + } + } + + $resolvedPaths +} + +function Check-PSGalleryApiAvailability +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PSGalleryV2ApiUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PSGalleryV3ApiUri + ) + + # check internet availability first + $connected = $false + $microsoftDomain = 'www.microsoft.com' + if(Get-Command Microsoft.PowerShell.Management\Test-Connection -ErrorAction SilentlyContinue) + { + $connected = Microsoft.PowerShell.Management\Test-Connection -ComputerName $microsoftDomain -Count 1 -Quiet + } + else + { + $connected = NetTCPIP\Test-NetConnection -ComputerName $microsoftDomain -InformationLevel Quiet + } + if ( -not $connected) + { + return + } + + $statusCode_v2 = $null + $resolvedUri_v2 = $null + $statusCode_v3 = $null + $resolvedUri_v3 = $null + + # ping V2 + $res_v2 = Ping-Endpoint -Endpoint $PSGalleryV2ApiUri + if ($res_v2.ContainsKey($Script:ResponseUri)) + { + $resolvedUri_v2 = $res_v2[$Script:ResponseUri] + } + if ($res_v2.ContainsKey($Script:StatusCode)) + { + $statusCode_v2 = $res_v2[$Script:StatusCode] + } + + + # ping V3 + $res_v3 = Ping-Endpoint -Endpoint $PSGalleryV3ApiUri + if ($res_v3.ContainsKey($Script:ResponseUri)) + { + $resolvedUri_v3 = $res_v3[$Script:ResponseUri] + } + if ($res_v3.ContainsKey($Script:StatusCode)) + { + $statusCode_v3 = $res_v3[$Script:StatusCode] + } + + + $Script:PSGalleryV2ApiAvailable = (($statusCode_v2 -eq 200) -and ($resolvedUri_v2)) + $Script:PSGalleryV3ApiAvailable = (($statusCode_v3 -eq 200) -and ($resolvedUri_v3)) + $Script:PSGalleryApiChecked = $true +} + +function Get-PSGalleryApiAvailability +{ + param + ( + [Parameter()] + [string[]] + $Repository + ) + + # skip if repository is null or not PSGallery + if ( -not $Repository) + { + return + } + + if ($Repository -notcontains $Script:PSGalleryModuleSource ) + { + return + } + + # run check only once + if( -not $Script:PSGalleryApiChecked) + { + $null = Check-PSGalleryApiAvailability -PSGalleryV2ApiUri $Script:PSGallerySourceUri -PSGalleryV3ApiUri $Script:PSGalleryV3SourceUri + } + + if ( -not $Script:PSGalleryV2ApiAvailable ) + { + if ($Script:PSGalleryV3ApiAvailable) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $LocalizedData.PSGalleryApiV2Discontinued ` + -ErrorId "PSGalleryApiV2Discontinued" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + else + { + # both APIs are down, throw error + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $LocalizedData.PowerShellGalleryUnavailable ` + -ErrorId "PowerShellGalleryUnavailable" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + } + else + { + if ($Script:PSGalleryV3ApiAvailable) + { + Write-Warning -Message $LocalizedData.PSGalleryApiV2Deprecated + return + } + } + + # if V2 is available and V3 is not available, do nothing +} + +function HttpClientApisAvailable +{ + $HttpClientApisAvailable = $false + try + { + [System.Net.Http.HttpClient] + $HttpClientApisAvailable = $true + } + catch + { + } + return $HttpClientApisAvailable +} + +function Ping-Endpoint +{ + [CmdletBinding()] + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Endpoint, + + [Parameter()] + $Credential, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential, + + [Parameter()] + [switch] + $AllowAutoRedirect = $true + ) + + $results = @{} + + $WebProxy = $null + if($Proxy) + { + $ProxyNetworkCredential = $null + if($ProxyCredential) + { + $ProxyNetworkCredential = $ProxyCredential.GetNetworkCredential() + } + + $WebProxy = New-Object Microsoft.PowerShell.Get.InternalWebProxy -ArgumentList $Proxy,$ProxyNetworkCredential + } + + if(HttpClientApisAvailable) + { + $response = $null + try + { + $handler = New-Object System.Net.Http.HttpClientHandler + + if($Credential) + { + $handler.Credentials = $Credential.GetNetworkCredential() + } + else + { + $handler.UseDefaultCredentials = $true + } + + if($WebProxy) + { + $handler.Proxy = $WebProxy + } + + $httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler + $response = $httpclient.GetAsync($endpoint) + } + catch + { + } + + if ($response -ne $null -and $response.result -ne $null) + { + $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString()) + $results.Add($Script:StatusCode,$response.result.StatusCode.value__) + } + } + else + { + $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create() + $iss.types.clear() + $iss.formats.clear() + $iss.LanguageMode = "FullLanguage" + + $WebRequestcmd = @' + param($Credential, $WebProxy) + + try + {{ + $request = [System.Net.WebRequest]::Create("{0}") + $request.Method = 'GET' + $request.Timeout = 30000 + if($Credential) + {{ + $request.Credentials = $Credential.GetNetworkCredential() + }} + else + {{ + $request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials + }} + + $request.AllowAutoRedirect = ${1} + + if($WebProxy) + {{ + $request.Proxy = $WebProxy + }} + + $response = [System.Net.HttpWebResponse]$request.GetResponse() + if($response.StatusCode.value__ -eq 302) + {{ + $response.Headers["Location"].ToString() + }} + else + {{ + $response + }} + $response.Close() + }} + catch [System.Net.WebException] + {{ + "Error:System.Net.WebException" + }} +'@ -f $EndPoint, $AllowAutoRedirect + + $ps = [powershell]::Create($iss).AddScript($WebRequestcmd) + + if($WebProxy) + { + $null = $ps.AddParameter('WebProxy', $WebProxy) + } + + if($Credential) + { + $null = $ps.AddParameter('Credential', $Credential) + } + + $response = $ps.Invoke() + $ps.dispose() + if ($response -ne "Error:System.Net.WebException") + { + if($AllowAutoRedirect) + { + $results.Add($Script:ResponseUri,$response.ResponseUri.ToString()) + $results.Add($Script:StatusCode,$response.StatusCode.value__) + } + else + { + $results.Add($Script:ResponseUri,[String]$response) + } + } + } + return $results +} + +function Validate-VersionParameters +{ + Param( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [Parameter()] + [String[]] + $Name, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $AllVersions, + + [Parameter()] + [Switch] + $TestWildcardsInName + ) + + if($TestWildcardsInName -and $Name -and (Test-WildcardPattern -Name "$Name")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.NameShouldNotContainWildcardCharacters -f "$($Name -join ',')") ` + -ErrorId 'NameShouldNotContainWildcardCharacters' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + elseif($AllVersions -and ($RequiredVersion -or $MinimumVersion -or $MaximumVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.AllVersionsCannotBeUsedWithOtherVersionParameters ` + -ErrorId 'AllVersionsCannotBeUsedWithOtherVersionParameters' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($RequiredVersion -and ($MinimumVersion -or $MaximumVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` + -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($MinimumVersion -and $MaximumVersion -and ($MinimumVersion -gt $MaximumVersion)) + { + $Message = $LocalizedData.MinimumVersionIsGreaterThanMaximumVersion -f ($MinimumVersion, $MaximumVersion) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $Message ` + -ErrorId "MinimumVersionIsGreaterThanMaximumVersion" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($AllVersions -or $RequiredVersion -or $MinimumVersion -or $MaximumVersion) + { + if(-not $Name -or $Name.Count -ne 1 -or (Test-WildcardPattern -Name $Name[0])) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` + -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + return $true +} + +function ValidateAndSet-PATHVariableIfUserAccepts +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Scope, + + [Parameter(Mandatory=$true)] + [string] + $ScopePath, + + [Parameter()] + [Switch] + $NoPathUpdate, + + [Parameter()] + [Switch] + $Force, + + [Parameter()] + $Request + ) + + Set-PSGetSettingsVariable + + # Check and add the scope path to PATH environment variable if USER accepts the prompt. + if($Scope -eq 'AllUsers') + { + $envVariableTarget = $script:EnvironmentVariableTarget.Machine + $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath + $scopeSpecificKey = 'AllUsersScope_AllowPATHChangeForScripts' + } + else + { + $envVariableTarget = $script:EnvironmentVariableTarget.User + $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath + $scopeSpecificKey = 'CurrentUserScope_AllowPATHChangeForScripts' + } + + $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) + Write-Debug "Already prompted for the current scope:$AlreadyPromptedForScope" + + if(-not $AlreadyPromptedForScope) + { + # Read the file contents once again to ensure that it was not set in another PowerShell Session + Set-PSGetSettingsVariable -Force + + $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) + Write-Debug "After reading contents of PowerShellGetSettings.xml file, the Already prompted for the current scope:$AlreadyPromptedForScope" + + if($AlreadyPromptedForScope) + { + return + } + + $userResponse = $false + + if(-not $NoPathUpdate) + { + $scopePathEndingWithBackSlash = "$scopePath\" + + # Check and add the $scopePath to $env:Path value + if( (($env:PATH -split ';') -notcontains $scopePath) -and + (($env:PATH -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + if($Force) + { + $userResponse = $true + } + else + { + $scriptPATHPromptCaption = $LocalizedData.ScriptPATHPromptCaption + + if($Request) + { + $userResponse = $Request.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) + } + else + { + $userResponse = $PSCmdlet.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) + } + } + + if($userResponse) + { + $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $envVariableTarget + + if((($currentPATHValue -split ';') -notcontains $scopePath) -and + (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + # To ensure that the installed script is immediately usable, + # we need to add the scope path to the PATH enviroment variable. + Set-EnvironmentVariable -Name 'PATH' ` + -Value "$currentPATHValue;$scopePath" ` + -Target $envVariableTarget + + Write-Verbose ($LocalizedData.AddedScopePathToPATHVariable -f ($scopePath,$Scope)) + } + + # Process specific PATH + # Check and add the $scopePath to $env:Path value of current process + # so that installed scripts can be used in the current process. + $target = $script:EnvironmentVariableTarget.Process + $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $target + + if((($currentPATHValue -split ';') -notcontains $scopePath) -and + (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + # To ensure that the installed script is immediately usable, + # we need to add the scope path to the PATH enviroment variable. + Set-EnvironmentVariable -Name 'PATH' ` + -Value "$currentPATHValue;$scopePath" ` + -Target $target + + Write-Verbose ($LocalizedData.AddedScopePathToProcessSpecificPATHVariable -f ($scopePath,$Scope)) + } + } + } + } + + # Add user's response to the PowerShellGet.settings file + $script:PSGetSettings[$scopeSpecificKey] = $userResponse + + Save-PSGetSettings + } +} + +function Save-PSGetSettings +{ + if($script:PSGetSettings) + { + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetAppLocalPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` + -ItemType Directory ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false ` + -WhatIf:$false + } + + Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetSettingsFilePath -Force ` + -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetSettings)) + + Write-Debug "In Save-PSGetSettings, persisted the $script:PSGetSettingsFilePath file" + } +} + +function Set-PSGetSettingsVariable +{ + [CmdletBinding()] + param([switch]$Force) + + if(-not $script:PSGetSettings -or $Force) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetSettingsFilePath) + { + $script:PSGetSettings = DeSerialize-PSObject -Path $script:PSGetSettingsFilePath + } + else + { + $script:PSGetSettings = [ordered]@{} + } + } +} + +function Set-PSGalleryRepository +{ + [CmdletBinding()] + param( + [Parameter()] + [switch] + $Trusted, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential + ) + + $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri ` + -LocationParameterName 'SourceLocation' ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri ` + -LocationParameterName 'ScriptSourceLocation' ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($psgalleryLocation) + { + $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false -Proxy $Proxy -ProxyCredential $ProxyCredential + if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri]) + { + $script:PSGalleryPublishUri = $result[$Script:ResponseUri] + } + + $repository = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $Script:PSGalleryModuleSource + SourceLocation = $psgalleryLocation + PublishLocation = $Script:PSGalleryPublishUri + ScriptSourceLocation = $scriptSourceLocation + ScriptPublishLocation = $Script:PSGalleryPublishUri + Trusted=$Trusted + Registered=$true + InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} + PackageManagementProvider=$script:NuGetProviderName + ProviderOptions = @{} + }) + + $repository.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + $script:PSGetModuleSources[$Script:PSGalleryModuleSource] = $repository + + Save-ModuleSources + + return $repository + } +} + +function Set-ModuleSourcesVariable +{ + [CmdletBinding()] + param( + [switch] + $Force, + + $Proxy, + + $ProxyCredential + ) + + if(-not $script:PSGetModuleSources -or $Force) + { + $isPersistRequired = $false + if(Microsoft.PowerShell.Management\Test-Path $script:PSGetModuleSourcesFilePath) + { + $script:PSGetModuleSources = DeSerialize-PSObject -Path $script:PSGetModuleSourcesFilePath + } + else + { + $script:PSGetModuleSources = [ordered]@{} + + if(-not $script:PSGetModuleSources.Contains($Script:PSGalleryModuleSource)) + { + $null = Set-PSGalleryRepository -Proxy $Proxy -ProxyCredential $ProxyCredential + } + } + + # Already registed repositories may not have the ScriptSourceLocation property, try to populate it from the existing SourceLocation + # Also populate the PublishLocation and ScriptPublishLocation from the SourceLocation if PublishLocation is empty/null. + # + $script:PSGetModuleSources.Keys | Microsoft.PowerShell.Core\ForEach-Object { + $moduleSource = $script:PSGetModuleSources[$_] + + if(-not (Get-Member -InputObject $moduleSource -Name $script:ScriptSourceLocation)) + { + $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation -Proxy $Proxy -ProxyCredential $ProxyCredential + + Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` + -MemberType NoteProperty ` + -Name $script:ScriptSourceLocation ` + -Value $scriptSourceLocation + + if(Get-Member -InputObject $moduleSource -Name $script:PublishLocation) + { + if(-not $moduleSource.PublishLocation) + { + $script:PSGetModuleSources[$_].PublishLocation = Get-PublishLocation -Location $moduleSource.SourceLocation + } + + Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` + -MemberType NoteProperty ` + -Name $script:ScriptPublishLocation ` + -Value $moduleSource.PublishLocation + } + + $isPersistRequired = $true + } + } + + if($isPersistRequired) + { + Save-ModuleSources + } + } +} + +function Get-PackageManagementProviderName +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Location + ) + + $PackageManagementProviderName = $null + $loc = Get-LocationString -LocationUri $Location + + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + foreach($provider in $providers) + { + # Skip the PowerShellGet provider + if($provider.ProviderName -eq $script:PSModuleProviderName) + { + continue + } + + $packageSource = Get-PackageSource -Location $loc -Provider $provider.ProviderName -ErrorAction SilentlyContinue + + if($packageSource) + { + $PackageManagementProviderName = $provider.ProviderName + break + } + } + + return $PackageManagementProviderName +} + +function Get-ProviderName +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSCustomObject + ) + + $providerName = $script:NuGetProviderName + + if((Get-Member -InputObject $PSCustomObject -Name PackageManagementProvider)) + { + $providerName = $PSCustomObject.PackageManagementProvider + } + + return $providerName +} + +function Get-DynamicParameters +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Location, + + [Parameter(Mandatory=$true)] + [REF] + $PackageManagementProvider + ) + + $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary + $dynamicOptions = $null + + $loc = Get-LocationString -LocationUri $Location + + if(-not $loc) + { + return $paramDictionary + } + + # Ping and resolve the specified location + $loc = Resolve-Location -Location $loc ` + -LocationParameterName 'Location' ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if(-not $loc) + { + return $paramDictionary + } + + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if ($PackageManagementProvider.Value) + { + # Skip the PowerShellGet provider + if($PackageManagementProvider.Value -ne $script:PSModuleProviderName) + { + $SelectedProvider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} + + if($SelectedProvider) + { + $res = Get-PackageSource -Location $loc -Provider $PackageManagementProvider.Value -ErrorAction SilentlyContinue + + if($res) + { + $dynamicOptions = $SelectedProvider.DynamicOptions + } + } + } + } + else + { + $PackageManagementProvider.Value = Get-PackageManagementProviderName -Location $Location + if($PackageManagementProvider.Value) + { + $provider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} + $dynamicOptions = $provider.DynamicOptions + } + } + + foreach ($option in $dynamicOptions) + { + # Skip the Destination parameter + if( $option.IsRequired -and + ($option.Name -eq "Destination") ) + { + continue + } + + $paramAttribute = New-Object System.Management.Automation.ParameterAttribute + $paramAttribute.Mandatory = $option.IsRequired + + $message = $LocalizedData.DynamicParameterHelpMessage -f ($option.Name, $PackageManagementProvider.Value, $loc, $option.Name) + $paramAttribute.HelpMessage = $message + + $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] + $attributeCollection.Add($paramAttribute) + + $ageParam = New-Object System.Management.Automation.RuntimeDefinedParameter($option.Name, + $script:DynamicOptionTypeMap[$option.Type.value__], + $attributeCollection) + $paramDictionary.Add($option.Name, $ageParam) + } + + return $paramDictionary +} + +function New-PSGetItemInfo +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter()] + $PackageManagementProviderName, + + [Parameter()] + [string] + $SourceLocation, + + [Parameter(Mandatory=$true)] + [string] + $Type, + + [Parameter()] + [string] + $InstalledLocation, + + [Parameter()] + [System.DateTime] + $InstalledDate, + + [Parameter()] + [System.DateTime] + $UpdatedDate + ) + + foreach($swid in $SoftwareIdentity) + { + + if($SourceLocation) + { + $sourceName = (Get-SourceName -Location $SourceLocation) + } + else + { + # First get the source name from the Metadata + # if not exists, get the source name from $swid.Source + # otherwise default to $swid.Source + $sourceName = (Get-First $swid.Metadata["SourceName"]) + + if(-not $sourceName) + { + $sourceName = (Get-SourceName -Location $swid.Source) + } + + if(-not $sourceName) + { + $sourceName = $swid.Source + } + + $SourceLocation = Get-SourceLocation -SourceName $sourceName + } + + $published = (Get-First $swid.Metadata["published"]) + $PublishedDate = New-Object System.DateTime + + $InstalledDateString = (Get-First $swid.Metadata['installeddate']) + if(-not $InstalledDate -and $InstalledDateString) + { + $InstalledDate = New-Object System.DateTime + if(-not ([System.DateTime]::TryParse($InstalledDateString, ([ref]$InstalledDate)))) + { + $InstalledDate = $null + } + } + + $UpdatedDateString = (Get-First $swid.Metadata['updateddate']) + if(-not $UpdatedDate -and $UpdatedDateString) + { + $UpdatedDate = New-Object System.DateTime + if(-not ([System.DateTime]::TryParse($UpdatedDateString, ([ref]$UpdatedDate)))) + { + $UpdatedDate = $null + } + } + + $tags = (Get-First $swid.Metadata["tags"]) -split " " + $userTags = @() + + $exportedDscResources = @() + $exportedRoleCapabilities = @() + $exportedCmdlets = @() + $exportedFunctions = @() + $exportedWorkflows = @() + $exportedCommands = @() + + $exportedRoleCapabilities += (Get-First $swid.Metadata['RoleCapabilities']) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedDscResources += (Get-First $swid.Metadata["DscResources"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedCmdlets += (Get-First $swid.Metadata["Cmdlets"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedFunctions += (Get-First $swid.Metadata["Functions"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedWorkflows += (Get-First $swid.Metadata["Workflows"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedCommands += $exportedCmdlets + $exportedFunctions + $exportedWorkflows + $PSGetFormatVersion = $null + + ForEach($tag in $tags) + { + if(-not $tag.Trim()) + { + continue + } + + $parts = $tag -split "_",2 + if($parts.Count -ne 2) + { + $userTags += $tag + continue + } + + Switch($parts[0]) + { + $script:Command { $exportedCommands += $parts[1]; break } + $script:DscResource { $exportedDscResources += $parts[1]; break } + $script:Cmdlet { $exportedCmdlets += $parts[1]; break } + $script:Function { $exportedFunctions += $parts[1]; break } + $script:Workflow { $exportedWorkflows += $parts[1]; break } + $script:RoleCapability { $exportedRoleCapabilities += $parts[1]; break } + $script:PSGetFormatVersion { $PSGetFormatVersion = $parts[1]; break } + $script:Includes { break } + Default { $userTags += $tag; break } + } + } + + $ArtifactDependencies = @() + Foreach ($dependencyString in $swid.Dependencies) + { + [Uri]$packageId = $null + if([Uri]::TryCreate($dependencyString, [System.UriKind]::Absolute, ([ref]$packageId))) + { + $segments = $packageId.Segments + $Version = $null + $DependencyName = $null + if ($segments) + { + $DependencyName = [Uri]::UnescapeDataString($segments[0].Trim('/', '\')) + $Version = if($segments.Count -gt 1){[Uri]::UnescapeDataString($segments[1])} + } + + $dep = [ordered]@{ + Name=$DependencyName + } + + if($Version) + { + # Required/exact version is represented in NuGet as "[2.0]" + if ($Version -match "\[+[0-9.]+\]") + { + $dep["RequiredVersion"] = $Version.Trim('[', ']') + } + elseif ($Version -match "\[+[0-9., ]+\]") + { + # Minimum and Maximum version range is represented in NuGet as "[1.0, 2.0]" + $versionRange = $Version.Trim('[', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} + if($versionRange -and $versionRange.count -eq 2) + { + $dep["MinimumVersion"] = $versionRange[0].Trim() + $dep["MaximumVersion"] = $versionRange[1].Trim() + } + } + elseif ($Version -match "\(+[0-9., ]+\]") + { + # Maximum version is represented in NuGet as "(, 2.0]" + $maximumVersion = $Version.Trim('(', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} + + if($maximumVersion) + { + $dep["MaximumVersion"] = $maximumVersion.Trim() + } + } + else + { + $dep['MinimumVersion'] = $Version + } + } + + $dep["CanonicalId"]=$dependencyString + + $ArtifactDependencies += $dep + } + } + + $additionalMetadata = New-Object -TypeName System.Collections.Hashtable + foreach ( $key in $swid.Metadata.Keys.LocalName) + { + if (!$additionalMetadata.ContainsKey($key)) + { + $additionalMetadata.Add($key, (Get-First $swid.Metadata[$key]) ) + } + } + + if($additionalMetadata.ContainsKey('ItemType')) + { + $Type = $additionalMetadata['ItemType'] + } + elseif($userTags -contains 'PSModule') + { + $Type = $script:PSArtifactTypeModule + } + elseif($userTags -contains 'PSScript') + { + $Type = $script:PSArtifactTypeScript + } + + $PSGetItemInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $swid.Name + Version = [Version]$swid.Version + Type = $Type + Description = (Get-First $swid.Metadata["description"]) + Author = (Get-EntityName -SoftwareIdentity $swid -Role "author") + CompanyName = (Get-EntityName -SoftwareIdentity $swid -Role "owner") + Copyright = (Get-First $swid.Metadata["copyright"]) + PublishedDate = if([System.DateTime]::TryParse($published, ([ref]$PublishedDate))){$PublishedDate}; + InstalledDate = $InstalledDate; + UpdatedDate = $UpdatedDate; + LicenseUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "license") + ProjectUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "project") + IconUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "icon") + Tags = $userTags + + Includes = @{ + DscResource = $exportedDscResources + Command = $exportedCommands + Cmdlet = $exportedCmdlets + Function = $exportedFunctions + Workflow = $exportedWorkflows + RoleCapability = $exportedRoleCapabilities + } + + PowerShellGetFormatVersion=[Version]$PSGetFormatVersion + + ReleaseNotes = (Get-First $swid.Metadata["releaseNotes"]) + + Dependencies = $ArtifactDependencies + + RepositorySourceLocation = $SourceLocation + Repository = $sourceName + PackageManagementProvider = if($PackageManagementProviderName) { $PackageManagementProviderName } else { (Get-First $swid.Metadata["PackageManagementProvider"]) } + + AdditionalMetadata = $additionalMetadata + }) + + if(-not $InstalledLocation) + { + $InstalledLocation = (Get-First $swid.Metadata[$script:InstalledLocation]) + } + + if($InstalledLocation) + { + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSGetItemInfo -MemberType NoteProperty -Name $script:InstalledLocation -Value $InstalledLocation + } + + $PSGetItemInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") + $PSGetItemInfo + } +} + +function Get-SourceName +{ + [CmdletBinding()] + [OutputType("string")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + Set-ModuleSourcesVariable + + foreach($psModuleSource in $script:PSGetModuleSources.Values) + { + if(($psModuleSource.Name -eq $Location) -or + ($psModuleSource.SourceLocation -eq $Location) -or + ((Get-Member -InputObject $psModuleSource -Name $script:ScriptSourceLocation) -and + ($psModuleSource.ScriptSourceLocation -eq $Location))) + { + return $psModuleSource.Name + } + } +} + +function Get-SourceLocation +{ + [CmdletBinding()] + [OutputType("string")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourceName + ) + + Set-ModuleSourcesVariable + + if($script:PSGetModuleSources.Contains($SourceName)) + { + return $script:PSGetModuleSources[$SourceName].SourceLocation + } + else + { + return $SourceName + } +} + +function Get-UrlFromSwid +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter(Mandatory=$true)] + $UrlName + ) + + foreach($link in $SoftwareIdentity.Links) + { + if( $link.Relationship -eq $UrlName) + { + return $link.HRef + } + } + + return $null +} + +function Get-EntityName +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter(Mandatory=$true)] + $Role + ) + + foreach( $entity in $SoftwareIdentity.Entities ) + { + if( $entity.Role -eq $Role) + { + $entity.Name + } + } +} + +function Install-NuGetClientBinaries +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [parameter()] + [switch] + $BootstrapNuGetExe, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential, + + [parameter()] + [switch] + $Force + ) + + if($script:NuGetProvider -and + (-not $BootstrapNuGetExe -or + ($script:NuGetExePath -and (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath)))) + { + return + } + + $bootstrapNuGetProvider = (-not $script:NuGetProvider) + + if($bootstrapNuGetProvider) + { + # Bootstrap the NuGet provider only if it is not available. + # By default PackageManagement loads the latest version of the NuGet provider. + $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + + $bootstrapNuGetProvider = $false + } + else + { + # User might have installed it in an another console or in the same process, check available NuGet providers and import the required provider. + $availableNugetProviders = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName ` + -ListAvailable ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($availableNugetProviders) + { + # Force import ensures that nuget provider with minimum version got loaded. + $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Force + + $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + + $bootstrapNuGetProvider = $false + } + } + } + } + + if($BootstrapNuGetExe -and + (-not $script:NuGetExePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) + { + $programDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName + $applocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName + + # Check if NuGet.exe is available under one of the predefined PowerShellGet locations under ProgramData or LocalAppData + if(Microsoft.PowerShell.Management\Test-Path -Path $programDataExePath) + { + $script:NuGetExePath = $programDataExePath + $BootstrapNuGetExe = $false + } + elseif(Microsoft.PowerShell.Management\Test-Path -Path $applocalDataExePath) + { + $script:NuGetExePath = $applocalDataExePath + $BootstrapNuGetExe = $false + } + else + { + # Using Get-Command cmdlet, get the location of NuGet.exe if it is available under $env:PATH. + # NuGet.exe does not work if it is under $env:WINDIR, so skip it from the Get-Command results. + $nugetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:NuGetExeName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Path -and + ((Microsoft.PowerShell.Management\Split-Path -Path $_.Path -Leaf) -eq $script:NuGetExeName) -and + (-not $_.Path.StartsWith($env:windir, [System.StringComparison]::OrdinalIgnoreCase)) + } | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if($nugetCmd -and $nugetCmd.Path) + { + $script:NuGetExePath = $nugetCmd.Path + $BootstrapNuGetExe = $false + } + } + } + else + { + # No need to bootstrap the NuGet.exe when $BootstrapNuGetExe is false or NuGet.exe path is already assigned. + $BootstrapNuGetExe = $false + } + + # On Nano server we don't need NuGet.exe + if(-not $bootstrapNuGetProvider -and ($script:isNanoServer -or -not $BootstrapNuGetExe)) + { + return + } + + # We should prompt only once for bootstrapping the NuGet provider and/or NuGet.exe + + # Should continue message for bootstrapping only NuGet provider + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetProviderShouldContinueQuery -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetProviderShouldContinueCaption + + # Should continue message for bootstrapping both NuGet provider and NuGet.exe + if($bootstrapNuGetProvider -and $BootstrapNuGetExe) + { + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetBinariesShouldContinueQuery2 -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath, $script:PSGetProgramDataPath, $script:PSGetAppLocalPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetBinariesShouldContinueCaption2 + } + elseif($BootstrapNuGetExe) + { + # Should continue message for bootstrapping only NuGet.exe + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetExeShouldContinueQuery -f ($script:PSGetProgramDataPath, $script:PSGetAppLocalPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetExeShouldContinueCaption + } + + $AdditionalParams = Get-ParametersHashtable -Proxy $Proxy -ProxyCredential $ProxyCredential + + if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessage, $shouldContinueCaption)) + { + if($bootstrapNuGetProvider) + { + Write-Verbose -Message $LocalizedData.DownloadingNugetProvider + + $scope = 'CurrentUser' + if(Test-RunningAsElevated) + { + $scope = 'AllUsers' + } + + # Bootstrap the NuGet provider + $null = PackageManagement\Install-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Scope $scope ` + -Force @AdditionalParams + + # Force import ensures that nuget provider with minimum version got loaded. + $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Force + + $nugetProvider = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName + + if ($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + } + } + + if($BootstrapNuGetExe -and -not $script:isNanoServer) + { + Write-Verbose -Message $LocalizedData.DownloadingNugetExe + + $nugetExeBasePath = $script:PSGetAppLocalPath + + # if the current process is running with elevated privileges, + # install NuGet.exe to $script:PSGetProgramDataPath + if(Test-RunningAsElevated) + { + $nugetExeBasePath = $script:PSGetProgramDataPath + } + + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeBasePath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $nugetExeBasePath ` + -ItemType Directory -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + $nugetExeFilePath = Microsoft.PowerShell.Management\Join-Path -Path $nugetExeBasePath -ChildPath $script:NuGetExeName + + # Download the NuGet.exe from http://nuget.org/NuGet.exe + $null = Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri $script:NuGetClientSourceURL ` + -OutFile $nugetExeFilePath ` + @AdditionalParams + + if (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeFilePath) + { + $script:NuGetExePath = $nugetExeFilePath + } + } + } + + $message = $null + $errorId = $null + $failedToBootstrapNuGetProvider = $false + $failedToBootstrapNuGetExe = $false + + if($bootstrapNuGetProvider -and -not $script:NuGetProvider) + { + $failedToBootstrapNuGetProvider = $true + + $message = $LocalizedData.CouldNotInstallNuGetProvider -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetProvider' + } + + if($BootstrapNuGetExe -and + (-not $script:NuGetExePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) + { + $failedToBootstrapNuGetExe = $true + + $message = $LocalizedData.CouldNotInstallNuGetExe -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetExe' + } + + # Change the error id and message if both NuGet provider and NuGet.exe are not installed. + if($failedToBootstrapNuGetProvider -and $failedToBootstrapNuGetExe) + { + $message = $LocalizedData.CouldNotInstallNuGetBinaries2 -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetBinaries' + } + + # Throw the error message if one of the above conditions are met + if($message -and $errorId) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId $errorId ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } +} + +# Check if current user is running with elevated privileges +function Test-RunningAsElevated +{ + [CmdletBinding()] + [OutputType([bool])] + Param() + + $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent() + $prp=new-object System.Security.Principal.WindowsPrincipal($wid) + $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator + return $prp.IsInRole($adm) +} + +function Get-EscapedString +{ + [CmdletBinding()] + [OutputType([String])] + Param + ( + [Parameter()] + [string] + $ElementValue + ) + + return [System.Security.SecurityElement]::Escape($ElementValue) +} + +function ValidateAndGet-ScriptDependencies +{ + param( + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [PSCustomObject] + $DependentScriptInfo, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $DependenciesDetails = @() + + # Validate dependent modules + $RequiredModuleSpecification = $DependentScriptInfo.RequiredModules + if($RequiredModuleSpecification) + { + ForEach($moduleSpecification in $RequiredModuleSpecification) + { + $ModuleName = $moduleSpecification.Name + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($DependentScriptInfo.ExternalModuleDependencies -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + $FindModuleArguments['Name'] = $ModuleName + $ReqModuleInfo = @{} + $ReqModuleInfo['Name'] = $ModuleName + + if($moduleSpecification.Version) + { + $FindModuleArguments['MinimumVersion'] = $moduleSpecification.Version + $ReqModuleInfo['MinimumVersion'] = $moduleSpecification.Version + } + elseif((Get-Member -InputObject $moduleSpecification -Name RequiredVersion) -and $moduleSpecification.RequiredVersion) + { + $FindModuleArguments['RequiredVersion'] = $moduleSpecification.RequiredVersion + $ReqModuleInfo['RequiredVersion'] = $moduleSpecification.RequiredVersion + } + + if((Get-Member -InputObject $moduleSpecification -Name MaximumVersion) -and $moduleSpecification.MaximumVersion) + { + # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. + # like 1.0.0.* --> 1.0.0.99999999 + # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. + $maximumVersion = $moduleSpecification.MaximumVersion -replace '\*','99999999' + $FindModuleArguments['MaximumVersion'] = $maximumVersion + $ReqModuleInfo['MaximumVersion'] = $maximumVersion + } + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveScriptDependency -f ('module', $ModuleName, $DependentScriptInfo.Name, $Repository, 'ExternalModuleDependencies') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveScriptDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $DependenciesDetails += $ReqModuleInfo + } + } + + # Validate dependent scrips + $RequiredScripts = $DependentScriptInfo.RequiredScripts + if($RequiredScripts) + { + ForEach($requiredScript in $RequiredScripts) + { + $FindScriptArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($DependentScriptInfo.ExternalScriptDependencies -contains $requiredScript) + { + Write-Verbose -Message ($LocalizedData.SkippedScriptDependency -f $requiredScript) + + continue + } + + $FindScriptArguments['Name'] = $requiredScript + $ReqScriptInfo = @{} + $ReqScriptInfo['Name'] = $requiredScript + + $psgetItemInfo = Find-Script @FindScriptArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $requiredScript} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveScriptDependency -f ('script', $requiredScript, $DependentScriptInfo.Name, $Repository, 'ExternalScriptDependencies') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveScriptDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $DependenciesDetails += $ReqScriptInfo + } + } + + return $DependenciesDetails +} + +function ValidateAndGet-RequiredModuleDetails +{ + param( + [Parameter()] + $ModuleManifestRequiredModules, + + [Parameter()] + [PSModuleInfo[]] + $RequiredPSModuleInfos, + + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $DependentModuleInfo, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $RequiredModuleDetails = @() + + if(-not $RequiredPSModuleInfos) + { + return $RequiredModuleDetails + } + + if($ModuleManifestRequiredModules) + { + ForEach($RequiredModule in $ModuleManifestRequiredModules) + { + $ModuleName = $null + $VersionString = $null + + $ReqModuleInfo = @{} + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + # ModuleSpecification case + if($RequiredModule.GetType().ToString() -eq 'System.Collections.Hashtable') + { + $ModuleName = $RequiredModule.ModuleName + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + if($RequiredModule.Keys -Contains "RequiredVersion") + { + $FindModuleArguments['RequiredVersion'] = $RequiredModule.RequiredVersion + $ReqModuleInfo['RequiredVersion'] = $RequiredModule.RequiredVersion + } + elseif($RequiredModule.Keys -Contains "ModuleVersion") + { + $FindModuleArguments['MinimumVersion'] = $RequiredModule.ModuleVersion + $ReqModuleInfo['MinimumVersion'] = $RequiredModule.ModuleVersion + } + + if($RequiredModule.Keys -Contains 'MaximumVersion' -and $RequiredModule.MaximumVersion) + { + # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. + # like 1.0.0.* --> 1.0.0.99999999 + # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. + $maximumVersion = $RequiredModule.MaximumVersion -replace '\*','99999999' + + $FindModuleArguments['MaximumVersion'] = $maximumVersion + $ReqModuleInfo['MaximumVersion'] = $maximumVersion + } + } + else + { + # Just module name was specified + $ModuleName = $RequiredModule.ToString() + } + + if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + # Skip this module name if it's name is not in $RequiredPSModuleInfos. + # This is required when a ModuleName is part of the NestedModules list of the actual module. + # $ModuleName is packaged as part of the actual module When $RequiredPSModuleInfos doesn't contain it's name. + if($RequiredPSModuleInfos.Name -notcontains $ModuleName) + { + continue + } + + $ReqModuleInfo['Name'] = $ModuleName + + # Add the dependency only if the module is available on the gallery + # Otherwise Module installation will fail as all required modules need to be available on + # the same Repository + $FindModuleArguments['Name'] = $ModuleName + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveModuleDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $RequiredModuleDetails += $ReqModuleInfo + } + } + else + { + # If Import-LocalizedData cmdlet was failed to read the .psd1 contents + # use provided $RequiredPSModuleInfos (PSModuleInfo.RequiredModules or PSModuleInfo.NestedModules of the actual dependent module) + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + ForEach($RequiredModuleInfo in $RequiredPSModuleInfos) + { + $ModuleName = $requiredModuleInfo.Name + + if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + $FindModuleArguments['Name'] = $ModuleName + $FindModuleArguments['MinimumVersion'] = $requiredModuleInfo.Version + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveModuleDependency" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + $RequiredModuleDetails += @{ + Name=$_.Name + MinimumVersion=$_.Version + } + } + } + + return $RequiredModuleDetails +} + +function Get-ExternalModuleDependencies +{ + Param ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $PSModuleInfo + ) + + if($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'] -and + ($PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'].GetType().ToString() -eq "System.Object[]") + ) + { + return $PSModuleInfo.PrivateData.PSData.ExternalModuleDependencies + } +} + +function Get-ModuleDependencies +{ + Param ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $DependentModuleDetails = @() + + if($PSModuleInfo.RequiredModules -or $PSModuleInfo.NestedModules) + { + # PSModuleInfo.RequiredModules doesn't provide the RequiredVersion info from the ModuleSpecification + # Reading the contents of module manifest file + # to get the RequiredVersion details. + $ModuleManifestHashTable = Get-ManifestHashTable -Path $PSModuleInfo.Path + + if($PSModuleInfo.RequiredModules) + { + $ModuleManifestRequiredModules = $null + + if($ModuleManifestHashTable) + { + $ModuleManifestRequiredModules = $ModuleManifestHashTable.RequiredModules + } + + + $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules ` + -RequiredPSModuleInfos $PSModuleInfo.RequiredModules ` + -Repository $Repository ` + -DependentModuleInfo $PSModuleInfo ` + -CallerPSCmdlet $CallerPSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + + if($PSModuleInfo.NestedModules) + { + $ModuleManifestRequiredModules = $null + + if($ModuleManifestHashTable) + { + $ModuleManifestRequiredModules = $ModuleManifestHashTable.NestedModules + } + + # A nested module is be considered as a dependency + # 1) whose module base is not under the specified module base OR + # 2) whose module base is under the specified module base and it's path doesn't exists + # + $RequiredPSModuleInfos = $PSModuleInfo.NestedModules | Microsoft.PowerShell.Core\Where-Object { + -not $_.ModuleBase.StartsWith($PSModuleInfo.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase) -or + -not $_.Path -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $_.Path) + } + + $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules ` + -RequiredPSModuleInfos $RequiredPSModuleInfos ` + -Repository $Repository ` + -DependentModuleInfo $PSModuleInfo ` + -CallerPSCmdlet $CallerPSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + } + + return $DependentModuleDetails +} + +function Publish-PSArtifactUtility +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishScript')] + [ValidateNotNullOrEmpty()] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [string] + $ManifestPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Destination, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetApiKey, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetPackageRoot, + + [Parameter(ParameterSetName='PublishModule')] + [Version] + $FormatVersion, + + [Parameter(ParameterSetName='PublishModule')] + [string] + $ReleaseNotes, + + [Parameter(ParameterSetName='PublishModule')] + [string[]] + $Tags, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $LicenseUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $IconUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $ProjectUri + ) + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + + $PSArtifactType = $script:PSArtifactTypeModule + $Name = $null + $Description = $null + $Version = $null + $Author = $null + $CompanyName = $null + $Copyright = $null + + if($PSModuleInfo) + { + $Name = $PSModuleInfo.Name + $Description = $PSModuleInfo.Description + $Version = $PSModuleInfo.Version + $Author = $PSModuleInfo.Author + $CompanyName = $PSModuleInfo.CompanyName + $Copyright = $PSModuleInfo.Copyright + + if($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") + ) + { + if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) + { + $Tags = $PSModuleInfo.PrivateData.PSData.Tags + } + + if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) + { + $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes + } + + if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) + { + $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri + } + + if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) + { + $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri + } + + if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) + { + $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri + } + } + } + else + { + $PSArtifactType = $script:PSArtifactTypeScript + + $Name = $PSScriptInfo.Name + $Description = $PSScriptInfo.Description + $Version = $PSScriptInfo.Version + $Author = $PSScriptInfo.Author + $CompanyName = $PSScriptInfo.CompanyName + $Copyright = $PSScriptInfo.Copyright + + if($PSScriptInfo.'Tags') + { + $Tags = $PSScriptInfo.Tags + } + + if($PSScriptInfo.'ReleaseNotes') + { + $ReleaseNotes = $PSScriptInfo.ReleaseNotes + } + + if($PSScriptInfo.'LicenseUri') + { + $LicenseUri = $PSScriptInfo.LicenseUri + } + + if($PSScriptInfo.'IconUri') + { + $IconUri = $PSScriptInfo.IconUri + } + + if($PSScriptInfo.'ProjectUri') + { + $ProjectUri = $PSScriptInfo.ProjectUri + } + } + + + # Add PSModule and PSGet format version tags + if(-not $Tags) + { + $Tags = @() + } + + if($FormatVersion) + { + $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" + } + + $DependentModuleDetails = @() + + if($PSScriptInfo) + { + $Tags += "PSScript" + + if($PSScriptInfo.DefinedCommands) + { + if($PSScriptInfo.DefinedFunctions) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + } + + if($PSScriptInfo.DefinedWorkflows) + { + $Tags += "$($script:Includes)_Workflow" + $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } + } + + $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + # Populate the dependencies elements from RequiredModules and RequiredScripts + # + $DependentModuleDetails += ValidateAndGet-ScriptDependencies -Repository $Repository ` + -DependentScriptInfo $PSScriptInfo ` + -CallerPSCmdlet $PSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + else + { + $Tags += "PSModule" + + $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath + + if($PSModuleInfo.ExportedCommands.Count) + { + if($PSModuleInfo.ExportedCmdlets.Count) + { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + if($PSModuleInfo.ExportedFunctions.Count) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if($dscResourceNames) + { + $Tags += "$($script:Includes)_DscResource" + + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) + { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if($RoleCapabilityNames) + { + $Tags += "$($script:Includes)_RoleCapability" + + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } + + # Populate the module dependencies elements from RequiredModules and + # NestedModules properties of the current PSModuleInfo + $DependentModuleDetails = Get-ModuleDependencies -PSModuleInfo $PSModuleInfo ` + -Repository $Repository ` + -CallerPSCmdlet $PSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + + $dependencies = @() + ForEach($Dependency in $DependentModuleDetails) + { + $ModuleName = $Dependency.Name + $VersionString = $null + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + # + # When only MaximumVersion is specified in the ModuleSpecification + # (,1.0] = x <= 1.0 + # + # When both Minimum and Maximum versions are specified in the ModuleSpecification + # [1.0,2.0] = 1.0 <= x <= 2.0 + + if($Dependency.Keys -Contains "RequiredVersion") + { + $VersionString = "[$($Dependency.RequiredVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "(,$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion') + { + $VersionString = "$($Dependency.MinimumVersion)" + } + + $dependencies += "" + } + + # Populate the nuspec elements + $nuspec = @" + + + + $(Get-EscapedString -ElementValue "$Name") + $($Version) + $(Get-EscapedString -ElementValue "$Author") + $(Get-EscapedString -ElementValue "$CompanyName") + $(Get-EscapedString -ElementValue "$Description") + $(Get-EscapedString -ElementValue "$ReleaseNotes") + $(Get-EscapedString -ElementValue "$Copyright") + $(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')}) + $(if($LicenseUri){ + "$(Get-EscapedString -ElementValue "$LicenseUri") + true" + }) + $(if($ProjectUri){ + "$(Get-EscapedString -ElementValue "$ProjectUri")" + }) + $(if($IconUri){ + "$(Get-EscapedString -ElementValue "$IconUri")" + }) + + $dependencies + + + +"@ + + $NupkgPath = "$NugetPackageRoot\$Name.$($Version.ToString()).nupkg" + $NuspecPath = "$NugetPackageRoot\$Name.nuspec" + $tempErrorFile = $null + $tempOutputFile = $null + + try + { + # Remove existing nuspec and nupkg files + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + + Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false + + # Create .nupkg file + $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot + if($LASTEXITCODE) + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToCreateCompressedModule -f ($output) + $errorId = "FailedToCreateCompressedModule" + } + else + { + $message = $LocalizedData.FailedToCreateCompressedScript -f ($output) + $errorId = "FailedToCreateCompressedScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + return + } + + # Publish the .nupkg to gallery + $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt" + $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt" + + Microsoft.PowerShell.Management\Start-Process -FilePath "$script:NuGetExePath" ` + -ArgumentList @('push', "`"$NupkgPath`"", '-source', "`"$($Destination.TrimEnd('\'))`"", '-NonInteractive', '-ApiKey', "`"$NugetApiKey`"") ` + -RedirectStandardError $tempErrorFile ` + -RedirectStandardOutput $tempOutputFile ` + -NoNewWindow ` + -Wait + + $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw + + if($errorMsg) + { + if(($NugetApiKey -eq 'VSTS') -and + ($errorMsg -match 'Cannot prompt for input in non-interactive mode.') ) + { + $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) + } + + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheModule" + } + else + { + $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + } + else + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) + } + else + { + $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) + } + + Write-Verbose -Message $message + } + } + finally + { + if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function ValidateAndAdd-PSScriptInfoEntry +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory=$true)] + [string] + $PropertyName, + + [Parameter()] + $PropertyValue, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $Value = $PropertyValue + $KeyName = $PropertyName + + # return if $KeyName value is not null in $PSScriptInfo + if(-not $value -or -not $KeyName -or (Get-Member -InputObject $PSScriptInfo -Name $KeyName) -and $PSScriptInfo."$KeyName") + { + return + } + + switch($PropertyName) + { + # Validate the property value and also use proper key name as users can specify the property name in any case. + $script:Version { + $KeyName = $script:Version + + [Version]$Version = $null + + if([System.Version]::TryParse($Value, ([ref]$Version))) + { + $Value = $Version + } + else + { + $message = $LocalizedData.InvalidVersion -f ($Value) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidVersion" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + break + } + + $script:Author { $KeyName = $script:Author } + + $script:Guid { + $KeyName = $script:Guid + + [Guid]$guid = [System.Guid]::Empty + if([System.Guid]::TryParse($Value, ([ref]$guid))) + { + $Value = $guid + } + else + { + $message = $LocalizedData.InvalidGuid -f ($Value) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidGuid' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + break + } + + $script:Description { $KeyName = $script:Description } + + $script:CompanyName { $KeyName = $script:CompanyName } + + $script:Copyright { $KeyName = $script:Copyright } + + $script:Tags { + $KeyName = $script:Tags + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + break + } + + $script:LicenseUri { + $KeyName = $script:LicenseUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:ProjectUri { + $KeyName = $script:ProjectUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:IconUri { + $KeyName = $script:IconUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:ExternalModuleDependencies { + $KeyName = $script:ExternalModuleDependencies + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:ReleaseNotes { $KeyName = $script:ReleaseNotes } + + $script:RequiredModules { $KeyName = $script:RequiredModules } + + $script:RequiredScripts { + $KeyName = $script:RequiredScripts + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:ExternalScriptDependencies { + $KeyName = $script:ExternalScriptDependencies + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:DefinedCommands { $KeyName = $script:DefinedCommands } + + $script:DefinedFunctions { $KeyName = $script:DefinedFunctions } + + $script:DefinedWorkflows { $KeyName = $script:DefinedWorkflows } + } + + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` + -MemberType NoteProperty ` + -Name $KeyName ` + -Value $Value ` + -Force +} + +function Get-ExportedDscResources +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo + ) + + $dscResources = @() + + if(Get-Command -Name Get-DscResource -Module PSDesiredStateConfiguration -ErrorAction SilentlyContinue) + { + $OldPSModulePath = $env:PSModulePath + + try + { + $env:PSModulePath = Join-Path -Path $PSHOME -ChildPath "Modules" + $env:PSModulePath = "$env:PSModulePath;$(Split-Path -Path $PSModuleInfo.ModuleBase -Parent)" + + $dscResources = PSDesiredStateConfiguration\Get-DscResource -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\ForEach-Object { + if($_.Module -and ($_.Module.Name -eq $PSModuleInfo.Name)) + { + $_.Name + } + } + } + finally + { + $env:PSModulePath = $OldPSModulePath + } + } + else + { + $dscResourcesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath "DscResources" + if(Microsoft.PowerShell.Management\Test-Path $dscResourcesDir) + { + $dscResources = Microsoft.PowerShell.Management\Get-ChildItem -Path $dscResourcesDir -Directory -Name + } + } + + return $dscResources +} + +function Get-AvailableRoleCapabilityName +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo + ) + + $RoleCapabilityNames = @() + + $RoleCapabilitiesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath 'RoleCapabilities' + if(Microsoft.PowerShell.Management\Test-Path -Path $RoleCapabilitiesDir -PathType Container) + { + $RoleCapabilityNames = Microsoft.PowerShell.Management\Get-ChildItem -Path $RoleCapabilitiesDir ` + -Name -Filter *.psrc | + ForEach-Object {[System.IO.Path]::GetFileNameWithoutExtension($_)} + } + + return $RoleCapabilityNames +} + +function Get-LocationString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [Uri] + $LocationUri + ) + + $LocationString = $null + + if($LocationUri) + { + if($LocationUri.Scheme -eq 'file') + { + $LocationString = $LocationUri.OriginalString + } + elseif($LocationUri.AbsoluteUri) + { + $LocationString = $LocationUri.AbsoluteUri + } + else + { + $LocationString = $LocationUri.ToString() + } + } + + return $LocationString +} + +#endregion Utility functions + +#region PowerShellGet Provider APIs Implementation +function Get-PackageProviderName +{ + return $script:PSModuleProviderName +} + +function Get-Feature +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-Feature')) + Write-Output -InputObject (New-Feature $script:SupportsPSModulesFeatureName ) +} + +function Initialize-Provider +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Initialize-Provider')) +} + +function Get-DynamicOptions +{ + param + ( + [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] + $category + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions')) + + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PackageManagementProviderParam -ExpectedType String -IsRequired $false) + + switch($category) + { + Package { + Write-Output -InputObject (New-DynamicOption -Category $category ` + -Name $script:PSArtifactType ` + -ExpectedType String ` + -IsRequired $false ` + -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All)) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Filter -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Tag -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name Includes -ExpectedType StringArray -IsRequired $false -PermittedValues $script:IncludeValidSet) + Write-Output -InputObject (New-DynamicOption -Category $category -Name DscResource -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name RoleCapability -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name Command -ExpectedType StringArray -IsRequired $false) + } + + Source { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PublishLocation -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptSourceLocation -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptPublishLocation -ExpectedType String -IsRequired $false) + } + + Install + { + Write-Output -InputObject (New-DynamicOption -Category $category ` + -Name $script:PSArtifactType ` + -ExpectedType String ` + -IsRequired $false ` + -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All)) + Write-Output -InputObject (New-DynamicOption -Category $category -Name "Scope" -ExpectedType String -IsRequired $false -PermittedValues @("CurrentUser","AllUsers")) + Write-Output -InputObject (New-DynamicOption -Category $category -Name 'AllowClobber' -ExpectedType Switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name 'SkipPublisherCheck' -ExpectedType Switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name "InstallUpdate" -ExpectedType Switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name 'NoPathUpdate' -ExpectedType Switch -IsRequired $false) + } + } +} + +function Add-PackageSource +{ + [CmdletBinding()] + param + ( + [string] + $Name, + + [string] + $Location, + + [bool] + $Trusted + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource')) + + if(-not $Name) + { + return + } + + $Credential = $request.Credential + + $IsNewModuleSource = $false + $Options = $request.Options + + foreach( $o in $Options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $Options[$o]) ) + } + + $Proxy = $null + if($Options.ContainsKey($script:Proxy)) + { + $Proxy = $Options[$script:Proxy] + + if(-not (Test-WebUri -Uri $Proxy)) + { + $message = $LocalizedData.InvalidWebUri -f ($Proxy, $script:Proxy) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidWebUri' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Proxy + } + } + + $ProxyCredential = $null + if($Options.ContainsKey($script:ProxyCredential)) + { + $ProxyCredential = $Options[$script:ProxyCredential] + } + + Set-ModuleSourcesVariable -Force -Proxy $Proxy -ProxyCredential $ProxyCredential + + if($Options.ContainsKey('IsNewModuleSource')) + { + $IsNewModuleSource = $Options['IsNewModuleSource'] + + if($IsNewModuleSource.GetType().ToString() -eq 'System.String') + { + if($IsNewModuleSource -eq 'false') + { + $IsNewModuleSource = $false + } + elseif($IsNewModuleSource -eq 'true') + { + $IsNewModuleSource = $true + } + } + } + + $IsUpdatePackageSource = $false + if($Options.ContainsKey('IsUpdatePackageSource')) + { + $IsUpdatePackageSource = $Options['IsUpdatePackageSource'] + + if($IsUpdatePackageSource.GetType().ToString() -eq 'System.String') + { + if($IsUpdatePackageSource -eq 'false') + { + $IsUpdatePackageSource = $false + } + elseif($IsUpdatePackageSource -eq 'true') + { + $IsUpdatePackageSource = $true + } + } + } + + $PublishLocation = $null + if($Options.ContainsKey($script:PublishLocation)) + { + if($Name -eq $Script:PSGalleryModuleSource) + { + $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('PublishLocation') + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PublishLocation + } + + $PublishLocation = $Options[$script:PublishLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $PublishLocation) -and + -not (Test-WebUri -uri $PublishLocation)) + { + $PublishLocationUri = [Uri]$PublishLocation + if($PublishLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($PublishLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PublishLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($PublishLocation, "PublishLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PublishLocation + } + } + } + + $ScriptSourceLocation = $null + if($Options.ContainsKey($script:ScriptSourceLocation)) + { + if($Name -eq $Script:PSGalleryModuleSource) + { + $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptSourceLocation') + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptSourceLocation + } + + $ScriptSourceLocation = $Options[$script:ScriptSourceLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptSourceLocation) -and + -not (Test-WebUri -uri $ScriptSourceLocation)) + { + $ScriptSourceLocationUri = [Uri]$ScriptSourceLocation + if($ScriptSourceLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($ScriptSourceLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptSourceLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($ScriptSourceLocation, "ScriptSourceLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptSourceLocation + } + } + } + + $ScriptPublishLocation = $null + if($Options.ContainsKey($script:ScriptPublishLocation)) + { + if($Name -eq $Script:PSGalleryModuleSource) + { + $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptPublishLocation') + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptPublishLocation + } + + $ScriptPublishLocation = $Options[$script:ScriptPublishLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptPublishLocation) -and + -not (Test-WebUri -uri $ScriptPublishLocation)) + { + $ScriptPublishLocationUri = [Uri]$ScriptPublishLocation + if($ScriptPublishLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($ScriptPublishLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptPublishLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($ScriptPublishLocation, "ScriptPublishLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptPublishLocation + } + } + } + + $currentSourceObject = $null + + # Check if Name is already registered + if($script:PSGetModuleSources.Contains($Name)) + { + $currentSourceObject = $script:PSGetModuleSources[$Name] + } + + # Location is not allowed for PSGallery source + # However OneGet passes Location value during Set-PackageSource cmdlet, + # that's why ensuring that Location value is same as the current SourceLocation + # + if(($Name -eq $Script:PSGalleryModuleSource) -and + $Location -and + ((-not $IsUpdatePackageSource) -or ($currentSourceObject -and $currentSourceObject.SourceLocation -ne $Location))) + { + $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('Location, NewLocation or SourceLocation') + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + + if($Name -eq $Script:PSGalleryModuleSource) + { + # Add or update the PSGallery repostory + $repository = Set-PSGalleryRepository -Trusted:$Trusted + + if($repository) + { + # return the package source object. + Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $repository) + } + + return + } + + if($Location) + { + # Ping and resolve the specified location + $Location = Resolve-Location -Location $Location ` + -LocationParameterName 'Location' ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -CallerPSCmdlet $PSCmdlet + } + + if(-not $Location) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Location) -and + -not (Test-WebUri -uri $Location) ) + { + $LocationUri = [Uri]$Location + if($LocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($Location) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($Location, "Location") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } + + if(Test-WildcardPattern $Name) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryNameContainsWildCards" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + + $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location" -Proxy $Proxy -ProxyCredential $ProxyCredential -Credential $Credential + + # Check if Location is already registered with another Name + $existingSourceName = Get-SourceName -Location $LocationString + + if($existingSourceName -and + ($Name -ne $existingSourceName) -and + -not $IsNewModuleSource) + { + $message = $LocalizedData.RepositoryAlreadyRegistered -f ($existingSourceName, $Location, $Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryAlreadyRegistered" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + if(-not $PublishLocation -and $currentSourceObject -and $currentSourceObject.PublishLocation) + { + $PublishLocation = $currentSourceObject.PublishLocation + } + + if((-not $ScriptPublishLocation) -and + $currentSourceObject -and + (Get-Member -InputObject $currentSourceObject -Name $script:ScriptPublishLocation) -and + $currentSourceObject.ScriptPublishLocation) + { + $ScriptPublishLocation = $currentSourceObject.ScriptPublishLocation + } + + if((-not $ScriptSourceLocation) -and + $currentSourceObject -and + (Get-Member -InputObject $currentSourceObject -Name $script:ScriptSourceLocation) -and + $currentSourceObject.ScriptSourceLocation) + { + $ScriptSourceLocation = $currentSourceObject.ScriptSourceLocation + } + + $IsProviderSpecified = $false; + if ($Options.ContainsKey($script:PackageManagementProviderParam)) + { + $SpecifiedProviderName = $Options[$script:PackageManagementProviderParam] + + $IsProviderSpecified = $true + + Write-Verbose ($LocalizedData.SpecifiedProviderName -f $SpecifiedProviderName) + if ($SpecifiedProviderName -eq $script:PSModuleProviderName) + { + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($SpecifiedProviderName, $script:NuGetProviderName, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $SpecifiedProviderName + return + } + } + else + { + $SpecifiedProviderName = $script:NuGetProviderName + Write-Verbose ($LocalizedData.ProviderNameNotSpecified -f $SpecifiedProviderName) + } + + $packageSource = $null + + $selProviders = $request.SelectProvider($SpecifiedProviderName) + + if(-not $selProviders -and $IsProviderSpecified) + { + $message = $LocalizedData.SpecifiedProviderNotAvailable -f $SpecifiedProviderName + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedProviderNotAvailable" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $SpecifiedProviderName + } + + # Try with user specified provider or NuGet provider + foreach($SelectedProvider in $selProviders) + { + if($request.IsCanceled) + { + return + } + + if($SelectedProvider -and $SelectedProvider.Features.ContainsKey($script:SupportsPSModulesFeatureName)) + { + $NewRequest = $request.CloneRequest( $null, @($LocationString), $request.Credential ) + $packageSource = $SelectedProvider.ResolvePackageSources( $NewRequest ) + } + else + { + $message = $LocalizedData.SpecifiedProviderDoesnotSupportPSModules -f $SelectedProvider.ProviderName + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedProviderDoesnotSupportPSModules" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $SelectedProvider.ProviderName + } + + if($packageSource) + { + break + } + } + + # Poll other package provider when NuGet provider doesn't resolves the specified location + if(-not $packageSource -and -not $IsProviderSpecified) + { + Write-Verbose ($LocalizedData.PollingPackageManagementProvidersForLocation -f $LocationString) + + $moduleProviders = $request.SelectProvidersWithFeature($script:SupportsPSModulesFeatureName) + + foreach($provider in $moduleProviders) + { + if($request.IsCanceled) + { + return + } + + # Skip already tried $SpecifiedProviderName and PowerShellGet provider + if($provider.ProviderName -eq $SpecifiedProviderName -or + $provider.ProviderName -eq $script:PSModuleProviderName) + { + continue + } + + Write-Verbose ($LocalizedData.PollingSingleProviderForLocation -f ($LocationString, $provider.ProviderName)) + $NewRequest = $request.CloneRequest( @{}, @($LocationString), $request.Credential ) + $packageSource = $provider.ResolvePackageSources($NewRequest) + + if($packageSource) + { + Write-Verbose ($LocalizedData.FoundProviderForLocation -f ($provider.ProviderName, $Location)) + $SelectedProvider = $provider + break + } + } + } + + if(-not $packageSource) + { + $message = $LocalizedData.SpecifiedLocationCannotBeRegistered -f $Location + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedLocationCannotBeRegistered" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + + $ProviderOptions = @{} + + $SelectedProvider.DynamicOptions | Microsoft.PowerShell.Core\ForEach-Object { + if($options.ContainsKey($_.Name) ) + { + $ProviderOptions[$_.Name] = $options[$_.Name] + } + } + + # Keep the existing provider options if not specified in Set-PSRepository + if($currentSourceObject) + { + $currentSourceObject.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if (-not $ProviderOptions.ContainsKey($_.Key) ) + { + $ProviderOptions[$_.Key] = $_.Value + } + } + } + + if(-not $PublishLocation) + { + $PublishLocation = Get-PublishLocation -Location $LocationString + } + + # Use the PublishLocation for the scripts when ScriptPublishLocation is not specified by the user + if(-not $ScriptPublishLocation) + { + $ScriptPublishLocation = $PublishLocation + + # ScriptPublishLocation and PublishLocation should be equal in case of SMB Share or Local directory paths + if($Options.ContainsKey($script:ScriptPublishLocation) -and + (Microsoft.PowerShell.Management\Test-Path -Path $ScriptPublishLocation)) + { + if($ScriptPublishLocation -ne $PublishLocation) + { + $message = $LocalizedData.PublishLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishLocationPathsForModulesAndScriptsShouldBeEqual" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + } + + if(-not $ScriptSourceLocation) + { + $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString -Proxy $Proxy -ProxyCredential $ProxyCredential -Credential $Credential + } + elseif($Options.ContainsKey($script:ScriptSourceLocation)) + { + # ScriptSourceLocation and SourceLocation cannot be same for they are URLs + # Both should be equal in case of SMB Share or Local directory paths + if(Microsoft.PowerShell.Management\Test-Path -Path $ScriptSourceLocation) + { + if($ScriptSourceLocation -ne $LocationString) + { + $message = $LocalizedData.SourceLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SourceLocationPathsForModulesAndScriptsShouldBeEqual" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + else + { + if($ScriptSourceLocation -eq $LocationString -and + -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase)) + ) + { + $message = $LocalizedData.SourceLocationUrisForModulesAndScriptsShouldBeDifferent -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SourceLocationUrisForModulesAndScriptsShouldBeDifferent" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + } + + # no error so we can safely remove the source + if($script:PSGetModuleSources.Contains($Name)) + { + $null = $script:PSGetModuleSources.Remove($Name) + } + + # Add new module source + $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $Name + SourceLocation = $LocationString + PublishLocation = $PublishLocation + ScriptSourceLocation = $ScriptSourceLocation + ScriptPublishLocation = $ScriptPublishLocation + Trusted=$Trusted + Registered= (-not $IsNewModuleSource) + InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} + PackageManagementProvider = $SelectedProvider.ProviderName + ProviderOptions = $ProviderOptions + }) + + #region telemetry - Capture non-PSGallery registrations as telemetry events + if ($script:TelemetryEnabled) + { + + Log-NonPSGalleryRegistration -sourceLocation $moduleSource.SourceLocation ` + -installationPolicy $moduleSource.InstallationPolicy ` + -packageManagementProvider $moduleSource.PackageManagementProvider ` + -publishLocation $moduleSource.PublishLocation ` + -scriptSourceLocation $moduleSource.ScriptSourceLocation ` + -scriptPublishLocation $moduleSource.ScriptPublishLocation ` + -operationName PSGET_NONPSGALLERY_REGISTRATION ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + } + #endregion + + $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + + # Persist the repositories only when Register-PSRepository cmdlet is used + if(-not $IsNewModuleSource) + { + $script:PSGetModuleSources.Add($Name, $moduleSource) + + $message = $LocalizedData.RepositoryRegistered -f ($Name, $LocationString) + Write-Verbose $message + + # Persist the module sources + Save-ModuleSources + } + + # return the package source object. + Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource) +} + +function Resolve-PackageSource +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource')) + + Set-ModuleSourcesVariable + + $SourceName = $request.PackageSources + + if(-not $SourceName) + { + $SourceName = "*" + } + + foreach($moduleSourceName in $SourceName) + { + if($request.IsCanceled) + { + return + } + + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $moduleSourceName,$script:wildcardOptions + $moduleSourceFound = $false + + $script:PSGetModuleSources.GetEnumerator() | + Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | + Microsoft.PowerShell.Core\ForEach-Object { + + $moduleSource = $script:PSGetModuleSources[$_.Key] + + $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource + + Write-Output -InputObject $packageSource + + $moduleSourceFound = $true + } + + if(-not $moduleSourceFound) + { + $sourceName = Get-SourceName -Location $moduleSourceName + + if($sourceName) + { + $moduleSource = $script:PSGetModuleSources[$sourceName] + + $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource + + Write-Output -InputObject $packageSource + } + elseif( -not (Test-WildcardPattern $moduleSourceName)) + { + $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) + + Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName + } + } + } +} + +function Remove-PackageSource +{ + param + ( + [string] + $Name + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource')) + + Set-ModuleSourcesVariable -Force + + $ModuleSourcesToBeRemoved = @() + + foreach ($moduleSourceName in $Name) + { + if($request.IsCanceled) + { + return + } + + # Check if $Name contains any wildcards + if(Test-WildcardPattern $moduleSourceName) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation -TargetObject $moduleSourceName + continue + } + + # Check if the specified module source name is in the registered module sources + if(-not $script:PSGetModuleSources.Contains($moduleSourceName)) + { + $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName + continue + } + + $ModuleSourcesToBeRemoved += $moduleSourceName + $message = $LocalizedData.RepositoryUnregistered -f ($moduleSourceName) + Write-Verbose $message + } + + # Remove the module source + $ModuleSourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:PSGetModuleSources.Remove($_) } + + # Persist the module sources + Save-ModuleSources +} + +function Find-Package +{ + [CmdletBinding()] + param + ( + [string[]] + $names, + + [string] + $requiredVersion, + + [string] + $minimumVersion, + + [string] + $maximumVersion + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package')) + + Set-ModuleSourcesVariable + + if($RequiredVersion -and $MinimumVersion) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` + -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + if($RequiredVersion -or $MinimumVersion) + { + if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0])) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` + -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $options = $request.Options + + foreach( $o in $options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) + } + + # When using -Name, we don't send PSGet-specific properties to the server - we will filter it ourselves + $postFilter = New-Object -TypeName System.Collections.Hashtable + if($options.ContainsKey("Name")) + { + if($options.ContainsKey("Includes")) + { + $postFilter["Includes"] = $options["Includes"] + $null = $options.Remove("Includes") + } + + if($options.ContainsKey("DscResource")) + { + $postFilter["DscResource"] = $options["DscResource"] + $null = $options.Remove("DscResource") + } + + if($options.ContainsKey('RoleCapability')) + { + $postFilter['RoleCapability'] = $options['RoleCapability'] + $null = $options.Remove('RoleCapability') + } + + if($options.ContainsKey("Command")) + { + $postFilter["Command"] = $options["Command"] + $null = $options.Remove("Command") + } + } + + $LocationOGPHashtable = [ordered]@{} + if($options -and $options.ContainsKey('Source')) + { + $SourceNames = $($options['Source']) + + Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames)) + + foreach($sourceName in $SourceNames) + { + if($script:PSGetModuleSources.Contains($sourceName)) + { + $ModuleSource = $script:PSGetModuleSources[$sourceName] + $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) + } + else + { + $sourceByLocation = Get-SourceName -Location $sourceName + + if ($sourceByLocation) + { + $ModuleSource = $script:PSGetModuleSources[$sourceByLocation] + $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) + } + else + { + $message = $LocalizedData.RepositoryNotFound -f ($sourceName) + Write-Error -Message $message ` + -ErrorId 'RepositoryNotFound' ` + -Category InvalidArgument ` + -TargetObject $sourceName + } + } + } + } + elseif($options -and + $options.ContainsKey($script:PackageManagementProviderParam) -and + $options.ContainsKey('Location')) + { + $Location = $options['Location'] + $PackageManagementProvider = $options['PackageManagementProvider'] + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $PackageManagementProvider)) + + $LocationOGPHashtable[$Location] = $PackageManagementProvider + } + else + { + Write-Verbose $LocalizedData.NoSourceNameIsSpecified + + $script:PSGetModuleSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $LocationOGPHashtable[$_.SourceLocation] = (Get-ProviderName -PSCustomObject $_) } + } + + $artifactTypes = $script:PSArtifactTypeModule + if($options.ContainsKey($script:PSArtifactType)) + { + $artifactTypes = $options[$script:PSArtifactType] + } + + if($artifactTypes -eq $script:All) + { + $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) + } + + $providerOptions = @{} + + if($options.ContainsKey($script:AllVersions)) + { + $providerOptions[$script:AllVersions] = $options[$script:AllVersions] + } + + if($options.ContainsKey($script:Filter)) + { + $Filter = $options[$script:Filter] + $providerOptions['Contains'] = $Filter + } + + if($options.ContainsKey($script:Tag)) + { + $userSpecifiedTags = $options[$script:Tag] | Microsoft.PowerShell.Utility\Select-Object -Unique + } + else + { + $userSpecifiedTags = @($script:NotSpecified) + } + + $specifiedDscResources = @() + if($options.ContainsKey('DscResource')) + { + $specifiedDscResources = $options['DscResource'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:DscResource)_$_"} + } + + $specifiedRoleCapabilities = @() + if($options.ContainsKey('RoleCapability')) + { + $specifiedRoleCapabilities = $options['RoleCapability'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:RoleCapability)_$_"} + } + + $specifiedCommands = @() + if($options.ContainsKey('Command')) + { + $specifiedCommands = $options['Command'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:Command)_$_"} + } + + $specifiedIncludes = @() + if($options.ContainsKey('Includes')) + { + $includes = $options['Includes'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:Includes)_$_"} + + # Add PSIncludes_DscResource to $specifiedIncludes iff -DscResource names are not specified + # Add PSIncludes_RoleCapability to $specifiedIncludes iff -RoleCapability names are not specified + # Add PSIncludes_Cmdlet or PSIncludes_Function to $specifiedIncludes iff -Command names are not specified + # otherwise $script:NotSpecified will be added to $specifiedIncludes + if($includes) + { + if(-not $specifiedDscResources -and ($includes -contains "$($script:Includes)_DscResource") ) + { + $specifiedIncludes += "$($script:Includes)_DscResource" + } + + if(-not $specifiedRoleCapabilities -and ($includes -contains "$($script:Includes)_RoleCapability") ) + { + $specifiedIncludes += "$($script:Includes)_RoleCapability" + } + + if(-not $specifiedCommands) + { + if($includes -contains "$($script:Includes)_Cmdlet") + { + $specifiedIncludes += "$($script:Includes)_Cmdlet" + } + + if($includes -contains "$($script:Includes)_Function") + { + $specifiedIncludes += "$($script:Includes)_Function" + } + + if($includes -contains "$($script:Includes)_Workflow") + { + $specifiedIncludes += "$($script:Includes)_Workflow" + } + } + } + } + + if(-not $specifiedDscResources) + { + $specifiedDscResources += $script:NotSpecified + } + + if(-not $specifiedRoleCapabilities) + { + $specifiedRoleCapabilities += $script:NotSpecified + } + + if(-not $specifiedCommands) + { + $specifiedCommands += $script:NotSpecified + } + + if(-not $specifiedIncludes) + { + $specifiedIncludes += $script:NotSpecified + } + + $providerSearchTags = @{} + + foreach($tag in $userSpecifiedTags) + { + foreach($include in $specifiedIncludes) + { + foreach($command in $specifiedCommands) + { + foreach($resource in $specifiedDscResources) + { + foreach($roleCapability in $specifiedRoleCapabilities) + { + $providerTags = @() + if($resource -ne $script:NotSpecified) + { + $providerTags += $resource + } + + if($roleCapability -ne $script:NotSpecified) + { + $providerTags += $roleCapability + } + + if($command -ne $script:NotSpecified) + { + $providerTags += $command + } + + if($include -ne $script:NotSpecified) + { + $providerTags += $include + } + + if($tag -ne $script:NotSpecified) + { + $providerTags += $tag + } + + if($providerTags) + { + $providerSearchTags["$tag $resource $roleCapability $command $include"] = $providerTags + } + } + } + } + } + } + + $InstallationPolicy = "Untrusted" + if($options.ContainsKey('InstallationPolicy')) + { + $InstallationPolicy = $options['InstallationPolicy'] + } + + $streamedResults = @() + + foreach($artifactType in $artifactTypes) + { + foreach($kvPair in $LocationOGPHashtable.GetEnumerator()) + { + if($request.IsCanceled) + { + return + } + + $Location = $kvPair.Key + if($artifactType -eq $script:PSArtifactTypeScript) + { + $sourceName = Get-SourceName -Location $Location + + if($SourceName) + { + $ModuleSource = $script:PSGetModuleSources[$SourceName] + + # Skip source if no ScriptSourceLocation is available. + if(-not $ModuleSource.ScriptSourceLocation) + { + if($options.ContainsKey('Source')) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($ModuleSource.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $ModuleSource.Name + } + + continue + } + + $Location = $ModuleSource.ScriptSourceLocation + } + } + + $ProviderName = $kvPair.Value + + Write-Verbose ($LocalizedData.GettingPackageManagementProviderObject -f ($ProviderName)) + + $provider = $request.SelectProvider($ProviderName) + + if(-not $provider) + { + Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $ProviderName) + + Continue + } + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $provider.ProviderName)) + + if($providerSearchTags.Values.Count) + { + $tagList = $providerSearchTags.Values + } + else + { + $tagList = @($script:NotSpecified) + } + + $namesParameterEmpty = ($names.Count -eq 1) -and ($names[0] -eq '') + + foreach($providerTag in $tagList) + { + if($request.IsCanceled) + { + return + } + + $FilterOnTag = @() + + if($providerTag -ne $script:NotSpecified) + { + $FilterOnTag = $providerTag + } + + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + if($artifactType -eq $script:PSArtifactTypeScript) + { + $FilterOnTag += 'PSScript' + } + elseif($artifactType -eq $script:PSArtifactTypeModule) + { + $FilterOnTag += 'PSModule' + } + } + + if($FilterOnTag) + { + $providerOptions["FilterOnTag"] = $FilterOnTag + } + elseif($providerOptions.ContainsKey('FilterOnTag')) + { + $null = $providerOptions.Remove('FilterOnTag') + } + + if($request.Options.ContainsKey($script:FindByCanonicalId)) + { + $providerOptions[$script:FindByCanonicalId] = $request.Options[$script:FindByCanonicalId] + } + + $providerOptions["Headers"] = 'PSGalleryClientVersion=1.1' + + $NewRequest = $request.CloneRequest( $providerOptions, @($Location), $request.Credential ) + + $pkgs = $provider.FindPackages($names, + $requiredVersion, + $minimumVersion, + $maximumVersion, + $NewRequest ) + + foreach($pkg in $pkgs) + { + if($request.IsCanceled) + { + return + } + + # $pkg.Name has to match any of the supplied names, using PowerShell wildcards + if ($namesParameterEmpty -or ($names | % { if ($pkg.Name -like $_){return $true; break} } -End {return $false})) + { + $includePackage = $true + + # If -Name was provided, we need to post-filter + # Filtering has AND semantics between different parameters and OR within a parameter (each parameter is potentially an array) + if($options.ContainsKey("Name") -and $postFilter.Count -gt 0) + { + if ($pkg.Metadata["DscResources"].Count -gt 0) + { + $pkgDscResources = $pkg.Metadata["DscResources"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgDscResources = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:DscResource, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:DscResource.Length + 1) } + } + + if ($pkg.Metadata['RoleCapabilities'].Count -gt 0) + { + $pkgRoleCapabilities = $pkg.Metadata['RoleCapabilities'] -Split ' ' | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgRoleCapabilities = $pkg.Metadata["tags"] -Split ' ' ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:RoleCapability, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:RoleCapability.Length + 1) } + } + + if ($pkg.Metadata["Functions"].Count -gt 0) + { + $pkgFunctions = $pkg.Metadata["Functions"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgFunctions = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Function, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Function.Length + 1) } + } + + if ($pkg.Metadata["Cmdlets"].Count -gt 0) + { + $pkgCmdlets = $pkg.Metadata["Cmdlets"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgCmdlets = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Cmdlet, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Cmdlet.Length + 1) } + } + + if ($pkg.Metadata["Workflows"].Count -gt 0) + { + $pkgWorkflows = $pkg.Metadata["Workflows"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgWorkflows = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Workflow, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Workflow.Length + 1) } + } + + foreach ($key in $postFilter.Keys) + { + switch ($key) + { + "DscResource" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgDscResources | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + 'RoleCapability' { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgRoleCapabilities | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + "Command" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgFunctions | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + + $pkgCmdlets | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + + $pkgWorkflows | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + "Includes" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + switch ($value) + { + "Cmdlet" { if ($pkgCmdlets ) { $includePackage = $true } } + "Function" { if ($pkgFunctions ) { $includePackage = $true } } + "DscResource" { if ($pkgDscResources ) { $includePackage = $true } } + "RoleCapability" { if ($pkgRoleCapabilities ) { $includePackage = $true } } + "Workflow" { if ($pkgWorkflows ) { $includePackage = $true } } + } + } + + if (-not $includePackage) + { + break + } + } + } + } + } + + if ($includePackage) + { + $fastPackageReference = New-FastPackageReference -ProviderName $provider.ProviderName ` + -PackageName $pkg.Name ` + -Version $pkg.Version ` + -Source $Location ` + -ArtifactType $artifactType + + if($streamedResults -notcontains $fastPackageReference) + { + $streamedResults += $fastPackageReference + + $FromTrustedSource = $false + + $ModuleSourceName = Get-SourceName -Location $Location + + if($ModuleSourceName) + { + $FromTrustedSource = $script:PSGetModuleSources[$ModuleSourceName].Trusted + } + elseif($InstallationPolicy -eq "Trusted") + { + $FromTrustedSource = $true + } + + $sid = New-SoftwareIdentityFromPackage -Package $pkg ` + -PackageManagementProviderName $provider.ProviderName ` + -SourceLocation $Location ` + -IsFromTrustedSource:$FromTrustedSource ` + -Type $artifactType ` + -request $request + + $script:FastPackRefHastable[$fastPackageReference] = $pkg + + Write-Output -InputObject $sid + } + } + } + } + } + } + } +} + +function Download-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Download-Package')) + + Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request -Location $Location +} + +function Install-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package')) + + Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request +} + +function Install-PackageUtility +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Location, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + $request + ) + + Set-ModuleSourcesVariable + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-PackageUtility')) + + Write-Debug ($LocalizedData.FastPackageReference -f $fastPackageReference) + + $Force = $false + $SkipPublisherCheck = $false + $AllowClobber = $false + $Debug = $false + $MinimumVersion = $null + $RequiredVersion = $null + $IsSavePackage = $false + $Scope = $null + $NoPathUpdate = $false + + # take the fastPackageReference and get the package object again. + $parts = $fastPackageReference -Split '[|]' + + if( $parts.Length -eq 5 ) + { + $providerName = $parts[0] + $packageName = $parts[1] + $version = $parts[2] + $sourceLocation= $parts[3] + $artfactType = $parts[4] + + # The default destination location for Modules and Scripts is ProgramFiles path + $scriptDestination = $script:ProgramFilesScriptsPath + $moduleDestination = $script:programFilesModulesPath + $Scope = 'AllUsers' + + if($artfactType -eq $script:PSArtifactTypeScript) + { + $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' + } + else + { + $AdminPreviligeErrorMessage = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) + $AdminPreviligeErrorId = 'InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser' + } + + $installUpdate = $false + + $options = $request.Options + + if($options) + { + foreach( $o in $options.Keys ) + { + Write-Debug ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) + } + + if($options.ContainsKey('Scope')) + { + $Scope = $options['Scope'] + Write-Verbose ($LocalizedData.SpecifiedInstallationScope -f $Scope) + + if($Scope -eq "CurrentUser") + { + $scriptDestination = $script:MyDocumentsScriptsPath + $moduleDestination = $script:MyDocumentsModulesPath + } + elseif($Scope -eq "AllUsers") + { + $scriptDestination = $script:ProgramFilesScriptsPath + $moduleDestination = $script:programFilesModulesPath + + if(-not (Test-RunningAsElevated)) + { + # Throw an error when Install-Module/Script is used as a non-admin user and '-Scope CurrentUser' is not specified + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + } + elseif($Location) + { + $IsSavePackage = $true + $Scope = $null + + $moduleDestination = $Location + $scriptDestination = $Location + } + # if no scope and no destination path and not elevated, then raise an error + elseif(-not (Test-RunningAsElevated)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + if($options.ContainsKey('SkipPublisherCheck')) + { + $SkipPublisherCheck = $options['SkipPublisherCheck'] + + if($SkipPublisherCheck.GetType().ToString() -eq 'System.String') + { + if($SkipPublisherCheck -eq 'true') + { + $SkipPublisherCheck = $true + } + else + { + $SkipPublisherCheck = $false + } + } + } + + if($options.ContainsKey('AllowClobber')) + { + $AllowClobber = $options['AllowClobber'] + + if($AllowClobber.GetType().ToString() -eq 'System.String') + { + if($AllowClobber -eq 'false') + { + $AllowClobber = $false + } + elseif($AllowClobber -eq 'true') + { + $AllowClobber = $true + } + } + } + + if($options.ContainsKey('Force')) + { + $Force = $options['Force'] + + if($Force.GetType().ToString() -eq 'System.String') + { + if($Force -eq 'false') + { + $Force = $false + } + elseif($Force -eq 'true') + { + $Force = $true + } + } + } + + if($options.ContainsKey('Debug')) + { + $Debug = $options['Debug'] + + if($Debug.GetType().ToString() -eq 'System.String') + { + if($Debug -eq 'false') + { + $Debug = $false + } + elseif($Debug -eq 'true') + { + $Debug = $true + } + } + } + + if($options.ContainsKey('NoPathUpdate')) + { + $NoPathUpdate = $options['NoPathUpdate'] + + if($NoPathUpdate.GetType().ToString() -eq 'System.String') + { + if($NoPathUpdate -eq 'false') + { + $NoPathUpdate = $false + } + elseif($NoPathUpdate -eq 'true') + { + $NoPathUpdate = $true + } + } + } + + if($options.ContainsKey('MinimumVersion')) + { + $MinimumVersion = $options['MinimumVersion'] + } + + if($options.ContainsKey('RequiredVersion')) + { + $RequiredVersion = $options['RequiredVersion'] + } + + if($options.ContainsKey('InstallUpdate')) + { + $installUpdate = $options['InstallUpdate'] + + if($installUpdate.GetType().ToString() -eq 'System.String') + { + if($installUpdate -eq 'false') + { + $installUpdate = $false + } + elseif($installUpdate -eq 'true') + { + $installUpdate = $true + } + } + } + + if($Scope -and ($artfactType -eq $script:PSArtifactTypeScript) -and (-not $installUpdate)) + { + ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` + -ScopePath $scriptDestination ` + -Request $request ` + -NoPathUpdate:$NoPathUpdate ` + -Force:$Force + } + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.ModuleDestination -f @($moduleDestination) + } + else + { + $message = $LocalizedData.ScriptDestination -f @($scriptDestination, $moduleDestination) + } + Write-Verbose $message + } + + Write-Debug "ArtfactType is $artfactType" + + if($artfactType -eq $script:PSArtifactTypeModule) + { + # Test if module is already installed + $InstalledModuleInfo = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $packageName -RequiredVersion $RequiredVersion } + + if(-not $Force -and $InstalledModuleInfo) + { + if($RequiredVersion -and (Test-ModuleSxSVersionSupport)) + { + # Check if the module with the required version is already installed otherwise proceed to install/update. + if($InstalledModuleInfo) + { + $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version) + Write-Error -Message $message -ErrorId "ModuleWithRequiredVersionAlreadyInstalled" -Category InvalidOperation + + return + } + } + else + { + if(-not $installUpdate) + { + if( (-not $MinimumVersion -and ($version -ne $InstalledModuleInfo.Version)) -or + ($MinimumVersion -and ($MinimumVersion -gt $InstalledModuleInfo.Version))) + { + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $message = $LocalizedData.ModuleAlreadyInstalledSxS -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $version, $InstalledModuleInfo.Version, $version) + } + else + { + $message = $LocalizedData.ModuleAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version, $version) + } + Write-Error -Message $message -ErrorId "ModuleAlreadyInstalled" -Category InvalidOperation + } + else + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) + Write-Verbose $message + } + + return + } + else + { + if($InstalledModuleInfo.Version -lt $version) + { + $message = $LocalizedData.FoundModuleUpdate -f ($InstalledModuleInfo.Name, $version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($InstalledModuleInfo.Name) + Write-Verbose $message + return + } + } + } + } + } + + if($artfactType -eq $script:PSArtifactTypeScript) + { + # Test if script is already installed + $InstalledScriptInfo = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $packageName } + + Write-Debug "InstalledScriptInfo is $InstalledScriptInfo" + + if(-not $Force -and $InstalledScriptInfo) + { + if(-not $installUpdate) + { + if( (-not $MinimumVersion -and ($version -ne $InstalledScriptInfo.Version)) -or + ($MinimumVersion -and ($MinimumVersion -gt $InstalledScriptInfo.Version))) + { + $message = $LocalizedData.ScriptAlreadyInstalled -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase, $InstalledScriptInfo.Version, $version) + Write-Error -Message $message -ErrorId "ScriptAlreadyInstalled" -Category InvalidOperation + } + else + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) + Write-Verbose $message + } + + return + } + else + { + if($InstalledScriptInfo.Version -lt $version) + { + $message = $LocalizedData.FoundScriptUpdate -f ($InstalledScriptInfo.Name, $version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoScriptUpdateAvailable -f ($InstalledScriptInfo.Name) + Write-Verbose $message + return + } + } + } + + # Throw an error if there is a command with the same name and -force is not specified. + if(-not $installUpdate -and + -not $IsSavePackage -and + -not $Force) + { + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $packageName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($packageName) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + return + } + } + } + + # create a temp folder and download the module + $tempDestination = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)" + $null = Microsoft.PowerShell.Management\New-Item -Path $tempDestination -ItemType Directory -Force -Confirm:$false -WhatIf:$false + + try + { + $provider = $request.SelectProvider($providerName) + if(-not $provider) + { + Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $providerName) + + return + } + + if($request.IsCanceled) + { + return + } + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($provider.ProviderName, $providerName)) + + $InstalledItemsList = $null + $pkg = $script:FastPackRefHastable[$fastPackageReference] + + # If an item has dependencies, prepare the list of installed items and + # pass it to the NuGet provider to not download the already installed items. + if($pkg.Dependencies.count -and + -not $IsSavePackage -and + -not $Force) + { + $InstalledItemsList = Microsoft.PowerShell.Core\Get-Module -ListAvailable | + Microsoft.PowerShell.Core\ForEach-Object {"$($_.Name)!#!$($_.Version)".ToLower()} + + if($artfactType -eq $script:PSArtifactTypeScript) + { + $InstalledItemsList += $script:PSGetInstalledScripts.GetEnumerator() | + Microsoft.PowerShell.Core\ForEach-Object { + "$($_.Value.PSGetItemInfo.Name)!#!$($_.Value.PSGetItemInfo.Version)".ToLower() + } + } + + $InstalledItemsList | Select-Object -Unique + + if($Debug) + { + $InstalledItemsList | Microsoft.PowerShell.Core\ForEach-Object { Write-Debug -Message "Locally available Item: $_"} + } + } + + $ProviderOptions = @{ + Destination=$tempDestination; + ExcludeVersion=$true + } + + if($InstalledItemsList) + { + $ProviderOptions['InstalledPackages'] = $InstalledItemsList + } + + $newRequest = $request.CloneRequest( $ProviderOptions, @($SourceLocation), $request.Credential ) + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.DownloadingModuleFromGallery -f ($packageName, $version, $sourceLocation) + } + else + { + $message = $LocalizedData.DownloadingScriptFromGallery -f ($packageName, $version, $sourceLocation) + } + Write-Verbose $message + + $installedPkgs = $provider.InstallPackage($script:FastPackRefHastable[$fastPackageReference], $newRequest) + + foreach($pkg in $installedPkgs) + { + if($request.IsCanceled) + { + return + } + + $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $moduleDestination -ChildPath $pkg.Name + + # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only + # By default, PowerShell module versions will be installed/updated Side-by-Side. + if(Test-ModuleSxSVersionSupport) + { + $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $destinationModulePath -ChildPath $pkg.Version + } + + $destinationscriptPath = $scriptDestination + + # Get actual artifact type from the package + $packageType = $script:PSArtifactTypeModule + $installLocation = $destinationModulePath + $tempPackagePath = Microsoft.PowerShell.Management\Join-Path -Path $tempDestination -ChildPath $pkg.Name + if(Microsoft.PowerShell.Management\Test-Path -Path $tempPackagePath) + { + $packageFiles = Microsoft.PowerShell.Management\Get-ChildItem -Path $tempPackagePath -Recurse -Exclude "*.nupkg","*.nuspec" + + if($packageFiles -and $packageFiles.GetType().ToString() -eq 'System.IO.FileInfo' -and $packageFiles.Name -eq "$($pkg.Name).ps1") + { + $packageType = $script:PSArtifactTypeScript + $installLocation = $destinationscriptPath + } + } + + $AdditionalParams = @{} + + if(-not $IsSavePackage) + { + # During the install operation: + # InstalledDate should be the current Get-Date value + # UpdatedDate should be null + # + # During the update operation: + # InstalledDate should be from the previous version's InstalledDate otherwise current Get-Date value + # UpdatedDate should be the current Get-Date value + # + $InstalledDate = Microsoft.PowerShell.Utility\Get-Date + + if($installUpdate) + { + $AdditionalParams['UpdatedDate'] = Microsoft.PowerShell.Utility\Get-Date + + $InstalledItemDetails = $null + if($packageType -eq $script:PSArtifactTypeModule) + { + $InstalledItemDetails = Get-InstalledModuleDetails -Name $pkg.Name | Select-Object -Last 1 + } + elseif($packageType -eq $script:PSArtifactTypeScript) + { + $InstalledItemDetails = Get-InstalledScriptDetails -Name $pkg.Name | Select-Object -Last 1 + } + + if($InstalledItemDetails -and + $InstalledItemDetails.PSGetItemInfo -and + (Get-Member -InputObject $InstalledItemDetails.PSGetItemInfo -Name 'InstalledDate') -and + $InstalledItemDetails.PSGetItemInfo.InstalledDate) + { + $InstalledDate = $InstalledItemDetails.PSGetItemInfo.InstalledDate + } + } + + $AdditionalParams['InstalledDate'] = $InstalledDate + } + + $sid = New-SoftwareIdentityFromPackage -Package $pkg ` + -SourceLocation $sourceLocation ` + -PackageManagementProviderName $provider.ProviderName ` + -Request $request ` + -Type $packageType ` + -InstalledLocation $installLocation ` + @AdditionalParams + + # construct the PSGetItemInfo from SoftwareIdentity and persist it + $psgItemInfo = New-PSGetItemInfo -SoftwareIdentity $pkg ` + -PackageManagementProviderName $provider.ProviderName ` + -SourceLocation $sourceLocation ` + -Type $packageType ` + -InstalledLocation $installLocation ` + @AdditionalParams + + if($packageType -eq $script:PSArtifactTypeModule) + { + if ($psgItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + if(-not $psgItemInfo.PowerShellGetFormatVersion) + { + $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination $pkg.Name + } + else + { + $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination "$($pkg.Name)\Content\*\$script:ModuleReferences\$($pkg.Name)" + } + + $CurrentModuleInfo = $null + + # Validate the module + if(-not $IsSavePackage) + { + $CurrentModuleInfo = Test-ValidManifestModule -ModuleBasePath $sourceModulePath ` + -InstallLocation $InstallLocation ` + -AllowClobber:$AllowClobber ` + -SkipPublisherCheck:$SkipPublisherCheck ` + -IsUpdateOperation:$installUpdate + + if(-not $CurrentModuleInfo) + { + # This Install-Package provider API gets called once per an item/package/SoftwareIdentity. + # Return if there is an error instead of continuing further to install the dependencies or current module. + # + return + } + } + + # Test if module is already installed + $InstalledModuleInfo2 = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $pkg.Name -RequiredVersion $pkg.Version } + + if($pkg.Name -ne $packageName) + { + if(-not $Force -and $InstalledModuleInfo2) + { + if(Test-ModuleSxSVersionSupport) + { + if($pkg.version -eq $InstalledModuleInfo2.Version) + { + if(-not $installUpdate) + { + $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase, $InstalledModuleInfo2.Version) + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) + } + + Write-Verbose $message + Continue + } + } + else + { + if(-not $installUpdate) + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase) + Write-Verbose $message + Continue + } + else + { + if($pkg.version -gt $InstalledModuleInfo2.Version) + { + $message = $LocalizedData.FoundModuleUpdate -f ($pkg.Name, $pkg.Version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) + Write-Verbose $message + Continue + } + } + } + } + + if($IsSavePackage) + { + $DependencyInstallMessage = $LocalizedData.SavingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName) + } + else + { + $DependencyInstallMessage = $LocalizedData.InstallingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName) + } + + Write-Verbose $DependencyInstallMessage + } + + # check if module is in use + if($InstalledModuleInfo2) + { + $moduleInUse = Test-ModuleInUse -ModuleBasePath $InstalledModuleInfo2.ModuleBase ` + -ModuleName $InstalledModuleInfo2.Name ` + -ModuleVersion $InstalledModuleInfo2.Version ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + + if($moduleInUse) + { + $message = $LocalizedData.ModuleIsInUse -f ($psgItemInfo.Name) + Write-Verbose $message + continue + } + } + + Copy-Module -SourcePath $sourceModulePath -DestinationPath $destinationModulePath -PSGetItemInfo $psgItemInfo + + if(-not $IsSavePackage) + { + # Write warning messages if externally managed module dependencies are not installed. + $ExternalModuleDependencies = Get-ExternalModuleDependencies -PSModuleInfo $CurrentModuleInfo + foreach($ExternalDependency in $ExternalModuleDependencies) + { + $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency + + if(-not $depModuleInfo) + { + Write-Warning -Message ($LocalizedData.MissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) + } + } + } + + if($IsSavePackage) + { + $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name, $installLocation) + } + else + { + $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation) + } + Write-Verbose $message + } + + + if($packageType -eq $script:PSArtifactTypeScript) + { + if ($psgItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $sourceScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $tempPackagePath -ChildPath "$($pkg.Name).ps1" + + $currentScriptInfo = $null + if(-not $IsSavePackage) + { + # Validate the script + $currentScriptInfo = Test-ScriptFileInfo -Path $sourceScriptPath -ErrorAction SilentlyContinue + + if(-not $currentScriptInfo) + { + $message = $LocalizedData.InvalidPowerShellScriptFile -f ($pkg.Name) + Write-Error -Message $message -ErrorId "InvalidPowerShellScriptFile" -Category InvalidOperation -TargetObject $pkg.Name + continue + } + } + + # Test if script is already installed + $InstalledScriptInfo2 = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $pkg.Name } + + if($pkg.Name -ne $packageName) + { + if(-not $Force -and $InstalledScriptInfo2) + { + if(-not $installUpdate) + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo2.Version, $InstalledScriptInfo2.Name, $InstalledScriptInfo2.ScriptBase) + Write-Verbose $message + Continue + } + else + { + if($pkg.version -gt $InstalledScriptInfo2.Version) + { + $message = $LocalizedData.FoundScriptUpdate -f ($pkg.Name, $pkg.Version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoScriptUpdateAvailable -f ($pkg.Name) + Write-Verbose $message + Continue + } + } + } + + if($IsSavePackage) + { + $DependencyInstallMessage = $LocalizedData.SavingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName) + } + else + { + $DependencyInstallMessage = $LocalizedData.InstallingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName) + } + + Write-Verbose $DependencyInstallMessage + } + + Write-Debug "SourceScriptPath is $sourceScriptPath and DestinationscriptPath is $destinationscriptPath" + Copy-ScriptFile -SourcePath $sourceScriptPath -DestinationPath $destinationscriptPath -PSGetItemInfo $psgItemInfo -Scope $Scope + + if(-not $IsSavePackage) + { + # Write warning messages if externally managed module dependencies are not installed. + foreach($ExternalDependency in $currentScriptInfo.ExternalModuleDependencies) + { + $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency + + if(-not $depModuleInfo) + { + Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) + } + } + + # Write warning messages if externally managed script dependencies are not installed. + foreach($ExternalDependency in $currentScriptInfo.ExternalScriptDependencies) + { + $depScriptInfo = Test-ScriptInstalled -Name $ExternalDependency + + if(-not $depScriptInfo) + { + Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedScriptDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ScriptExternallyManagedScriptDependencyIsInstalled -f $ExternalDependency) + } + } + } + + # Remove the old scriptfile if it's path different from the required destination script path when -Force is specified + if($Force -and + $InstalledScriptInfo2 -and + -not $destinationscriptPath.StartsWith($InstalledScriptInfo2.ScriptBase, [System.StringComparison]::OrdinalIgnoreCase)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $InstalledScriptInfo2.Path ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + if($IsSavePackage) + { + $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name, $installLocation) + } + else + { + $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation) + } + Write-Verbose $message + } + + Write-Output -InputObject $sid + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempDestination -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Uninstall-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $fastPackageReference + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package')) + + Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) + + # take the fastPackageReference and get the package object again. + $parts = $fastPackageReference -Split '[|]' + $Force = $false + + $options = $request.Options + if($options) + { + foreach( $o in $options.Keys ) + { + Write-Debug -Message ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) + } + } + + if($parts.Length -eq 5) + { + $providerName = $parts[0] + $packageName = $parts[1] + $version = $parts[2] + $sourceLocation= $parts[3] + $artfactType = $parts[4] + + if($request.IsCanceled) + { + return + } + + if($options.ContainsKey('Force')) + { + $Force = $options['Force'] + + if($Force.GetType().ToString() -eq 'System.String') + { + if($Force -eq 'false') + { + $Force = $false + } + elseif($Force -eq 'true') + { + $Force = $true + } + } + } + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $moduleName = $packageName + $InstalledModuleInfo = $script:PSGetInstalledModules["$($moduleName)$($version)"] + + if(-not $InstalledModuleInfo) + { + $message = $LocalizedData.ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $moduleName + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + + $moduleBase = $InstalledModuleInfo.PSGetItemInfo.InstalledLocation + + if(-not (Test-RunningAsElevated) -and $moduleBase.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForUninstall -f ($moduleName, $moduleBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "AdminPrivilegesRequiredForUninstall" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $dependentModuleScript = { + param ([string] $moduleName) + Microsoft.PowerShell.Core\Get-Module -ListAvailable | + Microsoft.PowerShell.Core\Where-Object { + ($moduleName -ne $_.Name) -and ( + ($_.RequiredModules -and $_.RequiredModules.Name -contains $moduleName) -or + ($_.NestedModules -and $_.NestedModules.Name -contains $moduleName)) + } + } + $dependentModulesJob = Microsoft.PowerShell.Core\Start-Job -ScriptBlock $dependentModuleScript -ArgumentList $moduleName + Microsoft.PowerShell.Core\Wait-Job -job $dependentModulesJob + $dependentModules = Microsoft.PowerShell.Core\Receive-Job -job $dependentModulesJob + + if(-not $Force -and $dependentModules) + { + $message = $LocalizedData.UnableToUninstallAsOtherModulesNeedThisModule -f ($moduleName, $version, $moduleBase, $(($dependentModules.Name | Select-Object -Unique) -join ','), $moduleName) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToUninstallAsOtherModulesNeedThisModule" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $moduleInUse = Test-ModuleInUse -ModuleBasePath $moduleBase ` + -ModuleName $InstalledModuleInfo.PSGetItemInfo.Name` + -ModuleVersion $InstalledModuleInfo.PSGetItemInfo.Version ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + + if($moduleInUse) + { + $message = $LocalizedData.ModuleIsInUse -f ($moduleName) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleIsInUse" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $ModuleBaseFolderToBeRemoved = $moduleBase + + # With SxS version support, more than one version of the module can be installed. + # - Remove the parent directory of the module version base when only one version is installed + # - Don't remove the modulebase when it was installed before SxS version support and + # other versions are installed under the module base folder + # + if(Test-ModuleSxSVersionSupport) + { + $ModuleBaseWithoutVersion = $moduleBase + $IsModuleInstalledAsSxSVersion = $false + + if($moduleBase.EndsWith("$version", [System.StringComparison]::OrdinalIgnoreCase)) + { + $IsModuleInstalledAsSxSVersion = $true + $ModuleBaseWithoutVersion = Microsoft.PowerShell.Management\Split-Path -Path $moduleBase -Parent + } + + $InstalledVersionsWithSameModuleBase = @() + Get-Module -Name $moduleName -ListAvailable | + Microsoft.PowerShell.Core\ForEach-Object { + if($_.ModuleBase.StartsWith($ModuleBaseWithoutVersion, [System.StringComparison]::OrdinalIgnoreCase)) + { + $InstalledVersionsWithSameModuleBase += $_.ModuleBase + } + } + + # Remove ..\ModuleName directory when only one module is installed with the same ..\ModuleName path + # like ..\ModuleName\1.0 or ..\ModuleName + if($InstalledVersionsWithSameModuleBase.Count -eq 1) + { + $ModuleBaseFolderToBeRemoved = $ModuleBaseWithoutVersion + } + elseif($ModuleBaseWithoutVersion -eq $moduleBase) + { + # There are version specific folders under the same module base dir + # Throw an error saying uninstall other versions then uninstall this current version + $message = $LocalizedData.UnableToUninstallModuleVersion -f ($moduleName, $version, $moduleBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToUninstallModuleVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + # Otherwise specified version folder will be removed as current module base is assigned to $ModuleBaseFolderToBeRemoved + } + + Microsoft.PowerShell.Management\Remove-Item -Path $ModuleBaseFolderToBeRemoved ` + -Force -Recurse ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + + $message = $LocalizedData.ModuleUninstallationSucceeded -f $moduleName, $moduleBase + Write-Verbose $message + + Write-Output -InputObject $InstalledModuleInfo.SoftwareIdentity + } + elseif($artfactType -eq $script:PSArtifactTypeScript) + { + $scriptName = $packageName + $InstalledScriptInfo = $script:PSGetInstalledScripts["$($scriptName)$($version)"] + + if(-not $InstalledScriptInfo) + { + $message = $LocalizedData.ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $scriptName + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + + $scriptBase = $InstalledScriptInfo.PSGetItemInfo.InstalledLocation + $installedScriptInfoPath = $script:MyDocumentsInstalledScriptInfosPath + + if($scriptBase.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-RunningAsElevated)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForScriptUninstall -f ($scriptName, $scriptBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "AdminPrivilegesRequiredForUninstall" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $installedScriptInfoPath = $script:ProgramFilesInstalledScriptInfosPath + } + + # Check if there are any dependent scripts + $dependentScriptDetails = $script:PSGetInstalledScripts.Values | + Microsoft.PowerShell.Core\Where-Object { + $_.PSGetItemInfo.Dependencies -contains $scriptName + } + + $dependentScriptNames = $dependentScriptDetails | + Microsoft.PowerShell.Core\ForEach-Object { $_.PSGetItemInfo.Name } + + if(-not $Force -and $dependentScriptNames) + { + $message = $LocalizedData.UnableToUninstallAsOtherScriptsNeedThisScript -f + ($scriptName, + $version, + $scriptBase, + $(($dependentScriptNames | Select-Object -Unique) -join ','), + $scriptName) + + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'UnableToUninstallAsOtherScriptsNeedThisScript' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + return + } + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $scriptBase ` + -ChildPath "$($scriptName).ps1" + + $installledScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $installedScriptInfoPath ` + -ChildPath "$($scriptName)_$($script:InstalledScriptInfoFileName)" + + # Remove the script file and it's corresponding InstalledScriptInfo.xml + if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) + { + Microsoft.PowerShell.Management\Remove-Item -Path $scriptFilePath ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + if(Microsoft.PowerShell.Management\Test-Path -Path $installledScriptInfoFilePath -PathType Leaf) + { + Microsoft.PowerShell.Management\Remove-Item -Path $installledScriptInfoFilePath ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + $message = $LocalizedData.ScriptUninstallationSucceeded -f $scriptName, $scriptBase + Write-Verbose $message + + Write-Output -InputObject $InstalledScriptInfo.SoftwareIdentity + } + } +} + +function Get-InstalledPackage +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage')) + + $options = $request.Options + + foreach( $o in $options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) + } + + $artifactTypes = $script:PSArtifactTypeModule + if($options.ContainsKey($script:PSArtifactType)) + { + $artifactTypes = $options[$script:PSArtifactType] + } + + if($artifactTypes -eq $script:All) + { + $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) + } + + if($artifactTypes -contains $script:PSArtifactTypeModule) + { + Get-InstalledModuleDetails -Name $Name ` + -RequiredVersion $RequiredVersion ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} + } + + if($artifactTypes -contains $script:PSArtifactTypeScript) + { + Get-InstalledScriptDetails -Name $Name ` + -RequiredVersion $RequiredVersion ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} + } +} + +#endregion + +#region Internal Utility functions for the PackageManagement Provider Implementation + +function Set-InstalledScriptsVariable +{ + # Initialize list of scripts installed by the PowerShellGet provider + $script:PSGetInstalledScripts = [ordered]@{} + $scriptPaths = @($script:ProgramFilesInstalledScriptInfosPath, $script:MyDocumentsInstalledScriptInfosPath) + + foreach ($location in $scriptPaths) + { + # find all scripts installed using PowerShellGet + $scriptInfoFiles = Get-ChildItem -Path $location ` + -Filter "*$script:InstalledScriptInfoFileName" ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if($scriptInfoFiles) + { + foreach ($scriptInfoFile in $scriptInfoFiles) + { + $psgetItemInfo = DeSerialize-PSObject -Path $scriptInfoFile.FullName + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` + -ChildPath "$($psgetItemInfo.Name).ps1" + + # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $scriptInfoFile.FullName -Force -ErrorAction SilentlyContinue + + continue + } + + $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo + + if($package) + { + $script:PSGetInstalledScripts["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ + SoftwareIdentity = $package + PSGetItemInfo = $psgetItemInfo + } + } + } + } + } +} + +function Get-InstalledScriptDetails +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Set-InstalledScriptsVariable + + # Keys in $script:PSGetInstalledScripts are "", + # first filter the installed scripts using "$Name*" wildcard search + # then apply $Name wildcard search to get the script name which meets the specified name with wildcards. + # + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions + $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + + $script:PSGetInstalledScripts.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.Key)) + { + $InstalledScriptDetails = $_.Value + + if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledScriptDetails.PSGetItemInfo.Name)) + { + if($RequiredVersion) + { + if($RequiredVersion -eq $InstalledScriptDetails.PSGetItemInfo.Version) + { + $InstalledScriptDetails + } + } + else + { + if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledScriptDetails.PSGetItemInfo.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledScriptDetails.PSGetItemInfo.Version))) + { + $InstalledScriptDetails + } + } + } + } + } +} + +function Get-InstalledModuleDetails +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Set-InstalledModulesVariable + + # Keys in $script:PSGetInstalledModules are "", + # first filter the installed modules using "$Name*" wildcard search + # then apply $Name wildcard search to get the module name which meets the specified name with wildcards. + # + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions + $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + + $script:PSGetInstalledModules.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.Key)) + { + $InstalledModuleDetails = $_.Value + + if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledModuleDetails.PSGetItemInfo.Name)) + { + if($RequiredVersion) + { + if($RequiredVersion -eq $InstalledModuleDetails.PSGetItemInfo.Version) + { + $InstalledModuleDetails + } + } + else + { + if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledModuleDetails.PSGetItemInfo.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledModuleDetails.PSGetItemInfo.Version))) + { + $InstalledModuleDetails + } + } + } + } + } +} + +function New-SoftwareIdentityFromPackage +{ + param + ( + [Parameter(Mandatory=$true)] + $Package, + + [Parameter(Mandatory=$true)] + [string] + $PackageManagementProviderName, + + [Parameter(Mandatory=$true)] + [string] + $SourceLocation, + + [Parameter()] + [switch] + $IsFromTrustedSource, + + [Parameter(Mandatory=$true)] + $request, + + [Parameter(Mandatory=$true)] + [string] + $Type, + + [Parameter()] + [string] + $InstalledLocation, + + [Parameter()] + [System.DateTime] + $InstalledDate, + + [Parameter()] + [System.DateTime] + $UpdatedDate + ) + + $fastPackageReference = New-FastPackageReference -ProviderName $PackageManagementProviderName ` + -PackageName $Package.Name ` + -Version $Package.Version ` + -Source $SourceLocation ` + -ArtifactType $Type + + $links = New-Object -TypeName System.Collections.ArrayList + foreach($lnk in $Package.Links) + { + if( $lnk.Relationship -eq "icon" -or $lnk.Relationship -eq "license" -or $lnk.Relationship -eq "project" ) + { + $links.Add( (New-Link -Href $lnk.HRef -RelationShip $lnk.Relationship ) ) + } + } + + $entities = New-Object -TypeName System.Collections.ArrayList + foreach( $entity in $Package.Entities ) + { + if( $entity.Role -eq "author" -or $entity.Role -eq "owner" ) + { + $entities.Add( (New-Entity -Name $entity.Name -Role $entity.Role -RegId $entity.RegId -Thumbprint $entity.Thumbprint) ) + } + } + + $deps = (new-Object -TypeName System.Collections.ArrayList) + foreach( $dep in $pkg.Dependencies ) + { + # Add each dependency and say it's from this provider. + $newDep = New-Dependency -ProviderName $script:PSModuleProviderName ` + -PackageName $request.Services.ParsePackageName($dep) ` + -Version $request.Services.ParsePackageVersion($dep) ` + -Source $SourceLocation + + $deps.Add( $newDep ) + } + + + $details = New-Object -TypeName System.Collections.Hashtable + + foreach ( $key in $Package.Metadata.Keys.LocalName) + { + if (!$details.ContainsKey($key)) + { + $details.Add($key, (Get-First $Package.Metadata[$key]) ) + } + } + + $details.Add( "PackageManagementProvider" , $PackageManagementProviderName ) + + if($InstalledLocation) + { + $details.Add( $script:InstalledLocation , $InstalledLocation ) + } + + if($InstalledDate) + { + $details.Add( 'installeddate' , $InstalledDate.ToString() ) + } + + if($UpdatedDate) + { + $details.Add( 'updateddate' , $UpdatedDate.ToString() ) + } + + # Initialize package source name to the source location + $sourceNameForSoftwareIdentity = $SourceLocation + + $sourceName = (Get-SourceName -Location $SourceLocation) + + if($sourceName) + { + $details.Add( "SourceName" , $sourceName ) + + # Override the source name only if we are able to map source location to source name + $sourceNameForSoftwareIdentity = $sourceName + } + + $params = @{FastPackageReference = $fastPackageReference; + Name = $Package.Name; + Version = $Package.Version; + versionScheme = "MultiPartNumeric"; + Source = $sourceNameForSoftwareIdentity; + Summary = $Package.Summary; + SearchKey = $Package.Name; + FullPath = $Package.FullPath; + FileName = $Package.Name; + Details = $details; + Entities = $entities; + Links = $links; + Dependencies = $deps; + } + + if($IsFromTrustedSource) + { + $params["FromTrustedSource"] = $true + } + + $sid = New-SoftwareIdentity @params + + return $sid +} + +function New-PackageSourceFromModuleSource +{ + param + ( + [Parameter(Mandatory=$true)] + $ModuleSource + ) + + $ScriptSourceLocation = $null + if(Get-Member -InputObject $ModuleSource -Name $script:ScriptSourceLocation) + { + $ScriptSourceLocation = $ModuleSource.ScriptSourceLocation + } + + $ScriptPublishLocation = $ModuleSource.PublishLocation + if(Get-Member -InputObject $ModuleSource -Name $script:ScriptPublishLocation) + { + $ScriptPublishLocation = $ModuleSource.ScriptPublishLocation + } + + $packageSourceDetails = @{} + $packageSourceDetails["InstallationPolicy"] = $ModuleSource.InstallationPolicy + $packageSourceDetails["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $ModuleSource) + $packageSourceDetails[$script:PublishLocation] = $ModuleSource.PublishLocation + $packageSourceDetails[$script:ScriptSourceLocation] = $ScriptSourceLocation + $packageSourceDetails[$script:ScriptPublishLocation] = $ScriptPublishLocation + + $ModuleSource.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + $packageSourceDetails[$_.Key] = $_.Value + } + + # create a new package source + $src = New-PackageSource -Name $ModuleSource.Name ` + -Location $ModuleSource.SourceLocation ` + -Trusted $ModuleSource.Trusted ` + -Registered $ModuleSource.Registered ` + -Details $packageSourceDetails + + Write-Verbose ( $LocalizedData.RepositoryDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) ) + + # return the package source object. + Write-Output -InputObject $src +} + +function New-ModuleSourceFromPackageSource +{ + param + ( + [Parameter(Mandatory=$true)] + $PackageSource + ) + + $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $PackageSource.Name + SourceLocation = $PackageSource.Location + Trusted=$PackageSource.IsTrusted + Registered=$PackageSource.IsRegistered + InstallationPolicy = $PackageSource.Details['InstallationPolicy'] + PackageManagementProvider=$PackageSource.Details['PackageManagementProvider'] + PublishLocation=$PackageSource.Details[$script:PublishLocation] + ScriptSourceLocation=$PackageSource.Details[$script:ScriptSourceLocation] + ScriptPublishLocation=$PackageSource.Details[$script:ScriptPublishLocation] + ProviderOptions = @{} + }) + + $PackageSource.Details.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($_.Key -ne 'PackageManagementProvider' -and + $_.Key -ne $script:PublishLocation -and + $_.Key -ne $script:ScriptPublishLocation -and + $_.Key -ne $script:ScriptSourceLocation -and + $_.Key -ne 'InstallationPolicy') + { + $moduleSource.ProviderOptions[$_.Key] = $_.Value + } + } + + $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + + # return the module source object. + Write-Output -InputObject $moduleSource +} + +function New-FastPackageReference +{ + param + ( + [Parameter(Mandatory=$true)] + [string] + $ProviderName, + + [Parameter(Mandatory=$true)] + [string] + $PackageName, + + [Parameter(Mandatory=$true)] + [string] + $Version, + + [Parameter(Mandatory=$true)] + [string] + $Source, + + [Parameter(Mandatory=$true)] + [string] + $ArtifactType + ) + + return "$ProviderName|$PackageName|$Version|$Source|$ArtifactType" +} + +function Get-First +{ + param + ( + [Parameter(Mandatory=$true)] + $IEnumerator + ) + + foreach($item in $IEnumerator) + { + return $item + } + + return $null +} + +function Set-InstalledModulesVariable +{ + # Initialize list of modules installed by the PowerShellGet provider + $script:PSGetInstalledModules = [ordered]@{} + + $modulePaths = @($script:ProgramFilesModulesPath, $script:MyDocumentsModulesPath) + + foreach ($location in $modulePaths) + { + # find all modules installed using PowerShellGet + $moduleBases = Get-ChildItem $location -Recurse ` + -Attributes Hidden -Filter $script:PSGetItemInfoFileName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + | Foreach-Object { $_.Directory } + + + foreach ($moduleBase in $moduleBases) + { + $PSGetItemInfoPath = Microsoft.PowerShell.Management\Join-Path $moduleBase.FullName $script:PSGetItemInfoFileName + + # Check if this module got installed using PSGet, read its contents to create a SoftwareIdentity object + if (Microsoft.PowerShell.Management\Test-Path $PSGetItemInfoPath) + { + $psgetItemInfo = DeSerialize-PSObject -Path $PSGetItemInfoPath + + # Add InstalledLocation if this module was installed with older version of PowerShellGet + if(-not (Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation)) + { + Microsoft.PowerShell.Utility\Add-Member -InputObject $psgetItemInfo ` + -MemberType NoteProperty ` + -Name $script:InstalledLocation ` + -Value $moduleBase.FullName + } + + $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo + + if($package) + { + $script:PSGetInstalledModules["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ + SoftwareIdentity = $package + PSGetItemInfo = $psgetItemInfo + } + } + } + } + } +} + +function New-SoftwareIdentityFromPSGetItemInfo +{ + param + ( + [Parameter(Mandatory=$true)] + $PSGetItemInfo + ) + + $SourceLocation = $psgetItemInfo.RepositorySourceLocation + + if(Get-Member -InputObject $PSGetItemInfo -Name $script:PSArtifactType) + { + $artifactType = $psgetItemInfo.Type + } + else + { + $artifactType = $script:PSArtifactTypeModule + } + + $fastPackageReference = New-FastPackageReference -ProviderName (Get-ProviderName -PSCustomObject $psgetItemInfo) ` + -PackageName $psgetItemInfo.Name ` + -Version $psgetItemInfo.Version ` + -Source $SourceLocation ` + -ArtifactType $artifactType + + $links = New-Object -TypeName System.Collections.ArrayList + if($psgetItemInfo.IconUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.IconUri -RelationShip "icon") ) + } + + if($psgetItemInfo.LicenseUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.LicenseUri -RelationShip "license") ) + } + + if($psgetItemInfo.ProjectUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.ProjectUri -RelationShip "project") ) + } + + $entities = New-Object -TypeName System.Collections.ArrayList + if($psgetItemInfo.Author -and $psgetItemInfo.Author.ToString()) + { + $entities.Add( (New-Entity -Name $psgetItemInfo.Author -Role 'author') ) + } + + if($psgetItemInfo.CompanyName -and $psgetItemInfo.CompanyName.ToString()) + { + $entities.Add( (New-Entity -Name $psgetItemInfo.CompanyName -Role 'owner') ) + } + + $details = @{ + description = $psgetItemInfo.Description + copyright = $psgetItemInfo.Copyright + published = $psgetItemInfo.PublishedDate.ToString() + installeddate = $null + updateddate = $null + tags = $psgetItemInfo.Tags + releaseNotes = $psgetItemInfo.ReleaseNotes + PackageManagementProvider = (Get-ProviderName -PSCustomObject $psgetItemInfo) + } + + if((Get-Member -InputObject $psgetItemInfo -Name 'InstalledDate') -and $psgetItemInfo.InstalledDate) + { + $details['installeddate'] = $psgetItemInfo.InstalledDate.ToString() + } + + if((Get-Member -InputObject $psgetItemInfo -Name 'UpdatedDate') -and $psgetItemInfo.UpdatedDate) + { + $details['updateddate'] = $psgetItemInfo.UpdatedDate.ToString() + } + + if(Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation) + { + $details[$script:InstalledLocation] = $psgetItemInfo.InstalledLocation + } + + $details[$script:PSArtifactType] = $artifactType + + $sourceName = Get-SourceName -Location $SourceLocation + if($sourceName) + { + $details["SourceName"] = $sourceName + } + + $params = @{ + FastPackageReference = $fastPackageReference; + Name = $psgetItemInfo.Name; + Version = $psgetItemInfo.Version; + versionScheme = "MultiPartNumeric"; + Source = $SourceLocation; + Summary = $psgetItemInfo.Description; + Details = $details; + Entities = $entities; + Links = $links + } + + if($sourceName -and $script:PSGetModuleSources[$sourceName].Trusted) + { + $params["FromTrustedSource"] = $true + } + + $sid = New-SoftwareIdentity @params + + return $sid +} + +#endregion + +#region Common functions + +function Get-EnvironmentVariable +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [parameter(Mandatory = $true)] + [int] + $Target + ) + + if ($Target -eq $script:EnvironmentVariableTarget.Process) + { + return [System.Environment]::GetEnvironmentVariable($Name) + } + elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) + { + $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:SystemEnvironmentKey -Name $Name -ErrorAction SilentlyContinue + + if($itemPropertyValue) + { + return $itemPropertyValue.$Name + } + } + elseif ($Target -eq $script:EnvironmentVariableTarget.User) + { + $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:UserEnvironmentKey -Name $Name -ErrorAction SilentlyContinue + + if($itemPropertyValue) + { + return $itemPropertyValue.$Name + } + } +} + +function Set-EnvironmentVariable +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [parameter()] + [String] + $Value, + + [parameter(Mandatory = $true)] + [int] + $Target + ) + + if ($Target -eq $script:EnvironmentVariableTarget.Process) + { + [System.Environment]::SetEnvironmentVariable($Name, $Value) + + return + } + elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) + { + if ($Name.Length -ge $script:SystemEnvironmentVariableMaximumLength) + { + $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:SystemEnvironmentVariableMaximumLength) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidEnvironmentVariableName' ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + return + } + + $Path = $script:SystemEnvironmentKey + } + elseif ($Target -eq $script:EnvironmentVariableTarget.User) + { + if ($Name.Length -ge $script:UserEnvironmentVariableMaximumLength) + { + $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:UserEnvironmentVariableMaximumLength) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidEnvironmentVariableName' ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + return + } + + $Path = $script:UserEnvironmentKey + } + + if (!$Value) + { + Microsoft.PowerShell.Management\Remove-ItemProperty $Path -Name $Name -ErrorAction SilentlyContinue + } + else + { + Microsoft.PowerShell.Management\Set-ItemProperty $Path -Name $Name -Value $Value + } +} + +function DeSerialize-PSObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + $Path + ) + $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path + [System.Management.Automation.PSSerializer]::Deserialize($filecontent) +} + +function Log-ArtifactNotFoundInPSGallery +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [string[]] + $SearchedName, + + [Parameter()] + [string[]] + $FoundName, + + [Parameter(Mandatory=$true)] + [string] + $operationName + ) + + if (-not $script:TelemetryEnabled) + { + return + } + + if(-not $SearchedName) + { + return + } + + $SearchedNameNoWildCards = @() + + # Ignore wild cards + foreach ($artifactName in $SearchedName) + { + if (-not (Test-WildcardPattern $artifactName)) + { + $SearchedNameNoWildCards += $artifactName + } + } + + # Find artifacts searched, but not found in the specified gallery + $notFoundArtifacts = @() + foreach ($element in $SearchedNameNoWildCards) + { + if (-not ($FoundName -contains $element)) + { + $notFoundArtifacts += $element + } + } + + # Perform Telemetry only if searched artifacts are not available in specified Gallery + if ($notFoundArtifacts) + { + [Microsoft.PowerShell.Get.Telemetry]::TraceMessageArtifactsNotFound($notFoundArtifacts, $operationName) + } +} + +# Function to record non-PSGallery registration for telemetry +# Function consumes the type of registration (i.e hosted (http(s)), non-hosted (file/unc)), locations, installation policy, provider and event name +function Log-NonPSGalleryRegistration +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [string] + $sourceLocation, + + [Parameter()] + [string] + $installationPolicy, + + [Parameter()] + [string] + $packageManagementProvider, + + [Parameter()] + [string] + $publishLocation, + + [Parameter()] + [string] + $scriptSourceLocation, + + [Parameter()] + [string] + $scriptPublishLocation, + + [Parameter(Mandatory=$true)] + [string] + $operationName + ) + + if (-not $script:TelemetryEnabled) + { + return + } + + # Initialize source location type - this can be hosted (http(s)) or not hosted (unc/file) + $sourceLocationType = "NON_WEB_HOSTED" + if (Test-WebUri -uri $sourceLocation) + { + $sourceLocationType = "WEB_HOSTED" + } + + # Create a hash of the source location + # We cannot log the actual source location, since this might contain PII (Personally identifiable information) data + $sourceLocationHash = Get-Hash -locationString $sourceLocation + $publishLocationHash = Get-Hash -locationString $publishLocation + $scriptSourceLocationHash = Get-Hash -locationString $scriptSourceLocation + $scriptPublishLocationHash = Get-Hash -locationString $scriptPublishLocation + + # Log the telemetry event + [Microsoft.PowerShell.Get.Telemetry]::TraceMessageNonPSGalleryRegistration($sourceLocationType, $sourceLocationHash, $installationPolicy, $packageManagementProvider, $publishLocationHash, $scriptSourceLocationHash, $scriptPublishLocationHash, $operationName) +} + +# Returns a SHA1 hash of the specified string +function Get-Hash +{ + [CmdletBinding()] + Param + ( + [string] + $locationString + ) + + if(-not $locationString) + { + return "" + } + + $sha1Object = New-Object System.Security.Cryptography.SHA1Managed + $stringHash = $sha1Object.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($locationString)); + $stringHashInHex = [System.BitConverter]::ToString($stringHash) + + if ($stringHashInHex) + { + # Remove all dashes in the hex string + return $stringHashInHex.Replace('-', '') + } + + return "" +} + +function Get-ValidModuleLocation +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $LocationString, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ParameterName, + + [Parameter()] + $Credential, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential + ) + + # Get the actual Uri from the Location + if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString)) + { + # Append '/api/v2/' to the $LocationString, return if that URI works. + if(($LocationString -notmatch 'LinkID') -and + -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + ) + { + $tempLocation = $null + + if($LocationString.EndsWith('/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempLocation = $LocationString + 'api/v2/' + } + else + { + $tempLocation = $LocationString + '/api/v2/' + } + + if($tempLocation) + { + # Ping and resolve the specified location + $tempLocation = Resolve-Location -Location $tempLocation ` + -LocationParameterName $ParameterName ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($tempLocation) + { + return $tempLocation + } + # No error if we can't resolve the URL appended with '/api/v2/' + } + } + + # Ping and resolve the specified location + $LocationString = Resolve-Location -Location $LocationString ` + -LocationParameterName $ParameterName ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -CallerPSCmdlet $PSCmdlet + } + + return $LocationString +} + +function Save-ModuleSources +{ + if($script:PSGetModuleSources) + { + if(-not (Microsoft.PowerShell.Management\Test-Path $script:PSGetAppLocalPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` + -ItemType Directory -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetModuleSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetModuleSources)) + } +} + +function Test-ModuleSxSVersionSupport +{ + # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only + # By default, PowerShell module versions will be installed/updated Side-by-Side. + $PSVersionTable.PSVersion -ge [Version]"5.0" +} + +function Test-ModuleInstalled +{ + [CmdletBinding(PositionalBinding=$false)] + [OutputType("PSModuleInfo")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion + ) + + # Check if module is already installed + $availableModule = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | + Microsoft.PowerShell.Core\Where-Object {-not (Test-ModuleSxSVersionSupport) -or -not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} | + Microsoft.PowerShell.Utility\Select-Object -Unique + + return $availableModule +} + +function Test-ScriptInstalled +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion + ) + + $scriptInfo = $null + $scriptFileName = "$Name.ps1" + $scriptPaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $scriptInfos = @() + + foreach ($location in $scriptPaths) + { + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $location -ChildPath $scriptFileName + + if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) + { + $scriptInfo = $null + try + { + $scriptInfo = Test-ScriptFileInfo -Path $scriptFilePath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + catch + { + # Ignore any terminating error from the Test-ScriptFileInfo cmdlet, + # if it does not contain valid Script metadata + Write-Verbose -Message "$_" + } + + if($scriptInfo) + { + $scriptInfos += $scriptInfo + } + else + { + # Since the script file doesn't contain the valid script metadata, + # create dummy PSScriptInfo object with 0.0 version + $scriptInfo = New-PSScriptInfoObject -Path $scriptFilePath + $scriptInfo.$script:Version = [Version]'0.0' + + $scriptInfos += $scriptInfo + } + } + } + + $scriptInfo = $scriptInfos | Microsoft.PowerShell.Core\Where-Object { + (-not $RequiredVersion) -or ($RequiredVersion -eq $_.Version) + } | Microsoft.PowerShell.Utility\Select-Object -First 1 + + return $scriptInfo +} + +function New-PSScriptInfoObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Path + ) + + $PSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{}) + $script:PSScriptInfoProperties | Microsoft.PowerShell.Core\ForEach-Object { + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` + -MemberType NoteProperty ` + -Name $_ ` + -Value $null + } + + $PSScriptInfo.$script:Name = [System.IO.Path]::GetFileNameWithoutExtension($Path) + $PSScriptInfo.$script:Path = $Path + $PSScriptInfo.$script:ScriptBase = (Microsoft.PowerShell.Management\Split-Path -Path $Path -Parent) + + return $PSScriptInfo +} + +function Get-OrderedPSScriptInfoObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSScriptInfo + ) + + $NewPSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + $script:Name = $PSScriptInfo.$script:Name + $script:Version = $PSScriptInfo.$script:Version + $script:Guid = $PSScriptInfo.$script:Guid + $script:Path = $PSScriptInfo.$script:Path + $script:ScriptBase = $PSScriptInfo.$script:ScriptBase + $script:Description = $PSScriptInfo.$script:Description + $script:Author = $PSScriptInfo.$script:Author + $script:CompanyName = $PSScriptInfo.$script:CompanyName + $script:Copyright = $PSScriptInfo.$script:Copyright + $script:Tags = $PSScriptInfo.$script:Tags + $script:ReleaseNotes = $PSScriptInfo.$script:ReleaseNotes + $script:RequiredModules = $PSScriptInfo.$script:RequiredModules + $script:ExternalModuleDependencies = $PSScriptInfo.$script:ExternalModuleDependencies + $script:RequiredScripts = $PSScriptInfo.$script:RequiredScripts + $script:ExternalScriptDependencies = $PSScriptInfo.$script:ExternalScriptDependencies + $script:LicenseUri = $PSScriptInfo.$script:LicenseUri + $script:ProjectUri = $PSScriptInfo.$script:ProjectUri + $script:IconUri = $PSScriptInfo.$script:IconUri + $script:DefinedCommands = $PSScriptInfo.$script:DefinedCommands + $script:DefinedFunctions = $PSScriptInfo.$script:DefinedFunctions + $script:DefinedWorkflows = $PSScriptInfo.$script:DefinedWorkflows + }) + + $NewPSScriptInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSScriptInfo") + + return $NewPSScriptInfo +} + +function Get-AvailableScriptFilePath +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [string] + $Name + ) + + $scriptInfo = $null + $scriptFileName = '*.ps1' + $scriptBasePaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $scriptFilePaths = @() + $wildcardPattern = $null + + if($Name) + { + if(Test-WildcardPattern -Name $Name) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + } + else + { + $scriptFileName = "$Name.ps1" + } + + } + + foreach ($location in $scriptBasePaths) + { + $scriptFiles = Get-ChildItem -Path $location ` + -Filter $scriptFileName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if($wildcardPattern) + { + $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.BaseName)) + { + $scriptFilePaths += $_.FullName + } + } + } + else + { + $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { $scriptFilePaths += $_.FullName } + } + } + + return $scriptFilePaths +} + +function Get-InstalledScriptFilePath +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [string] + $Name + ) + + $installedScriptFilePaths = @() + $scriptFilePaths = Get-AvailableScriptFilePath @PSBoundParameters + + foreach ($scriptFilePath in $scriptFilePaths) + { + $scriptInfo = Test-ScriptInstalled -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) + + if($scriptInfo) + { + $installedScriptInfoFilePath = $null + $installedScriptInfoFileName = "$($scriptInfo.Name)_$script:InstalledScriptInfoFileName" + + if($scriptInfo.Path.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + elseif($scriptInfo.Path.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + + if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) + { + $installedScriptFilePaths += $scriptInfo.Path + } + } + } + + return $installedScriptFilePaths +} + + +function Update-ModuleManifest +{ +<# +.ExternalHelp PSGet.psm1-help.xml +#> +[CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619311')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [ValidateNotNullOrEmpty()] + [Object[]] + $NestedModules, + + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $RootModule, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $ModuleVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Reflection.ProcessorArchitecture] + $ProcessorArchitecture, + + [Parameter()] + [ValidateSet('Desktop','Core')] + [string[]] + $CompatiblePSEditions, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $PowerShellVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $ClrVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $DotNetFrameworkVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $PowerShellHostName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $PowerShellHostVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $TypesToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FormatsToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $ScriptsToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredAssemblies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FileList, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [object[]] + $ModuleList, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FunctionsToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $AliasesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $VariablesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $CmdletsToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $DscResourcesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Collections.Hashtable] + $PrivateData, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $HelpInfoUri, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $DefaultCommandPrefix, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $PackageManagementProviders + ) + + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Path -PathType Leaf)) + { + $message = $LocalizedData.UpdateModuleManifestPathCannotFound -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleManifestFilePath" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + $ModuleManifestHashTable = $null + + try + { + $ModuleManifestHashTable = Get-ManifestHashTable -Path $Path -CallerPSCmdlet $PSCmdlet + } + catch + { + $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleManifestFile" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + #Get the original module manifest and migrate all the fields to the new module manifest, including the specified parameter values + $moduleInfo = $null + + try + { + $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $Path -ErrorAction Stop + } + catch + { + # Throw an error only if Test-ModuleManifest did not return the PSModuleInfo object. + # This enables the users to use Update-ModuleManifest cmdlet to update the metadata. + if(-not $moduleInfo) + { + $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleManifestFile" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + } + + #Params to pass to New-ModuleManifest module + $params = @{} + + #NestedModules is read-only property + if($NestedModules) + { + $params.Add("NestedModules",$NestedModules) + } + elseif($moduleInfo.NestedModules) + { + #Get the original module info from ManifestHashTab + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("NestedModules")) + { + $params.Add("NestedModules",$ModuleManifestHashtable.NestedModules) + } + } + + #Guid is read-only property + if($Guid) + { + $params.Add("Guid",$Guid) + } + elseif($moduleInfo.Guid) + { + $params.Add("Guid",$moduleInfo.Guid) + } + + if($Author) + { + $params.Add("Author",$Author) + } + elseif($moduleInfo.Author) + { + $params.Add("Author",$moduleInfo.Author) + } + + if($CompanyName) + { + $params.Add("CompanyName",$CompanyName) + } + elseif($moduleInfo.CompanyName) + { + $params.Add("CompanyName",$moduleInfo.CompanyName) + } + + if($Copyright) + { + $params.Add("CopyRight",$Copyright) + } + elseif($moduleInfo.Copyright) + { + $params.Add("Copyright",$moduleInfo.Copyright) + } + + if($RootModule) + { + $params.Add("RootModule",$RootModule) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RootModule") -and $moduleInfo.RootModule) + { + $params.Add("RootModule",$ModuleManifestHashTable.RootModule) + } + + if($ModuleVersion) + { + $params.Add("ModuleVersion",$ModuleVersion) + } + elseif($moduleInfo.Version) + { + $params.Add("ModuleVersion",$moduleInfo.Version) + } + + if($Description) + { + $params.Add("Description",$Description) + } + elseif($moduleInfo.Description) + { + $params.Add("Description",$moduleInfo.Description) + } + + if($ProcessorArchitecture) + { + $params.Add("ProcessorArchitecture",$ProcessorArchitecture) + } + #Check if ProcessorArchitecture has a value and is not 'None' on lower verison PS + elseif($moduleInfo.ProcessorArchitecture -and $moduleInfo.ProcessorArchitecture -ne 'None') + { + $params.Add("ProcessorArchitecture",$moduleInfo.ProcessorArchitecture) + } + + if($PowerShellVersion) + { + $params.Add("PowerShellVersion",$PowerShellVersion) + } + elseif($moduleinfo.PowerShellVersion) + { + $params.Add("PowerShellVersion",$moduleinfo.PowerShellVersion) + } + + if($ClrVersion) + { + $params.Add("ClrVersion",$ClrVersion) + } + elseif($moduleInfo.ClrVersion) + { + $params.Add("ClrVersion",$moduleInfo.ClrVersion) + } + + if($DotNetFrameworkVersion) + { + $params.Add("DotNetFrameworkVersion",$DotNetFrameworkVersion) + } + elseif($moduleInfo.DotNetFrameworkVersion) + { + $params.Add("DotNetFrameworkVersion",$moduleInfo.DotNetFrameworkVersion) + } + + if($PowerShellHostName) + { + $params.Add("PowerShellHostName",$PowerShellHostName) + } + elseif($moduleInfo.PowerShellHostName) + { + $params.Add("PowerShellHostName",$moduleInfo.PowerShellHostName) + } + + if($PowerShellHostVersion) + { + $params.Add("PowerShellHostVersion",$PowerShellHostVersion) + } + elseif($moduleInfo.PowerShellHostVersion) + { + $params.Add("PowerShellHostVersion",$moduleInfo.PowerShellHostVersion) + } + + if($RequiredModules) + { + $params.Add("RequiredModules",$RequiredModules) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredModules") -and $moduleInfo.RequiredModules) + { + $params.Add("RequiredModules",$ModuleManifestHashtable.RequiredModules) + } + + if($TypesToProcess) + { + $params.Add("TypesToProcess",$TypesToProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("TypesToProcess") -and $moduleInfo.ExportedTypeFiles) + { + $params.Add("TypesToProcess",$ModuleManifestHashTable.TypesToProcess) + } + + if($FormatsToProcess) + { + $params.Add("FormatsToProcess",$FormatsToProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FormatsToProcess") -and $moduleInfo.ExportedFormatFiles) + { + $params.Add("FormatsToProcess",$ModuleManifestHashTable.FormatsToProcess) + } + + if($ScriptsToProcess) + { + $params.Add("ScriptsToProcess",$ScriptstoProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ScriptsToProcess") -and $moduleInfo.Scripts) + { + $params.Add("ScriptsToProcess",$ModuleManifestHashTable.ScriptsToProcess) + } + + if($RequiredAssemblies) + { + $params.Add("RequiredAssemblies",$RequiredAssemblies) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredAssemblies") -and $moduleInfo.RequiredAssemblies) + { + $params.Add("RequiredAssemblies",$moduleInfo.RequiredAssemblies) + } + + if($FileList) + { + $params.Add("FileList",$FileList) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FileList") -and $moduleInfo.FileList) + { + $params.Add("FileList",$ModuleManifestHashTable.FileList) + } + + #Make sure every path defined under FileList is within module base + $moduleBase = $moduleInfo.ModuleBase + foreach($file in $params["FileList"]) + { + #If path is not root path, append the module base to it and check if the file exists + if(-not [System.IO.Path]::IsPathRooted($file)) + { + $combinedPath = Join-Path $moduleBase -ChildPath $file + } + else + { + $combinedPath = $file + } + if(-not (Microsoft.PowerShell.Management\Test-Path -Type Leaf -LiteralPath $combinedPath)) + { + $message = $LocalizedData.FilePathInFileListNotWithinModuleBase -f ($file,$moduleBase) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "FilePathInFileListNotWithinModuleBase" ` + -ExceptionObject $file ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + } + + if($ModuleList) + { + $params.Add("ModuleList",$ModuleList) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ModuleList") -and $moduleInfo.ModuleList) + { + $params.Add("ModuleList",$ModuleManifestHashtable.ModuleList) + } + + if($FunctionsToExport) + { + $params.Add("FunctionsToExport",$FunctionsToExport) + } + + elseif($moduleInfo.ExportedFunctions) + { + #Since $moduleInfo.ExportedFunctions is a hashtable, we need to take the name of the + #functions and make them into a list + $params.Add("FunctionsToExport",($moduleInfo.ExportedFunctions.Keys -split ' ')) + } + + + if($AliasesToExport) + { + $params.Add("AliasesToExport",$AliasesToExport) + } + elseif($moduleInfo.ExportedAliases) + { + $params.Add("AliasesToExport",($moduleInfo.ExportedAliases.Keys -split ' ')) + } + if($VariablesToExport) + { + $params.Add("VariablesToExport",$VariablesToExport) + } + elseif($moduleInfo.ExportedVariables) + { + $params.Add("VariablesToExport",($moduleInfo.ExportedVariables.Keys -split ' ')) + } + if($CmdletsToExport) + { + $params.Add("CmdletsToExport", $CmdletsToExport) + } + elseif($moduleInfo.ExportedCmdlets) + { + $params.Add("CmdletsToExport",($moduleInfo.ExportedCmdlets.Keys -split ' ')) + } + if($DscResourcesToExport) + { + #DscResourcesToExport field is not available in PowerShell version lower than 5.0 + + if (($PSVersionTable.PSVersion -lt [Version]"5.0") -or ($PowerShellVersion -and $PowerShellVersion -lt [Version]"5.0") ` + -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt [Version]"5.0") ` + -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.ExportedDscResourcesNotSupportedOnLowerPowerShellVersion ` + -ErrorId "ExportedDscResourcesNotSupported" ` + -ExceptionObject $DscResourcesToExport ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + $params.Add("DscResourcesToExport",$DscResourcesToExport) + } + elseif(Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name "ExportedDscResources") + { + if($moduleInfo.ExportedDscResources) + { + $params.Add("DscResourcesToExport",$moduleInfo.ExportedDscResources) + } + } + + if($CompatiblePSEditions) + { + # CompatiblePSEditions field is not available in PowerShell version lower than 5.1 + # + if (($PSVersionTable.PSVersion -lt [Version]'5.1') -or ($PowerShellVersion -and $PowerShellVersion -lt [Version]'5.1') ` + -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt [Version]'5.1') ` + -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion)) + { + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $LocalizedData.CompatiblePSEditionsNotSupportedOnLowerPowerShellVersion ` + -ErrorId 'CompatiblePSEditionsNotSupported' ` + -ExceptionObject $CompatiblePSEditions ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + $params.Add('CompatiblePSEditions', $CompatiblePSEditions) + } + elseif( (Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name 'CompatiblePSEditions') -and + $moduleInfo.CompatiblePSEditions) + { + $params.Add('CompatiblePSEditions', $moduleInfo.CompatiblePSEditions) + } + + if($HelpInfoUri) + { + $params.Add("HelpInfoUri",$HelpInfoUri) + } + elseif($moduleInfo.HelpInfoUri) + { + $params.Add("HelpInfoUri",$moduleInfo.HelpInfoUri) + } + + if($DefaultCommandPrefix) + { + $params.Add("DefaultCommandPrefix",$DefaultCommandPrefix) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("DefaultCommandPrefix") -and $ModuleManifestHashTable.DefaultCommandPrefix) + { + $params.Add("DefaultCommandPrefix",$ModuleManifestHashTable.DefaultCommandPrefix) + } + + #Create a temp file within the directory and generate a new temporary manifest with the input + $tempPath = Microsoft.PowerShell.Management\Join-Path -Path $moduleInfo.ModuleBase -ChildPath "PSGet_$($moduleInfo.Name).psd1" + $params.Add("Path",$tempPath) + + try + { + #Terminates if there is error creating new module manifest + try{ + Microsoft.PowerShell.Core\New-ModuleManifest @params -Confirm:$false -WhatIf:$false + } + catch + { + $ErrorMessage = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $ErrorMessage ` + -ErrorId "NewModuleManifestFailure" ` + -ExceptionObject $params ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + #Manually update the section in PrivateData since New-ModuleManifest works differently on different PS version + $PrivateDataInput = "" + $ExistingData = $moduleInfo.PrivateData + $Data = @{} + if($ExistingData) + { + foreach($key in $ExistingData.Keys) + { + if($key -ne "PSData"){ + $Data.Add($key,$ExistingData[$key]) + } + else + { + $PSData = $ExistingData["PSData"] + foreach($entry in $PSData.Keys) + { + $Data.Add($entry,$PSData[$Entry]) + } + } + } + } + + if($PrivateData) + { + foreach($key in $PrivateData.Keys) + { + #if user provides PSData within PrivateData, we will parse through the PSData + if($key -ne "PSData") + { + $Data[$key] = $PrivateData[$Key] + } + + else + { + $PSData = $ExistingData["PSData"] + foreach($entry in $PSData.Keys) + { + $Data[$entry] = $PSData[$entry] + } + } + } + } + + #Tags is a read-only property + if($Tags) + { + $Data["Tags"] = $Tags + } + + + #The following Uris and ReleaseNotes cannot be empty + if($ProjectUri) + { + $Data["ProjectUri"] = $ProjectUri + } + + if($LicenseUri) + { + $Data["LicenseUri"] = $LicenseUri + } + if($IconUri) + { + $Data["IconUri"] = $IconUri + } + + if($ReleaseNotes) + { + #If value is provided as an array, we append the string. + $Data["ReleaseNotes"] = $($ReleaseNotes -join "`r`n") + } + + if($ExternalModuleDependencies) + { + #ExternalModuleDependencies have to be specified either under $RequiredModules or $NestedModules + #Extract all the module names specified in the moduleInfo of NestedModules and RequiredModules + $DependentModuleNames = @() + foreach($moduleInfo in $params["NestedModules"]) + { + if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) + { + $DependentModuleNames += $moduleInfo.ModuleName + } + } + + foreach($moduleInfo in $params["RequiredModules"]) + { + if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) + { + $DependentModuleNames += $moduleInfo.ModuleName + } + } + + foreach($dependency in $ExternalModuleDependencies) + { + if($params["NestedModules"] -notcontains $dependency -and + $params["RequiredModules"] -notContains $dependency -and + $DependentModuleNames -notcontains $dependency) + { + $message = $LocalizedData.ExternalModuleDependenciesNotSpecifiedInRequiredOrNestedModules -f ($dependency) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidExternalModuleDependencies" ` + -ExceptionObject $Exception ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + } + if($Data.ContainsKey("ExternalModuleDependencies")) + { + $Data["ExternalModuleDependencies"] = $ExternalModuleDependencies + } + else + { + $Data.Add("ExternalModuleDependencies", $ExternalModuleDependencies) + } + } + if($PackageManagementProviders) + { + #Check if the provided value is within the relative path + $ModuleBase = Microsoft.PowerShell.Management\Split-Path $Path -Parent + $Files = Microsoft.PowerShell.Management\Get-ChildItem -Path $ModuleBase + foreach($provider in $PackageManagementProviders) + { + if ($Files.Name -notcontains $provider) + { + $message = $LocalizedData.PackageManagementProvidersNotInModuleBaseFolder -f ($provider,$ModuleBase) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviders" ` + -ExceptionObject $PackageManagementProviders ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + } + + $Data["PackageManagementProviders"] = $PackageManagementProviders + } + $PrivateDataInput = Get-PrivateData -PrivateData $Data + + #Repleace the PrivateData section by first locating the linenumbers of start line and endline. + $PrivateDataBegin = Select-String -Path $tempPath -Pattern "PrivateData =" + $PrivateDataBeginLine = $PrivateDataBegin.LineNumber + + $newManifest = Microsoft.PowerShell.Management\Get-Content -Path $tempPath + #Look up the endline of PrivateData section by finding the matching brackets since private data could + #consist of multiple pairs of brackets. + $PrivateDataEndLine=0 + if($PrivateDataBegin -match "@{") + { + $leftBrace = 0 + $EndLineOfFile = $newManifest.Length-1 + + For($i = $PrivateDataBeginLine;$i -lt $EndLineOfFile; $i++) + { + if($newManifest[$i] -match "{") + { + $leftBrace ++ + } + elseif($newManifest[$i] -match "}") + { + if($leftBrace -gt 0) + { + $leftBrace -- + } + else + { + $PrivateDataEndLine = $i + break + } + } + } + } + + + try + { + if($PrivateDataEndLine -ne 0) + { + #If PrivateData section has more than one line, we will remove the old content and insert the new PrivataData + $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataEndLine+1} ` + | ForEach-Object { + $_ + if($_ -match "PrivateData = ") + { + $PrivateDataInput + } + } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false + } + + #In lower version, PrivateData is just a single line + else + { + $PrivateDataForDownlevelPS = "PrivateData = @{ `n"+$PrivateDataInput + + $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataBeginLine } ` + | ForEach-Object { + $_ + if($_ -match "PrivateData = ") + { + $PrivateDataForDownlevelPS + } + } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false + } + + #Verify the new module manifest is valid + $testModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $tempPath ` + -Verbose:$VerbosePreference ` + } + #Catch the exceptions from Test-ModuleManifest + catch + { + $message = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "UpdateManifestFileFail" ` + -ExceptionObject $_.Exception ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + + $newContent = Microsoft.PowerShell.Management\Get-Content -Path $tempPath + + try{ + #Ask for confirmation of the new manifest before replacing the original one + if($PSCmdlet.ShouldProcess($Path,$LocalizedData.UpdateManifestContentMessage+$newContent)) + { + Microsoft.PowerShell.Management\Set-Content -Path $Path -Value $newContent -Confirm:$false -WhatIf:$false + } + + #Return the new content if -PassThru is specified + if($PassThru) + { + return $newContent + } + } + catch + { + $message = $LocalizedData.ManifestFileReadWritePermissionDenied -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ManifestFileReadWritePermissionDenied" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } +} + +#Utility function to help form the content string for PrivateData +function Get-PrivateData +{ + param + ( + [System.Collections.Hashtable] + $PrivateData + ) + + if($PrivateData.Keys.Count -eq 0) + { + $content = " + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # External dependent modules of this module + # ExternalModuleDependencies = '' + + } # End of PSData hashtable + +} # End of PrivateData hashtable" + return $content + } + + + #Validate each of the property of PSData is of the desired data type + $Tags= $PrivateData["Tags"] -join "','" | %{"'$_'"} + $LicenseUri = $PrivateData["LicenseUri"]| %{"'$_'"} + $ProjectUri = $PrivateData["ProjectUri"] | %{"'$_'"} + $IconUri = $PrivateData["IconUri"] | %{"'$_'"} + $ReleaseNotesEscape = $PrivateData["ReleaseNotes"] -Replace "'","''" + $ReleaseNotes = $ReleaseNotesEscape | %{"'$_'"} + $ExternalModuleDependencies = $PrivateData["ExternalModuleDependencies"] -join "','" | %{"'$_'"} + + $DefaultProperties = @("Tags","LicenseUri","ProjectUri","IconUri","ReleaseNotes","ExternalModuleDependencies") + + $ExtraProperties = @() + foreach($key in $PrivateData.Keys) + { + if($DefaultProperties -notcontains $key) + { + $PropertyString = "#"+"$key"+ " of this module" + $PropertyString += "`r`n " + $PropertyString += $key +" = " + "'"+$PrivateData[$key]+"'" + $ExtraProperties += ,$PropertyString + } + } + + $ExtraPropertiesString = "" + $firstProperty = $true + foreach($property in $ExtraProperties) + { + if($firstProperty) + { + $firstProperty = $false + } + else + { + $ExtraPropertiesString += "`r`n`r`n " + } + $ExtraPropertiesString += $Property + } + + $TagsLine ="# Tags = @()" + if($Tags -ne "''") + { + $TagsLine = "Tags = "+$Tags + } + $LicenseUriLine = "# LicenseUri = ''" + if($LicenseUri -ne "''") + { + $LicenseUriLine = "LicenseUri = "+$LicenseUri + } + $ProjectUriLine = "# ProjectUri = ''" + if($ProjectUri -ne "''") + { + $ProjectUriLine = "ProjectUri = " +$ProjectUri + } + $IconUriLine = "# IconUri = ''" + if($IconUri -ne "''") + { + $IconUriLine = "IconUri = " +$IconUri + } + $ReleaseNotesLine = "# ReleaseNotes = ''" + if($ReleaseNotes -ne "''") + { + $ReleaseNotesLine = "ReleaseNotes = "+$ReleaseNotes + } + $ExternalModuleDependenciesLine ="# ExternalModuleDependencies = ''" + if($ExternalModuleDependencies -ne "''") + { + $ExternalModuleDependenciesLine = "ExternalModuleDependencies = "+$ExternalModuleDependencies + } + + if(-not $ExtraPropertiesString -eq "") + { + $Content = " + ExtraProperties + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + $TagsLine + + # A URL to the license for this module. + $LicenseUriLine + + # A URL to the main website for this project. + $ProjectUriLine + + # A URL to an icon representing this module. + $IconUriLine + + # ReleaseNotes of this module + $ReleaseNotesLine + + # External dependent modules of this module + $ExternalModuleDependenciesLine + + } # End of PSData hashtable + +} # End of PrivateData hashtable" + + #Replace the Extra PrivateData in the block + $Content -replace "ExtraProperties", $ExtraPropertiesString + } + else + { + $content = " + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + $TagsLine + + # A URL to the license for this module. + $LicenseUriLine + + # A URL to the main website for this project. + $ProjectUriLine + + # A URL to an icon representing this module. + $IconUriLine + + # ReleaseNotes of this module + $ReleaseNotesLine + + # External dependent modules of this module + $ExternalModuleDependenciesLine + + } # End of PSData hashtable + + } # End of PrivateData hashtable" + return $content + } +} + +function Copy-ScriptFile +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourcePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $DestinationPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [PSCustomObject] + $PSGetItemInfo, + + [Parameter()] + [string] + $Scope + ) + + # Copy the script file to destination + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath ` + -ItemType Directory ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false ` + -WhatIf:$false + } + + Microsoft.PowerShell.Management\Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Confirm:$false -WhatIf:$false -Verbose + + if($Scope) + { + # Create _InstalledScriptInfo.xml + $InstalledScriptInfoFileName = "$($PSGetItemInfo.Name)_$script:InstalledScriptInfoFileName" + + if($scope -eq 'AllUsers') + { + $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $InstalledScriptInfoFileName + } + else + { + $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $InstalledScriptInfoFileName + } + + Microsoft.PowerShell.Utility\Out-File -FilePath $scriptInfopath ` + -Force ` + -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) + } +} + +function Copy-Module +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourcePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $DestinationPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [PSCustomObject] + $PSGetItemInfo + ) + + if(Microsoft.PowerShell.Management\Test-Path $DestinationPath) + { + Microsoft.PowerShell.Management\Remove-Item -Path $DestinationPath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + # Copy the module to destination + $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Copy-Item -Path "$SourcePath\*" -Destination $DestinationPath -Force -Recurse -Confirm:$false -WhatIf:$false + + # Remove the *.nupkg file + if(Microsoft.PowerShell.Management\Test-Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg") + { + Microsoft.PowerShell.Management\Remove-Item -Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg" -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + # Create PSGetModuleInfo.xml + $psgetItemInfopath = Microsoft.PowerShell.Management\Join-Path $DestinationPath $script:PSGetItemInfoFileName + + Microsoft.PowerShell.Utility\Out-File -FilePath $psgetItemInfopath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) + + [System.IO.File]::SetAttributes($psgetItemInfopath, [System.IO.FileAttributes]::Hidden) +} + +function Test-FileInUse +{ + [CmdletBinding()] + [OutputType([bool])] + param + ( + [string] + $FilePath + ) + + if(Microsoft.PowerShell.Management\Test-Path -LiteralPath $FilePath -PathType Leaf) + { + # Attempts to open a file and handles the exception if the file is already open/locked + try + { + $fileInfo = New-Object System.IO.FileInfo $FilePath + $fileStream = $fileInfo.Open( [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) + + if ($fileStream) + { + $fileStream.Close() + } + } + catch + { + Write-Debug "In Test-FileInUse function, unable to open the $FilePath file in ReadWrite access. $_" + return $true + } + } + + return $false +} + +function Test-ModuleInUse +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleBasePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Version] + $ModuleVersion + ) + + $FileList = Get-ChildItem -Path $ModuleBasePath ` + -File ` + -Recurse ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + $IsModuleInUse = $false + + foreach($file in $FileList) + { + $IsModuleInUse = Test-FileInUse -FilePath $file.FullName + + if($IsModuleInUse) + { + break + } + } + + if($IsModuleInUse) + { + $message = $LocalizedData.ModuleVersionInUse -f ($ModuleVersion, $ModuleName) + Write-Error -Message $message -ErrorId 'ModuleIsInUse' -Category InvalidOperation + + return $true + } + + return $false +} + +function Validate-ModuleAuthenticodeSignature +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + $CurrentModuleInfo, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $InstallLocation, + + [Parameter()] + [Switch] + $SkipPublisherCheck + ) + + $InstalledModuleDetails = $null + $InstalledModuleInfo = Test-ModuleInstalled -Name $CurrentModuleInfo.Name + if($InstalledModuleInfo) + { + $InstalledModuleDetails = Get-InstalledModuleAuthenticodeSignature -InstalledModuleInfo $InstalledModuleInfo ` + -InstallLocation $InstallLocation + } + + # Skip the publisher check when -SkipPublisherCheck is specified and + # previously-installed module is not signed by Microsoft + if($SkipPublisherCheck) + { + if($InstalledModuleDetails -and $InstalledModuleDetails.IsMicrosoftCertificate) + { + $Message = $LocalizedData.ProceedingWithPublisherCheckForMicrosoftModules -f ($CurrentModuleInfo.Name) + Write-Verbose -Message $message + } + else + { + $Message = $LocalizedData.SkippingPublisherCheck -f ($CurrentModuleInfo.Version, $CurrentModuleInfo.Name) + Write-Verbose -Message $message + + return $true + } + } + + # Validate the catalog signature for the current module being installed. + $ev = $null + $CurrentModuleDetails = ValidateAndGet-AuthenticodeSignature -ModuleInfo $CurrentModuleInfo -ErrorVariable ev + + if($ev) + { + return $false + } + + if($InstalledModuleInfo) + { + $CurrentModuleAuthenticodePublisher = $null + $IsCurrentModuleSignedByMicrosoft = $false + + if($CurrentModuleDetails) + { + $CurrentModuleAuthenticodePublisher = $CurrentModuleDetails.Publisher + $IsCurrentModuleSignedByMicrosoft = $CurrentModuleDetails.IsMicrosoftCertificate + + $message = $LocalizedData.NewModuleVersionDetailsForPublisherValidation -f ($CurrentModuleInfo.Name, + $CurrentModuleInfo.Version, + $CurrentModuleDetails.Publisher, + $CurrentModuleDetails.IsMicrosoftCertificate) + Write-Verbose $message + } + + $InstalledModuleAuthenticodePublisher = $null + $IsInstalledModuleSignedByMicrosoft = $false + $InstalledModuleVersion = [Version]'0.0' + + if($InstalledModuleDetails) + { + $InstalledModuleAuthenticodePublisher = $InstalledModuleDetails.Publisher + $IsInstalledModuleSignedByMicrosoft = $InstalledModuleDetails.IsMicrosoftCertificate + $InstalledModuleVersion = $InstalledModuleDetails.Version + + $message = $LocalizedData.SourceModuleDetailsForPublisherValidation -f ($CurrentModuleInfo.Name, + $InstalledModuleDetails.Version, + $InstalledModuleDetails.ModuleBase, + $InstalledModuleDetails.Publisher, + $InstalledModuleDetails.IsMicrosoftCertificate) + Write-Verbose $message + } + + Write-Debug -Message "Previously-installed module publisher: $InstalledModuleAuthenticodePublisher" + Write-Debug -Message "Current module publisher: $CurrentModuleAuthenticodePublisher" + Write-Debug -Message "Is previously-installed module signed by Microsoft: $IsInstalledModuleSignedByMicrosoft" + Write-Debug -Message "Is current module signed by Microsoft: $IsCurrentModuleSignedByMicrosoft" + + if($InstalledModuleAuthenticodePublisher) + { + if(-not $CurrentModuleAuthenticodePublisher) + { + $Message = $LocalizedData.ModuleIsNotCatalogSigned -f ($CurrentModuleInfo.Version, $CurrentModuleInfo.Name, "$($CurrentModuleInfo.Name).cat", $InstalledModuleAuthenticodePublisher, $InstalledModuleDetails.Version, $InstalledModuleDetails.ModuleBase) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'ModuleIsNotCatalogSigned' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + return $false + } + elseif($InstalledModuleAuthenticodePublisher -eq $CurrentModuleAuthenticodePublisher) + { + $Message = $LocalizedData.AuthenticodeIssuerMatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) + Write-Verbose -Message $message + } + elseif($IsInstalledModuleSignedByMicrosoft) + { + if($IsCurrentModuleSignedByMicrosoft) + { + $Message = $LocalizedData.PublishersMatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) + Write-Verbose -Message $message + } + else + { + $Message = $LocalizedData.PublishersMismatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'PublishersMismatch' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return $false + } + } + else + { + $Message = $LocalizedData.AuthenticodeIssuerMismatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'AuthenticodeIssuerMismatch' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + return $false + } + } + } + + return $true +} + +function Validate-ModuleCommandAlreadyAvailable +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $CurrentModuleInfo, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $InstallLocation, + + [Parameter()] + [Switch] + $AllowClobber, + + [Parameter()] + [Switch] + $IsUpdateOperation + ) + + <# + Install-Module must generate an error message when there is a conflict. + User can specify -AllowClobber to avoid the message. + Scenario: A large module could be separated into 2 smaller modules. + Reason 1: the consumer might have to change code (aka: import-module) to use the command from the new module. + Reason 2: it is too confusing to troubleshoot this problem if the user isn't informed right away. + #> + # When new module has some commands, no clobber error if + # - AllowClobber is specified, or + # - Installing to the same module base, or + # - Update operation + if($CurrentModuleInfo.ExportedCommands.Keys.Count -and + -not $AllowClobber -and + -not $IsUpdateOperation) + { + # Remove the version folder on 5.0 to get the actual module base folder without version + if(Test-ModuleSxSVersionSupport) + { + $InstallLocation = Microsoft.PowerShell.Management\Split-Path -Path $InstallLocation + } + + $InstalledModuleInfo = Test-ModuleInstalled -Name $CurrentModuleInfo.Name + if(-not $InstalledModuleInfo -or -not $InstalledModuleInfo.ModuleBase.StartsWith($InstallLocation, [System.StringComparison]::OrdinalIgnoreCase)) + { + # Throw an error if there is a command with the same name from a different source. + # Get-Command loads the module if a command is already available. + # To avoid that, appending '*' at the end for each name then comparing the results. + $CommandNames = $CurrentModuleInfo.ExportedCommands.Values.Name + $CommandNamesWithWildcards = $CommandNames | Microsoft.PowerShell.Core\Foreach-Object { "$_*" } + + $AvailableCommand = Microsoft.PowerShell.Core\Get-Command -Name $CommandNamesWithWildcards ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { ($CommandNames -contains $_.Name) -and + ($_.Source -ne $CurrentModuleInfo.Name) } | + Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction SilentlyContinue + if($AvailableCommand) + { + $message = $LocalizedData.ModuleCommandAlreadyAvailable -f ($AvailableCommand.Name, $CurrentModuleInfo.Name) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'CommandAlreadyAvailable' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return $false + } + } + } + + return $true +} + +function ValidateAndGet-AuthenticodeSignature +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $ModuleInfo + ) + + $ModuleDetails = $null + $AuthenticodeSignature = $null + + $ModuleName = $ModuleInfo.Name + $ModuleBasePath = $ModuleInfo.ModuleBase + $CatalogFileName = "$ModuleName.cat" + $CatalogFilePath = Microsoft.PowerShell.Management\Join-Path -Path $ModuleBasePath -ChildPath $CatalogFileName + + if(Microsoft.PowerShell.Management\Test-Path -Path $CatalogFilePath -PathType Leaf) + { + $message = $LocalizedData.CatalogFileFound -f ($CatalogFileName, $ModuleName) + Write-Verbose -Message $message + + $AuthenticodeSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $CatalogFilePath + + if(-not $AuthenticodeSignature -or ($AuthenticodeSignature.Status -ne "Valid")) + { + $message = $LocalizedData.InvalidModuleAuthenticodeSignature -f ($ModuleName, $CatalogFileName) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidAuthenticodeSignature' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + Write-Verbose -Message ($LocalizedData.ValidAuthenticodeSignature -f @($CatalogFileName, $ModuleName)) + + if(Get-Command -Name Test-FileCatalog -Module Microsoft.PowerShell.Security -ErrorAction SilentlyContinue) + { + Write-Verbose -Message ($LocalizedData.ValidatingCatalogSignature -f @($ModuleName, $CatalogFileName)) + + # Skip the PSGetModuleInfo.xml and ModuleName.cat files in the catalog validation + $TestFileCatalogResult = Microsoft.PowerShell.Security\Test-FileCatalog -Path $ModuleBasePath ` + -CatalogFilePath $CatalogFilePath ` + -FilesToSkip $script:PSGetItemInfoFileName,'*.cat' ` + -Detailed ` + -ErrorAction SilentlyContinue + if(-not $TestFileCatalogResult -or + ($TestFileCatalogResult.Status -ne "Valid") -or + ($TestFileCatalogResult.Signature.Status -ne "Valid")) + { + $message = $LocalizedData.InvalidCatalogSignature -f ($ModuleName, $CatalogFileName) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidCatalogSignature' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + return + } + else + { + Write-Verbose -Message ($LocalizedData.ValidCatalogSignature -f @($CatalogFileName, $ModuleName)) + } + } + } + else + { + Write-Verbose -Message ($LocalizedData.CatalogFileNotFoundInNewModule -f ($CatalogFileName, $ModuleName)) + } + + if($AuthenticodeSignature) + { + $ModuleDetails = @{} + $ModuleDetails['AuthenticodeSignature'] = $AuthenticodeSignature + $ModuleDetails['Version'] = $ModuleInfo.Version + $ModuleDetails['ModuleBase']=$ModuleInfo.ModuleBase + $ModuleDetails['IsMicrosoftCertificate'] = Test-MicrosoftCertificate -AuthenticodeSignature $AuthenticodeSignature + $ModuleDetails['Publisher'] = Get-AuthenticodePublisher -AuthenticodeSignature $AuthenticodeSignature + + $message = $LocalizedData.NewModuleVersionDetailsForPublisherValidation -f ($ModuleInfo.Name, $ModuleInfo.Version, $ModuleDetails.Publisher, $ModuleDetails.IsMicrosoftCertificate) + Write-Debug $message + } + + return $ModuleDetails +} + +function Get-AuthenticodePublisher +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [System.Management.Automation.Signature] + $AuthenticodeSignature + ) + + if($AuthenticodeSignature.SignerCertificate) + { + $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain + $null = $chain.Build($AuthenticodeSignature.SignerCertificate) + + $certStoreLocations = @('cert:\LocalMachine\Root', + 'cert:\LocalMachine\AuthRoot', + 'cert:\CurrentUser\Root', + 'cert:\CurrentUser\AuthRoot') + + foreach($element in $chain.ChainElements.Certificate) + { + foreach($certStoreLocation in $certStoreLocations) + { + $rootCertificateAuthority = Microsoft.PowerShell.Management\Get-ChildItem -Path $certStoreLocation | + Microsoft.PowerShell.Core\Where-Object { $_.Subject -eq $element.Subject } + if($rootCertificateAuthority) + { + return $rootCertificateAuthority.Subject + } + } + } + } +} + +function Get-InstalledModuleAuthenticodeSignature +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $InstalledModuleInfo, + + [Parameter(Mandatory=$true)] + [string] + $InstallLocation + ) + + $ModuleName = $InstalledModuleInfo.Name + + # Priority order for getting the published details of the installed module: + # 1. Latest version under the $InstallLocation + # 2. Latest available version in $PSModulePath + # 3. $InstalledModuleInfo + $AvailableModules = Microsoft.PowerShell.Core\Get-Module -ListAvailable ` + -Name $ModuleName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Verbose:$false | + Microsoft.PowerShell.Utility\Sort-Object -Property Version -Descending + + # Remove the version folder on 5.0 to get the actual module base folder without version + if(Test-ModuleSxSVersionSupport) + { + $InstallLocation = Microsoft.PowerShell.Management\Split-Path -Path $InstallLocation + } + + $SourceModule = $AvailableModules | Microsoft.PowerShell.Core\Where-Object { + $_.ModuleBase.StartsWith($InstallLocation, [System.StringComparison]::OrdinalIgnoreCase) + } | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $SourceModule) + { + $SourceModule = $AvailableModules | Microsoft.PowerShell.Utility\Select-Object -First 1 + } + else + { + $SourceModule = $InstalledModuleInfo + } + + $SignedFilePath = $SourceModule.Path + + $CatalogFileName = "$ModuleName.cat" + $CatalogFilePath = Microsoft.PowerShell.Management\Join-Path -Path $SourceModule.ModuleBase -ChildPath $CatalogFileName + + if(Microsoft.PowerShell.Management\Test-Path -Path $CatalogFilePath -PathType Leaf) + { + $message = $LocalizedData.CatalogFileFound -f ($CatalogFileName, $ModuleName) + Write-Debug -Message $message + + $SignedFilePath = $CatalogFilePath + } + else + { + Write-Debug -Message ($LocalizedData.CatalogFileNotFoundInAvailableModule -f ($CatalogFileName, $ModuleName)) + } + + $message = "Using the previously-installed module '{0}' with version '{1}' under '{2}' for getting the publisher details." -f ($SourceModule.Name, $SourceModule.Version, $SourceModule.ModuleBase) + Write-Debug -Message $message + + $message = "Using the '{0}' file for getting the authenticode signature." -f ($SignedFilePath) + Write-Debug -Message $message + + $AuthenticodeSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $SignedFilePath + $ModuleDetails = $null + + if($AuthenticodeSignature) + { + $ModuleDetails = @{} + $ModuleDetails['AuthenticodeSignature'] = $AuthenticodeSignature + $ModuleDetails['Version'] = $SourceModule.Version + $ModuleDetails['ModuleBase']=$SourceModule.ModuleBase + $ModuleDetails['IsMicrosoftCertificate'] = Test-MicrosoftCertificate -AuthenticodeSignature $AuthenticodeSignature + $ModuleDetails['Publisher'] = Get-AuthenticodePublisher -AuthenticodeSignature $AuthenticodeSignature + + $message = $LocalizedData.SourceModuleDetailsForPublisherValidation -f ($ModuleName, $SourceModule.Version, $SourceModule.ModuleBase, $ModuleDetails.Publisher, $ModuleDetails.IsMicrosoftCertificate) + Write-Debug $message + } + + return $ModuleDetails +} + +function Test-MicrosoftCertificate +{ + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [System.Management.Automation.Signature] + $AuthenticodeSignature + ) + + if($AuthenticodeSignature.SignerCertificate) + { + try + { + $X509Chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain + $null = $X509Chain.Build($AuthenticodeSignature.SignerCertificate) + } + catch + { + return $false + } + + $SafeX509ChainHandle = [Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers]::CertDuplicateCertificateChain($X509Chain.ChainContext) + return [Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers]::IsMicrosoftCertificate($SafeX509ChainHandle) + } + + return $false +} + +function Test-ValidManifestModule +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleBasePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $InstallLocation, + + [Parameter()] + [Switch] + $SkipPublisherCheck, + + [Parameter()] + [Switch] + $AllowClobber, + + [Parameter()] + [Switch] + $IsUpdateOperation + ) + + $moduleName = Microsoft.PowerShell.Management\Split-Path $ModuleBasePath -Leaf + $manifestPath = Microsoft.PowerShell.Management\Join-Path $ModuleBasePath "$moduleName.psd1" + $PSModuleInfo = $null + + if(Microsoft.PowerShell.Management\Test-Path $manifestPath) + { + $PSModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if(-not $PSModuleInfo) + { + $message = $LocalizedData.InvalidPSModule -f ($moduleName) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidManifestModule' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + else + { + $ValidationResult = Validate-ModuleAuthenticodeSignature -CurrentModuleInfo $PSModuleInfo ` + -InstallLocation $InstallLocation ` + -SkipPublisherCheck:$SkipPublisherCheck + + if($ValidationResult) + { + # Checking for the possible command clobbering. + $ValidationResult = Validate-ModuleCommandAlreadyAvailable -CurrentModuleInfo $PSModuleInfo ` + -InstallLocation $InstallLocation ` + -AllowClobber:$AllowClobber ` + -IsUpdateOperation:$IsUpdateOperation + + + } + + if(-not $ValidationResult) + { + $PSModuleInfo = $null + } + } + } + + return $PSModuleInfo +} + +function Get-ScriptSourceLocation +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [String] + $Location, + + [Parameter()] + $Credential, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential + ) + + $scriptLocation = $null + + if($Location) + { + # For local dir or SMB-share locations, ScriptSourceLocation is SourceLocation. + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + $scriptLocation = $Location + } + else + { + $tempScriptLocation = $null + + if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempScriptLocation = $Location + '/items/psscript/' + } + elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempScriptLocation = $Location + 'items/psscript/' + } + + if($tempScriptLocation) + { + # Ping and resolve the specified location + $scriptLocation = Resolve-Location -Location $tempScriptLocation ` + -LocationParameterName 'ScriptSourceLocation' ` + -Credential $Credential ` + -Proxy $Proxy ` + -ProxyCredential $ProxyCredential ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + } + } + } + + return $scriptLocation +} + +function Get-PublishLocation +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [String] + $Location + ) + + $PublishLocation = $null + + if($Location) + { + # For local dir or SMB-share locations, ScriptPublishLocation is PublishLocation. + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + $PublishLocation = $Location + } + else + { + $tempPublishLocation = $null + + if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempPublishLocation = $Location + '/package/' + } + elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempPublishLocation = $Location + 'package/' + } + + if($tempPublishLocation) + { + $PublishLocation = $tempPublishLocation + } + } + } + + return $PublishLocation +} + +function Resolve-Location +{ + [CmdletBinding()] + [OutputType([string])] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Location, + + [Parameter(Mandatory=$true)] + [string] + $LocationParameterName, + + [Parameter()] + $Credential, + + [Parameter()] + $Proxy, + + [Parameter()] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + # Ping and resolve the specified location + if(-not (Test-WebUri -uri $Location)) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + return $Location + } + elseif($CallerPSCmdlet) + { + $message = $LocalizedData.PathNotFound -f ($Location) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } + else + { + $pingResult = Ping-Endpoint -Endpoint $Location -Credential $Credential -Proxy $Proxy -ProxyCredential $ProxyCredential + $statusCode = $null + $exception = $null + $resolvedLocation = $null + if($pingResult -and $pingResult.ContainsKey($Script:ResponseUri)) + { + $resolvedLocation = $pingResult[$Script:ResponseUri] + } + + if($pingResult -and $pingResult.ContainsKey($Script:StatusCode)) + { + $statusCode = $pingResult[$Script:StatusCode] + } + + Write-Debug -Message "Ping-Endpoint: location=$Location, statuscode=$statusCode, resolvedLocation=$resolvedLocation" + + if((($statusCode -eq 200) -or ($statusCode -eq 401)) -and $resolvedLocation) + { + return $resolvedLocation + } + elseif($CallerPSCmdlet) + { + $message = $LocalizedData.InvalidWebUri -f ($Location, $LocationParameterName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } +} + +function Test-WebUri +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $uri + ) + + return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]') +} + +function Test-WildcardPattern +{ + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + $Name + ) + + return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) +} + +# Utility to throw an errorrecord +function ThrowError +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionName, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionMessage, + + [System.Object] + $ExceptionObject, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorId, + + [parameter(Mandatory = $true)] + [ValidateNotNull()] + [System.Management.Automation.ErrorCategory] + $ErrorCategory + ) + + $exception = New-Object $ExceptionName $ExceptionMessage; + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject + $CallerPSCmdlet.ThrowTerminatingError($errorRecord) +} + + +#endregion + +# Create install locations for scripts if they are not already created +if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:ProgramFilesInstalledScriptInfosPath) -and (Test-RunningAsElevated)) +{ + $null = Microsoft.PowerShell.Management\New-Item -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ItemType Directory ` + -Force ` + -Confirm:$false ` + -WhatIf:$false +} + +if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:MyDocumentsInstalledScriptInfosPath)) +{ + $null = Microsoft.PowerShell.Management\New-Item -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ItemType Directory ` + -Force ` + -Confirm:$false ` + -WhatIf:$false +} + +Set-Alias -Name fimo -Value Find-Module +Set-Alias -Name inmo -Value Install-Module +Set-Alias -Name upmo -Value Update-Module +Set-Alias -Name pumo -Value Publish-Module +Set-Alias -Name uimo -Value Uninstall-Module + +Export-ModuleMember -Function Find-Module, ` + Save-Module, ` + Install-Module, ` + Update-Module, ` + Publish-Module, ` + Uninstall-Module, ` + Get-InstalledModule, ` + Find-Command, ` + Find-DscResource, ` + Find-RoleCapability, ` + Install-Script, ` + Find-Script, ` + Save-Script, ` + Update-Script, ` + Publish-Script, ` + Get-InstalledScript, ` + Uninstall-Script, ` + Test-ScriptFileInfo, ` + New-ScriptFileInfo, ` + Update-ScriptFileInfo, ` + Get-PSRepository, ` + Register-PSRepository, ` + Unregister-PSRepository, ` + Set-PSRepository, ` + Find-Package, ` + Get-PackageDependencies, ` + Download-Package, ` + Install-Package, ` + Uninstall-Package, ` + Get-InstalledPackage, ` + Remove-PackageSource, ` + Resolve-PackageSource, ` + Add-PackageSource, ` + Get-DynamicOptions, ` + Initialize-Provider, ` + Get-Feature, ` + Get-PackageProviderName, ` + Update-ModuleManifest ` + -Alias fimo, ` + inmo, ` + upmo, ` + pumo diff --git a/src/Modules/PowerShellGet/PowerShellGet.psd1 b/src/Modules/PowerShellGet/PowerShellGet.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..e1b86328db03000f1e9253730dca4d98e2757d8c GIT binary patch literal 4318 zcmcJTTTk0S5QXQtQvXAgm(Z$&rchd1p@N`Lq=F&>yoWeI)ZCg20ag6{$R z9FP@zZSR~tbMwyR-`^ekW3TO%omz{dXUCia>s#Hbma%PqIV)Nz@jP#B>srGKypwEP z<^s76Z)@N*M+gPW+xy`!lsdF?JF@-QoWMTWx|MB{xdmIb4L7d1(YjUaBcn^6t=ko& zP3CNIU$D=db!;HFG32z14n4bpMQ60aF{~=wx8T2&&WuAE6UN60CplcaT z?(KwYBW9H}Xl-yhtZ@x9t?uo+0;@ONJsmO6>|K0R=NjR4-CY&!~q(3 z+Skx1)H7sIMALzjD#5HeL~igjiiH8ZWzh^MvP;9+B>**pExnxs=4h3cTV2eW==zQs z8g-E`JM8FrA2tC`#Yl5AL(~k<`}nl(5N}3r#XylcnQ(fD1q9(am_OR$8eH6#(SEg>g;W!vt^>XTSb&X9GN9o|<5 z&YH5Xu+F$Eg54T2)2dNk9>SxCY+T0YXTk39QGMwD19WRToA?O#xZj!MV?T_>9a}-- zDB-QuM26?EoU%T%z>$NW{2P$BaWAC9Dq$H#_j6#KqrZ>8=fNu`qV_SvObXk1AFqyi zMcKW)Ezj|aJQL;SW6sNX+kZpDZ-xAw#sX3F?8CJ3C|{Sy4Rif*rr(nfX(E0+hvHv| zbcm4^mdA>6XnCw;4lR#2oy;N=XxOS+n(%GW~k}N$7b&>sU@feaW*XW_|u&TG& zTo%VyjCNjpjcI%7F*~;QnJXAb!yNUlbhzNTswP!dit1@qN!H$4)=8-9)qK^s(`Ne` zM!T9S*hM2E2g_PYNmaAy)>O6YCB0?BZ21WnS2VHLdhhM;fnd!oF)8PZsffg=)S`u2h+&sPbcVW=$7aUlY>F zYFilNz39U*7FA={s4G=$wF1^rubdsOGQZQFzkUe| zx7}A!oseq8Nj-@7f4pZ%+9~4XBThEE8)fZm77s2@f3S8P9^pQ9&e!^Aq^G*y9&f+c y8pkzRnkV|lyYoE0R;Rf}Mh;xwH}U