tag:blogger.com,1999:blog-60187912584419283082024-03-14T02:17:55.049+00:00Technical Deep DiveA blog on all things DevOps and infrastructure as codeMark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.comBlogger131125tag:blogger.com,1999:blog-6018791258441928308.post-79460671685499821602020-06-15T08:04:00.003+01:002020-06-15T08:04:00.183+01:00Azure Service Bus First In, First Out (FIFO)<span style="font-size: x-large;">Introduction</span><br />
<br />
With Azure Service Bus, you get some great features but to get guaranteed FIFO (First-In, First-Out, i.e. ordered delivery), there was a lot of documentation to read through so I thought I'd show a quick example using a Topic and Subscriber.<br />
<br />
<span style="font-size: large;">Service Bus Message Sessions</span><br />
<br />
To ensure FIFO, Service Bus requires that a Session is used which is fairly simple. The sender needs to set the <b>SessionId</b> property on the Message that it sends.<div><br /></div><div>You need to enable message sessions, we will need to enable this when we create the subscription:</div><div><br /></div><div><img alt="" src="data:image/png;base64,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p53aDtaBBx6YNm7cmI444oi0ww47pJNPPjkdcsghbetYTfeupg8++OC0du3adO2116YNGzZU+69//evT9ttv75j7wmoGzIAZMAOzxkBPogeRgdjYvHlzeuc73znB+WOOOSa9//3v70qQTEVc9CJ6nvWsZ6X3ve996cwzz5zg91R8GfS6e+21V7ryyivTYYcd1rbfx4wtTHx76c9zn/vcdOmll6a3vOUt4wQOYoc0BBBlerHtOr2LUMfOsTMDZsAM/JmBKYue6667Lu26666tiYyVlMsuu6xaWelmFWYqA9GL6JlKe8NcN652lfqxz9jcagzPHFuc+FJGaaXypTQETztRQx6rP6W6TvNF2QyYATNgBqabgSmJnmuuuSbddNNNiUcXcvTlL395WrduXbr++utbKz0LFixIp5xySrrllluq1aH169dXKw6kn3/++ZWN5z//+WnOnDnp3HPPrSbGZz/72S2bsn3AAQckRBarSKxa8I3C6qUvfWmVzwoU5V796ldXNuKEv/vuu1f+rVixIr3mNa9JmzZtSq997WtbbZ1++ulVXYScVkdoD5+PPvroykfZw3f6hPh629veVgk98vCXvpCOAEQIqg9sFy5cmN7xjne04nHVVVclVqDmzZuX3vrWt1Zt0Qdiqza1uoZN2aIPxJo+ySdW3hSjCy+8MO28886tPGzyVR3ZYbtl7Cnpm2NPTV8c26n6sk9aLNNun0darObEMqTxjWmUydNivvd90TMDZsAMmIHpYmBKoodJVV8EDE4iGpQmQbLjjjum4447Lu2zzz5pzz33rMQKE/Muu+ySXvCCF1STO5M1Ezci4sgjjxw3UWIXEcQqAUJnv/32S4cffnhVVm28+MUvrsTCaaedVtnFD0QDYkqCgHd6ouihffw455xzqvae8YxnJIQcddXeqlWr0pIlSypRw+MZRJ3sXXHFFemZz3xmVZd2aA8hgr+saiAu3vzmN4/rC2KIMoitt7/97el5z3teZRuRtXz58iodAbXHHnsk+kI5xFm3okfxOf7449Ott95atY/IOvTQQytRduyxx1Z9Q2DlUB04Nj/9aOxp1Zf9PL/dMWOTv7NDPPnGepRhRSimed8XODNgBsyAGZgJBqYkelh1YJWEVZCXvOQl1WMuJj/SyJMgyTsSVyjIY7LHBiseF110UbUSktfhXRQEwKte9apqwkQ8IEjUxoknnliJDD1eQZggUqgnkZKLHtpA4CB0mJwRNPjBlnrUpy7lJJZoR/aioEH0IfaY0JnYicENN9xQia7YFwkt3imiD8pDGCKiLr744iQBqbKIsm5FjwSj/P2Xf/mXqg35TAzUZr790NiO6ZaxHdKqsSenD479TW25vB7HpcdWrOrkqz91ZUs2neaLoBkwA2bADPSTgSmLHh6fXH311dXqBS8wM/kxWUfRw6oCkzHlEBU8LoqPWHbbbbfqcRiiBsFR6iBig5UUVkCUH9tgX49v4pZJPk74EgNakUFEsbrEltUmfKRP5Ec72ic92pMvbBE69GvvvfeuVo8QQRIwKveP//iPlZiSOFG6/JJIIT0KnbivOlE85j7JHnGhfJ4vG9r+zdicdPXY9oktX4QPW+V32k5G9CAmO9lzvi90ZsAMmAEz0G8Gpix6cOiEE06oxA6CQb/mioIEMcREx7s/TN5xsqY+Kz0IGlZGLrjggglCgTKIBH52zns7HOcrPdjkUVV8qZpyfOOELzFAefIk2ljxYdVI6YglxBArWLKjbbSnNLa0jQ8INH4hhgiK+eyrfdqLee1Weigr0cPqllaIWAGSeMx9Ujvdip7oSy/7iJ788VZppYcyJYHUS5uu4wuiGTADZsAMTIaBvoge3rG5+eabx4mEKHoQAQgW3k2hLO+daLLWOz0IH/JVLu/EvvvuW60S8fgIG7zwy8qQHm8x6SOszjvvvOo9mRe+8IWVGENMREEgMSBxQzsINfy/8cYbWyKHd48QYatXr67a490bxB3v+kR7uZ8IFFazED0lAcbKDy9A00/er8Eu7/bUvdOD8OIFboQOMeX4n//5n6t3mmhHccx9Uj8lejRGPFZ7+tOfPk5w5X3o5XgyLzK/4Q1v6Hv7vfjsOr5YmgEzYAaaxUBfRI/eZ4mPc6Lo4ZEUQofHWry3gzBhsmbC5x0e7vwRE/zKCZHBOzb8mimHkfds9HiMFaFLLrmkJXoQBbzczIoRj6IQRLwIjG9REEgMRNHDIzXK57+0YlUJ3/Cbl4LpEysu0V7uo2zp5eg8n+OnPOUp6eyzz65sYpsYIETyX3WxaqRfoFEPISd/EH/Y6Fb0YJtfxtEeYq4kyEq+TiYN3/ROVamefrKerwiVyjqtWRcij7fH2wyYgZlgoCfRMxOODWsbiB6EWd27ScPar278lqjhsVYUNuyT1kkUddOGy/jCaAbMgBkwA70yYNHTpz8HzsvaL3rRi6oVLVar8r/N0+sADVs9BA6PrxA4PG7kv6NgVcp/m8cXqWFj2f6aWTMwegxY9PRJ9PDiM4+OeIwXf2Hmk2b0ThqPqcfUDJgBMzCcDFj09En0+AQYzhPA4+ZxMwNmwAw0hwGLHoueCS+M+wLQnAuAx9pjbQbMQJMYsOix6LHoMQNmwAyYATPQCAYsegx6I0Bv0p2M++o7dzNgBsxAmQGLHoseix4zYAbMgBkwA41goCfRs+RVy9PSDY+kQz+U/HUMzIAZMANmwAyYgVlhAC2CJul2Zasn0UMjO/7d/l030q0zLldejnNcHBczYAbMgBkwAxMZQIugSbqNTU+ihxWebhtwuYmD5Jg4JmbADJgBM2AG+sPAZDSJRY+f41rAmgEzYAbMgBkYWgYsegzv0MLrO5/+3Pk4jo6jGTADTWHAoseix6LHDJgBM2AGzEAjGLDoMeiNAL0pdzHup+/YzYAZMAP1DAyM6NmyZUvSZ9u2bWnZsmWtyZh90vg8/vjjadWqVV3leeDrB96xcWzMgBkwA2ZgVBmYt/hJLZ0Q+zgQogdRc++997YcRABt3bo1LV26tPqyv379+iqfrUQR+XV5sZPe94ltBsyAGTADZqAZDCx56f9M/3TWf29pijjuAyF6okPss5LzyCOPVKs97D/00EOV+CEvCp12eblNHzcDdo+zx9kMmAEz0FwGEDwHrfxvaaBXenJAWc158MEHWys72lc5jlkNiuXyPB1721z4PfYeezNgBsxAcxjoJHhgYeBWeli94fEVWxxE3OSihzR96/IMenNA91h7rM2AGTADo8/A0/b6X8VHVox9N4KHcgMlehAyepdHALdbzWmXp/rejv6J4DH2GJsBM2AGRp+BfU/467Tv8X89Qfh0K3hgZGBEj1ZucnARNlEIxXd62uXldnw8+ieEx9hjbAbMgBkYbQZy4TMZwQMbAyF68heSI7RR5JAehU67vGjD+6N9Enh8Pb5mwAyYgeYwgPDhZeXnHPw/2r60XGJiIEQPQqb0IR2nEUX8fR4++rm6OtMuT2W8bc7J4LH2WJsBM2AGRp8BCZ+6X2nVMTAQoqfOOaePPrgeY4+xGTADZsAM9MLAZAUPbVj0+L+hmPBSWC/wuY4vWmbADJgBMzDoDFj0WPRY9JgBM2AGzIAZaAQDFj0GvRGgD/rdh/3zHbIZMANmYPoZsOix6LHoMQNmwAyYATPQCAYsegx6I0D3HdT030E5xo6xGTADg87AtIuepRseSTv+3f6eWC2uzIAZMANmwAyYgVljAC2CJulWmP1VtwVjuSWvWl41grry1zEwA2bADJgBM2AGZoMBBA+aJGqUdvs9iZ52Bp3npVAzYAbMgBkwA2ZgEBmw6PGyZNcKeRABtk++sJoBM2AGzEC3DFj0WPRY9JgBM2AGzIAZaAQDFj0GvRGgd3sX4HK+YzQDZsAMjC4DFj0WPRY9ZsAMmAEzYAYawYBFj0FvBOi+cxvdOzePrcfWDJiBbhmw6LHosegxA2bADJgBM9AIBix6DHojQO/2LsDlfMdoBsyAGRhdBix6LHosesyAGTADZsAMNIIBix6D3gjQfec2unduHluPrRkwA90yYNFj0WPRYwbMgBkwA2agEQxY9Bj0RoDe7V2Ay/mO0QyYATMwugxY9Fj0WPSYATNgBsyAGWgEAxY9Br0RoPvObXTv3Dy2HlszYAa6ZcCix6LHoscMmAEzYAbMQCMYsOgx6I0Avdu7AJfzHaMZMANmYHQZsOix6LHoMQNmwAyYATPQCAYsegx6I0D3ndvo3rl5bD22ZsAMdMuARY9Fz9CJnoMPPjitXbs2XXvttWnDhg3V/utf//q0/fbbD11fuj1RXc4XdTNgBszA1BkYOdGzcuXKtGbNmrTTTju1nQAPPPDAtHHjxnTEEUe0LTedkO2xxx7pyiuvTO9///vTihUr+u7HQQcdlP71X/817bzzzkXbMVZTicdhhx2W1q9fX8UTO9MVs+c+97np0ksvTW95y1vGCRzEDmkIIMpMV/u2O/ULjmPoGJoBMzCbDExJ9MyZMyede+65afPmzeltb3vbpCYbJserrroqHXDAAZOq1ylYcSJvV3Yyk/yJJ56YLr744o5Cql17pbwLLrgg3XDDDVUMmLj32muvSgQhIkrlJ5v21re+Nd10003pRS96UdFejNVk4hH92HXXXas+vOc970m77757mjdvXrGtWKfXfQRPO1FDHqs/vdp3PV+MzYAZMAOjzcCURM/zn//8dP3116err746XXbZZWmHHXboesJhhYWVln6vDMSJvB28k5nku7XZrr1SXm53Mj6V7E02Lbbfa9sInXXr1k3LSlXsD4+0WM3J00iPaZTJ02K+90f7gubx9fiaATPQjoEpiZ43v/nNleDR442Xv/zlrQkoFzVxciSP1SF99TiKlY7Vq1dXj3tuvfXWdNFFF6XddtutZbPUEVaKrrvuuqoOj4r4yh7lX/rSl1b5tEW5V7/61ZW9fJLXKguPmnhUc/TRRydWshAG8pMtj6FYzTjhhBMq0Ub5Oj8XLFiQTjnllHTLLbdUNrBLrHj0ho/RLo+hEIFKQ0gQM4TkmWeemYgH37PPPjs95SlPqfIoQ9usFsU+K074KjuktYtVt/GQbbaqk/vcbhxV5/zzz6/iQnyjzbp9VnDyd3ae8YxnJL6xDmVYEYpp3vdF0AyYATNgBmCgZ9HDZMzqzjvf+c5qYta+wGonepiYjj322GqSf+1rX5v+9m//NvGYhIkN0bLffvsl3kdhMkcE1a0gPfvZzx5X5/DDD68mUgmAF7/4xZWAOe2009Iuu+ySTj/99OpxDytUmnzxU3ZWrVqVlixZUj2q4/0QRNzTn/70SljwKO4FL3hBJViWL19etYOAed7znlcJvwsvvDAhctR/tjvuuGM67rjj0j777JP23HPPqm8IL9qgzwgW2X3a056WDj300ComxAaf5s+fX4kcPQJDtCBiiLlEJCtt+BXb1X4UPeqj4pvHqtt4yDbbhQsXpn/4h3+oYkqMaeM5z3nOuDHJx1HtXHHFFemZz3xm0e/YhvZLj61Y1clXfyhfKis73vrCZwbMgBloLgM9ix4mLybjl7zkJdXExcoHEzriAqDaiZ5SPgJi06ZN6VWvelVrIuQ9oZtvvrkSQZosWVXQY7G8DiszCBeJHt7FQSToPRBsIGaoJ3v4yTHppOGbBAX1OY6PgRAyTNik0R75iAtigXDjuO4bRUhul+PoE8d6X4Z6skm7tI/QoW8IOeXl29hep1jFtjvFI7ajWMnHvB3KlsaRVcJop9N+ScjUiR7GspM959dz6tg4NmbADIwqAz2LHlYb9FhDWx6/sHJDsCYrepg0eemWXzQp2LkNpWuLKMnrRIHCvnyLW+zGSZ62Y772NZFHm5rkVUbb+BhJ/vEY7Mgjj6xWgni0xaOwWC7apU70KR6rDW0RdbycjC35qDbjljy11ylWse1O8YhtKB7yg20+JnEcYzvRTqd9RE/+eKskeihTEkid7DvfF3kzYAbMwOgz0JPoYTWHVZ2TTjqpWhVh4uMxz+WXX570mEcTHe/UABKPrFi10eSofCZB8utWCBALe++9d0sIRSgRFKz6qI18pYe28LO0AhMnX3zhvRutWsU22I/iRO/j8Ks1rfTk5XV8zDHHVCtI/A0Z6uGPREhul+PoE8cSFKyiyaa2ylM8lR63sb1OsYptd4pHbCP3o9M4xnainU77k3mR+Q1veMOEeHWy7/zRv9h5jD3GZsAM9CR6WM1BJDCBRYiYZLnLj+/M8LNs3mlBOMS/R/Oa17ymejGXRx8IgvydE70Lwguv+bsyanPfffet3tnhxVVEFT/R5hGZHm/hH486zjvvvEqUvfCFL6xeQOYRVZx8ed9G7w9hBwGH0MAn2jrnnHOqflGH91joJ2KLd2+Y9JmQERXyS1tWVyhHX7HL+zTtRI+EIS8u8y4R/SZ+N954Y7WCRltHHXVUesUrXtESRN2Knm5iha8Ink7xUP/Y5qKn0zjGuEc73eyzgqNHlaXy+sl6viJUKus0X/zMgBkwA81jYNKih4mY1Zxrrrlmwi9neB8H0YFgoNzJJ59cCRsmU606aJLmD+a9973vrYQQ76ggRHhkgzBAHMVfKrUDk5UFPTpCIFxyySUt0cNKDC/sIsR4NIRvvHCLb/nky2oRk6raRqQhxmibPNlAyPBi9RlnnFHZwy55CJvcz/jHB3lhGfHVTvQgqFhBwge9I8TLvrynRDxIx8f9999/gtjI2+ZYMUeYcNwuVpOJR2wrFz3ktRvHvJ1oq9O+RA2PtaKwYZ+0TqKok33nN+8C6DH3mJuBZjEwadFjQJoFyKCNNwKHx1cIHFbx+O8oWOnz3+Yxl4PGqv0xk2Zg8Biw6GnzaysDO3jAekw8JmbADJgBM9ArAxY9Fj0THsv1CpPr+UJkBsyAGTADg8yARY9Fj0WPGTADZsAMmIFGMGDRY9AbAfog33nYN98ZmwEzYAZmhgGLHoseix4zYAbMgBkwA41gwKLHoDcCdN9FzcxdlOPsOJsBMzDIDFj0WPRY9JgBM2AGzIAZaAQDFj0GvRGgD/Kdh33znbEZMANmYGYYsOix6LHoMQNmwAyYATPQCAYsegx6I0D3XdTM3EU5zo6zGTADg8yARY9Fj0WPGTADZsAMmIFGMNCT6OE/4uR/Muc/29RX/7P5ICs8+zazdyD8j+38x60x7vwHpfE/c4153p/Z8RmEeOtaknMi30hXHv9ZLf/Xmv4DXZXxdvS5ESeab/QfV8/W2JeubbPli9udHP89i57Vq1dX/1O5Ap7/j95K93ZyAzJK8SpdGCx6mstDiW0mM64l3DTlYgaRw38se84554wTziU73aaVmOy2rsvNHrsI3yh0li9fnmBntsbEHM0eC1Md876JHhwBygjmVJ1z/eEFi7ErXRgseoZ7TPt9Tkr0IHzyawfHp59+ukVPwx+7iBFEcL/569Ve6drWqy3Xm9lrYl9FD1By8QJSoNBS5MaNG6tVIdLiYzAmQJarqccFTuW1nG0YZhaGfse7dGHIRQ9jDx8ae+rgR2QpP1YerK1bty696EUvGve4VTb63R/b6z+PmtC4c9e1gzjDCdcK0nU90LhTR/uIItjRNYa6lI8M6Jg0caby2KIdpateLBuvWWag/wx0E1PmB851uMjLw4KuIbFMN2MrDrDZjqloizpwJy7NyuwwkXPQ7fG0iZ7oAFAACOBwYQMu8pWuC1wJ6GjH+8MFV7wYaFJhq0kEDm688cYWD4y/RLAuQDDDuMdj9rnwYD9yZD6Giw/GK14TJE40pkx0ukaQVmKAMuSx1SQU7ZAXj6O92DbldB1CRMfrFHn+zn4MdD3R9YMxiUxwHMeXcRcfGj/yozCivt4T03VFdXKmxBfc4APHOUNqx9vZ56VuDPouevT8XWBoshOogCSodDFSWZWpc9bpgwtSaWziBUj5TCy6WJAvFpQvPvKLWTyO+9TLL1ay5e3g8xInDfFSStM4azWoxIDydF3R+MdjtUEeLDIB6hrFVnf+1ImTo2x5O/tMcY3QXMF4xvFjnzyt/jLGccyoS52YJj7qmNI1K9qKHJmV2Wcijmen/b6KHgYfqCRiBFeESQC98IUvbE1+clKTF3aU5u1wARXHK14YlK7xhxHy4UV5bDnmG5khPR7H/bwuFz1xF/O8P5gcRYGjfR5p6eYpMhTHPe7nfGgS05jH42gPFpkg42SmOmxJR/hogo153p89nsQJDMTxjGOS86E8ri359UF85HV0XBJQebtmZfZ40Nh2u+2b6AEcXRwAQI8pcATQlMcxFzSeiZKeO0rddheivLyPBxe2/MLAWDG+sMKFi4tK3eOtdgzpYoSNfPxLbeZlfDw4zMQJjHHhmhCFaxzPOO5xn3rxGBswRjocIVyww3G0R9tca0rXIcryzf1TurczxxBjwHzBlrjHawPjHq8hGpe6sWX84woe9ePjLa0WYicyBU/iRLbFWGzTj0VnjgvFfbLbnkUPF4u4rJgDoIsXZQAhwpSDpwuT7OkCNdnOuPxgARcnGI0NYw0ruoBRRuPONo59HUPxYoTdaCNe0NSmt4PFRRwPOIgTRYkPXVviuMd97MXjeD3RSo24Up4eY+lYDOqGK17fNNlFv70/s0zFczy/TuR5Gq98bMVAvK6Ig5yh/Djaoo5eZJYAEj9q23zMLB+TiXdPomcyDZTKAp8uZKV8pw0uMB4bj40ZMANmwAwMKwMzLnqkjKW6hzVw9tsnvRkwA2bA8xV+zwAAIABJREFUDJiB4WJgRkWPliG9BDhckPik9niZATNgBszAKDAwo6JnFALmPvjENwNmwAyYATMwnAxY9PgPj1W/iPAJPJwnsMfN42YGzIAZ6J4Bix6LHoseM2AGzIAZMAONYMCix6A3AnTfCXV/J+RYOVZmwAyMKgM9iZ7ddtstHXbYYenII4/01zGoWICJ/CQxJz4/dI3gemFGzIN4qNuaEzNSx4bS6xjJ55+6455ED43uvPPOEya5ukacPtp3DbAAE/k4m5PRHvd8vNsdmxGz0I4P5ZkTcyIW6rZ1jNSVz9N7Ej0ortyQj5sNa4mJUpo5aS4nJR5KaWakuYww9iUmSmnmpLmcTIUHix6/09MXAVuCsJTmC5UvVJEBM9JcHiIHcb/ERCkt1vF+sziaCg8WPRY9Fj1moC8MdJp4SheqUlonO84f7QmuxEQpzRyMNgftxncqPFj0eMLry4RXgrCU1g5k5432RazEQynNHIw2B53Gt8REKa2THeePLkdT4cGix6LHoscM9IWBTpNM6UJVSutkx/mjO5kxtiUmSmnmYLQ5aDe+U+Fh2kXPsmXL0rZt29KDDz5YvLAqf8uWLcX8dh133uBAX4KwlFYaM8ZenzpOSvWcNjjj381YlHgopZVs6ToBJ48//nhatWqVrxcjKtZLTJTSSpz4WjJc14TSGHaT1i0PJVvTKnoAEMHzwAMP1IoeQcq25KDThgPiEoSltHw8169fn7Zu3ZqWLl1afdk3C8Mx5vlYdjou8VBKy+3ABlzACnlsua4ghPKyPh5+dkpMlNLysfa1ZPjHPh/TuuNueKirO62iR40yiZXu4Llbe+ihh6qvJ7rhBrYEYSlNTGgLF5rMSIsXLpXxdrjZ0PiVeCilqby2uk4gfkjLRZDKedtsTnwtGY3x7+Y87ua6UWdn1kQPFy4EDxc0YLXoGW5gSxCW0iKIkQGlw8Mjjzziu/gRfHRR4qGUJha0RQjnN02+Zgz39UJjW9qWmCilxbq+lowuD3Gctd+JB5UrbWdN9MSLVtwvOem0wQe6BGEpLY4ljycQOAgdpZPGoww/uhj8MdeYdbst8VBKy+2VVopJ843S6DHC2JeYKKVFTnwtGU0W4hjH/U48xLL5/qyInvzOzaJn+IEtQVhKiwD67mz4xz2OZ6f9Eg+ltNxOfr0g39eM0WWnxEQpLXLia8no8hDHWfudeFC50nbGRQ9wcidf+nAhKznptMEHugRhKS2OpVhgUlM6+/BBntK8Hfzx72aMSjyU0nJbORMlbvI6Ph5eZkpMlNLiGJeYyLmJ5b0/vHwwdp14aDe+My56Ss74rm24AayDsBsw44WpdOEq8eK04eSlxEMpLR/fnIvITF7Wx8PJRhy3EhOltFiH/chFzkxe1sfDzUk3PNSNsUXPCL4wWjfY05legrCUVvIB0auP39MY7otRaXyVVuKhlKbycct7X/x9Hj7+ufroMsKYl5gopUU+tO9ryWizoXHulgeVj9sZET2xQe+PJpQlCEtpHv/RHP9uxrXEQymtG1suM7oclZgopZmB0WWg09hOhQeLHq/09OXdmRKEpbROMDt/dC9kJR5KaWZgdBnoZmxLTJTSurHlMqPJ0lR4sOix6LHoMQN9YaDTBFO6UJXSOtlx/mhOZBrXEhOlNJX3drR5KI3vVHiw6PGE15cJrwRhKa0EsNOacdEq8VBKMw/N4KFunEtMlNLq6jt99PmZCg8WPRY9Fj1moC8MdJpsSheqUlonO84f7UmtxEQpzRyMNgftxncqPFj0eMLry4RXgrCU1g5k5432RazEQynNHIw2B53Gt8REKa2THeePLkdT4aEn0XPYYYelnXfeuS+TpcEcfjCf/vSnJ5jIx9KcDP/Y5mPa67EZMQvdsGNOzEknTuoY6VRP+T2Jnt12262a5FBb/joGiBuYEFTamhOzoeuDGTELYqHd1pyYk3Z8kFfHiOadTtueRE8no863WjcDZsAMmAEzYAYGjQGLHr/TM2GFZtAgtT++cJoBM2AGzEA/GLDoseix6DEDZsAMmAEz0AgGLHoMeiNA78cdgm34TtMMmAEzMNwMTEn0zJkzJ03la3iGGx6Pn8fPDJgBM2AGhomBnkUPYmeqHe2Hjan64Po+Yc2AGTADZsAMNIMBix4/3pqyePXFohkXC4+zx9kMmIFhZ8CiZ0REz4oVKxLfTkCuXLmyq3Kd7DjfFz8zYAbMgBkYNgYGXvTstNNOac2aNdWX/Rjgbif6WGe29w888MC0du3atPvuu4/ry1T96jYW3YqeI444ohjzqfrp+r5ImgEzYAbMwGwxMBSiZ/Xq1enGG2+csELR7UQ/W8EttWvR45O9xIXTzIUZMANmYPoZGBrRw8oDKySIBoGRix7yNm7cmDZv3pzWrVtXraaUREasV6qDfcogtlhlki21qy2rJrTFl3JaiSIdf1WOfaWpPFvaoAyrPrShPMqqbt02+k3bp59+essedbBdsodttVtXLtbFhvoS26yLSZ2/Tp/+k9kxdozNgBkwA+0ZGBrRw4TL5BvFBZOzJnCEQxRFKks6dTRxI0wQM9irq0MZ7CKgKFeCiLqnnXZalUd52pAvEjiqR9sSMtiLj7fyutTJhYnsaJv7jU18VfvqO7Zze9F2u3J5Xt5mni/fvG1/wjk+jo8ZMANmYPYYGCrRAyhx0maS10TPVsKCckzSCBG2sRwCAdEjYdOuTszrBGlsg3qIAtVhX7Zy0VMSD7mPWrGR4Mv7SjtqXyKqrn38oGyncrlfeZsxvuqnt7N3Ijv2jr0ZMANmoDMDQyd64oqDJnoGmn2JA221UhNFRBQk7erkk3wJprw+x5SLbXDcSfRIEKmNToKCdtSW6ihNYkYx0FaCKRc9ytdW5UqiR2W0VXzlg7edTzjHyDEyA2bADMweA0MneoBFE3J8j0WTfgkmhACrO6qHqKBcuzrk5WIk2s7zo63Jih4JDdmPIk1pcZu3TV4UM3p8F+tov9tyihWxo27sn2x5O3snrmPv2JsBM2AGJs/AUIoeBprJmxUHJmOOEQr8wottCQTKIQbOOeecVn67OiVhEe1KPJCm1RX5EusisHjpl/LyM77To3zVpUy0HdvUfu43x/GdHmzlQkp1o+125XLRk7cpe95O/qRzzBwzM2AGzMDsMDC0oqckFpio9eiFrYQGcEkYUCbCVlcnCpdYXvtqn3YQHAgqCZeYh+BZvnz5OF/wKwq2WD6mq63SNvqNwImrXpRXG9jjq35H0dOunIRcrBvbJD3Gt+Sj02bnpHbcHXczYAbMQJmBgRc9HrjywDkujosZMANmwAyYgckxYNEzIv8NhcGfHPiOl+NlBsyAGWgeAxY9Fj3jHvf5ItC8i4DH3GNuBsxAUxiw6LHosegxA2bADJgBM9AIBnoWPajCOXPmTOnbFGXpfvouygyYATNgBszA7DMwJdHjAZz9AfQYeAzMgBkwA2bADHTHgEWPlzQbsaTpC0J3FwTHyXEyA2ZglBmw6LHosegxA2bADJgBM9AIBix6DHojQB/lOxf3zXfmZsAMmIHuGLDoseix6DEDZsAMmAEz0AgGLHoMeiNA911Qd3dBjpPjZAbMwCgzYNFj0WPRYwbMgBkwA2agEQxY9Bj0RoA+yncu7pvvzM2AGTAD3TFg0WPRY9FjBsyAGTADZqARDFj0GPRGgO67oO7ughwnx8kMmIFRZsCix6LHoscMmAEzYAbMQCMYsOgx6I0AfZTvXNw335mbATNgBrpjwKLHoseixwyYATNgBsxAIxiw6DHojQDdd0Hd3QU5To6TGTADo8yARY9Fj0WPGTADZsAMmIFGMGDRY9AbAfoo37m4b74zNwNmwAx0x4BFj0WPRY8ZMANmwAyYgUYwYNFj0BsBuu+CursLcpwcJzNgBkaZAYseix6LHjNgBsyAGTADjWDAosegNwL0Ub5zcd98Z24GzIAZ6I4Bix6LHoseM2AGzIAZMAONYMCix6A3AnTfBXV3F+Q4OU5mwAyMMgMWPRY9Fj1mwAyYATNgBhrBgEWPQW8E6KN85+K++c7cDJgBM9AdAxY9Fj0WPWbADJgBM2AGGsFAT6Jn6dKlaevWrYnPZz7zmQmB2rx5c/rTn/5UlaFsLF9VSilt27YtLVu2LO2www5p48aN6ec//3lVh3rf+c530kEHHdQ2T6qW+l/+8pcrsx/5yEcm+HLAAQekj33sY+mXv/xlyz77t9xyS1V2/fr1cqm13bJlywQ77fycjv4RG2IUfTnuuOPS1772tfT73/++8vW3v/1t+vznP59e+cpXtvxVf771rW+lvffeu5We26MOdbHB5w9/+EP66Ec/2iqv+Hrb3d2D4+Q4mQEzYAYGn4Epix7EyrHHHtuaLBEZDz/8cDWZIoyi6GEiZvLl+6Y3vSktWbIkrV27tprEv/rVr6bTTjstXXrppdVEj+hplye4Tj755Eow/eQnP6napX3lHXrooYk2EQkPPPBAet/73peuvfbadP/996e77rqrKodIePzxx9N1113X8g2fZUPbdr5I9PSzf7lIOemkk9IvfvGLKq733HNP2rRpU7rvvvuqvn3/+9+v4oyvEj2IxzvuuKPVj2gPAUcM6PeHP/zhhG2E6q233toqr357O/gnscfIY2QGzIAZ6I6BKYkehMavf/3rdPPNN7cmy/e+973VCgViKBc9Dz74YKucBoiVjF/96lfp+OOPn1Se6t9+++0JP9atW5d+85vfJNpXHsKGlYzLL7+8laY8bSV6Vq1aVVuGsu38lOjpZ/+iSKF9VtToy8UXXzzOT4QKqzSIFsqpP9/97nfTo48+mlasWFGlR3vy9xvf+Ea1mqZYeNvdSeM4OU5mwAyYgeFkYEqi55vf/GbSd88996wmV1YflNaN6Fm5cmU1mSNc3vWud42bhNvlAZxWlRAEcZ88Vop+8IMfpG9/+9tJvpUglUjoJHra+SIRURI97eq1y+tWpBx++OGV6OOxF/1Tf1jV+uEPf5i+/vWvV4+5oj3KsVr0xz/+sVoBe+Mb31jVLcXHacN5YnvcPG5mwAyYgYkMTEn0MMlff/311QrLueeeWz3m+ulPf1qlkZeLntZLMym18hiUs88+u5q4eSTDRK3ViU55CBVWM2ibsnfffXf62c9+lo466qjKF/I++clPtiZ0fNJHviES8g9pJVjq/JToiXZkv1Mf6mxGkRL3c7/UtgSXRA+xWbNmTSUoWQ3KbfBo8bbbbqvyWSni/Z74aDBvx8cTTx7HxDExA2bADAwXA1MWPbw3wyoNj394xCLRURI98Z2XI488ctyqjt7vQahgg3d+BFNdHis8+YfVC4TYwQcfnH70ox+l+Ajnda97XTr11FPTj3/845bokkiI7/Tsv//+rbblg7YlXyQ8+tm/KFJKfZE/WunhnSXS1B9ED+/u3HvvvdW7QHrsGF+MpjwvNH/iE5+o3g3iPR/qyLa3w3Uye7w8XmbADJiB9gxMWfQQYFZYWOFB/OjXXCXRo9WIdoNy5ZVXVhMw7+jk5WIeqzmIIyZxBAJfXsjlpV4er/FIi0n8scceS+ecc07LlgSKVmKiSMjba3ccfZHNfvYvih78UF/e/e53t/pCOqs4vKiN0OM47w+PrhiX733ve9X7V7noUR+/8IUvVKtm8aV05Xnb/iRyfBwfM2AGzMBwMNAX0XPWWWdV4oIXbfWoqSR64koIkzorKnfeeWf61Kc+VdVjQmdy5oXkM844o20ekzyCJn8Xh0mdF6P5VRciCGGEX7zDwnsu/FqJl69z0RNXevJVKGBu56dETz/7l4se/XoL3z/+8Y+P+/UWv3zTz9Nz0YPvPOb63e9+Vy2KER/8/dKXvlT9ugu7GzZsqF4+508FtFvl8kk9HCe1x8njZAbMgBkoM9AX0cOqil5e1kvDJdGTP4pigubv5cS/ofPII48kVlEYsLo8tccKBo934uBeccUV1coHq0+kH3LIIRP+Hg2PvW644YbqUQ4+5B8Jomi3zhfKSPTkdnrtHzZz0UPaCSecMO7v9CAOETHxXZyS6NFP1PGP8ggbVnYQg3xYKWL8+DtAsc/eL580jovjYgbMgBkYTgZ6Ej0e7OEcbI+bx80MmAEzYAaazIBFj//0uFd3zIAZMANmwAw0ggGLHoPeCNCbfGfjvvvO3gyYATPwZwYseix6LHrMgBkwA2bADDSCAYseg94I0H2X4ztdM2AGzIAZsOix6LHoMQNmwAyYATPQCAYsegx6I0D3HZ7v8MyAGTADZsCix6LHoscMmAEzYAbMQCMYsOgx6I0A3Xd4vsMzA2bADJgBix6LHoseM2AGzIAZMAONYMCix6A3AnTf4fkOzwyYATNgBix6LHosesyAGTADZsAMNIIBix6D3gjQfYfnOzwzYAbMgBmw6LHosegxA2bADJgBM9AIBix6DHojQPcdnu/wzIAZMANmwKLHoseixwyYATNgBsxAIxiw6DHojQDdd3i+wzMDZsAMmIGeRc/69euTPtu2bUvLli3ry+S5ZcuW9OCDD07ZFnb4Dgvk9Hm2/I2xivuDEjtY6wcTdf2p6/OqVavSQw89lJYuXTotHMV+RR/Yn87+5nGgLT60m+dN9pjrwNatW/t2PZiJ9hlfxpnxnmx7TSlPbB5//PE0lWt9ZLzfcZtt7vrdn8nYK12nuLZwHsZrl+aYdteX6RyjyfRpOsv2JHoI8iOPPNK6sHF81VVXDdQFowmD1y8wYqzifr/sT9VOFAdTtVWqX9fn0sWkVL/XtNivOh96td1tvX73cbYnn17at+jpfPfPhAmv3XJVKtcN473y2Mu4l3wcxrQSv4xXFKilMvQ1j3c3YzSMMYo+9yR64sU6Ghuk/SYMXr/iHWMV9/tlf6p2ppu3uj7nF4Sp9iOvH/tV50Nep9/H/e7jbE8+vbRfNyH0O9bDbM+ip7MwnM3xjeOjc4CVHgnVuvM8T5+t69BMxq4n0UNQUZEEqOQsA6CPyii4LCM/9thjVX3SVF+Dlge9zhZLrXyimpUttti57777qiW+vFycbCgbj9nXJ18epKz6Thl8UB/YlnzCD33oi3zL09R/8rkI07Y+qkce+3fddVfVb/KVl9cR7NTRN/Yt+h5jHvfVnvxQPDSWtKky1GOf+OCT8tR27p/8Jp+6DzzwQNUn1VX/8ZNxjOVjP+STTnTsqG91YxLHEH6oI//lL1v1k/b5yC550YeYjp3InfyjToxB3i/qyYe4T79L4537wHnV7hENdvSRTzE+sQ/Y5kudyFE8rvNL44DP+qhfeQzIx47So//ESsclm9Ev7OvDWNI/6mA3jpP6nae3i11dffzWJ/avzhexpPMiPy6106nfpTqRMfyjTN7fGAfy9I08xLqxrxov1ZGP8byr84HYKFYxTrqGd9O+6tN+tJGPu/xji8/xHCImqptzH/uqtugjPvJR+VJa3u8YqzhWOW95vcmMmfpJHbVHHIlHTIv79ItvKd6k112/1Nawb3sSPXQ6DpQGiXQCr2PK6MKlACtPgaeOThy2MZ19DaQCjR1sYpu0OJgqw5a6AlTHspXX0XH0N9qK+9E/pdf5FPulsqU08hQ3xZV2VIc8HbOviwS2eMxI++qD6nTaxvKxT3GftvjKFnkcxz5oX2MS7apepz5hV32iTmxXdeVHbl/+4gc2OMZG3ZjInsrl9eSzbMCQyrKVH7Fc9Iky4k5tkU/5dv2iXmxH+9RRbPBV403/SGeLbdpQu9G3vF2Osa1+5HGKdSkj32VHx3V+KZ6yH31WPNQ32eSYPF0rSI/HuU180MTNvuJDPWzpmDz5oTzyu41d9IH6+sa4xDLtfMnjHI/r/GzXb+rHVwzwLfrCMfWJ0+rVq8fFVv2I2zwmcdwoF/sc68lHjWmdD5SjjMpFGzE9xiVvN9puF+toWzbEBPbrzunYx9hW9E+2S2nKYxvr57HFd52rsRz1JjNmsT3aEA/yLcYy9k351I9lOCYv+gY/+BvbGvb9nkWPOi7oCQwDSJDyD3l5cOMx+QRbQWc/h0HtUTb/6AKoMtGO0gQTW2wAgfLiMek6QZQft2qfrdKVFv3CpzPPPLOKR/RPMYpp2BGU+Mc+5WQ/xkrllKdjysSTWflxq7blp3yIJ4H2KYtt/JGNGEO1S9+1EkM+9WNsqNupT2qTsqV2sUd75FM2/8hP+iN/68aECYDyMb6xffWVbYx7ftxNLOUv9rvpF+ViHfYVZ/bjcYwJ6diPokHlS+3Gccz7qHqxLaVFX+J+LBttq57i244DzpXof+xPbjMeYzvylueVWKG8Yo2PsS35rC39jNcDysJZ/pHNOl/yOMdjfMk/tBv7gj/xWDGVn8rH1/jRBJb3I9ZjX/7H9NhGPt4qF30ijeM6H6K9vBz2qR/j0mus5Zu20ffcX/pNfru2KMMnjm0pjfaUrjHgmK/6R5nIWx4H6nU7ZupfbpNVHuKodnjfNp5bcRxivLET80rHsc1h3Z+y6KHjGlQFmUDmAcmDq7J1A5LDKXtqS8d123zwor3cRn4sECUKSm0AseDM6+fl6TtlI/h5GnnYoW32iY/sxNipnPLyY/qdn6CUxR79oQ2Oo80YK+1THtv4o7ZKMWTZGFvUu+222ybUoW6nPqlNlY3ihbQY31hWfpXqxTqxXOy30uts5mV1LDHbKZbYl+0YO7UbfVS5WIf9fHx1HMtTTucTPsq+0tuNo/oUeVN9tVU6rssr9VO+tuOgV9GT+xHbV7vyX9s8vS52Ko9NJnK4zP1UGbbtfMnjHI9zf2Qz9oW0eJy3lefLRtzGfuTjDYv4EctHv0rtldqMPkZb7MseZbRiSXo8D2Jc2o1L7k+7dmPZvJzabteW+oEdXfNLadiKc4baVb9VJ7aV+6My2pIv9vIxUxltaSd/zIcP3JQielQ/+hPjjZ2YVzpWW8O87Un0MLh81XECRXA5Zqt95bPNg0saNhgMBkplY9BLtrADBGxVp7TFTgQw+khdLQVSt9ROBLNknzT52o1PJbhjGj4QD9rFb2yrXfJ0rHIxL44F6RxTTmXY0la80GBP8VE/KBf3sRHtkKdj7Gns8JkY/PSnPx03lmq/U59im9ShDdLYV121S98Yf9qXfbYxlhzXjYnsKWbUw57aizaxES8WOma1qJtYYiv2rV2/Yrm4Tx35ij0d40tkmDL5BVl9oQ5fHWNfx+oTcVG+trGc4iRf5IfK6jgvx7FipdhjN9bTMTa0j186z7EBq2ypF4/xRxyTR33xQZ721R7bycRO9fAdFqiLn3yVp207X2IcKI+f8rvOz9hP6sTjUp1SfOWbtrEfSmMb481x7q/GN9ZRuTg27Xygz3zz+Md4khfPuZgX224X61iO/eh7jCF52CFf5bSf29Cx+qBjtkpjq/q0A3vYz/tLms7VdvFSG3HMYl+Ury12aTPOp6RxXZZf0V/283irL7KZHyt9mLc9iR4NlJbwdPISiDxPF508uJSNYCiIMci5LfIox0DGj9Jlgy1pnDzAxSf6SD4Q6MM+37r2cruqF22WfFL/VJ4ypTT5Qz77eZkILPsqF+vF9hXz6Df7xEQfYqOLC+mKYdzP4xH7q7ZVT2Wjb7H9dn2KbVInlmX89PhM9igfP7RJHfxjq3IxJpSXr7AoLnSRUJ7qss2ZjcfRh7pYYoNyst2uX7Fc3K8bb9lWHOQDPsY+sK+xUdk4jrFPeb3oL3Ginsa3zi+NA2X1UR3sR5vkR7bxReOCUMIGabLJVjbI0zE29MnvdIll/MiXmF4Xuzxu1CnFM55v3fqiNmkDm9Ef/MXPTv2OdYgHtqiDP/qQrpVJpakftBu/tBk/ihVl8vFWvdxH0ks+4Bvtqu0YJ/b5UjfGnPbjMb51G2v5xzb6nvtLG6W2Y1ulOJfSYr/z8yWW19jrXI31aLfdmMW+xD6yLztx3HROxTR84UudGF/KxDzy8+O8zWE87kn0DGNH7fP4C5zjMVrxyC/mHt/ZH1+PyeyPwSCeB+Zidrmw6MnudgbxJLFPs3uSDEP8uSPTHesw+NsEHz25+bwtce5zdXa5sOix6Bm3xF06SZ02uydpKf5MqPljDJaqS2WdNjvjZ9EzO3EfNN59rg4WBxY9Fj2eKM2AGTADZsAMNIIBix6D3gjQB+3uz/4M1t2fx8PjYQaawYBFj0WPRY8ZMANmwAyYgUYwYNFj0BsBuu/imnEX53H2OJsBM9COgYESPcP2Vjt/A4G/uVB6gbSXlxixgz39/YZ2A9ePvHb+T8V+r+PYa72p+Oq65Qtk/Psdn/70p1t/YLBf8eL80B8t7MUmv1TjI2bY9mJnNuvEvxFT50c8R9mPf5Cyrs5MpeMPf1cp/u2cmWp7INrZ961pjK9vnIcqBgMleoYNnnhByn1vsujJY1F33C5+dXWcXhYp3Uygk4ndVO1NtX47X6fKzVTrt/NtMv3upux0+tquH93ktftDed3UH/oyFj1DJXbEm0XPFFR6uwuSRU95chZ4bNvFL5bzfudYdjOBTiaOU7U31frtfJ0qN1Ot3863yfS7m7LT6Wu7fnSTZ9HjlZ5uOBm0Mj2Jnrj0zRIzJy8d4wTVn5GPS54sPeujP6BGHX30J9QpF5eptYRNOZWhHcrwXxOQVsqTXbWVB73UtkQK/4GmPuoXefFvoshHXZDwRZ9YB/+oS/ulNvP0/M+TR79jfWJM2zGf/einyshHPYKLx9qv8199lq3cX40J8eDP/1OemHOsGLGNYyUuaFusEDv6F+vRVi/jn8ck2og+abzkj9pj/NXvOn5inClL32WbOmJANnVMGX3ydokR8aBM3ViTF2Op+NeVL/Udn2J52Yhxi/n4ecMNN1TnGv3mSx36jL+bNm1qnYcax1g/shPbkJ1os3TuxTrsR25kO8ac/bpY4ve///u/T+Aub4Pj/BqHXaXHR9CU03Gnfkeb+I6fsott9vURTzpHqav9/P9+U13a136dHXxpdd71AAAgAElEQVR97LHHKsaxR3nVUZtKYxvjrfFVebUR+0CexlbjCUOnnXZai5PIXIxJtI8N6vHROHdKo2zsQxyP/Noa+xXPRerrk/crxqXar1vp2fn56Ukn3p+edOp30pOW3ZPGFj/tz3He961/TsvSn/SqVWnsH06u6lSPy7DL8RHr/1z+iPVpbN7i1li1/MjKVXV3O6jVxthuBz1RJ/p06ndSK2/x0/7czkvP+nP7Oz8/jcWy0f8pLBC0fB4AGz2JHmDKgdAJCcR0UGV0ArBVxymjC4XS2AKcoMV+bIN0HbOvE0EnDe2V2or22ZdfSlebOqHUBuXiyanysQ2dOPKZYz1zj+Xq2qQ8Jxxb+aZ+qb3SNrenMuqLjtlim1hrXOIx+7RX8r/OlvoX26BsfuGQTbaxTxwrxtEX7JGnepRROeXpONqM4x99yuvkeTrO21Q/GL/SOydqT36KGx3jI+Mj+/mx0vN2S6xRNo41dRRL+aG2YjnqxXYpq/MtLxf9kG95u5HlvL+5PdmoS1d+yabGl7p18aB+zk3sK/uqG/utdkv1Yx77iq3GlDTscpzbzI/b9RsbfGMbOmZLXeVpvGJf434ctxjLdnZgR23U1ad9fWkvXp9oJ54TsS3VYStG1DfaKnGbxy72I/on26U05aldxh47ue/0Wz7EOFJPYxbbj3Zr90uiB8HwmiufECmIEERNiGu1H+qSj8BpCRvE0Yn3V+KDtCovChjZiuUQL8vueaIt2pVNfFr2//zZHnUpe/Qdfz7+S73Wu0nd+i8fhnDbk+gBGgACQg0m4OQfANR/dqcLkcpzQmiCUZqg5mQgHwiVF4FUOeXpmHq0k7elcmwpm3/UFvXUZmwvr1d38lAOW8Qi1q9rk3Lkyb/8IqB0tuqbfC/1UWPAVnXzEzwex32Vl/8lW4qzymqbp8fjuE/5GJe8fZXtdfzlD9t2scQH2NOHPlNHfZed/Jj06L/Kye9ONrptt26sYzu0FY8ZL/Ujr69+UoY6+Uf11B+20V7sc9ynHGOYXwvy+rk/2I524j514zFl9RHzOTdxnOI+tjjOrzOl+mqD+NA+9fAbG3xVh+uZBAnplInHMW6qq3LYxLbSVTaPj3whX+1Spm6fcvjdrR3aj7bkh/zSVnZ1zDYyl8da5eL4kZbbVz3KxfOQfuvaSh0+bGW3lCafFLNYn3ZUN46T7KgOW9iqm6tkY8I2CJdWXlhpqVZ6WNWR+JAwIY3vX8RQtY2iJrebH0toxHTEEWKLlRryo3jBNmVVj63q4hP+aTWqnf+x/hDv9yR6FDxdQIGIb4RMZbTlJAPIWEbQ62KmEwpAKRcvEPFEUjnZzo9LbdWVVXq0T1o8xr78jidPvHDIDuWIRV4fGyqjbe53tK0ybEknRtjluNRuLI8POvnzsvE47qu+/I/HspXnqUzej3gc9ykf45K3r7JTHf+8Hfmp9Hi3GrnN+5cfUz/3mTT5zX5eR8f0u5t22411bCdvN/ajjqO8Dsd132gvjlncj3XxjY8YjfVjOe1HO3Gf/PxYdbTNx0AxJj/uqzz2mFx1ncnrq5y2lMcOcVSa6vQqekp9UozajZfapUzcV52rrrqqJbqURjn5rW2sqzQeUZKurdK1xT/GVcdsI4OlWFMm76v6KTuql5dTftxSVtcfpcc0/OGYvNj/6Geel/sju9oSk3yuUt64rYRDPI/qVnbi6grlQ7mBEz2llanYxyHfn5LoAQABBChcWNiOAyMEqAR5HaiALJixF+HOgc6PKV9qS/7md36l8rE+ftAG5WI/477ymNioG+sTo1Kb1Fd5+Zaf4PItTpj4ogs4+aWvYoIfdXXb+R9tylZdP5SvOvGY/egrxxpX2ucuGQaoG+tNdfyxl9sgLY95LMM+fVQ/8mPS8TUKUOLL2OI7+bF/ysNmt+22G68YH7WldmkDf6Pv8VjpdWOofG2jPXyiz2zjvspqG+vEfeXHbbQT9ymTH8d67OfcxHGK+7FevM7k9WM59jXGii1p2NVx3MdWvO6163espzZIk33tR3+ir3GfMrTF+YNoUR1sdLKjstSnLuXxR+na5n1jXOK1hHrYUHlt8/HLY6J6ioHiqvr5lvy8jNKwpbzoL/t119ZYLm9Lx+oD70/FlTzlV9uS6MkfJen6TDqPlP6yolI90pqplZ7cpyjA8pWevKz8z1eSlD6E255EDxDrEyfzmE4+MALPLx96KP3ua19Lv92yJX38pJPS5c9/ftp6wQVp2+WXV9//OOmkdMr8+ek/3vGO6vuv8+enq/baK21917vStksvrb5bzz8/Xb3XXunU+fPTV048sfq+c/78xLc6fvvb04b9908/fc970rbVq6vvp/73/06nz5/f+mJ3+bx56f7zz0+P3X13evwzn0m/+8pX0uZLL00nHHts68IO0IKeLScJYoQPJxITAGl82SeNTxQssT72iEX86GIR0zm56k6wUrn8QhXL4JfyY7raIK+d/7FOnS2lU5avLgjxmH3aVPxUh7K66BEX4hHrxTzyY71YTrElTe1rm9tQGS6U+rDPlzpsNS6lY9mNPMA/E4dsM+6k8WGL37LZbbvY0ieOF+lqB1/isdoVg3nf43ka7dOO/FP/2JKmuESW477KydfYRu5PtM1+tBP387y8HsfEn7jQR47juMX9PAaKXUwv9V0+aBzpn2Kh9sVzvB7EehoH0vRVTLBHfnyROfpEvmIZ+xr3Y1uxD93Yyf2J9ZWnLXnxE8vGWKs823w8qRPjF+vFmNCOzvPIaLu0eC7mYxFt6DyiPD7m/aJs7gtliCd1VS/2k0dErUdY8TFW9ohIj5YqoRMebVUrPGNjf37MNZ2Pt2Aw90nt5aKnVBZx13TRM27gx8bSc+fMSUvnzk1vmzcvnTV/flqzYEHavGhR+uzixel7ixenrU9+8lB8/9/Fi9M9ixalTQsXpisWLkznL1hQiawT5s9Px8ybl147b156+XbbpRdvt1163nbbpb+dMyftEC5qeVx8PH5iHtV4xIv4qPbR/XpCvIxKLHJxMir9KvWjSX0t9d9pT5y/Pa30EMB9t9suvXvBgnTvokVDIWimU3h9/8lPTp9evDhtWLgwrZw/P/2f+fPTofPmpb+bM6d1l9dU6LiD4juq/ecOkDtMLqqj2kf364kL5ijFgvMyrsCMUt/yvjSpr3nffTz+/J206GGFg5WcyYiIBxYvTnctWpTWLVyY3jN/fvUoC2GQf1lR6eZ7/Pz5Kf/y2KrTl/Z43LVywYKqD+sXLkwfXLiwEizfmabVKMQQfT5s7tz0jAaKoFEUPUwU+pQeY/giM/4i43gMVjz0GEePjUZxfNRHnaej3NdRHL/p7NOkRM/Bc+em/6/wuOqTfxE058yfn5bNm5deM3du9Qho1zlz0oIhmuifMmdO9ajuH7fbrlqpOWbu3EqE8d4Qj7ouXbAgXb9wYXr/woXpozy+W7QoPViIRztBeMfChdVjQB6NTefA2vZgTTQeD4+HGTADZmD2Geha9LBKkk/mF86fX4mbpg/k3LGx9Jzttksvmzs3IZRYTbpywYL0lQ6rR6sXLEhnzp+f/m3+/OpdqLPnz08Ix3P/IrIQWth6y7x5CcHJI8VnWSxZLPo9MjNgBsyAGeiJgY6iZ87YWLooe5y1ZdEii50ugfv77babIBZz8TjZY14QZ0zeMG9eYjWt6aLT/Z/9uyePgcfADJiBYWCgrehZNDaWbl+4cNykfd3Chempnmi7Fhq7zJkzLn6TFTjdlL970aLq/SjaGgbo7KMvjmbADJgBMzAbDLQVPauyR1o8ipkNJ4e9TX7irhe09bI1P++PgpJHWG+eNy+96S+PyPiJPF8eK543f366ZsGC9H8tXNjxkdm1CxemV8+d63HqciVu2Nmy/544zIAZMAPdM1Areo6cN2/cCsVR8+Z5Ip2GiZSXpvlOBtoXbbdd9Us1XqouvVjO6hCC6nUWP5OK62TGwGW7v8g4Vo6VGTADg8JAUfRsNzaWvhp+lcQLtYPisP0Yf/LwzhU/h0cAlR6FfWTRovTPFj/mdxoEu8/F8eei4+F4mIHBZ6Aoel4/d25rAuV9ESZWD+bgx4CXms+YPz89VPjVGKKIl6o9joM/jh4jj5EZMANmYHoYKIoe/rKwVg14B8XBn57gT1dc+XtDK+bNG7dap/Hkr2j7Z+/DNZ7TxYntmgMzYAaaxsAE0cMvtjRBst3ZvwgaWtGH+OFvAMXxZJ//D+0d8+Z5Bc8rmEPLdtMu1O6vxYkZ6A8DE0TP7uHvyvCXlusCvd/2L0tnL7kmrdr1lp6+1MVGnX2n92eAieNe/NchYfVOIoj/IuONXskzgxZ/ZsAMmIGGMDBB9LwkiB7+u4U68YFo2WXBc2rz6+opnbrY0LG3/RM5dbF82XbbpdsK/0Es48xfk66r5/TpHxvH2DE2A2bADEw/AxNED/87uFYCWB2oGwRWeOryuk3vh41u23K5J2DizxHw/4ZpnLW9fMEC/8/wDbnb8fnwxPngWDgWZqA5DEwQPccF0XNWmz9G2A/B0g8bvcC6YsWKtHLlylrRRh5lerE9HXV23333tG7dunTEEUf0zSf+vzBedv5+9ksv/lTB8/0rr77FeTp4sM3mXKA91h5rM9BfBiaIHn7yrDt//opwXcB7FSyvfOUrWza7sbHTTjulNWvWpM2bN7e+HJNe51un9GETPZ36M5X8JXPmpJVhzBn7/3vRIr/A7hWfns+vqfDouv29wDuejqcZGM/ABNHzrvCfi7b7K8zdCJY82Bs2bEh8ld6NDcTN6tWr04EHHtiqp/q9bi16xkNAHPmvMv4zrPrwv7v3Gl/Xmxhfx8QxMQNmwAzMPgMTRE+862/3y55uBEsc4FzwkNeNjXaiR+KFx1GsBG3cuHGcOCJfK0Q8HuIxEe3m9SgTHx3lj7dkn3LUjf2K+3Xl6tKjf5TBlh5lxf6Qtnbt2nF9izZj3xCHlF2+fHmr79Fn8okT9mM92j4k/FFKVnwW+M8V1I51HHfvz/6FzGPgMTADZqAbBiaIngvDo47D2/yipxvBIgdKgoe8bmx0Ej1RsDC569EX9U4//fTWYzBEgoSFxIaEDkLgxhtvbIkKykkosFU9bGJf9dQ/trFcXXqsjw35qvIxX2lsc9FDW7FutCVRI59j33I7sQ3t82hLjzf38bs9Fj1+zGcGzIAZGCEGJoieS8LjrXb/YWUuWO68887093//9xPgqBM8TLK5DU28cSshgLjRtyRIqMMEzyoHk3u0wT7CQEKgJFCi0NF+SSRQV+3HNqLwUHq7+nW+qm3ZYBvtxH2VIUZ6BJjbVfzwL+6rbr5dE8bfP2P3nVPOh4/NhBkwA8PMwATRc1mY9Pj5el3ncsGC4Hn44YfHCZ92gge7uY1SW3FCz/Nz8YIgYAWELWWZ6CWU2LYTPVHMSHhgh0dA0Ua0U/KHfK3CdKov/+JjJgkT7EhcYUePt9iPfZQP+Iy9XPSQrzz2o0+UV31t439BYtHji5u48NYsmAEzMAoMTBA9vMCqxxuT/fVWFD6dBA/Bm07Rw4Qu8UFbHLcTPVEYsI/gqBMYnQZeYqzb+rmv2Jf4IQ87UfRoX35EYdhJ9KhOtKk0tp9dvLg1/vx17pjnfV/0zIAZMANmYJgZmCB6jgkvs/KfU9Z1rk6wIHweffTRcb/SmqyNWD5O6DGdfYkLpUeRkechZKLoiS89IyziaotED3ZjPbXTaRtFTDf1S0JFbUt8RaGDzVzQ6bhki/L4FP2OokrpO4T/d+2Lixen7UboOa766K0v2GbADJiB5jIwQfS8PPw3FDf2IHqACfHRDVR1winW1eQcHzFJoOTCJoqevF4UH9TjHRiEAnajAKJtylKG/dxOXla+Ul4+yr929REhKi+beVv4gY3Sqgx5qi/BQ9l2ogc7+KZ66qP68I9h7D/Y5q9xq7y3zb1weOw99mbADAwjAxNEz9/NmdN6vLGlzX842o1g6RSQftjo1Ibzuz8x3xr+GvfKNoLXMe0+po6VY2UGzIAZGBwGJogeBoe7fL3X8281f6SuH4KlHzYMU/9guiv8XN3/FUX/4mpGHUszYAbMwGAwUBQ9/CVmiR62byv8iqsfgqUfNgxSf0B6bRjzBxcvTvP9hwm7ekRr/vrDn+PoOJoBMzATDBRFDw3zP25H4cNPmV8Ufs1z9pJr0i4LntPzxEBdbMxEJ91G+5Ppn8PL64x5u/9o1rFsH0vHx/ExA2bADAwuA7WiZ+c5c9Jt4XGHBNDNCxemw+bOTftt/7JKtLBa08sXwYMNwzF7cCwaG6sEjsaWLY+4PCazNyaOvWNvBsyAGZg+BmpFj4L+9vB3e+Lk+MDixenc+fOr/6hSZb2dvoHqd2wRrp/NRC3/BQX/63q/27K94eHCY+WxMgNmYJQZ6Ch66Pxe222XLs0ed0UB9MlFi9L5CxakV8yd63dBBvxv2/CCcvyvJjSOpI0y6O6bL+RmwAyYATPQlegRKM+YMyex8sNP2TVZ5tuHnvzk9L4FC9Ix8+alXb1qMDBC4ulz5lQrc/l4sdrT7v9Y09h764uFGTADZsAMDDsDkxI9sbMHzJ2bLliwIH05/LcF+YTK8X2LFqWrFixI/2f+/PRPc+f+/+2di6+cVbnG/wfame6ABDVeUASVoIJAxB5RDwoFUbFFKwqFYkuAtnBKL7GlokCxcmtBKKXIpbUlXIyXqIlRwjEaEwLnYAAveDkqaBS8gvd18lvhmbx79Zvp7D2zZ3+737OT2ev7vnV713qfed9nvWvNTOJbf2M7vp7a+eBblS9otdKTBxywB1HlwPKY9WE8GgPGgDFgDDQEA5MmPZGs8E2+q9rtfAi2iviUzzgsu3lsLP1Xu51O51D0rFmJg9OxTV8PToY+3GqN+y0t6WHr2Fg6NnwSz3M9+Fx7Dj2HxoAxYAzUHwNDIT1R0fxI5aJWK20bG0v/WxFdkOOtSv9n//3TPWNjacucOYlfe9/Ybudo0rp2O61pt9OKdjud32qlJa1WOrvVSue0Wmlxq5W/R4hnS9vtxI+kElWiHBGOha1WIirFVtt+DWCyR82alda224mD5uUc3zs2lubNnm1y2QAcxPekr+tviK0j68gYGA0Ghk56SsUdvt9+acHs2fmg8/3hm55LhzyK+/874ID03/vvn3aNjWVSxS/KL2+18mtZq5UufIEoQZg4uwSB4gWZglTx4qcaIFoQLl6QL0jembNnJ36sNb9arXymiS95JNpCyhkn5Z/1Qh21QZt8AeQexO0F8oZcyCdZIX8Xt9s5UnZJu52uaLfT7rGxSqLDvPLL6chR6sb3o3mTeZ49z8aAMWAM1AMDU056SkVzhoQvOeQj0zhxPhV239hYerQiMjEKIrQv98GBcwiVfy29Hm+28r3ge+vFGDAGjIHRYmDkpKeXgvl02NxZs9LJs2cnfhaBCBFREiIpREGIwBDlIELDIVx+F4xtL148I+qx8oUoCOUgVVfNmZN2jo3t8Z00+yrZeWL//dOmOXPSf3oby5Etb+MZA8aAMWAMjMNArUhPL0I0jDx+T+qwWbPSf8yalebPnp23rjj3E7eOIEoQpote2D6CREGmOKgNseIFyeLcDKQL8sVrfbudPxK+od3OW3l8b9Flc+bkM0mk3JPHFzpyRkmkjXbUZknckEHkDbni9hvnlrT1xtYZ55YO9mHwceAeBmbcxmhXYZ5vz7cxYAxMJQYaRXqmciLdtt+oxoAxYAwYA8ZAvTFg0uPQn6MjxoAxYAwYA8ZAIzBg0mOgNwLoXn3Ve/Vl/Vg/xoAxMAoMmPSY9Jj0GAPGgDFgDBgDjcCASY+B3gigj2IF4T68UjUGjAFjoN4YMOkx6THpMQaMAWPAGDAGGoEBkx4DvRFA9+qr3qsv68f6MQaMgVFgwKTHpMekxxgwBowBY8AYaAQGTHoM9EYAfRQrCPfhlaoxYAwYA/XGgEmPSY9JjzFgDBgDxoAx0AgMmPQY6I0Auldf9V59WT/WjzFgDIwCAyY9Jj0mPcaAMWAMGAPGQCMwYNJjoDcC6KNYQbgPr1SNAWPAGKg3Bkx6THpMeowBY8AYMAaMgUZgwKTHQG8E0L36qvfqy/qxfowBY2AUGDDpMekx6TEGjAFjwBgwBhqBAZMeA70RQB/FCsJ9eKVqDBgDxkC9MWDSY9Jj0mMMGAPGgDFgDDQCAyY9BnojgO7VV71XX9aP9WMMGAOjwIBJj0mPSY8xYAwYA8aAMdAIDJj0GOiNAPooVhDuwytVY8AYMAbqjQGTHpMekx5jwBgwBowBY6ARGDDpMdAbAXSvvuq9+rJ+rB9jwBgYBQZMekx6THqMAWPAGDAGjIFGYMCkx0BvBNBHsYJwH16pGgPGgDFQbwxMivTMmzcv/epXv0r8ffvb397Dad59993p3//+dy5D2Vg+V0op/elPf0qLFy9OBx54YNqxY0d69tlncx3qPfnkk+mEE07omSdgUf+RRx7JzX75y1/eQ5bjjz8+fe1rX0t//OMfO+1zfeedd+ayt99+u0TqpN/85jfHtYOcyFv1xzysXbs2j/Xxxx/P9VSesTAXklUpc8ZfWT62T7vMm+pUzaHKay6PPPLI9NWvfjX9+c9/zln//Oc/089+9rO0evXqTjtqTyljVX09I2Ve/va3v6Urr7wyj4G2br755nHtXHrppemvf/1r7lNjlkyk5Rhi+730prb+8pe/pJUrV47rkzlTuyqnPpnvZ555Jn3+859PhxxyyLh66rvU9z/+8Y/005/+NK1bt65Tvmy3aizg6uc//3n617/+tce89NOH5ImpdCxcxDz0VP7RT9VzlfvhD3+oyz1S6vUaZ9UYHnrooXTiiSfmeSJf+EBOyfGd73wnv28lO/ihHOX17NRTT03f+9730nPPPZflkt4oqzJO6+04rB/rZ6ZiYGDSA1lZtGhRx1jJGeAM5ZxkzH/0ox9lQ4uxPfPMM7NjwpHieB599NG0atWqdM0112QDCunplacJX7FiRSZMv/nNb7ITon/lve9970v0SfsPP/xwuummm9LWrVsTxvsrX/lKLifjfcstt3Rki2SDtnCgyIvc9913XzbiKr9w4cJ02mmnVZIeLDqOMcrEXP3ud7/LMsm5yfngMLjmRbsQA42Fa56RR984EmThHtlOOumkPIc4kO9///tp586d6Utf+lL6wx/+kInJ5Zdf3mlLbZLirPZGepYsWZJJI3MY60Kwnn/++fTxj388y0E7vcYQ6/bSG2OiLf7QH2ROdatID30uXbo0bd++PT3xxBOZ3IKnWE/1o77B2/33359++9vfJkgd5Jty6r/XWK6++uosI7qEdEdd9dOH5Imp3ifCRcxDT5DZT33qU1k+ZJw7d24mxlxDDn/961/n+eKe17nnntspyzySTzny6Iu0m87iGJjbr3/963mO0DlyKV9ERaTn73//e9q8eXNHXyXpoS3eq9iHBx98MF1//fV5AcKYwXUcs6/tWI0BY2DYGBiI9GC8WI3fcccdHWMlZwAZKklPL2OOMSwHJ0Nflaey99xzTzaiODxWjvSvPIgNxvW6667rPFOe0tJ463m3tKp86azkTH7xi19kmeQYaJPID3NGtEnzofKMt1u/8XnpSMhj3BAh2ogOePny5Zn4sOo/4ogj9mif8nsjPbSHYyeKcsYZZ+Q2RG5//OMf53YnOoZeelNbRKkgVbt27erIzZwJVyoX5w1ZuWcuIhY0f1X6gxz/8pe/zDjiuqpd1Vf63e9+NzGnEE/mDxKnvH76UNmYljiKed30pDK96lImzpvq9BpnOYZTTjklPf3005lQU7/MRz7ef8zjU089lZhHykWsohsWHBBxCKfkcGrHZgwYA6PCwECkB6OvlxyqnAHP5Zx6GWQiEBATCNRll102zmH3ymOC5HjZLorX5BEpwgDLKXeb0NJ4dyun51Xly/HJmRDCZ1zaAmSOkAfDz9wMk/TgdIgEVBFEdIKjiRE5jaebMy3HuW3bthyd0hYXW1sQEm3facy0p7a7pVFX8Vrl1da3vvWtxAvZIW/kR+etcmWfF198cSaW3/jGN/aQpRyX+oSEgUNFUiAyZbsqyzxCABl7vFZ+P32obExLHMW8bnpSmV51KRPnTXW6zR/5GgPRl2XLlmUMMz/Sv/JF6CXftddem/WF3iA5kfQwV+gSPEoGp3Z2xoAxMEoMDER6MKQ4Q1Z4OEGMGuF+nkUjK4Oc9yte+CdCxGA5TwE5YGuGVaIc3N7yMKgYUfqmLKF3RSNkYB944IGOgUUm/al/jHf5x7NuSiiNPeU0PtrnPjoTZNIWIHJyzRZeFemJcqitKjmiI1F+nG89UyqHhFx6prRbXjlOIjzMrRwW9YhWsfVFWxpzP2PopbfYFn186EMfyth47LHH8nZVHKf6pJzGU9aPz7kux6X8+FztdhsLkU3mAowpCkZUiu2mfvuQDumDqBT3JY4kGyljjH+qozK96lImzpvq9Bon8xH/eJ9t2LChM89xviSfIob33ntvJpCbNm0aR3oglBCnu+66K7cjmdVPL8xLZqd2kMaAMTAIBgYmPYSxISwYZVa+Ih3RyMq4xTM95ZkVzs2wisS40gbnVDSwbnk6ECyjScrBUkiXwvE/+MEPOtEjzt7o7EMkPTgQndHBEch5qf+YlsaePI1PRlvOhDlh2wNngKNEXpwjBKKK9MQzJMga+43XcpjIoueQu16RHulF5ZUio5yVnpFWjRPCg67PP//8LH88y6Ix9zOGXnqjb7WFbNxzRgRnyZmbiKuynOTnjBFRKKI3eqa0alzkcQiebUeiRGq3aixE64hiln/IJ/LdTx+SJ6YljmIecxHP9EC44pmlXnVpJ86b2u01zjgGSDrziQyQPOrHfO4jjpCL9zqRVs7R8f6iPFFIxqCFCG1hByBDPNf7R/I5tXMzBoyBYWNgYNKDQEQziPDErZxoZPdmkJtHxwQAABNJSURBVOOgtmzZkrdROKMTn3Md8xR5wNhivHkRhuccDU4J58Q2EsZ6/fr1nbYkS0l6IBJlf1X3pbGnjNqU0ZYzkZOAHNDf73//+0wMe5Wv6rN8VkV6brjhhjxv6EKOiXo60xMJSmwvOqv4vGqcnJFhPtk2IoVcqk4cs55Vpf3orWyL8UBAiJJxrkS6K8vRn8riROM5G8lSNS5Fk4SbqnZVH0IFOeITYpTjBb6QTduY/fSh9mJa4iLmddOTyvSqS5n4flSdXuMsx8D5OMiLDimX+aV8LC7QAdu5Ij0sJvhkZrmokRx6/0g+p3Z4xoAxMGwMDIX0aGUdV7vRyMogx0gPhg4jyCeM+BQHq2RWfERC2C5bs2ZNzzwcLo63JCsYXzk8SBAGFrlw1Kw6v/jFL2anJccp4x0jPWUUKk66ysd+NT4ZbRlxZKEuESwiUNrm6lY+RhbKlXyUoYr0sLrmE0t8ColPWcVPb0G2mIvYhq41XzrLguzIVzVORfWYTwju/PnzO21qzHsbQz96U1uaP2QVMSHCIt2pHH0SRYAo/+QnP8nkT5/E0jiValzom8O0X/jCF3J0Mc5RbJdrXtIHpDJu69EuRIvtN+aEOeqnD8kTU+Eivk/Ub5WeYjRQdYXB2C7X8f2ovF7j1BiEc80/i4oqfCBfGTFkm4sta/5oj343btyY37dEdHnvQ9apy6e+uskueZ3aARoDxsCgGBgK6VHIXytlhIpGVga53BLAEPJ9OTgRjCMvPj5MRIc2uuWpv9LxUoePwPIRdZwT9/pOEBw1f5ACogW33nprdlbIUP7JqVK/fJXOgHyNT0ZbzkROW2RBkYBu5aMcrI7lcEoZqkgPZTgUzHcSQfr4Yx7QyXnnnbfHONQmMpZ/PKsaJ3VUXmNROxpzbKscQ796U1uaP/UBeUR/0o/KqU/GW37njuoqLfUNwebAOThRmbJd2mcsu3fvzsSm6nA8W2naWu2nD/UVU+FC41G/6FvzHvOEN9pQ3fgsth3fj3rebZz0V6V/zuIw/5CZMh/5StIDHtEHf5RXv+CRr1VAX/xJbxAilXG6p+3xnHhOjIHBMTAp0uOJH3ziPYeeQ2PAGDAGjAFjYLQYMOmpiOYYhKMFoefb820MGAPGgDEwCgyY9Jj0eEvBGDAGjAFjwBhoBAZMegz0RgB9FCsI9+GVqjFgDBgD9caASY9Jj0mPMWAMGAPGgDHQCAyY9BjojQC6V1/1Xn1ZP9aPMWAMjAIDJj0mPSY9xoAxYAwYA8ZAIzBg0mOgNwLoo1hBuA+vVI0BY8AYqDcGTHpMekx6jAFjwBgwBoyBRmDApMdAbwTQvfqq9+rL+rF+jAFjYBQYMOkx6THpMQaMAWPAGDAGGoEBkx4DvRFAH8UKwn14pWoMGAPGQL0xYNJj0mPSYwwYA8aAMWAMNAIDJj0GeiOA7tVXvVdf1o/1YwwYA6PAgEmPSY9JjzFgDBgDxoAx0AgMmPQY6I0A+ihWEO7DK1VjwBgwBuqNAZMekx6Tnh4YOOWUU9LNN9+ctm7dmu666658ffrpp6cXvehFnrce82bDX2/Db/1YP03FgElPH4b7wAMPTCtWrEinnnpqrR3d5ZdfnjZv3pxe8pKXpEMOOSRdcsklae7cuSOTecGCBWnHjh3pHe94x177fNnLXpauvPLKtHv37oTck30Dvva1r03bt29Py5cvn3QbVX2//vWvT9dcc006++yzxxEcyA7PIECUqarrZ3YoxoAxYAzUEwOTIj04VZzr3XffnR1rqdyPfvSj2ZnJAZf5db/Had9www3p+OOPz07t4IMPTjfddFNau3btlDq5st+JzlMkPccee2z63Oc+l84555yhynzhhRem6667LkFaSvkmQnouuOCCTJDe+973ZpJWttXvfUl64hzut99+mQxde+21E+4DwtOL1JBH9KdfOV2ungbQerFejIFmYWBg0nPLLbekQw89tGP8iYrgZFjxz1TSMxHnPcw3zKD9RtIzTLnU1nHHHZduvfXWNG/evI6+lUc6EfmJzBChgbTENiZ6XZKeUgYI64033piWLFnSdz9saRHNibLwjFd8RpnyWcz3dbOMqfVtfRsD9cfAQKTns5/9bI4mcMZByn7Xu96Vndm2bdvGkZ43vvGNacuWLTkCdPvtt6ePfOQjiZX42NhYWrlyZSZJbHVQBkfFtgzt82znzp1p0aJFuY/3vOc9ibZ5vmvXrrRmzZrcBv0TmYGEkcdKnYhEJF7vfOc7cz4RKsqdfPLJHbklP06TfL2of8wxx4zbQoFc4Eg3bNiQZSCicuKJJ2ZZkOnOO+9MH/jABzptT7ZfImrM22c+85nOeK+66qp02GGHddqW3KSR9BDxgHieccYZeS4gohBSyh155JEJHZx33nmp1WrllLLMW6/22S5jXnWeJW5R0d4nP/nJ3Cd90w/9ER1jTnitW7cuvfjFL85yan5JIUBvectbcnQNGXix9UX7iioyNo01EqZIeqp0R33Gib6qolNqM6ZEcDRGPX/FK16ReOmelDLMR3zm6/obPevIOjIGmouBgUjPxo0bk15z5szJxn/16tWdZyIcr3nNa/JWAI6MsyYf+9jH8pkICBKECYe7cOHCnMf2yZvf/OZMVnAor3vd6zKhOOuss3L78+fPz5EGHBBkCWfKFon6gDThQCkH+ZAMRClwzKtWrUqvfvWrE3JCVt70pjeNc1o4MggWMr3//e9Pr3rVq7IM8dwIDph+GYdIHvc6Q4ODlZMdpF8iaDhgjemEE07IkRZIkAhMfPNWkR6IAHLecccdeV4oz1wyF5AfIiAiaW94wxuy3OhU+lT7Ih9sS/EMwgqJoS5zzZwjJ/MG6VE+kSHIKC/mkDl6+ctfnvXA/L/tbW/LxIY6YOCVr3xlnn/Nr/rth/RU6Q45aJu+6Uvj6ZVWbVsR1SmjP7RRVbZX285rrrG17q17Y2D6MTAQ6cERQQxwoG9961vzNhdOgGfRARP14OCnIgBaneNAOf9DJOfcc8/tRGxYkUMacKIlKYmgoT2cLI6dPmjnpJNO6jhlSJZID33h+HROg7rIFCMyapv25Lx5Jnl1WJaxIdtLX/rS3Bf3se2LLroo31NvkH7LMSFLSWAkM2mc8zg3iuxAdiAzIqrM8/XXX5/rQQ5ogzFCVOKWJc81B8wN9+RTDvLIPS9Ii+ZN+Zoz8pGP/g466KDcD3NGu6qvVH1RdyKkh/ql7nim9iS7+umWVhGZbqQHDHVrx8+n38BZB9aBMWAMRAwMTHpEUHBQEBgcBpGU6IDJi9sZuuY521tsUbGyx2EuXbo0RwniVhUE4/DDD8/OhYgCTpsoAXVoC2cGueCZyjHIKAPX6jemVY6wdJxymshbtlt1Tzk59EH6pZ1yTKVsUZlxvJH0QHQ+/elP59fRRx+dbrvttqwrjSvOB9eSPbatspovoiY4fIiOykXZ1H/ZtkhonCPqoze2CyFSkFfqUWa6SE+5vVVFeihTRZA0H05tbI0BY8AYqBcGBiY9KJQzExh/ojNsX/AsOmCcIdsgRIO6AYCzHpAfHKm2IYg+vP3tb89OmPMiRH0gAZRjO4uzMor0KMrAM/qQo49Otjx03U2W6LwpI4ePE+Y+jq3qPjp0rifbb7dIj7amSvmjXCIdIikQUggFuiIl4iVCcemll2aiWbYX7zUHag+Sgi6IaqmcdEDfKk9/yo9pnCMRZ84T0S4viBdlJCNRO0Wj1q9f3yFm6oeytF/qjmcqI9mjHFXXEznI/MEPfrByfFXt+lm9jJ/1YX0YA83DwFBID9EXzoxEYhMd8BFHHJEdLWdRKMvZEZwhxGXx4sV5i4mtomXLlmXSc9ppp+VtEw7s8tFrCBWkR9EFzvLgGDmfw6FXnBnlIAP0cdRRR+VtICJBIj04YggV0QT6J+KBDGy1lMDnjFA8UyKnKccax0bd8j469EH6Lc8p6UzPJz7xiT3O3JRylKQHwgjZgahEkoOsEEfOMTFOHH6M3mhu0A8RNyJqPCPKsWnTptwe5AzZIHfa3oJ0ojOiSmx30jaHqt/97nfn+nGOtBV2xRVXZL2yhcf8Uwaiw/yCLQ6xc34IPSsaVeqm1B2yghvGLjKtMfVKwZy2QqvK6SPrZUSoqqyfNc+wWufWuTFQTwwMhfTEcyJco+ySCBCBwZFAUnBo5LOK51NcODS2M3BmkCAOKXOIWZ/kgchAcuJWGHWIKinSQ584X9qgHg4XpyzSg/PEYeL06YstFEiT5I0AJfJw9dVX53Y4g8LBakUeqsZWjjU69EH6hZDxyTHIhuZNn4CK8uo6ylGSHumIuYeEqA4HoomcaUuJ+YE4KD+mzDfbZJozdCLZ0C1RH5Ee6nEomQgNfSI/ZfRlieUcsa1JXeRAHuSgDO1AUIUdcMEcdCM9pe6YQ8itDpbH8fS6FqlhWysSG655hjy9SFGvtp1XT2NovVgvxsC+j4FJkZ6ZAAycOR/TxklGpzUTZK+rjPqeHj6xVlcZS7km8z09agPcsH0FwSFKyM9RgCd/N8++bxiFAafWtTGwb2FgnyE9bJGwbcMWBttXbIERNeAsi0E7HNAStSL60u0bmes2z5J3Mt/IXLexWJ7hYNjz6Hk0BpqNgX2G9PDdLxyEZSuF7Su2R/gYPF++Z5A3G+TWv/VvDBgDxoAxAAb2GdJjQBvQxoAxYAwYA8aAMdALAyY9ffzKeq8JdJ7fYMaAMWAMGAPGwMzAgEmPSY+3/4wBY8AYMAaMgUZgwKTHQG8E0L0KmxmrMOvJejIGjIGpxIBJj0mPSY8xYAwYA8aAMdAIDJj0GOiNAPpUrhzctlemxoAxYAzMDAyY9Jj0mPQYA8aAMWAMGAONwIBJj4HeCKB7FTYzVmHWk/VkDBgDU4kBkx6THpMeY8AYMAaMAWOgERiYFOnhh0L5IU+++Vgv/bDnVDI0tz2zVgALFizIPywb9cavouvHZuNzX88s3Q5LX7IlYKKqTZ4rjx/R5ffPwFBVWT/bdzEknMjf6MeIp0vnVbZtumRxvxPD/aRJD798jhHShMdfzdYzpxNTxr42X1WGwaSn2ZgoMY4zw5awaCrJDPaFH3tdv359x86U9Sd6X4XJibbh8qPHMMQ3Ep0lS5YksDNdujCORo+BYel6aKQHgQBlBOawhHQ7MxNgVYbBpGdm6nKq3oMiPRCf0nZwv3r1apOehm+7CCNxkT1VeOy33Srb1m9dl5teGzhU0gMoMV6AFFAoFLljx44cFeJZ3AbDARKuph4GTuUVzjY4phccg85/lWEoSQ+6Bx/SPXXoN2KpvFceWNu+fXs65phjxm23qo1B5Xf9qcefHBord9kO5h2cYCt4LnsgvVNH15AisCMbQ13KRwzonmfCmcrTFv3ouerFstFmGRNTj4mqOcY/8F4HF2U+WJANiWX60a1wQJu9MBXbog64Ey6NlenBRImDfu+njPREAQAFAAE4GDbARb6ey8BVATq24+uZBa5oDORUSOVEwMFtt93WwQP6FwmWAQIz6D3ec43hof2II+NjZuEDfUWbIHIineLoZCN4VoUBypBHKicU2yEv3sf2Yt+Ukx2CREc7RZ5f0z8HsieyH+gkYoL7qF/0LnxIf+RHYkR9nROTXVGdElPCF7hBBu5LDKkfp9OPl246GDrp0f67gCFnJ6ACJIFKxkhlVaabsH5eXyBV6SYaIOXjWGQsyBcWlC98lMYs3sdr6pXGSm05rT9eotMQXqqeSc+KBlVhQHmyK9J/vFcf5IFFHKBsFKlW/tSJzlFtOZ1+TGEj5CvQZ9Qf1+Qp+ouOo86oS534TPjohinZrNhWxJGxMv2YiPrc2/VQSQ/KB1QiMQJXBJMAdPTRR3ecn4SU86IdPXM6swAV9RUNg55L/2CEfPCiPFLueUXM8Dzex+uyLkZPuIt5vq4njiLB0TVbWlo8RQxFvcfrEh9yYtJ5vI/tgUUcZHRmqkPKc4iPHGzM8/X04Uk4AQNRn1EnJT6Uh20p7YPwUdbRfRWBKvs1VqYPD9Jtv+nQSA/AkXEAANqmQBCApjzuMWjsifK8FJS6vQxRWd739QVbaRjQFfoFKxgujEq37a1eGJIxoo1S/1V9lmV8Xx/MRAeGXrAJkbhGfUa9x2vqxXvaAGM8B0cQF9rhPrZH39iaKjtEWV6lfHrudHQYQgf4C1LmPdoG9B5tiPTSTbfoP0bwqB+3txQtpJ2IKfAknKhtYSz26W3R0eFC8z7RdNKkB2MRw4olAGS8KAMQIphK4MkwqT0ZqIkOxuXrBbjoYKQbdA1WZMAoI72TRt13w1A0RrQb24gGTX06rRcuoj7AQXQUVfiQbYl6j9e0F++jPVGkRrhSnraxdC8MasEV7ZucXZTb16PFVHyPl3aizJO+St0KA9GuCAclhsr72BZ1dJBZBEj4Ud/Gx2jxMZH5nhTpmUgHVWUBnwxZVb6f1Rcw1o11YwwYA8aAMTBTMTBy0iNmLNY9UyfOcvtNbwwYA8aAMWAMzCwMjJT0KAzpEODMAonf1NaXMWAMGAPGwL6AgZGSnn1hwjwGv/GNAWPAGDAGjIGZiQGTHn/xWP5EhN/AM/MNbL1Zb8aAMWAM9I+B/wf5w/JYY7hwsQAAAABJRU5ErkJggg==" /><br />
<br />
<b><u>Sender:</u></b><br />
This method below initialises a <b>TopicClient </b>using a connection string and topic name. It then creates a list of messages to send to the service bus topic and it sets the same <b>SessionId</b> on each one. If you don't specify the same <b>SessionId</b>, you'll find messages received in the wrong order.<br />
<br />
<script src="https://gist.github.com/markgossa/3fa0b38deaeb8f76353f4c4feeae470e.js"></script><br />
<br />
<b><u>Receiver:</u></b><br />
The receiver, initialises a <b>SubscriptionClient</b> then calls the <b>RegisterSessionHandle()</b> method which registers a message handler and takes a <b>SessionHandlerOptions</b> parameter. This <b>SessionHandlerOptions </b>object requires that a exception message handler is specified which is called in case of an exception handling the message.<br />
<br />
<script src="https://gist.github.com/markgossa/538ad5539bb91626eab744fe139c60db.js"></script><br />
<br />
This handler references the <b>ProcessMessageAsync() </b>method which takes an <b>IMessageSession</b>, <b>Message </b>and <b>CancellationToken:</b><br />
<b><br />
</b> <script src="https://gist.github.com/markgossa/4cc70aad8376e3d54f6e3a59d13db33b.js"></script><br />
<b><br />
</b> The <b>ProcessMessageException() </b>method looks like this:<br />
<b><br />
</b> <script src="https://gist.github.com/markgossa/1773eb166b9fb3d54f413750dfd1acfc.js"></script><br />
<b><br />
</b> That's all you need to do to get this working. Let's test it out.<br />
<br />
<br />
<span style="font-size: large;">Testing</span><br />
<br />
To test it out, I set up a simple console app which sends the messages to the topic, waits for them to be processed and then checks to make sure all received messages are in the correct order. See below:<br />
<br />
<br />
<script src="https://gist.github.com/markgossa/174168ee1605a2b13c3f219758ba54d4.js"></script></div>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-54186409897624650302019-04-08T08:00:00.000+01:002019-04-08T08:00:00.445+01:00Run PowerShell from Terraform<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Introduction</span></h2>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">As great as Terraform is, you will find times when you need to fall back to running other scripts or using other tools. One such tool is PowerShell. We'll do a quick demo on how to run PowerShell scripts from Terraform configurations.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We've got three options and we'll run through each one:</span></div>
<div>
<ol>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform the first time only</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform every time</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform on a trigger</span></li>
</ol>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: small; font-weight: normal;">To run PowerShell, we'll be using the null_resource in Terraform. You can find out more about it </span><a href="https://www.terraform.io/docs/provisioners/null_resource.html" style="font-size: medium; font-weight: normal;">here</a><span style="font-size: small; font-weight: normal;">. Using the </span><span style="font-size: small;">null_resource</span><span style="font-size: small; font-weight: normal;">, we'll be calling the </span><span style="font-size: small;">local_exec </span><span style="font-size: small; font-weight: normal;">provisioner which specifies that the PowerShell script will be run on the machine running the Terraform configuration. More info on that is <a href="https://www.terraform.io/docs/provisioners/local-exec.html">here</a>.</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: small; font-weight: normal;"><br /></span></span>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">All the code for this blog post can be found on GitHub <a href="https://github.com/markgossa/TerraformPowerShell">here</a>.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform the first time only</span></h2>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">In this example, we want to run a PowerShell script only the first time the Terraform configuration runs.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We have a pretty simple PowerShell script which I'll put in a sub folder called <b>helpers.</b></span><br />
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<script src="https://gist.github.com/markgossa/f87aef098593696075c509d72b5b1f3b.js"></script><br /></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Our configuration is pretty simple for this one. Basically, we're calling the </span><b style="font-family: arial, helvetica, sans-serif;">null_resource </b><span style="font-family: "arial" , "helvetica" , sans-serif;">and the </span><b style="font-family: arial, helvetica, sans-serif;">local_exec </b><span style="font-family: "arial" , "helvetica" , sans-serif;">provisioner. We then pass in the path to our PowerShell script and the parameters. Note that you need to dot source your PowerShell script by putting a . before it and you also need to surround it in '' in case the path includes a space. </span><br />
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<script src="https://gist.github.com/markgossa/ca0fc7dabd755b56202a98fe475eadb6.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">We can then run <b>terraform init </b>and <b>terraform apply </b>and we see the output below and we can see Terraform ran the PowerShell script (no, you don't need to run <b>terraform plan</b>).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-_bIOMsR7H2Y/XKijs6kV01I/AAAAAAAADSM/ERVdOUXVSeUIloWr52gyw3KgQe5cMOIvwCLcBGAs/s1600/1terraforminit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="1072" height="222" src="https://2.bp.blogspot.com/-_bIOMsR7H2Y/XKijs6kV01I/AAAAAAAADSM/ERVdOUXVSeUIloWr52gyw3KgQe5cMOIvwCLcBGAs/s320/1terraforminit.png" width="550
" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-3gyvgQzhW8s/XKijswBar6I/AAAAAAAADSQ/U-_odvafmMskTTco82dU3tENQ-YhQpSwwCEwYBhgL/s1600/1terraformapply.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="743" data-original-width="1072" height="379" src="https://1.bp.blogspot.com/-3gyvgQzhW8s/XKijswBar6I/AAAAAAAADSQ/U-_odvafmMskTTco82dU3tENQ-YhQpSwwCEwYBhgL/s400/1terraformapply.png" width="550" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">If we then run terraform apply again, we find that it doesn't run the script:</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-L8YOXnsNuMo/XKilxs9yKkI/AAAAAAAADSg/DrARUdwd-fkmGaNveaxXrxJi0lgYeJ2MQCLcBGAs/s1600/1terraformapply2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="130" data-original-width="1072" height="65" src="https://1.bp.blogspot.com/-L8YOXnsNuMo/XKilxs9yKkI/AAAAAAAADSg/DrARUdwd-fkmGaNveaxXrxJi0lgYeJ2MQCLcBGAs/s320/1terraformapply2.png" width="550" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform every time</span></h2>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Note that now we're running the same script every time Terraform runs. Terraform is idempotent which means it only makes changes on the first run and each next run doesn't make a change unless it needs to. Make sure your PowerShell scripts are idempotent if you're using this approach.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The PowerShell script is the same as before and it's in a folder called <b>helpers</b> as before. It's not idempotent but as it's just writing out information to the console it's not causing a problem.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">As for the Terraform configuration, we're now adding a trigger which causes Terraform to run each time the trigger value changes. To do this, we're assigning a new <b>UUID</b> each time:</span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><script src="https://gist.github.com/markgossa/9fc7efa21d89ac8992ec6d2be081b9d0.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Terraform now runs the PowerShell script every time it runs.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;"></span><br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Run PowerShell from Terraform on a defined trigger</span></h2>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Rather than using a UUID as the trigger value, we can configure Terraform to run the PowerShell script only when a particular value changes. In this example, we'll only run the PowerShell script if the value of <b>TriggerValue</b> changes. This can be any output or variable in Terraform e.g. you could specify that only set IP restrictions if the list of IP restrictions changes. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Again, our PowerShell script is the same as before in the <b>helpers</b> folder.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">To demonstrate this, we can add a variable </span><b style="font-family: arial, helvetica, sans-serif;">TriggerValue </b><span style="font-family: "arial" , "helvetica" , sans-serif;">and specify this in a variables.tf file. Terraform will expect us to pass this variable on the command line or via a TFVARS file.</span></div>
<div>
<br /></div>
<script src="https://gist.github.com/markgossa/466ba5d364753e33ffb5765736b83fac.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Our Terraform configuration now needs to look like this. See that the trigger option is set to our <b>TriggerValue</b> variable.</span><br />
<br />
<script src="https://gist.github.com/markgossa/478607c20efb63d8d1df5ae690c1c6b7.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">When we run our configuration the first time using terraform apply, we need to specify the value for the variable (<b>terraform apply -var TriggerValue=100</b>)<b> </b>and we see that the script runs:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-vMI9MM7JC_4/XKirVECmQaI/AAAAAAAADSs/Z8sTiyPUvPYABBat5JO4Bfxq4jYXwNfwwCLcBGAs/s1600/3terraformapply1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="799" data-original-width="1096" height="400" src="https://4.bp.blogspot.com/-vMI9MM7JC_4/XKirVECmQaI/AAAAAAAADSs/Z8sTiyPUvPYABBat5JO4Bfxq4jYXwNfwwCLcBGAs/s320/3terraformapply1.png" width="550" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">If we run it again, we can see that Terraform has nothing to do and the script doesn't run:</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-nT1w9gTeJXw/XKirnOVmecI/AAAAAAAADS0/KsF_urTY2tsSt3o_se1NqoAjfpbVXf_egCLcBGAs/s1600/3terraformapply2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="1096" height="64" src="https://2.bp.blogspot.com/-nT1w9gTeJXw/XKirnOVmecI/AAAAAAAADS0/KsF_urTY2tsSt3o_se1NqoAjfpbVXf_egCLcBGAs/s320/3terraformapply2.png" width="550" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">If we change the value of <b>TriggerValue</b> and run it again, Terraform now runs our PowerShell script:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-beyYKPHX2y0/XKir3g7rAfI/AAAAAAAADS8/uN13IGm3DQkqLjFgXhMUOWfaw2FEZ_w0gCLcBGAs/s1600/3terraformapply3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="848" data-original-width="1096" height="425" src="https://4.bp.blogspot.com/-beyYKPHX2y0/XKir3g7rAfI/AAAAAAAADS8/uN13IGm3DQkqLjFgXhMUOWfaw2FEZ_w0gCLcBGAs/s320/3terraformapply3.png" width="550" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Conclusion</span></h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">In this article, we went through how you can run PowerShell scripts from Terraform either running every time, on a trigger or on the first time only.</span>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-84218495853580469282019-01-28T08:30:00.000+00:002019-01-28T08:30:02.295+00:00Terraform - Failed to load backend: Initialization requiredI came across this issue the other day and thought I'd share the solution.<br />
<br />
<h2>
Issue</h2>
<div>
When running <b>terraform plan</b>, you may get the error below:</div>
<div>
<br /></div>
<div>
<div>
<i><span style="font-size: x-small;">Backend reinitialization required. Please run "terraform init".</span></i></div>
<div>
<i><span style="font-size: x-small;">Reason: Initial configuration of the requested backend "azurerm"</span></i></div>
<div>
<i><span style="font-size: x-small;"><br /></span></i></div>
<div>
<i><span style="font-size: x-small;">The "backend" is the interface that Terraform uses to store state,e,</span></i></div>
<div>
<i><span style="font-size: x-small;">perform operations, etc. If this message is showing up, it means that theshowing up, it means that the</span></i></div>
<div>
<i><span style="font-size: x-small;">Terraform configuration you're using is using a custom configuration forthe Terraform backend.</span></i></div>
<div>
<i><span style="font-size: x-small;"><br /></span></i></div>
<div>
<i><span style="font-size: x-small;">Changes to backend configurations require reinitialization. This allows</span></i></div>
<div>
<i><span style="font-size: x-small;">Terraform to setup the new configuration, copy existing state, etc. This isonly done during "terraform init". Please run that command now then try again.</span></i></div>
<div>
<i><span style="font-size: x-small;">If the change reason above is incorrect, please verify your configuration</span></i></div>
<div>
<i><span style="font-size: x-small;">hasn't changed and try again. At this point, no changes to your existingconfiguration or state have been made.</span></i></div>
<div>
<i><span style="font-size: x-small;">Failed to load backend: Initialization required. Please see the error message above.</span></i></div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-U3Jorg3osEE/XEuPlnjYHTI/AAAAAAAADRI/RsCE_Z4GDmk-dR4VVs3jLLYLLrpfhDFpQCLcBGAs/s1600/terraform1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="276" data-original-width="550" height="200" src="https://3.bp.blogspot.com/-U3Jorg3osEE/XEuPlnjYHTI/AAAAAAAADRI/RsCE_Z4GDmk-dR4VVs3jLLYLLrpfhDFpQCLcBGAs/s400/terraform1.png" width="400" /></a></div>
<div>
<br /></div>
<h2>
Cause</h2>
<div>
I found that the cause of the problem was that I had used the <b>backend</b> block in my terraform configuration like below:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-9pcAbhpagC4/XEuQI469n7I/AAAAAAAADRQ/1dcIDoA315UGVCEOfynOAMGJcI1XPwr9QCLcBGAs/s1600/terraform2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="72" data-original-width="187" height="123" src="https://2.bp.blogspot.com/-9pcAbhpagC4/XEuQI469n7I/AAAAAAAADRQ/1dcIDoA315UGVCEOfynOAMGJcI1XPwr9QCLcBGAs/s320/terraform2.png" width="320" /></a></div>
<div>
<br /></div>
<div>
This tells terraform to expect some backend configuration however I was just testing and running terraform init without specifying a backend like below:</div>
<div>
<br /></div>
<div>
<b>terraform init -input=false -backend=false</b></div>
<div>
<b><br /></b></div>
<h2>
Solution</h2>
<div>
The solution is pretty simple. Basically, you need to either remove the backend settings from your terraform block but that's not the way you want to go if you want to use remote state. The other option is to specify backend settings when you run terraform init, like this:</div>
<div>
<br /></div>
<div>
<div>
<b>terraform init \</b></div>
<div>
<b>-backend-config="storage_account_name=MyStorageAccount" \</b></div>
<div>
<b>-backend-config="container_name=MyStorageContainer" \</b></div>
<div>
<b>-backend-config="key=Terraform.tfstate" \</b></div>
<div>
<b>-backend-config="access_key=MyStorageAccountAccessKey"</b></div>
</div>
<div>
<b><br /></b></div>
<div>
You should now be able to run terraform plan.</div>
Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-82185984781853287952019-01-21T08:30:00.000+00:002019-01-23T07:17:48.713+00:00Deploy Azure Durable Functions with Terraform and Azure Pipelines - Part 1<div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto; mso-outline-level: 1;"><h2><b><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Introduction</span></b></h2></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">I was recently doing the talk on Terraform and Azure Pipelines at the UK Cloud Infrastructure User Group and a number of people asked if I could write up a blog on Terraform and Azure Pipelines. We're also testing out Azure Durable Functions so I figure that I’ll write about deploying .NET Core Azure Durable Functions using Terraform and Azure Pipelines.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Azure Durable Functions</span></h2><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">To get more information about Azure Durable Functions, see <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview">here</a>. </span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">This series is more around the Azure Durable Function deployment rather than the durable function .NET core app itself so we won’t go into much detail however what I can tell you is that this durable function is triggered by an HTTP request, accepts a name value and it just responds with "<b>Hello <name>!”</b>.<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;">You can find the code on GitHub <a href="https://github.com/markgossa/AzureDurableFunctionsDemo1"><span style="color: blue;">here</span></a>. I’ll use this repo to deploy my durable function into Azure.<o:p></o:p></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><br />
</div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Terraform Configuration</span></h2><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Terraform is a great alternative to ARM Templates. Compared to JSON, Hashicorp Configuration Language (HCL) is much simpler and pretty much human-readable. You can find out more about Terraform by going to <a href="https://learn.hashicorp.com/terraform"><span style="color: blue;">https://learn.hashicorp.com/terraform</span></a> or my Terraform presentation <a href="https://github.com/markgossa/AzureTalks"><span style="color: blue;">here</span></a>.<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div class="MsoNormal" style="line-height: normal; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif;">There is a Terraform configuration in the same GitHub repo as the Azure Durable Function and we’ll use this configuration to deploy a Function App to Azure which will use the Consumption Plan. The Terraform configuration deploys a new resource group, app service plan, storage account and function app (V2).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: 12pt;"><br />
</span> <br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: 12pt;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Azure DevOps build definition as YAML</span></h2><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Azure DevOps has a cool feature where you can write out your Azure Pipeline build definition as code using YAML. This has the benefit that the build configuration is now stored in source control with the application code itself so you get all the benefits of </span><span style="font-family: "arial" , "helvetica" , sans-serif;">versioning and </span><span style="font-family: "arial" , "helvetica" , sans-serif;">peer review through pull requests and you can keep your application code and the build definition in sync. You can read more about pipelines as YAML <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema">here</a>.</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;">You can find the full YAML pipeline file in the repo <a href="https://github.com/markgossa/AzureDurableFunctionsDemo1/blob/master/azure-pipelines.yml">here</a> but we'll go through each part in turn. To get started, the first part of our YAML file needs to look like this:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><script src="https://gist.github.com/markgossa/f252b4253180951e9971514518ae2ea4.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">The </span><b style="font-family: Arial, Helvetica, sans-serif;">resources </b><span style="font-family: "arial" , "helvetica" , sans-serif;">section specifies that the code we are running tasks against is the same repo that the YAML file is stored in (</span><b style="font-family: Arial, Helvetica, sans-serif;">self</b><span style="font-family: "arial" , "helvetica" , sans-serif;">). We will also <b>clean </b>the build directory before starting our build.</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">The <b>pool</b> section specifies that we'll use the hosted <b>Visual Studio 2017 on Server 2016</b> hosted build agent.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">In the variables section, we're specifying that the variable <b>buildConfiguration </b>is set to <b>Release</b>. We'll use this variable when running our dotnet CLI commands.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Build a .NET Core app using Azure DevOps Pipeline as YAML</span></h2><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">In the <a href="https://github.com/markgossa/AzureDurableFunctionsDemo1">repo</a>, there's a few folders as below. </span></div><div><ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>AzureDurableFunctionsDemo1</b>: Contains the .NET Core project that includes the Azure Durable Functions</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>AzureDurableFunctionsDemo1.Tests</b>: Contains a .NET Core project that includes tests for the methods in the Azure Durable Functions Demo 1 project</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Deployment</b>: Contains a terraform folder which includes the terraform configuration</span></li>
</ul><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;">In order to build and test our app, we need to do as we would for any .NET Core application - i.e. build, test and publish. Using the Azure DevOps pipeline as YAML, this looks like below:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><script src="https://gist.github.com/markgossa/f245b7994b8cd15beea421a1ce05c6a7.js"></script><br />
<div><span style="font-family: "arial" , "helvetica" , sans-serif;">Notice the <b>steps</b> keyword here - we only need to specify this before the first task in the build pipeline. </span><br />
<br />
<ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Build: </b>This task is using the .NET Core CLI Azure DevOps V2 task template and it's specifying that we want to build all projects using the <b>configuration</b> parameter which is set to the <b>buildConfiguration </b>variable which itself is set to <b>release</b>.</span></li>
</ul><ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Test: </b>This task is using the same task template but is only running tests in projects which include test in the project folder name. It's also publishing the test results to Azure DevOps as the <b>publishTestResults </b>parameter is set to <b>true</b>.</span></li>
</ul><ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Publish: </b>Again using the same template, this task publishes only the <b>AzureDurableFunctionsDemo1</b> project and it publishes it to the artifact staging directory on the build agent which is specified by the built-in Azure DevOps variable <b>build.ArtifactStagingDirector</b>y. We don't have any web projects to publish so <b>publishWebProjects </b>is set to <b>false </b>however we do need to publish a zip file for deployment to Azure Functions so we'll set <b>zipAfterPublish </b>to <b>true</b>.</span></li>
</ul><span style="font-family: "arial" , "helvetica" , sans-serif;"> </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">That concludes the build and test for the .NET core app so let's move on to building and testing our terraform configuration.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Build a terraform configuration using Azure DevOps pipeline as YAML</span></h2></div></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">The YAML for the terraform build and test looks like below:</span><br />
<br />
</div><script src="https://gist.github.com/markgossa/607bf97ae88a394316a7b7592e06fc6e.js"></script><br />
<div><ul><li><b style="font-family: arial, helvetica, sans-serif;">Terraform Install: </b><span style="font-family: "arial" , "helvetica" , sans-serif;">As we're using the Visual Studio 2017 hosted build agent which doesn't have terraform installed on it so you'll see the first task is a </span><b style="font-family: arial, helvetica, sans-serif;">Terraform Install</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> task which uses </span><b style="font-family: arial, helvetica, sans-serif;">chocolatey </b><span style="font-family: "arial" , "helvetica" , sans-serif;">to install terraform: </span><b style="font-family: arial, helvetica, sans-serif;">choco install terraform</b><span style="font-family: "arial" , "helvetica" , sans-serif;">. This task uses the Command Line V2 task template in Azure DevOps.</span></li>
</ul></div><div><ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Terraform Init:</b> With terraform, we don't need to build/compile it as we do for a .NET app but we can run some basic form of unit tests on it by using <b>terraform validate</b> however before we run this, we need to initialize terraform which we do by running <b>terraform init</b>. We're setting <b>input</b> to <b>false </b>because we don't want terraform to prompt us for any missing variables as this is an unattended command and we'd want it to just fail instead. We'd use a backend configuration to specify the location for the remote state file when we're running the configuration however we're just validating our terraform in this case so we'll set the <b>backend </b>to <b>false</b>.</span></li>
</ul><ul><li><span style="font-family: "arial" , "helvetica" , sans-serif;"><b>Terraform Validate (Dev)</b>:<b> </b>For this task, we need to specify all the variables that terraform would expect when we attempt to deploy an infrastructure. These don't need to be the exact values but they need to be the correct type of variable (string, array or map) so as we just have strings, we can just set them to <b>test</b>. You'll see that we're specifying the envDev.tfvars file so that terraform validate can validate the variables which are set in this file. This task has no output unless there's a problem with the validation where it provides a non-zero exit code which fails the step in the pipeline.</span></li>
</ul><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">In both the <b>Terraform Init</b> and </span><b style="font-family: arial, helvetica, sans-serif;">Terraform Validate (Dev)</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> tasks, you'll see that we're specifying the terraform configuration path as <b>deployment\terraform</b> which is the relative path to our terraform configuration. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Publish the .NET Core app and terraform configuration</span></h2></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">We've now built and tested both our application and terraform code and are ready for the release stage however we first need to output some artifacts to pass through to the release. Below are the tasks to publish these artifacts:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><script src="https://gist.github.com/markgossa/1e398ddc14089c93edc3965979b5e2ac.js"></script><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Both tasks are using the <b>Publish Build Artifacts</b> Azure DevOps task templates and are simply specifying the path to publish and the name for the artifact. When run, this would output two artifacts - one called <b>app </b>and one called <b>terraform</b>.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Save the YAML pipeline</span></h2><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">The last step is to save the YAML pipeline as <b>azure-pipelines.yml</b> and store this in the root of the repo.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<h2><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-large;">Conclusion</span></h2><div><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br />
</span></div><span style="font-family: "arial" , "helvetica" , sans-serif;">In this post, we've gone through the </span><span style="font-family: "arial" , "helvetica" , sans-serif;">YAML build definition to build and test a .NET Core Azure Durable Function and terraform configuration. In part 2 we'll go through how to create the Azure Build in Azure DevOps.</span></div></div>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-65057331902553869892018-12-27T07:00:00.002+00:002018-12-27T07:00:08.467+00:00Azure Function - The listener for function was unable to start<h1></h1><h1>Issue</h1><p>When debugging one of my Azure Functions in Visual Studio 2017, I got the error below:</p><p><em>“The listener for function 'MyFunction' was unable to start. Microsoft.WindowsAzure.Storage: No connection could be made because the target machine actively refused it. System.Net.Http: No connection could be made because the target machine actively refused it. System.Private.CoreLib: No connection could be made because the target machine actively refused it.”</em></p><p><a href="https://lh3.googleusercontent.com/-alhGP6UID1k/XBohWSWFjVI/AAAAAAAADJY/MLrUImP8D14-NoNVjufIIC8hM9rM1rH5QCHMYCw/s1600-h/image%255B8%255D"><img width="504" height="201" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-OnScllOs9Qc/XBohXJG_BAI/AAAAAAAADJc/V_h9zqIOzdo1rdEOGY_EIaObz_OYnBWQgCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>After a Google search, I didn’t find much on the error message. I figured I’d write up the solution for the next person who has this problem. </p><h1>Solution</h1><p>I figured that this may be a firewall issue or a problem with one of the services that wasn’t started so I tried to eliminate those causes. I found that all services were started and that even with the firewall disabled, I still had the issue. I resorted to the classic <em>turn it off and on again</em> and that still didn’t fix it. </p><p>Eventually, it occurred to me to check that the Azure Storage Emulator was started and I found that it wasn’t. To check if it’s started, run the command below:</p><script src="https://gist.github.com/markgossa/f2c0a4a4bc3851866b42ad2e48263090.js"></script><p><a href="https://lh3.googleusercontent.com/-hmYjAEpyw2M/XBohXvRgOpI/AAAAAAAADJg/HBDhGPx1hzcxf_or0ZXeuaYgMnau4OjvwCHMYCw/s1600-h/image%255B11%255D"><img width="504" height="139" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ei1pQLcYgRI/XBohYP_f6XI/AAAAAAAADJk/10hYChCnjMIcuR-UgKSFo3pk9GAhCZEUwCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p>If you see <strong>IsRunning</strong> as <strong>False</strong> like above then you’re going to need to initialize and start the Azure Storage Emulator by running the commands below:</p><script src="https://gist.github.com/markgossa/c2b93d077000b02a83d87f3fec9a0c5a.js"></script><p>We can then check that the Azure Storage Emulator is running again by checking the status and we can see <strong>IsRunning </strong>is now <strong>True</strong>:</p><p><a href="https://lh3.googleusercontent.com/-T1Wi-BjuPUA/XBohYjsOGzI/AAAAAAAADJo/xxfqwQ-uCXUzSiX35PhVQgQ5RscXL0vdwCHMYCw/s1600-h/image%255B14%255D"><img width="504" height="120" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-rJ-Ces-R4lA/XBohZKX7cJI/AAAAAAAADJs/ZVZxwV-y1yMl_0VJOmFK9mdXRaFlCKtPwCHMYCw/image_thumb%255B4%255D?imgmax=800" border="0"></a></p><p>You should now be good to go and can now debug your functions.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-14052234044336184112018-12-20T07:00:00.000+00:002018-12-20T07:00:08.407+00:00Publish Azure Function with Visual Studio 2017<h1>Introduction</h1><p>In my <a href="https://markgossa.blogspot.com/2018/11/create-net-core-azure-function-with.html">last post</a>, I demonstrated how to create a new .NET Core Azure Function. In this post, I’ll demo how to publish your Azure Function using Visual Studio. </p><p>This post assumes that you’ve created your Azure Function already. If you need to go back over how to do that, click <a href="https://markgossa.blogspot.com/2018/11/create-net-core-azure-function-with.html">here</a>.</p><h1>Publish Azure Function with Visual Studio 2017</h1><p>1) Right click your project and click <strong>Publish</strong></p><p><a href="https://lh3.googleusercontent.com/-qxfyi_cA7qM/W_qrcuYBkgI/AAAAAAAADHc/wNgOVPL75VUIRIA8ogaBb2CgHswzyLFtgCHMYCw/s1600-h/image_thumb%255B25%255D%255B2%255D"><img width="504" height="241" title="image_thumb[25]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[25]" src="https://lh3.googleusercontent.com/-j5LyVz6c41g/W_qrdZbIypI/AAAAAAAADHg/3oORbDrNGf8pPfN7O53tgnINP_hR_m2_ACHMYCw/image_thumb%255B25%255D_thumb?imgmax=800" border="0"></a></p><p>2) If you have an existing Azure Function App already deployed in Azure then you can choose <strong>Select Existing</strong> to use an existing one however I’m creating one from scratch so I’ll choose <strong>Create New</strong></p><p><a href="https://lh3.googleusercontent.com/-2L_NMqiIsdo/W_qreCAvtHI/AAAAAAAADHk/eI2P7FFgm0EuVoZaeRfx5Rrk5r_8iAcIACHMYCw/s1600-h/image_thumb%255B26%255D%255B2%255D"><img width="504" height="379" title="image_thumb[26]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[26]" src="https://lh3.googleusercontent.com/-nY_7u7F3or8/W_qre34YufI/AAAAAAAADHo/oUyv6Js7eSQBD_tzjp9EBQgH_JcnGeKQwCHMYCw/image_thumb%255B26%255D_thumb?imgmax=800" border="0"></a></p><p>3) Log into Azure and fill out all the details then click <strong>Create</strong></p><p><a href="https://lh3.googleusercontent.com/-TTc68GCWFYk/W_qrf92q9VI/AAAAAAAADHs/Psdd319ggF8d4ykVgQIDDbwSJ_KAt54FwCHMYCw/s1600-h/image_thumb%255B27%255D%255B2%255D"><img width="504" height="379" title="image_thumb[27]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[27]" src="https://lh3.googleusercontent.com/-oxpckXtUir4/W_qrgsQAu2I/AAAAAAAADHw/ZA-k5zFjGe0wdrxMA_IeWVDp6osiiImKwCHMYCw/image_thumb%255B27%255D_thumb?imgmax=800" border="0"></a></p><p>You’ll be prompted to upgrade the version of Azure Function as we need V2, not V1 for .NET Core. If so, click Yes.</p><p><a href="https://lh3.googleusercontent.com/-EYFa6-p5FmU/W_qrhqScbuI/AAAAAAAADH0/crSefgtulH84tUsNM883xbFACKrZaZ2yACHMYCw/s1600-h/image_thumb%255B28%255D%255B2%255D"><img width="416" height="241" title="image_thumb[28]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[28]" src="https://lh3.googleusercontent.com/-TyVpfCqL534/W_qrigjTpLI/AAAAAAAADH4/4BTQuVk9V5Y80k_aXlhWA2RWoSm501hLACHMYCw/image_thumb%255B28%255D_thumb?imgmax=800" border="0"></a></p><p>4) After a few seconds, Visual Studio completes the deployment and you can now see your new Azure Function in the Azure Portal</p><p><a href="https://lh3.googleusercontent.com/-6gMlJtIlpsI/W_qrjTY2ZmI/AAAAAAAADH8/QxeNy8w_040Qe7xMsD6a-8TyctSCJKr2QCHMYCw/s1600-h/image_thumb%255B29%255D%255B2%255D"><img width="235" height="286" title="image_thumb[29]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[29]" src="https://lh3.googleusercontent.com/-bDiWBfaqcPQ/W_qrkbbq_CI/AAAAAAAADIA/CiRcBrZa0dsQxWD1UmKLN6eEtmaWyObJQCHMYCw/image_thumb%255B29%255D_thumb?imgmax=800" border="0"></a></p><p>5) On the overview tab, copy the URL into PostMan</p><p><a href="https://lh3.googleusercontent.com/-iZll8OF7NYk/W_qrlLwMltI/AAAAAAAADIE/zLYr95SFh60qDns3nS4s-QHrBZiA-4HXQCHMYCw/s1600-h/image_thumb%255B30%255D%255B2%255D"><img width="504" height="320" title="image_thumb[30]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[30]" src="https://lh3.googleusercontent.com/-e9tezU5JXpI/W_qrl8wxrFI/AAAAAAAADII/RRnpSklY8jQqCbpnUxPKyNsvBZ4DIATeQCHMYCw/image_thumb%255B30%255D_thumb?imgmax=800" border="0"></a></p><p>5) Click on Manage and copy down your function key. You can create a new key if you want.</p><p><a href="https://lh3.googleusercontent.com/-i9mslgs6XbY/W_qrmtlcC6I/AAAAAAAADIM/Zmm25adbgCkR4iKDGi9QwedLENkgXRbTgCHMYCw/s1600-h/image_thumb%255B31%255D%255B2%255D"><img width="504" height="341" title="image_thumb[31]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[31]" src="https://lh3.googleusercontent.com/-LmRNZ191_Kw/W_qrnUlhG8I/AAAAAAAADIQ/Quww3D8usckQNKaYCKizfFkHPTWBX0OBQCHMYCw/image_thumb%255B31%255D_thumb?imgmax=800" border="0"></a></p><p>6) In PostMan, add the key and the path to the HttpTrigger function as below</p><p><a href="https://httptrigger-markgossa.azurewebsites.net/api/HttpTrigger?code=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">https://httptrigger-markgossa.azurewebsites.net/api/HttpTrigger?code=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a></p><p>You can now click <strong>Send </strong>and see your output</p><p><a href="https://lh3.googleusercontent.com/-EUdeKwzUpN4/W_qroU4v20I/AAAAAAAADIU/QyOpVN0E3Pgfu2bDCL19IygTMLk75wWygCHMYCw/s1600-h/image_thumb%255B33%255D%255B2%255D"><img width="504" height="357" title="image_thumb[33]" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image_thumb[33]" src="https://lh3.googleusercontent.com/-kKV_O_LR9Qk/W_qrpORNJmI/AAAAAAAADIY/O-pEpOvsy5YKjYXEAVGE3QQGq5n_RMiegCHMYCw/image_thumb%255B33%255D_thumb?imgmax=800" border="0"></a></p><p>There you have it! .NET Core Azure Function published to Azure in very little time. You can find the project code on GitHub <a href="https://github.com/markgossa/AzureFunctionsV2Demo">here</a>.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-47857125160571801992018-11-29T07:00:00.000+00:002018-11-29T07:00:00.674+00:00Create .NET Core Azure Function with Visual Studio 2017<h1>Introduction</h1><p>With all the talk about Serverless and Azure Functions, it’s a good time to learn how to do this if you don’t already know. In this post, we’ll do a walkthrough of you to create a simple .NET Core 2.1 Azure Function with Visual Studio 2017.</p><h1>Prerequisites</h1><p>First of all, let’s set up our environment. </p><p>1) Install <strong>Visual Studio 2017 </strong>(you can download the Visual Studio Community Edition for free <a href="https://visualstudio.microsoft.com/downloads/">here</a>). </p><p>2) Install the <strong>.NET desktop development </strong>workload for Visual Studio. I have these options enabled:</p><p><a href="https://lh3.googleusercontent.com/-Ih4rilkhnoQ/W_qo4rHvY7I/AAAAAAAADDM/E-wE5S4LT-keUe1UwIe_pRBhPupjnT-KACHMYCw/s1600-h/image%255B8%255D"><img width="416" height="100" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-rNXIllxhbxk/W_qo5uZLQHI/AAAAAAAADDQ/sAr9AqlPCzg2Y21S88QErYwxOFXZdndmgCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-jBwUqmDmsRw/W_qo6MIHnsI/AAAAAAAADDU/qLU1X43GOsMINSCj5uIq4OtdStVqjiwDQCHMYCw/s1600-h/image%255B2%255D"><img width="321" height="429" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-e7ym4NMn42c/W_qo65IYfwI/AAAAAAAADDY/c67syXDLotstaPgrRk-kVhm2VU5bJsaAACHMYCw/image_thumb?imgmax=800" border="0"></a></p><p>3) Install the <strong>Universal Windows Platform development </strong>workload:</p><p><a href="https://lh3.googleusercontent.com/-XiplO9AtANU/W_qo7pTpnpI/AAAAAAAADDc/ALTF_34bI-sq_16QDeC1126wVXJuuZ0gACHMYCw/s1600-h/image%255B5%255D"><img width="424" height="104" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-S_pxtJZgKZs/W_qo8fZWqcI/AAAAAAAADDg/HXNRCvMKNHYXzS-A46mmcRYLB0d41RHVQCHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><p>4) Install the <strong>ASP.NET and web development </strong>workload:</p><p><a href="https://lh3.googleusercontent.com/-g9Zccses1Tk/W_qo9JWQEjI/AAAAAAAADDk/BR8VW19X-vMpzLNHahvsp-ad9OKMY-tdgCHMYCw/s1600-h/image%255B11%255D"><img width="420" height="98" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-3tXcGbR3MM4/W_qo929KKOI/AAAAAAAADDo/DGIbveAmvkkfgCjeuJJk5Ni6XVcFbfaQACHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-MNQdGXb9M4A/W_qo-kj68YI/AAAAAAAADDs/rURQlgo08h0rtapJD49_WH6uEB7kTHdSgCHMYCw/s1600-h/image%255B14%255D"><img width="329" height="407" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-h8t9fkkpaQc/W_qo_EM6hyI/AAAAAAAADDw/dMfIUQgInjMGXsKap30in4b088h_sEm7ACHMYCw/image_thumb%255B4%255D?imgmax=800" border="0"></a></p><p>5) Install the <strong>Azure development </strong>workload:</p><p><a href="https://lh3.googleusercontent.com/-wLVzscfirLA/W_qo_4bKBRI/AAAAAAAADD0/2M46PevslNsxB-wwwUORr6Hyd28eZeoFACHMYCw/s1600-h/image%255B17%255D"><img width="420" height="101" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-VkyGrzgL4ik/W_qpAt1DMmI/AAAAAAAADD4/BNjAWEI3bbEiQjbK8pDDc0Kg0Gpf6R5NgCHMYCw/image_thumb%255B5%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-_K-90tA1RvY/W_qpBa8gpvI/AAAAAAAADD8/Y1X-Kvl-n4AuwAgWmrEH12YyBUorhfDwgCHMYCw/s1600-h/image%255B20%255D"><img width="324" height="462" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-enlZtsYMplo/W_qpCHA3VAI/AAAAAAAADEA/wNSuTd9N9Lskzjg1-Ec6vqs9CNx_eSPnQCHMYCw/image_thumb%255B6%255D?imgmax=800" border="0"></a></p><p>6) Install the <strong>.NET Core cross-platform development</strong></p><p><a href="https://lh3.googleusercontent.com/-VsD4fUkr0FI/W_qpC7ZqAtI/AAAAAAAADEE/wXBDy3WaaY82S3VffMVYmA7eafG8v3JMgCHMYCw/s1600-h/image%255B23%255D"><img width="418" height="97" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-c4Bcx2AZecs/W_qpDi1FxFI/AAAAAAAADEI/dZealDJJosUeiUyu6glZJB7nRTKfkO6VACHMYCw/image_thumb%255B7%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-zXNMMn-OHlw/W_qpENNsoNI/AAAAAAAADEM/tSvYEwGL6gA35Dwv5P2pdnTvkLtzueQkwCHMYCw/s1600-h/image%255B26%255D"><img width="336" height="241" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-FA89zAbWQBk/W_qpEzhRC4I/AAAAAAAADEQ/erch6UUjf4UFmBZajSa42_TavJp-JJhFwCHMYCw/image_thumb%255B8%255D?imgmax=800" border="0"></a></p><p>7) Install the Azure Functions Core Tools:</p><p><span class="wlWriterPreserve" id="preserveac506138469348baaff18c001e74c791">
<SCRIPT src="https://gist.github.com/markgossa/47564a594bb7e286c821b07486ac48f2.js"></SCRIPT>
</span></p><p>You can find more info <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#v2">here</a>.</p><p>8) Install PostMan. This is a free tool for making HTTP requests so it’s great for testing out APIs. You can download it <a href="https://www.getpostman.com/">here</a>.</p><h1>Create a new Function App V2 project with Visual Studio 2017:</h1><p>1) Create a new project in Visual Studio (File > New > Project)</p><p><a href="https://lh3.googleusercontent.com/-ptboVhGRTCI/W_qpFrf2MeI/AAAAAAAADEU/2XFv90Do7AktumBXjvwJeax9GS17TGOFQCHMYCw/s1600-h/image%255B29%255D"><img width="504" height="297" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-t5ISvo8DRco/W_qpGZVI1fI/AAAAAAAADEY/oYBXMebyZf4VzPpZC6h-Q1J8zKy8XjZegCHMYCw/image_thumb%255B9%255D?imgmax=800" border="0"></a></p><p>2) Select <strong>Cloud > Azure Functions</strong> then select a folder and click <strong>OK</strong>.</p><p><a href="https://lh3.googleusercontent.com/-zAEnTT-LXBM/W_qpHKli1uI/AAAAAAAADEc/bcVk7PcOX0AViAPSZoSFMYO3jRm80EEbwCHMYCw/s1600-h/image%255B41%255D"><img width="504" height="351" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-5wUfIIfrkdg/W_qpHvVxTcI/AAAAAAAADEg/N5q5WZU8WDA-sZuleev6zgWqeeuyrGjRACHMYCw/image_thumb%255B13%255D?imgmax=800" border="0"></a></p><p>3) On the new window that pops up, make sure you click the drop down and select <strong>Azure Functions v2 (.NET Core) </strong>and <strong>Http Trigger.</strong></p><p><a href="https://lh3.googleusercontent.com/-67xCF9mEbQw/W_qpIfB9ONI/AAAAAAAADEk/TDdBqxKgOAw1BMCVvJQzofFYFW5qsjSNQCHMYCw/s1600-h/image%255B44%255D"><img width="504" height="292" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ajTTY3kw1YE/W_qpJIrVKDI/AAAAAAAADEo/SMcbuJXDX08YqaG9dGtVts4RCpM_gX9agCHMYCw/image_thumb%255B14%255D?imgmax=800" border="0"></a></p><p>Click <strong>OK</strong> when done.</p><p>4) Let’s add some code. Rename Function1.cs to <strong>HttpTrigger.cs </strong>and add the contents below.</p><p><script src="https://gist.github.com/markgossa/1b81834c2c273c2a956f92449cf0f166.js"></script>This method simply takes an <strong>HttpRequest </strong>input, extracts the two strings <strong>FirstName </strong>and <strong>LastName </strong>and outputs a greeting message.</p><h1>Debug your Azure Function in Visual Studio</h1><p>1) At the time of writing, there’s an issue with Visual Studio debugging for .NET Core Azure Functions V2. The workaround for this is <a href="https://markgossa.blogspot.com/2018/11/debug-net-core-21-azure-function-v2.html">here</a>.<font style=""><font style=""></font></font> Go ahead and go through this article then come back to continue at step 2. </p><p>2) Hit F5 to start debugging your function and you should be presented with something like this</p><p><a href="https://lh3.googleusercontent.com/-iIEqoDY-pN4/W_qpJ8PvsUI/AAAAAAAADEs/DRh42C5VvAkIR8wxwoOE-e-zjPHZI1AWwCHMYCw/s1600-h/image%255B47%255D"><img width="504" height="413" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-8T7U1Ehiifc/W_qpK_H5MUI/AAAAAAAADEw/GdHdsn4bbFsjtxW00zIgdIks38D3xXk8QCHMYCw/image_thumb%255B15%255D?imgmax=800" border="0"></a></p><p>As we can see, our function is running and the HttpTrigger is listed in green.</p><p>3) Let’s open up PostMan, create a new <strong>Request. </strong>It prompts you to create a request name and category.</p><p><a href="https://lh3.googleusercontent.com/-OmFD_JnlUWE/W_qpLsyavYI/AAAAAAAADE0/ewTW1L6dBiAf4eYiFDeScYeFVHYQxPGOQCHMYCw/s1600-h/image%255B50%255D"><img width="504" height="367" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-JkgQ9DjVn-E/W_qpMco_t6I/AAAAAAAADE4/jD2F59hzddkOzdP-ocfqLRV4h4NUXzM2gCHMYCw/image_thumb%255B16%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-IA7K3unOJRc/W_qpMxIYBbI/AAAAAAAADFA/-RXcW3hfWH8WJbc12jWCDQSFcvHKZsZQQCHMYCw/s1600-h/image%255B56%255D"><img width="488" height="610" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/--MuKRlCFE-I/W_qpNpzxYLI/AAAAAAAADFE/MCjYj3M16X8uhFA7KbFrHEsgDIofnMrOgCHMYCw/image_thumb%255B18%255D?imgmax=800" border="0"></a></p><p>4) Change the request to <strong>POST</strong></p><p><a href="https://lh3.googleusercontent.com/-xF7sq0bg1M0/W_qpOR4n-1I/AAAAAAAADFI/EXzDyPxTgOMV-4b0MHjDXRTLmo5wSP97wCHMYCw/s1600-h/image%255B62%255D"><img width="504" height="40" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ZtuH4_k5WAE/W_qpPPKOQmI/AAAAAAAADFM/bpZmvsAh5A8eA1bLN-4SArNWaSEwlSrrQCHMYCw/image_thumb%255B20%255D?imgmax=800" border="0"></a></p><p>5) Go to <strong>Body</strong>, select <strong>raw </strong>and add the JSON content below</p><p><script src="https://gist.github.com/markgossa/60477c0009ca071fdf6f940a20b05dfd.js"></script><a href="https://lh3.googleusercontent.com/-NJv1q4vsB44/W_qpP2w7sJI/AAAAAAAADFQ/3MfhPupHJf4oVjZoK6ASSBMUX7NKXcTKACHMYCw/s1600-h/image%255B59%255D"><img width="504" height="357" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-D20huNc-SRo/W_qpQcGi-FI/AAAAAAAADFU/AfJpAxVwn2MVjfgdJodGaKN7XuJ0xnFOgCHMYCw/image_thumb%255B19%255D?imgmax=800" border="0"></a></p><p>6) In the console window, copy the HttpTrigger URL into PostMan:</p><p><a href="https://lh3.googleusercontent.com/-_I9iHzvod24/W_qpRClsBiI/AAAAAAAADFY/gqjLTHHiv_YnmE3VUffllhvhVZfHfXQ1QCHMYCw/s1600-h/image%255B65%255D"><img width="504" height="87" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-H8EVZvWvE9s/W_qpR-Iu6eI/AAAAAAAADFc/9JA69vrDbrMAcbPjEvTm9NQ2ATixlBxggCHMYCw/image_thumb%255B21%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-kfRNngFAoyE/W_qpSknERwI/AAAAAAAADFg/HJng2xtHD4Q9AG3RF5pmPwcDWJNYvOScQCHMYCw/s1600-h/image%255B68%255D"><img width="504" height="35" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-g7xyc2lC9pE/W_qpTQ7IdfI/AAAAAAAADFk/N9kjwqsPoPM_gEL4alPxLzkC5WZfZP9kgCHMYCw/image_thumb%255B22%255D?imgmax=800" border="0"></a></p><p>7) Click <strong>Send</strong> in PostMan</p><p>You should get the greeting message below in PostMan</p><p><a href="https://lh3.googleusercontent.com/-3vFHfJ-phLs/W_qpT_v1HMI/AAAAAAAADFo/sFuazmfOxhk-BovWql2huAuOiL_Wwvg1ACHMYCw/s1600-h/image%255B71%255D"><img width="504" height="223" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-O9DDrKiINVI/W_qpUnfxUpI/AAAAAAAADFs/FA3KHr5iB50nRsdaK8ZJApuPnzU5t-hLQCHMYCw/image_thumb%255B23%255D?imgmax=800" border="0"></a></p><p>And you should see a request come through in the Azure Function console window</p><p><a href="https://lh3.googleusercontent.com/-WORlaa-Z2yg/W_qpVfYxmkI/AAAAAAAADFw/2ROF6hBOlyAtNopvNp7oLxLf5UKkN2RaACHMYCw/s1600-h/image%255B74%255D"><img width="504" height="202" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-m9umZwaBkR0/W_qpWM1lyeI/AAAAAAAADF0/TwDPbNe6PeMwZEogm2wVzppTGuO23g54gCHMYCw/image_thumb%255B24%255D?imgmax=800" border="0"></a></p><p>So, there you have it. Your first Azure Function running .NET Core 2.1. Hit <strong>Shift+F5</strong> to stop debugging. You can find the project code on GitHub <a href="https://github.com/markgossa/AzureFunctionsV2Demo">here</a>.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-87536658881587230462018-11-26T07:16:00.001+00:002018-11-26T07:16:01.013+00:00Debug .NET Core 2.1 Azure Function V2 with Visual Studio 2017<h1>Issue:</h1><p>When you create a new .NET Core 2.1 Azure Function in Visual Studio and then try to debug it, you see the console pop up and disappear then you get this error:</p><p align="center"><em>A fatal error has occurred and debugging needs to be terminated. For more details, please see the Microsoft Help and Support web site. HRESULT=0x8000ffff. ErrorCode=0x0.</em></p><p><a href="https://lh3.googleusercontent.com/-7zav4c5UQBQ/W_qCWBSP0XI/AAAAAAAADCg/6Sj9SFgLMm0bnKjiYKlDHyTFp7CjmUtHwCHMYCw/s1600-h/image%255B5%255D"><img width="401" height="184" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-KHBLjRz4rpI/W_qCW-hSmEI/AAAAAAAADCk/xpWgoMxKXbAd7HOW7hdlwVHmPx8pQ7W6ACHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><h1>Workaround:</h1><p>I’m sure Microsoft will resolve this soon but what you have to do to get around it is to configure the project debug properties and configure Visual Studio with the Executable to run and give it the path of func.dll. See steps below.</p><p>1) Install the Azure Functions Core Tools:</p><p><script src="https://gist.github.com/markgossa/47564a594bb7e286c821b07486ac48f2.js"></script></p><p>You can find more info <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#v2">here</a>.</p><p>2) Right click your project, click on <strong>Properties </strong>and go to the <strong>Debug </strong>tab</p><p>3) Set the <strong>Launch</strong> type to <strong>Executable</strong> </p><p>4) Set <strong>Executable </strong>to </p><p><script src="https://gist.github.com/markgossa/7ec3272bc36e40197495a9c8e95d18fd.js"></script></p><p>5) Set the <strong>Application arguments </strong></p><p><script src="https://gist.github.com/markgossa/911a94779041d34af3220d88da6d0d2a.js"></script></p><p>You settings should look like this when done.</p><p><a href="https://lh3.googleusercontent.com/-y_IgvG8fJnY/W_qCXtATasI/AAAAAAAADCo/SmT0VtAl094eGRMGxTOIOCkYzMshjBZewCHMYCw/s1600-h/image%255B8%255D"><img width="504" height="356" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-s1qz4iwR88M/W_qCYcEqumI/AAAAAAAADCs/G7frUVw-iRo57T-52u9hBc-fqOKkgkxFQCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>Let’s go ahead and try debug our function and we can see it’s working now:</p><p><a href="https://lh3.googleusercontent.com/-wMzr09XXnoI/W_qCZLJyIaI/AAAAAAAADCw/VINXTvEBKVAxs9FtRMa-gSkgP5Yh1Yz2QCHMYCw/s1600-h/image%255B11%255D"><img width="504" height="265" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-vXDubXLKi1k/W_qCZzb1DvI/AAAAAAAADC0/mQRGK8V1uY4AXNsNFBHd8HAUNBuYxGmqACHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p>Happy coding!</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-67237982925967461082018-11-18T22:38:00.000+00:002018-11-19T20:30:15.131+00:00Azure Policy - Deny inbound RDP from the internet<h1>Introduction</h1><p>In this article, I’ll do a quick run through of Azure Policy and what you can do with it. Given that we can now deploy infrastructure in Azure quickly and we can provide multiple teams access, the question is how do we control what can be deployed. In this article, we’ll look at how to prevent users opening up inbound RDP ports open from the internet to their Windows VMs.</p><h1>What is Azure Policy</h1><p>Azure Policy is a new Azure feature where you can assign policies to your Azure subscriptions or management groups (groups of Azure subscriptions). Using Azure Policy, you can specify what Azure resources should be denied, which should be audited and which should be automatically remediated by deploying an additional ARM template you specify. For example you can block all storage accounts that don’t use encryption. </p><p>There are some built in policies however you can create your own using JSON. There are different parts to the JSON policy as code file:</p><ul><li><strong>Policy definitions</strong>: These are policies that will be enforced such as <strong>Allowed Resource Types </strong>(set which resources can be deployed), <strong>Allowed Virtual Machine SKUs </strong>(sets which VM SKUs can be deployed).</li><li><strong>Initiative definitions</strong>: These are groups of policies that are aimed at achieving a larger goal. For example, you could have an initiative for reducing costs and then you can have a number of policies under that such as one policy which prevents users deploying large virtual machines and another which prevents them deploying databases which high DTUs. You can then assign the initiative definition to a subscription or management group.</li></ul><h1>Create Network Security Group for testing</h1><p>For starters, I’ll go ahead and create a new Network Security Group which allows TCP port 3389 from the internet. For more information on Network Security Groups, see <a href="https://docs.microsoft.com/en-us/azure/virtual-network/security-overview">here</a>.</p><p><a href="https://lh3.googleusercontent.com/-aXkiix1AicU/W_HprXXBm_I/AAAAAAAADAE/VoFg_jsY4n4LvVZzOE5yIQsjI09KSpxIQCHMYCw/s1600-h/image%255B38%255D"><img width="504" height="341" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ntyeoktIdsQ/W_HpsEcOqlI/AAAAAAAADAI/U4x7Bn584a84ftLd0Ts6_2t4cgjUv4AFwCHMYCw/image_thumb%255B12%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-2q_uaO8xDAs/W_Hpsy6WR2I/AAAAAAAADAM/uVxmeDCYG3Ebhy5G4NdbJFlQKRfLMSeWwCHMYCw/s1600-h/image%255B39%255D"><img width="504" height="315" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-bXTD_IE8K70/W_Hptqx0sqI/AAAAAAAADAQ/ZUOerfAdCjkD4hSRCcAJfZKhKJvIU3RkwCHMYCw/image_thumb%255B13%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-AYBUQmSbB2o/W_HpuXPSUoI/AAAAAAAADAU/Dukv1m-7RRgooo4B34XyZAoKdzefzdMcwCHMYCw/s1600-h/image%255B40%255D"><img width="504" height="132" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-62zN2URtoTA/W_HpvEe2LYI/AAAAAAAADAY/B2Ztp4tRxNwJZCsJPKo1QVRSKAz8FlFuwCHMYCw/image_thumb%255B14%255D?imgmax=800" border="0"></a></p><p><br></p><h1>Create Azure Policy Definition to deny inbound RDP</h1><p>Now that we have created our Network Security Group which we want to block, we will go ahead and create an Azure Policy Definition.<sub></sub></p><p>1) Log into your Azure Portal and search for <strong>Policy</strong>:</p><p><a href="https://lh3.googleusercontent.com/-V9yo8LK81bc/W_HpvylYzII/AAAAAAAADAc/rf51GGuKrGszDug_wSp0oG4C-JyJhHRPACHMYCw/s1600-h/image%255B4%255D"><img width="504" height="231" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-RYFo8e9Np9k/W_Hpwtcp2cI/AAAAAAAADAg/hvl1qkoWAjEVyKLNqmlN6JnNjdA766VxQCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>2) Here you see the <strong>Overview</strong> pane with a summary of your compliance status. There are no assigned policies so we can see that we’re 100% compliant.</p><p><a href="https://lh3.googleusercontent.com/-OQnQNRVIeY8/W_HpxXJxHHI/AAAAAAAADAk/Q6ww7viZmmw3xnAdc42mpTw1XYdbEV1cACHMYCw/s1600-h/image%255B7%255D"><img width="504" height="303" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-9_u9dSRx3PQ/W_HpyEf2AyI/AAAAAAAADAo/Zd_9IVkcDxM5E7Ytw6Vo-1KFBgHQOW3ygCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p>3) Create new policy code </p><p>The policy is written in JSON and includes a number of fields:</p><ul><li><strong>displayName </strong>- The name that will appear in the Azure Portal</li><li><strong>description </strong>- The description that will appear in the Azure Portal</li><li><strong>mode</strong>: If set to <em>all </em>then the policy applies to all resource types. If set to <em>indexed</em> then the policy applies to only resource types that support tags and location</li><li><strong>parameters</strong>: Here we can set the parameters for our policy. Rather than create a policy for each inbound port you want to block, you can create a single policy which takes a port parameter. See below:</li><script src="https://gist.github.com/markgossa/33f376cddd9ad8f15ddac1b5157570cd.js"></script></ul><p><br></p><ul><li><strong>if….then:</strong> This is the policy condition and action. It works like most if statements - i.e. if the resource meets certain criteria then an action will be taken. The action can be deny, audit and other options. There’s more information <a href="https://docs.microsoft.com/en-us/azure/governance/policy/concepts/effects">here</a>.</li></ul><p>The full JSON content is below:</p><p><script src="https://gist.github.com/markgossa/e6dd367626e7bf7616ded405fd327f60.js"></script><br></p><p>4) Click on <strong>Definitions</strong> and add a new <strong>Policy Definition, </strong>add the JSON content to it and click <strong>Save</strong>:</p><p><a href="https://lh3.googleusercontent.com/-dEkjK2lb0lE/W_H8KJ3vj3I/AAAAAAAADB4/yAiIPRpwT4saH7cF1Xjc5eBCpxpUnQ4lwCHMYCw/s1600-h/image%255B46%255D"><img width="504" height="431" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-JPJNebjsXZs/W_H8K5EVyVI/AAAAAAAADB8/FepeRe3iHOcTwLjunk_uIaU67KexzOxkgCHMYCw/image_thumb%255B16%255D?imgmax=800" border="0"></a></p><p>5) Assign the policy. Click the policy definition you just created and then click on <strong>Assign.</strong></p><p><a href="https://lh3.googleusercontent.com/-n2arDssW1NI/W_Hpy9lXXlI/AAAAAAAADAs/37fY_Mlg37Y59ZxHLT1Hl2PtoNAEKaC3QCHMYCw/s1600-h/image%255B10%255D"><img width="504" height="241" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-iHrfYvWxfuk/W_HpzuaimEI/AAAAAAAADAw/1DyKoLPnUKUGHQ2bwbBkFwSRZ_QpDuswgCHMYCw/image_thumb%255B4%255D?imgmax=800" border="0"></a></p><p>6) Select the subscription or management group you want to assign the policy to and then set the parameters. In this case, we want to block inbound RDP traffic from the internet so you’d need to specify <strong>3389</strong> in the <strong>parameters</strong> section at the bottom. Click <strong>assign</strong> when done.</p><p><a href="https://lh3.googleusercontent.com/-z0i06eQZt3E/W_Hp0bMfHOI/AAAAAAAADA0/pu3tJOzC44otQz8zx2Zv4hgxMffMR58cwCHMYCw/s1600-h/image%255B13%255D"><img width="504" height="394" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-uP0A39dr7q8/W_Hp0_10XxI/AAAAAAAADA4/yV_q_4Qply4dLXAjFEStNl-InmJAOgPOACHMYCw/image_thumb%255B5%255D?imgmax=800" border="0"></a></p><p><br></p><h1>Testing Azure Policy: </h1><p><p>Let’s test this out. We need to wait a bit of time for the policy to apply and hopefully we should see that the policy is not compliant and we can click through to find the offending resource.<br></p><p><a href="https://lh3.googleusercontent.com/-dpDDgHlAca8/W_Hp2ULWjpI/AAAAAAAADBA/lpp6zsm0ycUqptzfQ1CPsZ8aTpom-ZS9gCHMYCw/s1600-h/image%255B25%255D"><img width="504" height="275" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-x9mUKYSzplA/W_Hp3BmhbCI/AAAAAAAADBE/OzV7oyra9XcL39AOGXgxicCX1r4_ihNaQCHMYCw/image_thumb%255B9%255D?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-iS8mg8zZpAY/W_Hp36NqWeI/AAAAAAAADBI/GsrAQ-WxCpsXkUb6Sb5G6cqXkPu_FhNdACHMYCw/s1600-h/image%255B28%255D"><img width="504" height="302" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-I_hIl7m5UZk/W_Hp4mqx1qI/AAAAAAAADBM/7squDMwD_QwCsJ3onustFRD8I3Ect2naQCHMYCw/image_thumb%255B10%255D?imgmax=800" border="0"></a></p><p>If you try to create a new NSG rule which allows inbound port 3389 from the internet, it is denied by policy then you get an error like this:</p><p><a href="https://lh3.googleusercontent.com/-hYebXoGRcYw/W_Hp5eFCPZI/AAAAAAAADBQ/CnK9Do7LclsB43ilOPKb52xv2K1w0k_VgCHMYCw/s1600-h/image%255B31%255D"><img width="353" height="225" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-CvpWmKsEthk/W_Hp6FgIS7I/AAAAAAAADBU/6Hc_vrWcRMwA8-E8x3LLMdcKUSG3ArD8ACHMYCw/image_thumb%255B11%255D?imgmax=800" border="0"></a></p><p>You also get blocked if you try to deploy using PowerShell, terraform, the REST API or other methods as they all use the Azure Resource Manager. </p><h1>Conclusion</h1><p>In this article, we went through how you can use Azure Policy to deny the creation of any NSG rule that allows inbound traffic from the internet on specified ports. This is one step forward to achieving good Azure governance. </p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-75101518030933646362017-12-21T21:50:00.000+00:002017-12-23T14:35:36.080+00:00Using encrypted credentials with DSC<h1>Introduction</h1><p>So, to pass credentials to the target machine, you need to do a few things</p><h1>How to configure DSC to encrypt credentials</h1><p>In a nutshell, you basically need to deploy a certificate to the target machine and then the management machine encrypts the credentials using the public key of the target machine certificate. More detailed steps below:</p><ul><li>Connect to each target computer</li><li>Generate a self-signed certificate</li><li>Copy the public key to the management computer</li><li>Configure the Local Configuration Manager with the correct certificate thumbprint for that machine</li><li>Create the Configuration Data hashtable for use by other configurations</li></ul><h1>Script to configure DSC credential encryption</h1><p>If you know me, I can never really do the same thing twice and if it can be automated then it will be automated. So, this script does all the work for you - just run it from your management machine and point it at your target machine. Just note that it only works with Server 2016 or PowerShell v5.</p><p><br></p><h1></h1>
<script src="https://gist.github.com/markgossa/601b16ea9cbfbfd9110f0598b15a9a60.js"></script><p>How to run the script? First we copy and paste the above function into a PowerShell window then run this to save our configuration data into $ConfigurationData</p><p><span style="color: rgb(255, 69, 0);">$ConfigurationData</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Set-DscLCMCertificate</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">litex01</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span></p><p><a href="https://lh3.googleusercontent.com/-tSd-NOryENE/Wj5ofUM-ufI/AAAAAAAAC58/qHX--EcjV-UUkp8x-sj7SpjlJEdghz9QgCHMYCw/s1600-h/image%255B8%255D"><img width="504" height="321" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-l8HVeqnTIWk/Wj5ofwE1VYI/AAAAAAAAC6A/_c0kqTkcKYgRgkRJy_Nl5vUo_9fO7QsGgCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p><span style="color: rgb(255, 69, 0);"><font color="#000000">We can now confirm that your configuration data is correct:</font></span></p><p><span style="color: rgb(255, 69, 0);">$ConfigurationData</span></p><p><span style="color: rgb(255, 69, 0);"></span><span style="color: rgb(255, 69, 0);">$ConfigurationData</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">AllNodes</span></p><p><a href="https://lh3.googleusercontent.com/-ujimF0vXfSw/Wj5ogcLry5I/AAAAAAAAC6E/HBmu2lMMV_EeoYZenvBh1shFNyH05UMHgCHMYCw/s1600-h/image%255B11%255D"><img width="504" height="263" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-RQtBX4KTGGg/Wj5og-AzcsI/AAAAAAAAC6I/2VmXn0Mz2EMattCBFQJZVE4tZSPgOaedgCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><h1>Test out DSC credentials</h1><p>To do this, we’ll save credentials into $Credential then create a configuration that requires credentials and test it out with our configuration data. </p><p><br></p>
<script src="https://gist.github.com/markgossa/a90fab251fdad97d2a02824b024478da.js"></script><p><a href="https://lh3.googleusercontent.com/-QgxBId8I7dA/Wj5ohmsVfOI/AAAAAAAAC6M/JIyr72T8oJMISnvF6Qc5k2yiLMHOyw8YACHMYCw/s1600-h/image%255B17%255D"><img width="504" height="342" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-DMeKP8QUZh8/Wj5oisgpzhI/AAAAAAAAC6Q/tHaNRblO8MMTZ-MzEqj8OeTcoMyTpf4WQCHMYCw/image_thumb%255B5%255D?imgmax=800" border="0"></a></p><p>We can then check that our text file has been copied over:</p><p><span style="color: rgb(0, 0, 255);">Get-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'\\litex01\c$\temp\testfile1.txt'</span></p><p><a href="https://lh3.googleusercontent.com/-wnc76YtH14w/Wj5ojeJzolI/AAAAAAAAC6U/JsqVxk35LKcHk8RdbplvatiHHncxtkgrACHMYCw/s1600-h/image%255B20%255D"><img width="458" height="177" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-CXM6V7ljboU/Wj5oj70y-pI/AAAAAAAAC6Y/RQvnV4A47wUAOhcPz8VQjmg02MfiU7S3QCHMYCw/image_thumb%255B6%255D?imgmax=800" border="0"></a></p><p>All done! Happy configuration management! You can see the full code at <a title="https://github.com/markgossa/Set-DscLCMCertificate" href="https://github.com/markgossa/Set-DscLCMCertificate">https://github.com/markgossa/Set-DscLCMCertificate</a></p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-23518554356557578122017-11-23T07:21:00.000+00:002017-11-23T07:21:18.657+00:00Learn PowerShell DSC - Part 7<h1>Introduction</h1><p>In this part, we’ll go ahead and create our own DSC Resource. Why are we doing this? Well, when you start using DSC, you’ll find that you need to do something but cannot find a DSC Resource for it. </p><p>Other parts in this series:<ul><li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn PowerShell DSC Part 1</a><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-2.html">Learn PowerShell DSC Part 2</a><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-3.html">Learn PowerShell DSC Part 3</a><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-4.html">Learn PowerShell DSC Part 4</a></li><li><a href="https://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn PowerShell DSC Part 5</a></li><li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn PowerShell DSC Part 6</a></li></ul><h1>Create a new DSC Resource</h1><p>We’re going to create a simple resource which ensures a folder is present or absent. There’s already a DSC Resource for this but we’re more focussed on the process of creating a DSC resource. An overview of the steps is below:</p><ol><li>Install the DSC Resource Designer Module</li><li>Create the DSC Resource properties</li><li>Create the DSC Resource files</li><li>Create the module manifest</li><li>Add code to the DSC Resource</li><li>Copy the module to the PowerShell module directory</li><li>Test the DSC Resource</li></ol><p>Let’s get to it - follow the steps below.</p><h2>1) Install the DSC Resource Designer module</h2><p>This module includes the cmdlets we’ll use to create a new DSC resource. These cmdlets include:</p><ul><li>Import-xDscSchema</li><li>New-xDscResource</li><li>New-xDscResourceProperty</li><li>Test-xDscResource</li><li>Test-xDscSchema</li><li>Update-xDscResource</li></ul><p>Install it by running the command below:<br></p><p><span style="color: rgb(0, 0, 255);">Install-Module</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">xDscResourceDesigner</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span></p><h2>2) Create the DSC Resource properties</h2><p>These DSC Resource properties relate to what can be set when using the DSC Resource as part of a configuration. Our DSC Resource will be quite simple so in this case, we only need two properties:</p><ul><li><strong>Path</strong> - this is the path to the folder we will ensure is absent or present</li><li><strong>Ensure</strong> - this is what we will do to the folder. It will only be able to be set to Present or Absent.</li></ul><p><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 255);">New-xDscResourceProperty</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">string</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Attribute</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Key</span><br><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 255);">New-xDscResourceProperty</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">string</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Attribute</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Write</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ValidateSet</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Present</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Absent</span></p><h2>3) Create the DSC Resource files</h2><p>We’ll use the <strong>New-xDscResource </strong>cmdlet to create the file and folder structure for our new DSC Resource which we’ll call <strong>DemoFolder. </strong>We’ll call our new module <strong>DemoModule </strong>so we’ll be saving our new DSC Resource in a <strong>DemoModule </strong>folder<strong>:</strong></p><p><span style="color: rgb(0, 0, 255);">New-xDscResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DemoFolder</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Property</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\scripts\DemoModule'</span></p><p><span style="color: rgb(139, 0, 0);"><font color="#000000">This creates a number of files and folder structure in C:\Scripts. We’ll go through this later on.</font></span></p><h2>4) Create the module manifest</h2><p>As when creating a standard PowerShell module, we need to create a module manifest which includes information about the module. If you want more information on how to create a PowerShell module, see <a href="https://markgossa.blogspot.co.uk/2017/09/create-powershell-module.html">here</a>. <p>Let’s create our module manifest. We’re going to set a few options here:</p><ul><li><strong>Author</strong>: MG</li><li><strong>CompanyName</strong>: MG Enterprises</li><li><strong>Description</strong>: Demo Module <br></li></ul><p>
<span style="color: rgb(0, 0, 255);">New-ModuleManifest</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\Scripts\DemoModule\DemoModule.psd1'</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-Guid</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 128, 128);">[GUID]</span><span style="color: rgb(169, 169, 169);">::</span><span style="color: rgb(0, 0, 0);">NewGuid</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-ModuleVersion</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">1.0</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-Author</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">MG</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-CompanyName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'MG Enterprises'</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-Description</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Demo Module'</span></p><h2>5) Add code to the DSC Resource</h2><p>We should now have the below folder structure and files:</p><p><a href="https://lh3.googleusercontent.com/-5oeofznU30Q/WhYbflTu05I/AAAAAAAAC48/ZPJQxf7Ea_wK75lW3fJS6gaQvEH4tl-xQCHMYCw/s1600-h/image%255B3%255D"><img width="504" height="179" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-_x_sQ4Jde_Q/WhYbiKUbp1I/AAAAAAAAC5A/gP4LLwK4HuMSjY-SCGhgXQIbQ0-ccIw_ACHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><ul><li><strong>DemoModule.psd1 </strong>- this is the module manifest we created in step 4</li><li><strong>DemoFolder.psm1</strong> - this is the PowerShell module file which will hold our DSC Resource code</li><li><strong>DemoFolder.schema.mof </strong>- this is the MOF schema which contains information about the DSC Resource</li></ul><p>When we look in the .psm1 file for a particular DSC Resource we've created, we'll see that the DSC resource designer created three empty functions with some parameters which match the properties you created with New-xDscResourceProperty. These are:</p><ul><li><strong>Test-TargetResource</strong> - This function checks if the target machine configuration matches the DSC configuration. The function needs to provide a Boolean output (true or false) and it should be fast and lightweight as it will potentially run regularly. <li><strong>Set-TargetResource</strong> - This is what performs the configuration change if the Test-TargetResource comes back false - i.e. in our case it either creates or deletes the specified folder.<li><strong>Get-TargetResource</strong> - This must return a hash table of the current configuration. It's not used when setting or checking the configuration. It's only used when we use Get-DscConfiguration i.e. when troubleshooting.</li></ul><p>Our 'empty' DemoFolder.psm1 file is below:</p><p><span style="color: rgb(139, 0, 0);"></span></p><p>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Get-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">OutputType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 128, 128);">[System.Collections.Hashtable]</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Verbose "Use this cmdlet to deliver information about command processing."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Debug "Use this cmdlet to write debug information while troubleshooting."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"><#
$returnValue = @{
Path = [System.String]
Ensure = [System.String]
}
$returnValue
#></span><br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Set-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">,</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateSet</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(139, 0, 0);">"Present"</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(139, 0, 0);">"Absent"</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Verbose "Use this cmdlet to deliver information about command processing."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Debug "Use this cmdlet to write debug information while troubleshooting."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Include this line if the resource requires a system reboot.</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#$global:DSCMachineStatus = 1</span><br>
<br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Test-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">OutputType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 128, 128);">[System.Boolean]</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">,</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateSet</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(139, 0, 0);">"Present"</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(139, 0, 0);">"Absent"</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Verbose "Use this cmdlet to deliver information about command processing."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Write-Debug "Use this cmdlet to write debug information while troubleshooting."</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"><#
$result = [System.Boolean]
$result
#></span><br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 255);">Export-ModuleMember</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">*-TargetResource</span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000"><br></font></span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000">Let’s add some code to our DemoFolder.psm1 file. I’m not going to go through each line of code as this will really take some time and this post is all about creating the DSC resource. </font></span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000">Below you can see the completed file where I’ve written out the code.</font></span><br></p><p>
<span style="color: rgb(0, 0, 139);"><br></span></p><p><span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Get-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">OutputType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 128, 128);">[System.Collections.Hashtable]</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Write-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Checking if folder is present"</span><span style="color: rgb(0, 0, 0);"> </span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorAction</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">SilentlyContinue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorVariable</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">a</span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(139, 0, 0);">"Present” </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">else</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(139, 0, 0);">"Absent” </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># Create a hashtaable which has path, present and ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$returnValue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">@{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><span style="color: rgb(255, 69, 0);">$Path</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><span style="color: rgb(255, 69, 0);">$Ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># Output the hashtable - this is used for troubleshooting</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$returnValue</span><br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Set-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">,</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateSet</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(139, 0, 0);">"Present"</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(139, 0, 0);">"Absent"</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># If ensure is true, create the folder and if false then delete it and its contents</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">-eq</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Present'</span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Write-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Creating the folder"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">New-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ItemType</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Directory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorAction</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">SilentlyContinue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorVariable</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">a</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">|</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Out-Null</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">else</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Write-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Removing the folder"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Remove-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Recurse</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorAction</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">SilentlyContinue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorVariable</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">a</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#Include this line if the resource requires a system reboot.</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);">#$global:DSCMachineStatus = 1</span><br>
<br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Test-TargetResource</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">CmdletBinding</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">OutputType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 128, 128);">[System.Boolean]</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(169, 169, 169);">,</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateSet</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(139, 0, 0);">"Present"</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(139, 0, 0);">"Absent"</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[System.String]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Ensure</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># If ensure is true and the folder exists, return true. If folder doesn't exist then return false.</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># If ensure is false and folder exists then return false. If folder doens't exist then return true.</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">-eq</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Present'</span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Write-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Checking if the folder exists"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorAction</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">SilentlyContinue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorVariable</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">a</span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Result</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">else</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Result</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$false</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">else</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Write-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Checking that the folder does not exist"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorAction</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">SilentlyContinue</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ErrorVariable</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">a</span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Result</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$false</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">else</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$Result</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 255);">Write-Debug</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Exception</span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 100, 0);"># Write the boolean output - if false then DSC knows to then run the Set-DSCTargetResource function </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$result</span><br>
<span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 255);">Export-ModuleMember</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">*-TargetResource</span></p><h2><span style="color: rgb(138, 43, 226);"></span>6) Copy the module to the PowerShell module directory</h2><p>We now need to copy our module directory over to the PowerShell module directory:</p><p>
<span style="color: rgb(0, 0, 255);">Copy-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\scripts\DemoModule</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"C:\Program Files\WindowsPowerShell\Modules\DemoModule"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Recurse</span></p><p><font color="#000000">We can now confirm that our new module and DSC Resource is visible to PowerShell:</font><font color="#000000"><br></font><span style="color: rgb(0, 0, 255);"></span></p><p><span style="color: rgb(0, 0, 255);">Get-DscResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DemoFolder</span></p><p><a href="https://lh3.googleusercontent.com/-TqSUBaM3Y8Q/WhYbj4mvsHI/AAAAAAAAC5E/SL0nCqcvSh4k_NwsKgyVtzaS3QW5O9zLgCHMYCw/s1600-h/image%255B9%255D"><img width="504" height="129" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/--qu2h0Dw1nk/WhYbnkXcdjI/AAAAAAAAC5I/ItydGqp2WPsKqNgVDjagOyOh__LFVYZrACHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><h2>7) Test the DSC Resource</h2><p>So, we’re done creating our DSC Resource and are ready to create a DSC configuration to test it out. </p><p>Our simple test configuration is below - all it does is ensure that the <strong>C:\TestFolder</strong> is present on <strong>localhost</strong>. If you need a refresher on how to write configurations, then see <a href="https://markgossa.blogspot.co.uk/2017/08/learn-powershell-dsc-part-1.html">part 1</a>. </p><span style="color: rgb(0, 0, 139);">configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DemoCreateFolder</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string[]]</span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">Import-DscResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ModuleName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DemoModule</span><br><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">DemoFolder</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">TestFolder</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"C:\TestFolder"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><span style="color: rgb(0, 0, 0);">}</span><p>We then create the DSC Configuration document (MOF file) as normal:<p><span style="color: rgb(0, 0, 255);">DemoCreateFolder</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">localhost</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><p><span style="color: rgb(138, 43, 226);"><font color="#000000">Once done, let’s go ahead and push our DSC configuration:</font></span><p>
<span style="color: rgb(0, 0, 255);">Start-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Wait</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span><p><span style="color: rgb(0, 0, 128);"></span><a href="https://lh3.googleusercontent.com/-6D6bQCc_xdM/WhYbpQlqyEI/AAAAAAAAC5M/W3-aP0quWQkzv8czgQdR7Re_KV771qGkwCHMYCw/s1600-h/image%255B15%255D"><img width="504" height="252" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-jnoL3SoCFmI/WhYbrSPYGXI/AAAAAAAAC5Q/qX3qN_3fGeIg4udg3fm2RSvnrlczsw_xgCHMYCw/image_thumb%255B5%255D?imgmax=800" border="0"></a><p>We can then confirm our target machine is in the desired state and that our test folder exists:</p><span style="color: rgb(0, 0, 255);">Test-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><br><span style="color: rgb(0, 0, 255);">Get-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\TestFolder</span><p><a href="https://lh3.googleusercontent.com/-AmRfqdJA1Qw/WhYbt1eYwuI/AAAAAAAAC5U/AVMJ8arwqLwEUlDOyaUM6itog6CIvc7-QCHMYCw/s1600-h/image%255B21%255D"><img width="504" height="252" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-HrkiX16a3y4/WhYbvuCWpbI/AAAAAAAAC5Y/so0-o3Ul5JUsvtYYaxn7PHWYbVKIOvHSACHMYCw/image_thumb%255B7%255D?imgmax=800" border="0"></a>
</p><p><span style="color: rgb(138, 43, 226);"><font color="#000000">So, there we have it - we now know how to create DSC Resources. Next time we’ll go through composite resources and how we can save time.</font></span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000">Happy scripting!</font></span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000"></font></span></p><p><span style="color: rgb(138, 43, 226);"><font color="#000000"></font></span></p><p><span style="color: rgb(138, 43, 226);"></span></p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-6749592449042495472017-11-13T08:50:00.000+00:002017-12-23T15:37:30.199+00:00Learn PowerShell DSC - Part 6<h1>Introduction</h1><p>In Part 5, started looking at DSC Pull using an SMB share. If you need a refresher, click <a href="http://http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">here</a>. In this part, we’ll run through the setup of HTTP/HTTPS pull which is a little more complex but makes life a little easier especially as it requires fewer firewall ports open and is more secure. </p><p>Other parts in this series:</p><ul><!--StartFragment-->
<li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn
PowerShell DSC Part 1</a>
<li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-2.html">Learn
PowerShell DSC Part 2</a>
<li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-3.html">Learn
PowerShell DSC Part 3</a></li>
<li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-4.html">Learn
PowerShell DSC Part 4</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn PowerShell DSC Part 5</a></li><!--StartFragment-->
<li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn
PowerShell DSC Part 6</a></li>
<li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn
PowerShell DSC Part 7</a></li><!--EndFragment--></ul><h1>What is DSC HTTP/HTTPS Pull?</h1><p>HTTP/HTTPS pull allows you to store your DSC configurations (.MOF) on a web server which the target machines can connect to, download and apply their configurations. They do this over the standard ports: TCP port 80 for HTTP and TCP port 443 for HTTPS. </p><p>The setup steps we will run through are: </p><ol><li>Install the required DSC module on the DSC pull server</li><li>Install a certificate on the DSC pull server</li><li>Create a DSC configuration to deploy the DSC pull server</li><li>Create a MOF file</li><li>Deploy the DSC configuration to the DSC pull server</li></ol><p>The steps are almost the same whether you want to set up an HTTP or an HTTPS pull server but there are some differences. </p><h1>Set up a DSC HTTP/HTTPS pull server</h1><h2>1) Install the required DSC module on the DSC pull server</h2><p>We need to use some of the DSC Resources which are available in the <em>xPSDesiredStateConfiguration</em> DSC module which is not included in Windows. To install this module, we run the command:</p><p><span style="color: rgb(0, 0, 255);">Install-Module</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">xPSDesiredStateConfiguration</span>
<h2>2) Install a certificate on the DSC pull server</h2><p>The next step is to install a certificate on the HTTPS pull server. If you don’t need to have encrypted traffic and therefore don’t need to use HTTPS then you can skip this step. The certificate needs to have the correct Subject Name. Now, adding the certificate</p><p>In my case, my DSC pull server is called contchidsc01.contoso.com so this is what I need on my certificate. I’ll just confirm that contchidsc01 has a certificate with the correct subject:</p><p><span style="color: rgb(0, 0, 255);">Enter-PSSession</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">contchidsc01</span><br>
<span style="color: rgb(0, 0, 255);">Get-ChildItem</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Cert:\LocalMachine\My\</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">|</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">fl</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Thumbprint</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">Subject</span>
</p><p><a href="https://lh3.googleusercontent.com/-TAWWzyunvyg/WgRbQNzX66I/AAAAAAAAC3I/xkONSbRoYUoFCzLwG67JH3QHV-4UG618QCHMYCw/s1600-h/image31%255B1%255D"><img width="504" height="121" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-tRDOONbNbec/WgRbQ2vH0ZI/AAAAAAAAC3M/CfIqeirLI5EmhwnjedIJmp5P5m0qxzoTwCHMYCw/image_thumb111?imgmax=800" border="0"></a></p><p>We also need to note down the certificate thumbprint as we’ll need this in the next step. In my case it’s F8E20068359E75922F3EC35F58282C348D4511CF.</p><h2>3) Create a DSC configuration to deploy the DSC pull server</h2><p>The most interesting part! Deploying a DSC pull server requires a number of steps and so we’ll use DSC to configure the DSC pull server. The steps are below:</p><p>The full DSC configuration we need is below:</p><p><span style="color: rgb(0, 0, 139);">configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">HTTPSPullServer</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Param</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(169, 169, 169);">,</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateNotNullOrEmpty</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$certificateThumbPrint</span><span style="color: rgb(169, 169, 169);">,</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateNotNullOrEmpty</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Import-DSCResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ModuleName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">xPSDesiredStateConfiguration</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Import-DSCResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ModuleName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSDesiredStateConfiguration</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">WindowsFeature</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DSCServiceFeature</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"DSC-Service"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">WindowsFeature</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">IISConsole</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Web-Mgmt-Console"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">xDscWebService</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSDSCPullServer</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">EndpointName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"PSDSCPullServer"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Port</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">443</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">PhysicalPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">CertificateThumbPrint</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$certificateThumbPrint</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ModulePath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ConfigurationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">State</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Started"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">UseSecurityBestPractices</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$false</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DependsOn</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"[WindowsFeature]DSCServiceFeature"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">File</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">RegistrationKeyFile</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Present'</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'File'</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DestinationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:ProgramFiles\WindowsPowerShell\DscService\RegistrationKeys.txt"</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Contents</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span>
</p><p>Let’s go through what this actually does. </p><p>This first part collects parameters for the <strong>ComputerName</strong>, <strong>certificateThumbPrint </strong>and the <strong>RegistrationKey </strong>when we run the configuration to create a MOF file:</p><p><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Param</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(169, 169, 169);">,</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateNotNullOrEmpty</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$certificateThumbPrint</span><span style="color: rgb(169, 169, 169);">,</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">ValidateNotNullOrEmpty</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span></p><ul><li><span style="color: rgb(0, 0, 0);"><strong>ComputerName</strong> = The name of the target machine which we will configure to be a DSC HTTP/HTTPS pull user</span></li><li><span style="color: rgb(0, 0, 0);"><strong>certificateThumbprint</strong> = The thumbprint of the certificate which we installed on the DSC pull server</span></li><li><span style="color: rgb(0, 0, 0);"><strong>RegistrationKey</strong> = A key which target machines will use to do the initial registration with the pull server. After this initial registration, the target machine will generate a self-signed certificate which will be used to authenticate with the pull server.</span></li></ul><p><span style="color: rgb(0, 0, 0);">This next part installs the DSC Service and IIS Management Console Windows features we need installed on our pull server:</span></p><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">WindowsFeature</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DSCServiceFeature</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"DSC-Service"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">WindowsFeature</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">IISConsole</span><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Name</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Web-Mgmt-Console"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><p>The next part configures the DSC Web Service so that it works as a pull server. We need to specify a number of parameters here:</p><ul><li><strong>Port</strong> = Port number to use for the pull server.</li><li><strong>PhysicalPath</strong> = Path on disk for the virtual directory that will be set up in IIS.</li><li><strong>CertificateThumbprint</strong> = The certificate thumbprint for the certificate we installed on the pull server. As we have a parameter for this, we’ll set this to <span style="color: rgb(255, 69, 0);">$certificateThumbPrint<font color="#000000"> in the configuration.</font> <font color="#000000">If you don’t want to use HTTPS then you can set this value to <font color="#ff0000">“AllowUnencryptedTraffic”</font></font></span><font color="#000000"> and the pull server will use HTTP.</font></li><li><strong>ModulePath</strong> = The path where DSC modules will be stored. The target machines can download any required modules if they don’t already have these installed. </li><li><strong>ConfigurationPath</strong> = The path where DSC configurations will be stored.</li></ul><p><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">xDscWebService</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSDSCPullServer</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Present"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">EndpointName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"PSDSCPullServer"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Port</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">443</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">PhysicalPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">CertificateThumbPrint</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$certificateThumbPrint</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ModulePath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ConfigurationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">State</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Started"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">UseSecurityBestPractices</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$false</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DependsOn</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"[WindowsFeature]DSCServiceFeature"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span></p><p>The final part of the configuration is to store the registration key in a text file. We use the File DSC Resource to create a new text file and set the contents to <span style="color: rgb(255, 69, 0);">$RegistrationKey</span></p><p><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">File</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">RegistrationKeyFile</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Present'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'File'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DestinationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"$env:ProgramFiles\WindowsPowerShell\DscService\RegistrationKeys.txt"</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Contents</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span></p><h2><span style="color: rgb(0, 0, 0);">4) Generate the MOF file</span></h2><p><span style="color: rgb(0, 0, 0);">To generate our MOF file, we need to specify our parameters:</span></p><ul><li><span style="color: rgb(0, 0, 0);"><strong>ComputerName</strong> = contchidsc01</span></li><li><span style="color: rgb(0, 0, 0);"><strong>certificateThumbprint</strong> = <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">F8E20068359E75922F3EC35F58282C348D4511CF</span><span style="color: rgb(0, 0, 0);"> </span></span></li><li><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);"><strong>RegistrationKey</strong> = <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">New-Guid</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Guid</span></span></span></li></ul><p>We then call our configuration, specify the output path and the parameters:<br><br><span style="color: rgb(0, 0, 255);">HTTPSPullServer</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\HTTPS</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">contchidsc01</span><span style="color: rgb(0, 0, 0);"> </span>`<br><span style="color: rgb(0, 0, 128);">-certificateThumbPrint</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">F8E20068359E75922F3EC35F58282C348D4511CF</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">New-Guid</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Guid</span></p><h2>5) Deploy the DSC configuration to the DSC pull server</h2><p>The final step is to deploy the DSC configuration to the pull server using <strong>Start-DscConfiguration</strong>:</p><p><span style="color: rgb(0, 0, 255);">Start-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\HTTPS</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Wait</span></p><p><span style="color: rgb(0, 0, 0);">If we use the <strong>-Verbose</strong> and <strong>-Wait </strong>parameters, we can see detailed output as below:<br></span></p><p><a href="https://lh3.googleusercontent.com/-zHxgVXh8KO4/Wa2sJAPO-lI/AAAAAAAACx4/ODyR0UeBmmgg58w2UAVRGFptjyDgAqbgQCHMYCw/s1600-h/image%255B2%255D"><img width="504" height="313" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-zM1MEqnLdKQ/Wa2sJ-KbD_I/AAAAAAAACx8/IpVrR2NdwfE5grlwJ3zAzNV4oOeSCioUwCHMYCw/image_thumb?imgmax=800" border="0"></a></p><p><a href="https://lh3.googleusercontent.com/-9Rq1imb-aEQ/Wa2sKVzSMKI/AAAAAAAACyA/kbxRl8i6M8EMTsmZo-IbzN7Hw7oqbCebgCHMYCw/s1600-h/image%255B5%255D"><img width="504" height="395" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-sPa0Pkip3eQ/Wa2sLN2WBTI/AAAAAAAACyE/05KWQ9d6y8Y3ixCGScVVMnHJy5Vxq052ACHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><h2>6) Test the configuration</h2><p>Before moving on, let’s just test our configuration. We can do this using <strong>Test-DscConfiguration </strong>and we can see that contchidsc01 is in the desired state:</p><p><span style="color: rgb(0, 0, 255);">Test-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\HTTPS</span></p><p><a href="https://lh3.googleusercontent.com/-CJN1AlcmUAQ/WgRbRmG1GXI/AAAAAAAAC3Q/9DoPCJaIyHkgPIlR2SKyJeqc0GK0ffGsgCHMYCw/s1600-h/image3%255B1%255D"><img width="504" height="61" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-5UGBpleak2E/WgRbSCC3lEI/AAAAAAAAC3U/YOpKceZUmb4YKKTNaFrNWcwlCTTuO3JugCHMYCw/image_thumb1%255B1%255D?imgmax=800" border="0"></a></p><p>We can also see the PSDSCPullServer virtual directory in IIS:</p><p><a href="https://lh3.googleusercontent.com/-MDQ8NKwEOsA/WgRbS3FlqsI/AAAAAAAAC3Y/k606YnPO5Zk69dWZ7yvth-n1rb_owUKCACHMYCw/s1600-h/image311"><img width="338" height="388" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ahKwWeaH0s4/WgRbUTUl0ZI/AAAAAAAAC3c/qtF5gsJnaVAcTM4M8-9XgyvtwRegWfwpgCHMYCw/image_thumb11?imgmax=800" border="0"></a></p><p>….and we can confirm that our Registration Key was saved to the file we specified:</p><p><a href="https://lh3.googleusercontent.com/--sd4NGLC9Mc/WgRbVJTUGRI/AAAAAAAAC3g/gVwcXdVGdf4SWPcPgh1R8IUijKgha2EcACHMYCw/s1600-h/image6%255B1%255D"><img width="504" height="45" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-F5NMcGNOO44/WgRbVueAV2I/AAAAAAAAC3k/FQitUiEZoR4xItAgxVjn3pdikZ4QsMKuACHMYCw/image_thumb2%255B1%255D?imgmax=800" border="0"></a></p><p>We’ll move on to configuring a target machine to use the new pull server.</p><h1>Configure a target machine to use our DSC HTTPS pull server</h1><p>We need to configure our target machine Local Configuration Manager (LCM) with the DSC pull server URL and the registration key so it can complete the initial registration. </p><p>We’ll be configuring our target machine contchich01. In this configuration, we’re specifying the settings below: </p><ul><li><strong>ConfigurationID</strong>: This is the ID of the LCM on the target machine and is used to find the correct configuration to apply as there may be many configurations for other machines on the same pull server</li><li><strong>RefreshMode</strong>: This sets our LCM to pull instead of push which is the default</li><li><strong>ConfigurationRepositoryWeb ServerURL</strong>: This is the URL of the pull server</li><li><strong>ReportServerWeb ServerURL</strong>: This is the URL of the pull server</li><li><strong>RegistrationKey</strong>: We specify this for both the report server and the configuration repository so the target machine can register against the pull server</li></ul><p><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">DSCLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 139);">configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">ConfigurePullClient</span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Param</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(169, 169, 169);">,</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><span style="color: rgb(169, 169, 169);">,</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$GUID</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Settings</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">RefreshMode</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Pull'</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ConfigurationID</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$guid</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">ConfigurationRepositoryWeb</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">CONTOSO-PullSrv</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ServerURL</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'https://contchidsc01.contoso.com/PSDSCPullServer.svc/'</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);"> </span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">ReportServerWeb</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">CONTOSO-PullSrv</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ServerURL</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'https://contchidsc01.contoso.com/PSDSCPullServer.svc/'</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);">}</span></p><p><span style="color: rgb(0, 0, 0);">Once we have the LCM configuration, we need to push this out specifying the <strong>RegistrationKey</strong>, <strong>ComputerName</strong> and a <strong>GUID</strong> for the <strong>ConfigurationID</strong>:</span></p><p>
<span style="color: rgb(255, 69, 0);">$RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Get-Content</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'\\contchidsc01\c$\Program Files\WindowsPowerShell\DscService\RegistrationKeys.txt'</span><br>
<br>
<span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"contchich01"</span><br>
<span style="color: rgb(255, 69, 0);">$GUID</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">New-Guid</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">Guid</span><br>
<span style="color: rgb(0, 0, 255);">ConfigurePullClient</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$RegistrationKey</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-GUID</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$GUID</span><br></p><p>Next, we need to set the LCM using Set-DscLocalConfigurationManager:</p><p><span style="color: rgb(0, 0, 255);">Set-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span><br>
</p><p><a href="https://lh3.googleusercontent.com/-cfb_aQWQDfE/WgRbWvDbukI/AAAAAAAAC3o/B0Z7-ryG368C5cbwFMSKHN8E8KaWKX7mACHMYCw/s1600-h/image3"><img width="504" height="56" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-o_ny5DUYXaI/WgRbXMHgExI/AAAAAAAAC3s/QZXyaVDEkXs1ajpKVR4CA-coyeCDWjbrgCHMYCw/image_thumb1?imgmax=800" border="0"></a><br>
</p><p><font color="#000000">We then run these commands to confirm the configuration:</font></p><p><span style="color: rgb(255, 69, 0);">$Settings</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Get-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-CimSession</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(255, 69, 0);">$Settings</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">|</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">fl</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSComputerName</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">RefreshMode</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">RefreshFrequencyMins</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">RebootNodeIfNeeded</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">ConfigurationID</span><br>
<span style="color: rgb(255, 69, 0);">$Settings</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">ConfigurationDownloadManagers</span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(128, 0, 128);">0</span><span style="color: rgb(169, 169, 169);">]</span></p><span style="color: rgb(169, 169, 169);"></span><p><a href="https://lh3.googleusercontent.com/-AlB5ziUdMrI/WgRbYJkcuiI/AAAAAAAAC3w/Z8jGRvd68LY9_r6HFtEaQtlhP9lCMld_QCHMYCw/s1600-h/image6"><img width="504" height="248" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-exCeZq1Vl4Q/WgRbZMVf-fI/AAAAAAAAC30/Hu2MsHRstaEx7LMYvD9XzN8yt7aooAzRACHMYCw/image_thumb2?imgmax=800" border="0"></a></p><p>As you see above, we have the LCM set to pull and the ServerURL set to our new pull server.</p><h1>Create a DSC configuration for an HTTPS pull target machine</h1><p>This is basically the same as creating a normal DSC configuration but instead of naming the mof file according to our target machine i.e. contchich01.mof, we need to name it using the ConfigurationID of the LCM. The simple configuration is below and this creates a test file on the C drive called <strong>testfile.txt</strong>:</p><span style="color: rgb(0, 0, 139);">Configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">TestDSCPull</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Param</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Import-DscResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ModuleName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSDesiredStateConfiguration</span><br><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">File</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">TestFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DestinationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\testfile.txt'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'File'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Ensure</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Present'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Contents</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Test file contents'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><br><span style="color: rgb(0, 0, 0);">}</span><br><p>Create your MOF file as normal:</p><p>
<span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"contchich01"</span><br>
<span style="color: rgb(0, 0, 255);">TestDSCPull</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs</span><br>
<br>
In the next section, we get the ConfigurationID from the target machine and then copy the MOF file over to the configuration repository on the DSC pull server and rename it to <guid>.mof:<br>
<span style="color: rgb(255, 69, 0);"></span></p><p><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-CimSession</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">ConfigurationID</span>
<br>
<span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'\\contchidsc01\c$\Program Files\WindowsPowerShell\DscService\Configuration\'</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'.mof'</span><br>
<span style="color: rgb(0, 0, 255);">copy</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\DSC\Configs\$ComputerName.mof</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span><br>
<br>
<span style="color: rgb(0, 100, 0);"><font color="#000000">We also need a checksum file so create one using New-DscChecksum (use -Force to overwrite a checksum if there is already one there):</font></span><br>
<span style="color: rgb(0, 0, 255);"></span></p><p><span style="color: rgb(0, 0, 255);">New-DscChecksum</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span><br>
<br>
<font color="#000000">To get the machine to pull the configuration, we then use Update-DscConfiguration:</font><br>
<span style="color: rgb(0, 0, 255);"></span></p><p><span style="color: rgb(0, 0, 255);">Update-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Wait</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span></p><p><a href="https://lh3.googleusercontent.com/-71DaM0Rnowk/WgRba9hN-jI/AAAAAAAAC34/349xR4ssPLg_1R7PopZpWqBZiPURElxGQCHMYCw/s1600-h/image12"><img width="504" height="96" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-r5aEe6JPPFA/WgRbbjqIjcI/AAAAAAAAC38/xWfnJsOz3OYQgqEbJKUZczPCXqFhwlFJwCHMYCw/image_thumb4?imgmax=800" border="0"></a></p><p>…..and there we have it, the target machine pulled the configuration and we can confirm the test file exists and that the contents are correct:</p><p><a href="https://lh3.googleusercontent.com/-INhxCvjcE9k/WgRbceCqJJI/AAAAAAAAC4A/nBXISmimqLkUWVhNXhK2bhZ34NxfgZ4PgCHMYCw/s1600-h/image15"><img width="504" height="73" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-jW7hnQ0WTak/WgRbc09stkI/AAAAAAAAC4E/CJJ584tNe9Ud9d-97mF8i2Y8G9hWQMkYACHMYCw/image_thumb5?imgmax=800" border="0"></a></p><h1>Conclusion</h1><p>If you’ve made it this far then take a break - you deserve it! It takes a little bit of time to get it all set up but once you’re done, all your servers can be configured to automatically pull their configuration from the pull server and you have a central repository for your configurations so all you have to do is create configurations. </p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-25393056446650066242017-10-23T08:41:00.000+01:002017-12-23T15:36:35.830+00:00Learn PowerShell DSC - Part 5<h1>Introduction</h1><p>Welcome to part 5! Hopefully you’re getting the hang of pushing out DSC configurations and are wondering if there are other ways to deploy DSC configurations and in fact, you’re in luck! Today’s we’ll go through how you can get the target machine to automatically pull the DSC configuration rather than you having to push it out. </p><p>There are two methods you can use to pull DSC configurations - SMB and HTTP/HTTPS. We’ll go through the simplest one first - SMB pull. </p><p>Other parts in this series:<ul><li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn PowerShell DSC Part 1</a><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-2.html">Learn PowerShell DSC Part 2</a><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-3.html">Learn PowerShell DSC Part 3</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-4.html">Learn PowerShell DSC Part 4</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn PowerShell DSC Part 5</a></li><!--StartFragment-->
<li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn
PowerShell DSC Part 6</a></li>
<li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn
PowerShell DSC Part 7</a></li><!--EndFragment--></ul><h1>What is DSC SMB Pull?</h1><p>SMB Pull allows you to store your DSC configurations (.MOF) in an SMB share which the target machines then connect to, download and apply their configurations. There are three steps we will go through:</p><ul><li>Set up a DSC SMB Pull Server</li><li>Configure target machine for DSC SMB Pull</li><li>Create DSC configuration for SMB pull target machine</li></ul><p>Once done, we basically create a DSC configuration, target it at the target machine and also create a checksum file. We’ll go through this in more detail later on.</p><h1>Set up a DSC SMB Pull Server</h1><p>Now, this is easy. Just create a share and provide read access to the computer account of the target machine. This is because DSC runs as the Local System account by default. </p><blockquote><p>1. Create a folder e.g. <strong>C:\DSCSMB</strong></p></blockquote><blockquote><p>2. Share the folder as <strong>DSCSMB</strong> and grant full control to Everyone:</p></blockquote><p><a href="https://lh3.googleusercontent.com/-utQqpfdSmDo/Wey2xACfg1I/AAAAAAAAC1g/EFR-9_AnaIoCmVLCDb8BuvelRqgccE3iQCHMYCw/s1600-h/image%255B50%255D"><img width="367" height="454" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-hjsI4NQvEkc/Wey2yEaLwjI/AAAAAAAAC1k/L2KfJlgsZ8USUyqPiC5C0LFCzHxHM0CQACHMYCw/image_thumb%255B17%255D?imgmax=800" border="0"></a></p><blockquote><p>3. Configure the NTFS permissions by disabling inheritance, removing permissions for Users and granting read only permissions for the target machine computer account or an AD group which contains the computer accounts.As I’m just doing a demo, I’ll assign permissions to “<strong>Contoso\Domain Computers</strong>”.</p></blockquote><p><a href="https://lh3.googleusercontent.com/-px4S7dkSEYM/WeyjW0weK8I/AAAAAAAAC1M/12fKynI9k04YRCr5kN4N_MDqBO9CW9FpACHMYCw/s1600-h/image%255B2%255D"><img width="504" height="343" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-_Lt9wb9wjGw/WeyjXugbXvI/AAAAAAAAC1Q/tAK-TywWJ8o0BIizluCg9I5gBYQUM1bqwCHMYCw/image_thumb?imgmax=800" border="0"></a></p><h1>Configure target machine for DSC SMB Pull</h1><p>By default, DSC is configured for push configurations only and obviously it has no idea that we have an SMB Pull server or what its UNC path is so we’ll need to configure this. The DSC local configuration is configured using the the DSC Local Configuration Manager or LCM for short. The LCM is a WMI provider built into PowerShell v4 and later. </p><p>To configure DSC using the LCM, you basically create a configuration specifying <font color="#000000"><strong>[DSCLocalconfigurationManager()]</strong></font> and then you can create a MOF file, and then push this out to your target server using <strong>Set-DscLocalConfigurationManager</strong>.</p><blockquote><p>1. Create the LCM configuration as below. Note that we’re specifying the parameters:</p></blockquote><ul><ul><li>ConfigurationID: This is the ID of the LCM on the target machine and is used to find the correct configuration to apply as there may be many configurations for other machines in the same share</li><li>RefreshMode: This sets out LCM to pull instead of push which is the default</li><li>SourcePath: This is the UNC path of our DSC SMB Pull server</li></ul></ul><blockquote><p><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">DSCLocalconfigurationManager</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 139);">Configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Configure_LCM_SMBPULL</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">param</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string[]]</span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(169, 169, 169);">,</span><br>
<br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br>
<span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Settings</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">RefreshMode</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'Pull'</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">ConfigurationID</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$guid</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 139);">ConfigurationRepositoryShare</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">DSCSMB</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Sourcepath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"\\contchidsc01\DSCSMB"</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);">}</span><br>
</p></blockquote><blockquote><p>2. Specify the computer name and the GUID. Here we’re creating a new GUID.</p></blockquote><blockquote><p><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(139, 0, 0);">'contchisql01'</span><br>
<span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 128, 128);">[guid]</span><span style="color: rgb(169, 169, 169);">::</span><span style="color: rgb(0, 0, 0);">NewGuid</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><br>
</p></blockquote><blockquote><p>3. Create the MOF file however it’s a .meta.mof file for the LCM</p></blockquote><blockquote><p><span style="color: rgb(0, 0, 255);">Configure_LCM_SMBPULL</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Guid</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\Scripts\DSC</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-UovUGIeESqw/Wey2zn0id6I/AAAAAAAAC1o/yjNWq3fDiUIZaS1LfDKr-rPhhmsSQuu9wCHMYCw/s1600-h/image%255B17%255D"><img width="504" height="111" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-HtVxbwoHvtM/Wey21aAy-GI/AAAAAAAAC1s/a6KBs0KbVOMZM_ZFuTpjFB_FLTAb7nmaQCHMYCw/image_thumb%255B6%255D?imgmax=800" border="0"></a><br></p>
<blockquote><p>4. We now configure the LCM on the target machine using <strong>Set-DscLocalConfigurationManager</strong></p></blockquote><blockquote><p><span style="color: rgb(0, 0, 255);">Set-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> -</span><span style="color: rgb(0, 0, 128);">Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\Scripts\DSC</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span></p></blockquote><span style="color: rgb(0, 0, 128);"></span><p><a href="https://lh3.googleusercontent.com/-2MhbeCSIBbs/Wey22VpH1lI/AAAAAAAAC1w/BLSwnOqge50O0BdBkxsDeVwfbZ-6FjIMQCHMYCw/s1600-h/image%255B23%255D"><img width="504" height="130" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-jVyxmcz2uXE/Wey23h58cNI/AAAAAAAAC10/aXSLYKBWRikOQIBp9tj82zKpDOicBplawCHMYCw/image_thumb%255B8%255D?imgmax=800" border="0"></a><br>
</p><blockquote><p>5. Our LCM should now be configured and we can use <strong>Get-DscLocalConfigurationManager</strong> to confirm our settings:</p></blockquote><blockquote><p><span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Get-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-CimSession</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(255, 69, 0);">$a</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">|</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">ft</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSComputerName</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">RefreshMode</span><span style="color: rgb(169, 169, 169);">,</span><span style="color: rgb(138, 43, 226);">ConfigurationID</span><span style="color: rgb(169, 169, 169);">,</span>`<br>
<span style="color: rgb(0, 0, 0);">@{</span><span style="color: rgb(0, 0, 0);">Name</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(139, 0, 0);">'ConfigurationRepositoryShare'</span><span style="color: rgb(0, 0, 0);">;</span><span style="color: rgb(0, 0, 0);">Expression</span><span style="color: rgb(169, 169, 169);">=</span>`<br>
<span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(255, 69, 0);">$_</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">ConfigurationDownloadManagers</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">SourcePath</span><span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">}</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-NFw6Zy4PFtQ/Wey24DAx3RI/AAAAAAAAC14/KO6YXUq8eUQoNMxk04SOJdEaieZp6tofACHMYCw/s1600-h/image%255B32%255D"><img width="504" height="117" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-X7MXb0kw7pY/Wey24_pxT4I/AAAAAAAAC18/0P7LN8ON3zgf0AO_8JUtmi8TVVkFS93sgCHMYCw/image_thumb%255B11%255D?imgmax=800" border="0"></a></p><p>We can see that <strong>RefreshMode</strong> is set to <strong>Pull</strong>, a <strong>ConfigurationID</strong> is assigned and the <strong>ConfigurationRepositoryShare</strong> to our DSC SMB Pull server UNC path. Great! Our next task is to create a configuration for the target server and store it in the SMB share.</p><h1>Create DSC configuration for SMB pull target machine</h1><p>This is basically the same as creating a normal DSC configuration but instead of naming the mof file contchisql01.mof, we need to name it using the ConfigurationID of the target machine LCM i.e. c46a4a4b-8b5f-49e5-90f4-faaf80e2ec9f.mof. We also need to create a checksum file called c46a4a4b-8b5f-49e5-90f4-faaf80e2ec9f.mof.checksum.</p><blockquote><p>1. Create your configuration as normal. See my example one below which basically just creates a text file <strong>C:\testfile1.txt</strong> and sets the contents to <strong>My test file</strong></p></blockquote><blockquote><p><span style="color: rgb(0, 0, 139);">Configuration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">CreateTestFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Param</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">[</span><span style="color: rgb(173, 216, 230);">Parameter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">Mandatory</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(255, 69, 0);">$true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">]</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 128);">[string]</span><span style="color: rgb(255, 69, 0);">$ComputerName</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">)</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Import-DscResource</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ModuleName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">PSDesiredStateConfiguration</span><br><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">Node</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 139);">File</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">CreateTestFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Type</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'File'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">DestinationPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\testfile1.txt'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">Contents</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'My test file'</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><br><span style="color: rgb(0, 0, 0);">}</span></p></blockquote><blockquote><p>2. Specify the computer name and create your MOF file</p></blockquote><blockquote><p><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"contchisql01"</span><br><span style="color: rgb(0, 0, 255);">CreateTestFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-OutputPath</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\Scripts\DSC</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-puRKCByn68E/Wey25qwwnXI/AAAAAAAAC2A/kl5E75KKekMDV8dTCqi7knuYEYSbNYTtwCHMYCw/s1600-h/image%255B47%255D"><img width="504" height="126" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-AxCBMRhkOE4/Wey26V3r8WI/AAAAAAAAC2E/xxhQgf0LdI0GEXl04ExDxFT0yeF11DzkwCHMYCw/image_thumb%255B16%255D?imgmax=800" border="0"></a></p><blockquote><p>3. Get the LCM ConfigurationID and copy the mof file to the SMB share with a name <ConfigurationID>.mof</p></blockquote><blockquote><p><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-DscLocalConfigurationManager</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-CimSession</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);">).</span><span style="color: rgb(0, 0, 0);">ConfigurationID</span><br><span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\DSCSMB\'</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$guid</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'.mof'</span><br><span style="color: rgb(0, 0, 255);">Copy-Item</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">C:\Scripts\DSC\$ComputerName.mof</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-pU-68ydFjoQ/Wey26--t6zI/AAAAAAAAC2I/BOP3P1uaGtIcrZ6AOgiTLDaM_KJVQeF2gCHMYCw/s1600-h/image%255B41%255D"><img width="504" height="41" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-c-2o9PyPQ0Y/Wey27-j8ZlI/AAAAAAAAC2M/yz2Q8KJNul4YDMmAe7-F56PHuLK6KqMeQCHMYCw/image_thumb%255B14%255D?imgmax=800" border="0"></a></p><blockquote><p>4. Create a checksum file in the SMB share: <ConfigurationID>.mof.checksum</p></blockquote><blockquote><p><span style="color: rgb(0, 0, 255);">New-DscChecksum</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$DestinationFile</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Force</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-5q3xcS411AI/Wey28TJ2nNI/AAAAAAAAC2Q/IzKazxhTLL8rQlcKshyHNs5MEYVOtIDiwCHMYCw/s1600-h/image%255B44%255D"><img width="480" height="91" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-67YsBeE4mac/Wey29EDfT2I/AAAAAAAAC2U/Dd0f-NJy_DAtCMxNi-QXrI1xkyZZplqGACHMYCw/image_thumb%255B15%255D?imgmax=800" border="0"></a></p><blockquote><p>5. Now you can either wait 30mins for the target machine to apply the configuration or you can force it using <strong>Update-DscConfiguration</strong></p></blockquote><blockquote><p><span style="color: rgb(0, 0, 255);">Update-DscConfiguration</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$ComputerName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Wait</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Verbose</span></p></blockquote><strong></strong><p><a href="https://lh3.googleusercontent.com/-9-XIbPKaO-I/Wey2_HI9IkI/AAAAAAAAC2Y/VRNG6aYO2tIHNoJzX1mU9TErYqrJSO1awCHMYCw/s1600-h/image%255B53%255D"><img width="504" height="221" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-8Mf1yheXtk0/Wey3AWtfnmI/AAAAAAAAC2c/DWimeJKhSa4TTTQhJ-J98XA-jUcvnoK6wCHMYCw/image_thumb%255B18%255D?imgmax=800" border="0"></a></p><blockquote><p>6. That looks successful so let’s confirm our file is there and the contents are set:</p></blockquote><blockquote><p><span style="color: rgb(0, 0, 255);">Get-Content</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'\\contchisql01\c$\testfile1.txt'</span></p></blockquote><p><a href="https://lh3.googleusercontent.com/-PPNHWYSQX-4/Wey3BGSki0I/AAAAAAAAC2g/cE8VICLio3k1H41dyrNKtSHlud4nsxfmQCHMYCw/s1600-h/image%255B56%255D"><img width="461" height="41" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-mYuqW1LTNNA/Wey3CK22XKI/AAAAAAAAC2k/KmAUeLPJEwY3WkYaLTbCAdWwO3mKTYC4wCHMYCw/image_thumb%255B19%255D?imgmax=800" border="0"></a></p><p>There you have it - our test file is created!</p><h1>Conclusion</h1><p>In this post, we configured an SMB pull server then configured the LCM on a target machine to use the pull server. We then created a configuration for the target machine and put this in the SMB share and confirmed the target machine can pull it and apply it. </p><p>In the next post, we’ll look at HTTP pull servers.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-43481995831248083762017-10-04T20:06:00.000+01:002017-10-04T20:09:59.642+01:00VSCode - Keep focus on editor<p>In VSCode, you’ll find that when you run your script using F8 or F5, your focus will shift to the terminal which may not be what you want especially as ISE doesn’t change the focus. </p><p>To change this behaviour, just click on the settings icon and go to settings:</p><p><a href="https://lh3.googleusercontent.com/-ytIKONuutro/WdUxOCki8yI/AAAAAAAAC0k/afhPp4ByFrwmzqx5Pvl_RLFX9umOoX4WQCHMYCw/s1600-h/image%255B2%255D"><img width="214" height="238" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-5pH7I9rk69k/WdUxOiVnq-I/AAAAAAAAC0o/zOTTOk4aMPIvQLZ0g0RBgjwneCou1TV5ACHMYCw/image_thumb?imgmax=800" border="0"></a></p><p>Then add the below line into the user settings window on the right:</p><p><em><font color="#0000ff">"powershell.integratedConsole.focusConsoleOnExecute": false</font></em></p><p>It should now look like this:</p><p><a href="https://lh3.googleusercontent.com/-FiF1MitGJeE/WdUxPRmEatI/AAAAAAAAC0s/65SsqDjhBPgj6qzk_cJLoZpdiz1DXzhugCHMYCw/s1600-h/image%255B8%255D"><img width="504" height="404" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-rY5oNWkduUc/WdUxP-qKZWI/AAAAAAAAC0w/E2GsTronMPw4f5gQ947ZViR-6M6QejQDQCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>Close User Settings and save your changes and there you go. </p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-80687129157062204562017-09-18T21:17:00.000+01:002017-11-22T00:15:57.948+00:00Create a PowerShell Module<h1>Introduction</h1><p>When you build up your own library of functions, it’s really useful to have them always available on your machine without you having to load script files etc. This is where creating your own PowerShell module comes in handy. You can have all your functions available in this module and just take it around wherever you go. </p><p>Today, I’m going to write a simple function and then create my own module which includes this function.</p><h1>How to build a PowerShell module</h1><p>So, this is really not as hard as it seems. The basic steps are below:</p><ol><li>Create your functions in a single .psm1 file</li><li>Copy your .psm1 file into one of the PowerShell module folders</li><li>Create a module manifest</li></ol><h2>1 - Create your functions and save the file as .psm1 </h2><p>I’ve created three simple functions below: <span style="color: rgb(0, 0, 255);"><br></span></p><p>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">Get-LoggedOnUser</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(255, 69, 0);">$env:USERDOMAIN</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">ToLower</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"\"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(255, 69, 0);">$env:USERNAME</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">List-Process</span><span style="color: rgb(0, 0, 0);"> </span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">Get-Process</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-IncludeUserName</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br>
<br>
<span style="color: rgb(0, 0, 139);">function</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">List-MyProcesses</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">List-Process</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">|</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">?</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(255, 69, 0);">$_</span><span style="color: rgb(169, 169, 169);">.</span><span style="color: rgb(0, 0, 0);">UserName</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(169, 169, 169);">-eq</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">Get-LoggedOnUser</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">}</span><br>
<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">}</span><br><br>
</p><p><strong>Get-LoggedOnUser</strong> just gets the user name. <strong>List-Process</strong> gets a list of all processes and <strong>List-MyProcesses </strong>filters the processes using the logged on user details. </p><p>Save your functions in a .psm1 file.</p><h2>2 - Copy your .psm1 file</h2><p>You can store your psm1 file in one of three locations by default in Server 2016:</p><ul><li>C:\Users\Administrator.contoso\Documents\WindowsPowerShell\Modules<br></li><li>C:\Program Files\WindowsPowerShell\Modules<br></li><li>C:\Windows\system32\WindowsPowerShell\v1.0\Modules</li></ul><p>…..and you can confirm these are the locations by running the command below:</p><p><font color="#0000ff">$env:PSModulePath</font> -split ";"</p><p><a href="https://lh3.googleusercontent.com/-NWVbMh8Xe24/WcAp6px24cI/AAAAAAAACzs/1KROgjy_DSY_cdcE9Qec_aV-Br0lSYakACHMYCw/s1600-h/image5"><img width="504" height="106" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-j4z1hGfRLHg/WcAp7RQFxLI/AAAAAAAACzw/sFQPx0z8GA4Jr8AB3Ctut8ZNmh9fjXJSwCHMYCw/image_thumb1?imgmax=800" border="0"></a></p><p>We now need to make a folder for our module and give it a name. In this case, we will call our module <strong>ProcessTroubleshooting</strong> and we’ll save it in a module folder. </p><p>Make a new folder: <strong>C:\Program Files\WindowsPowerShell\Modules\ProcessTroubleshooting</strong></p><p>Copy the .psm1 file your created to <strong>C:\Program Files\WindowsPowerShell\Modules\ProcessTroubleshooting\ProcessTroubleshooting.psm1</strong></p><p>Note the psm1 extension. This is the convention for creating modules. </p><h2>3 - Create a module manifest</h2><p>We now need a module manifest so that our module can be loaded automatically and so that PowerShell knows which functions to provide to the user. To create a module manifest, you need to use the <strong>New-ModuleManifest </strong>cmdlet. The module manifest file is a .psd1 file.</p><h2></h2><p>
<span style="color: rgb(0, 0, 255);">New-ModuleManifest</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 128);">-Path</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\Program Files\WindowsPowerShell\Modules\ProcessTroubleshooting\ProcessTroubleshooting.psd1'</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-RootModule</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">'C:\Program Files\WindowsPowerShell\Modules\ProcessTroubleshooting\ProcessTroubleshooting.psm1'</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-Author</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(139, 0, 0);">"Mark Gossa"</span><span style="color: rgb(0, 0, 0);"> </span>`<br>
<span style="color: rgb(0, 0, 128);">-FunctionsToExport</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(138, 43, 226);">List-MyProcesses</span></p><p>We now have a module manifest which includes information about our module and very importantly which functions to export and allow the user to access. The <strong>FunctionsToExport</strong> parameter lists which functions we want to provide to users, i.e. which functions we want to export (i.e. only the <strong>List-MyProcesses</strong> function). It’s all nice and simple really. </p><p>You should now be able to import your module and use all the functions you’ve exported. In Server 2012 and later, you don’t need to even import it - Windows Server just imports it as you call one of the functions. See below for our function in action:</p><p><a href="https://lh3.googleusercontent.com/-aJMywKLvjzA/WcAp7yjXVFI/AAAAAAAACz0/Gq6rphszPvMatZN64foJTzHGZbN0AkddACHMYCw/s1600-h/image8"><img width="504" height="271" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-4d-U2tJGtxY/WcAp85ooV3I/AAAAAAAACz4/vEVBz1YPpxURH_DTr1q3QWvc04eUJp78wCHMYCw/image_thumb2?imgmax=800" border="0"></a></p><p>So, there we have it - that's how you create PowerShell modules but manual steps I hear you say? Well, you can just write your own function that will package up your module for you and create the manifest and you can even save that function in another module.</p><p>Happy scripting!</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-56406794815637241392017-09-04T22:39:00.000+01:002017-12-23T15:35:35.430+00:00Learn PowerShell DSC - Part 4<h1>Introduction</h1><p>Sometimes you can’t find the DSC resource you need built into Windows. For example, let’s say you want to deploy a certificate from your CA - the DSC resource just doesn’t exist but then there’s GitHub. I’ll demo how you can search for and install the xCertificate DSC resource then how to use it in your configuration. </p><p>Other parts in this series:</p><ul><li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn PowerShell DSC Part 1</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-2.html">Learn PowerShell DSC Part 2</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-3.html">Learn PowerShell DSC Part 3</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn PowerShell DSC Part 5</a></li><!--StartFragment-->
<li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn
PowerShell DSC Part 6</a></li>
<li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn
PowerShell DSC Part 7</a></li><!--EndFragment--></ul><h1>Find DSC Resources</h1><p>GitHub is a great repository for DSC resources which are not yet included in Windows. You can go to GitHub and download the additional DSC resources you need or you can just search for them using PowerShell:</p><p><font color="#0000ff" face="Courier New">Find-Module -Tag dsc</font></p><p><a href="https://lh3.googleusercontent.com/-097bxJB0SQ8/Wa3HtReB6pI/AAAAAAAACyY/ul8yl4y_acwN0EM4Tsz4OHFSalNuw1W_wCHMYCw/s1600-h/image5"><img width="504" height="229" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-IAsrg19n5DU/Wa3HuW08J_I/AAAAAAAACyc/8GvsTvdn_xkNpakFzVcZlSQYISZ45zP-ACHMYCw/image_thumb1?imgmax=800" border="0"></a></p><p>You can also filter by name e.g.</p><p><font color="#0000ff" face="Courier New">Find-Module -Tag dsc -Name *cert*</font></p><p><a href="https://lh3.googleusercontent.com/-d6NuxUbB7AA/Wa3HvLaDWbI/AAAAAAAACyg/_RlKUVmKJukimnpqWBWoT9ftNTLYEzYtgCHMYCw/s1600-h/image8"><img width="504" height="229" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-aLRx8ZHXCt4/Wa3HvxXR3SI/AAAAAAAACyk/LJWw3pu9t7EKpexl-IOHtZcJAThvfNf5wCHMYCw/image_thumb2?imgmax=800" border="0"></a></p><p>Our module is called xCertificate. Now, that was quite easy. Let’s move on.</p><h1>Install DSC Resource</h1><p>The DSC resource is actually part of a module which we need to install. To do this, we simply run the command below. It will prompt you to install a NuGet module if you don’t already have it - this is used to get modules from GitHub:</p><p><font color="#0000ff" face="Courier New">Install-Module xCertificate -Force</font></p><p><a href="https://lh3.googleusercontent.com/-wafBYozRJgg/Wa3H1oxK5KI/AAAAAAAACyo/S_6IJK8VhrEyCt2k6lX7FUOVhAx66R6UQCHMYCw/s1600-h/image11"><img width="504" height="229" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-3aDpZEJ1sNg/Wa3H25B_qsI/AAAAAAAACys/Mg9rjp-Yf5QaqInyrbf9Sa_gXxdDZ8KswCHMYCw/image_thumb3?imgmax=800" border="0"></a></p><p>We can check our module is installed too:</p><p><font color="#0000ff" face="Courier New">Get-Module xCertificate -ListAvailable</font></p><p><a href="https://lh3.googleusercontent.com/-i8g53vLc6EE/Wa3H4AgVA1I/AAAAAAAACyw/dxyGUMR8vYExH-pdVnr1sjcXWDhdvUtXQCHMYCw/s1600-h/image14"><img width="504" height="229" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-587QOj_UpU0/Wa3H5Lna2wI/AAAAAAAACy0/YeWGuuz_4NwU5jm2KVP18nL9e8YhcgXlQCHMYCw/image_thumb4?imgmax=800" border="0"></a></p><p>You need to install the module on the server you’re writing your configuration on and also on the target server (the one that will receive the configuration). In upcoming articles, I’ll explain how to pull configurations using SMB or HTTPS. Using a pull server, you not only have a central repository for configurations but also have a central repository for the modules which are pulled as well. How good is that!?</p><p>To save time and install the module on a remote computer (contchidsc01), we can use remote PowerShell to install the NuGet Package Provider and xCertificate module:</p><p><font color="#0000ff" face="Courier New">icm contchidsc01 {Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force<br> Install-Module xCertificate -Force<br> }</font></p><p><a href="https://lh3.googleusercontent.com/-4mlxQoY4__k/Wa3H5ou5oCI/AAAAAAAACy4/wmE-jO6xdfg5JVA70aX9NpjgVTrzIAevgCHMYCw/s1600-h/image17"><img width="504" height="39" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/--Y1mdBVdngk/Wa3H6bTzW8I/AAAAAAAACy8/NsKsX01NEzII3K9anmfER1skWaTCAmLPQCHMYCw/image_thumb5?imgmax=800" border="0"></a></p><h1>Deploy a certificate with DSC</h1><p>Okay, so we now have all the pre-requisites we need. We have the DSC resource on our development machine and our target server. Let’s go ahead and write a DSC configuration. If you’re not familiar with this then go back and review <a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">part 1</a>. You’ll see I’m using parameters in my configuration - if you’re not familiar with this, go and review <a href="http://markgossa.blogspot.co.uk/2017/09/learn-powershell-dsc-part-3.html">part 3</a>.</p><p>The plan is to deploy a new certificate to our target server, contchidsc01. The details are below:</p><ul><li>Subject: contchidsc01.contoso.com</li><li>Subject alternative names: contchidsc01.contoso.com, contshidsc01</li><li>Exportable: true</li><li>Certificate Template: Server</li></ul><p><font color="#0000ff" face="Courier New">configuration HTTPSPullServerCertificate<br> {<br> Param (<br> [Parameter(Mandatory = $true)]<br> [string] $ComputerName<br> )</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> # Modules must exist on target pull server<br> Import-DSCResource -ModuleName PSDesiredStateConfiguration<br> Import-DscResource -ModuleName xCertificate</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> Node $ComputerName<br> {<br> $ComputerFqdn = $ComputerName + ".contoso.com"</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> xCertReq Certificate<br> {<br> Subject = $ComputerFqdn<br> SubjectAltName = "dns=$ComputerFqdn&dns=$ComputerName"<br> Exportable = $true<br> CertificateTemplate = "Server"<br> }<br> }<br> }</font><br>
</p><p><a href="https://lh3.googleusercontent.com/-2FxlLCqKE90/Wa3H62aYWFI/AAAAAAAACzA/e_QXv-H6kkgJpoICj-PODB1I9nqoVk4zACHMYCw/s1600-h/image%255B2%255D"><img width="504" height="265" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ckFvQ48-B1U/Wa3H7m2ugjI/AAAAAAAACzE/ko-djhWmqAIpToKIKMaE_ilUq_u_z_GywCHMYCw/image_thumb?imgmax=800" border="0"></a></p>
<p>You’ll see we’re using our new xCertificate module and calling a new resource called xCertReq. The xCertReq DSC resource is what we need to request a certificate from the CA. There are other DSC resources available in the module and you can find all the documentation on GitHub <a href="https://github.com/PowerShell/xCertificate/blob/dev/README.md" target="_blank">here</a>.</p><p>This line below simply gets the FQDN of the computer and saves it as $ComputerFqdn. We use it to add it to the certificate names:</p><p><font color="#0000ff" face="Courier New">$ComputerFqdn = $ComputerName + ".contoso.com”</font></p><p>Now, let’s create our MOF files:</p><p><font color="#0000ff" face="Courier New">HTTPSPullServerCertificate -ComputerName contchidsc01 -OutputPath C:\DSC\Certificate</font><br>
</p><p>…..and push our configuration:</p><p><font color="#0000ff" face="Courier New">Start-DscConfiguration -Path C:\DSC\Certificate -Verbose -Wait -Force</font></p><p>then test our configuration was deployed successfully:</p><p><font color="#0000ff" face="Courier New">Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Certificate</font></p><p>The entire script is below:</p><p><font color="#0000ff" face="Courier New">configuration HTTPSPullServerCertificate<br> {<br> Param (<br> [Parameter(Mandatory = $true)]<br> [string] $ComputerName<br> )</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> # Modules must exist on target pull server<br> Import-DSCResource -ModuleName PSDesiredStateConfiguration<br> Import-DscResource -ModuleName xCertificate</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> Node $ComputerName<br> {<br> $ComputerFqdn = $ComputerName + ".contoso.com"</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> xCertReq Certificate<br> {<br> Subject = $ComputerFqdn<br> SubjectAltName = "dns=$ComputerFqdn&dns=$ComputerName"<br> Exportable = $true<br> CertificateTemplate = "Server"<br> }<br> }<br> }</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">#Create MOF file<br>
HTTPSPullServerCertificate -ComputerName contchidsc01 -OutputPath C:\DSC\Certificate<br>
#Push the configuration<br>
Start-DscConfiguration -Path C:\DSC\Certificate -Verbose -Wait -Force<br>
#Test the configuration<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Certificate</font></p><p><font color="#0000ff"></font></p><p><a href="https://lh3.googleusercontent.com/-OG9IRKSlN9c/Wa3H8RabZ2I/AAAAAAAACzI/AXhAjKjRbB85slDgCDen1FGdNtoV5vvPACHMYCw/s1600-h/image%255B5%255D"><img width="504" height="316" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-dfKaoAAdNCE/Wa3H9pCe9SI/AAAAAAAACzM/8DubnqfFy-EW8VivnTMl5qQFUpas_v-3ACHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><p>Let’s go ahead and run it:</p><p><a href="https://lh3.googleusercontent.com/-qOj6AN5IW9A/Wa3H_LOB-sI/AAAAAAAACzQ/i-wtBbCIXekyvdOUZN40RUiOYOgffnQZgCHMYCw/s1600-h/image26"><img width="504" height="430" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-6zTL0IF7QBc/Wa3IAMDntoI/AAAAAAAACzU/st_Y-RbLpE4QRD-1oGoK2H_XPqmlf5XvACHMYCw/image_thumb8?imgmax=800" border="0"></a></p><p>Now, that’s a lot of info because we’re using the -Verbose switch on the Start-DscConfiguration cmdlet. If you look closely at the blue section, you’ll see DSC doing this:</p><ul><li>Locate the CA</li><li>Call certutil to ping the CA to check it’s online</li><li>Check for a certificate which matches the names we’ve requested</li><li>Create a certificate request</li><li>Install the certificate</li></ul><p>At the end, in white, Test-DscConfiguration runs and states that our target machine is in the desired state so let’s check we have the correct certificate installed on our target machine:</p><p>Connect to remote PowerShell on the target computer:</p><p><font color="#0000ff" face="Courier New">Enter-PSSession contchidsc01</font></p><p>Open up the local computer certificate store:</p><p><font color="#0000ff" face="Courier New">cd Cert:\LocalMachine\My\</font></p><p>List the certificates:</p><p><font color="#0000ff" face="Courier New">dir</font></p><p><a href="https://lh3.googleusercontent.com/-AcPL7TAXD8s/Wa3IAxGou-I/AAAAAAAACzY/ThhZBgXP0W0YUb_NpwRTDroTENcUe4zHQCHMYCw/s1600-h/image29"><img width="504" height="229" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-helFjvnWVpU/Wa3ICN-1PTI/AAAAAAAACzc/WADj3FET-LkWntESwVaRVvT-y_LQeOfEgCHMYCw/image_thumb9?imgmax=800" border="0"></a></p><p>Now we have our certificate installed! </p><h1>Conclusion</h1><p>We’re learning quite a lot about DSC. We’re now able to find the DSC resources we need to do almost anything we need to do and we know how to find the documentation, download the modules and use the included DSC resources. So far, we’ve been pushing configurations using Start-DscConfiguration but in the upcoming posts, we’ll look at configuring SMB or HTTPS pull servers.<br></p>
<p><font face="Courier New"></font></p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-78603106285244865632017-09-03T22:51:00.000+01:002017-12-23T15:34:39.892+00:00Learn PowerShell DSC - Part 3<h1>Introduction</h1><p>So, we’ve learnt a bit about the basics of DSC with a simple configuration using the File DSC resource in <a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">part 1</a> and then moved on to discuss other DSC resources you can find built into Windows in <a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-2.html">part 2</a>. </p><p>In this post, I’ll show you how you can integrate parameters when creating DSC configurations and also how you can set up dependencies between different DSC resources in your configuration.</p><p>Other parts in the series can be found below:</p><ul><li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn PowerShell DSC Part 1</a></li><li><a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-2.html">Learn PowerShell DSC Part 2</a></li><li><a href="https://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-4.html">Learn PowerShell DSC Part 4</a></li></ul><ul><!--StartFragment-->
<li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn
PowerShell DSC Part 5</a></li>
<li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn
PowerShell DSC Part 6</a></li>
<li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn
PowerShell DSC Part 7</a></li><!--EndFragment--></ul><h1>PowerShell DSC parameters</h1><p>Why are we doing this? Well, it allows you to specify variables which are used to generate the configuration which is then pushed out to the target machines.</p><p>In this example which uses the Registry DSC resource to create registry values, I have four parameters that I want to pass to the configuration:</p><ul><li><strong>ComputerName</strong> - this determines which target machines the configuration will be pushed out to</li><li><strong>Key</strong> - this is the registry key</li><li><strong>ValueName</strong> - this is the name of the value</li><li><strong>ValueData</strong> - this is the data that goes in the registry value</li><li><strong>ValueType</strong> - this is the type of value, e.g. string, binary, dword</li></ul><p>You specify the parameters as you would normally when writing a script or a function so this section looks like this:</p><p><font color="#0000ff" face="Courier New">param<br> (<br> [Parameter(Mandatory=$true)]<br> [string]$ComputerName,<br> [Parameter(Mandatory=$true)]<br> [string]$Key,<br> [Parameter(Mandatory=$true)]<br> [string]$ValueName,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueData,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueType<br> )</font> </p><p>Nothing earth shattering here so stay with me. Let’s now make a configuration using the Registry DSC resource but instead of specifying the key, value and other parameters, we’ll use variables:</p><p><font color="#0000ff" face="Courier New">configuration RegistryConfig<br>
{<br> param<br> (<br> [Parameter(Mandatory=$true)]<br> [string]$ComputerName,<br> [Parameter(Mandatory=$true)]<br> [string]$Key,<br> [Parameter(Mandatory=$true)]<br> [string]$ValueName,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueData,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueType<br> ) </font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node $ComputerName<br> { <br> Registry CreateReg <br> {<br> Key = $Key<br> ValueName = $ValueName<br> ValueType = $ValueType<br> ValueData = $ValueData<br> Ensure = 'Present'<br> } <br> }<br>
}</font></p><p>We can then generate the MOF file and specify what we need the key, value, value data and type to be and also which target machine to create the configuration for:</p><p><font color="#0000ff" face="Courier New">RegistryConfig -OutputPath C:\DSC\Registry -ComputerName contchidsc01 `<br>
-Key HKEY_Local_Machine\Software\DSCTest -ValueName DSCTestGood -ValueData True -ValueType string</font></p><p>Now we have our MOF file, we can push it to our target machine contchidsc01:</p><p><font color="#0000ff" face="Courier New">Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Registry -Wait -Verbose -Force<br>
</font></p><p>The full script is below:</p><p><font color="#0000ff" face="Courier New">configuration RegistryConfig<br>
{<br> param<br> (<br> [Parameter(Mandatory=$true)]<br> [string]$ComputerName,<br> [Parameter(Mandatory=$true)]<br> [string]$Key,<br> [Parameter(Mandatory=$true)]<br> [string]$ValueName,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueData,<br> [Parameter(Mandatory=$false)]<br> [string]$ValueType<br> ) </font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node $ComputerName<br> { <br> Registry CreateReg <br> {<br> Key = $Key<br> ValueName = $ValueName<br> ValueType = $ValueType<br> ValueData = $ValueData<br> Ensure = 'Present'<br> } <br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">RegistryConfig -OutputPath C:\DSC\Registry -ComputerName contchidsc01 `<br>
-Key HKEY_Local_Machine\Software\DSCTest -ValueName DSCTestGood -ValueData True -ValueType string<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Registry -Wait -Verbose -Force<br>
</font></p>
<p><a href="https://lh3.googleusercontent.com/-Q2R4bSHDn2I/Wax5KxO37eI/AAAAAAAACxE/mu367YQIANo6BbiwfvDpdq2jAtG15gKZQCHMYCw/s1600-h/image%255B2%255D"><img width="504" height="300" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-7-brReZBPII/Wax5Ld-wnZI/AAAAAAAACxI/9vbCm_PJpYgJB40bc2Xcy_iBsXMQJOpQACHMYCw/image_thumb?imgmax=800" border="0"></a></p><p>When we run this, we can see that the <strong>HKEY_Local_Machine\Software\DSCTest</strong> key is created then the <strong>DSCTestGood</strong> value is created and set to <strong>True </strong>and the type is set to <strong>REG_SZ</strong>, (string)<strong>.</strong></p><p><a href="https://lh3.googleusercontent.com/-c6eq3dskSvM/Wax5LyI_DlI/AAAAAAAACxM/4z7obn-XmhYl9jfU-3JgnjsPZV-cspEhQCHMYCw/s1600-h/image%255B5%255D"><img width="504" height="287" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-37IHeOUN0pE/Wax5MrGo6-I/AAAAAAAACxQ/WI04q3v0N7gbbjpS27oFJ9ONO7eEpcvmwCHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><p>So, there we have it. PowerShell parameters. Now, let’s say you need to deploy a number of different registry keys and values to a number of machines and you have it all in a CSV. Well, now you can do that quite easily - all using the same configuration. </p><h1>PowerShell DSC DependsOn</h1><p>Let’s say we need to copy a zip file to a target machine and then extract that zip file to a folder. Now, clearly we don’t want DSC to try extract a zip file before it’s been copied over because that would be rather dumb. Here’s where we can specify the order that DSC Resources are processed in a configuration - by using the <strong>DependsOn </strong>parameter which is built into DSC resources.</p><p>We’ll use the File DSC resource to copy the zip file over then we’ll use the Archive DSC resource to extract it but we’ll specify that the Archive DSC resource depends on the File DSC resource:</p><p><font color="#0000ff" face="Courier New">configuration Archive<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> File CopyArchive<br> {<br> SourcePath = '\\contchisql01\Software\Docker.zip'<br> DestinationPath = 'C:\Software\Docker.zip'<br> Type = 'File'<br> Ensure = 'Present'<br> } </font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> Archive ExtractArchive<br> {<br> Path = 'C:\Software\Docker.zip'<br> Destination = 'C:\Software\Docker'<br> DependsOn = "[File]CopyArchive"<br> }<br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">Archive -OutputPath C:\DSC\Archive<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Archive -Wait -Verbose -Force<br>
</font></p>
<p><a href="https://lh3.googleusercontent.com/-l5saBnz9NPI/Wax5N6pdFpI/AAAAAAAACxU/wagJvG29XqoSYm2Pz8AdbkquSef9EC7GQCHMYCw/s1600-h/image%255B8%255D"><img width="504" height="232" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-wUvkpON3_9A/Wax5OrsbUHI/AAAAAAAACxY/cHB3dUiFN2ciT4P8jVoguTAtYRQLavkPgCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>When we run this configuration and push it out, we see that our zip file is copied then extracted:</p><p><a href="https://lh3.googleusercontent.com/-lDTAdUwLwM4/Wax5OzdmWdI/AAAAAAAACxc/Khb7x-v8YHoZmluNla2-kU6mMD9rXNz3wCHMYCw/s1600-h/image%255B11%255D"><img width="504" height="177" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-1ypn0keEoqE/Wax5Pf34cGI/AAAAAAAACxg/_S9XtskDObkO9euGRR_jzopzPASq99_YgCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p>We can also look at the output from Start-DscConfiguration and we’ll see that the File DSC resource is run before the Archive DSC resource:</p><p><a href="https://lh3.googleusercontent.com/-2dbZHawR-D4/Wax5QVLtDkI/AAAAAAAACxk/l51J10qGF0wTUFC5pbf_LAqTlXyd_mjVQCHMYCw/s1600-h/image%255B14%255D"><img width="504" height="231" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-pbTcXRORF2E/Wax5Q6jAY0I/AAAAAAAACxo/COJv4JqXVbEC5TC0gq7jPeyLl7lSk0A4wCHMYCw/image_thumb%255B4%255D?imgmax=800" border="0"></a></p><p>So, now you can get your configuration to apply DSC resources in order and ensure dependencies are met.</p><h1>Conclusion</h1><p>That’s DSC working with parameters and dependencies. I hope you’re starting to get into PowerShell DSC as much as I am! Next up, we’ll look at how to find, install and use DSC modules that are not build into Windows.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-90755526050127043462017-09-02T23:09:00.000+01:002017-12-23T15:33:43.111+00:00Learn PowerShell DSC - Part 2<h1>Introduction</h1><p>In <a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">part 1</a>, we went through how to make a simple configuration using the File DSC resource and then how to push it out to a single computer. In this part, we’ll go through how to learn about the available DSC resources and demo a few of them.</p><p>To go to other parts of this series, see below:</p><ul><li><a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">Learn PowerShell DSC Part 1</a></li><li><a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-3.html">Learn PowerShell DSC Part 3</a></li><li><a href="https://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-4.html">Learn PowerShell DSC Part 4</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn
PowerShell DSC Part 5</a></li>
<li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn
PowerShell DSC Part 6</a></li>
<li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn
PowerShell DSC Part 7</a></li><!--EndFragment--></ul><h1>List DSC Resources</h1><p>Windows has a number of DSC resources built in and you can view the list by using Get-DscResource:</p><p><font color="#0000ff" face="Courier New">Get-DscResource -Module PSDesiredStateConfiguration</font></p><p><a href="https://lh3.googleusercontent.com/-0NzRKIjUWQk/WasryGzo1tI/AAAAAAAACvI/o2vVAwUxoD0YidjIVuqgi2zOaj6BbUJdgCHMYCw/s1600-h/image%255B2%255D"><img width="504" height="220" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-wzS_ls3sntc/WasrzpOabKI/AAAAAAAACvM/9VznmsSd_vovFztXd6E320Cc7HmeA6EMwCHMYCw/image_thumb?imgmax=800" border="0"></a></p><h1>Get help for a DSC Resource</h1><p>Now, let’s say you think you need to use the Service DSC resource but you don’t know the syntax, you can use Get-DscResource:</p><p><font color="#0000ff" face="Courier New">Get-DscResource Service -Syntax</font></p><p><a href="https://lh3.googleusercontent.com/-Es3NAnJEfbg/Wasr0ESp6aI/AAAAAAAACvQ/yOsgrtmGK4gWnBpVMYQB3Cgo-Fg8IzBGQCHMYCw/s1600-h/image%255B5%255D"><img width="504" height="146" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-H7Okl-O1_X0/Wasr0-w3iWI/AAAAAAAACvU/8YRvhZh-plUXwBae2dF6I8RAe6UYatZaACHMYCw/image_thumb%255B1%255D?imgmax=800" border="0"></a></p><p>You can also use Get-DscResource to get information about what properties you can set:</p><p><font color="#0000ff" face="Courier New">Get-DscResource Service | % Properties</font></p><p><a href="https://lh3.googleusercontent.com/-Zm5yK-nKA_A/Wasr2sc9MtI/AAAAAAAACvY/tCeP93IgXNEMWGPWQjMEvJO2zvg5yzt-QCHMYCw/s1600-h/image%255B11%255D"><img width="504" height="146" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-O5YKCBMAKio/Wasr3pXgtfI/AAAAAAAACvc/-Umj_Ls2ILYyHAD6W2lhmteaIEQN-TupQCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><h1>Service DSC Resource Example</h1><p>As we’ve just seen the syntax of how to use this DSC resource, let’s start with this. </p><p>My target machine has the Windows Audio service stopped and the service is set to manual start:</p><p><font color="#0000ff" face="Courier New">Get-Service Audiosrv | fl *</font></p><p><a href="https://lh3.googleusercontent.com/-W8IwhID2o9Q/Wasr4BIFS1I/AAAAAAAACvg/I9bgFPMaoIERLtJz-r7aDsGNWAKIQEnygCHMYCw/s1600-h/image%255B14%255D"><img width="504" height="236" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-h-IWBxyqPr0/Wasr48Arn4I/AAAAAAAACvk/Hn4eW3J6v1sENSXMb-XijUvwBSqCyK8vACHMYCw/image_thumb%255B4%255D?imgmax=800" border="0"></a></p><p>I want to set this to start automatically and to also start the service so the configuration I’d use is below. (Remember to import the correct module that has your DSC resource - in our case it’s the PSDesiredStateConfiguration module):</p><p><font color="#0000ff" face="Courier New">configuration Service<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01 <br> {<br> Service WindowsAudio<br> {<br> Name = "audiosrv"<br> StartupType = "Automatic"<br> State = "Running"<br> }<br> }<br>
}</font><br></p>
<p><a href="https://lh3.googleusercontent.com/-85U6SBClny4/Wasr5SXJNkI/AAAAAAAACvo/zjuG0Bk1iagxpATOYrZJ7KNTLNiLoJcLACHMYCw/s1600-h/image%255B41%255D"><img width="502" height="181" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-Y7tWNvHTKcI/Wasr6T-yvvI/AAAAAAAACvs/wmcrTSX6K3ISEGIfLLG4TyVglKrZ3iWTwCHMYCw/image_thumb%255B13%255D?imgmax=800" border="0"></a></p><p>Run your configuration - you should see no output from this.</p><p>As in <a href="http://markgossa.blogspot.com/2017/08/learn-powershell-dsc-part-1.html">part 1</a>, we create a MOF file:</p><p><font color="#0000ff" face="Courier New">Service -OutputPath C:\DSC\Service</font></p><p><a href="https://lh3.googleusercontent.com/-0yobxBcjsH4/Wasr7OrXjpI/AAAAAAAACvw/1DfV9w0C3xciOJjNB-bSNOJGSivkK1C_wCHMYCw/s1600-h/image%255B44%255D"><img width="504" height="143" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-nO3SyfRrQK4/Wasr8KCxH7I/AAAAAAAACv0/o8eE2xI1by4VRJSbd3r1x5RB3odxS1PcwCHMYCw/image_thumb%255B14%255D?imgmax=800" border="0"></a></p><p>…….then push the configuration to our target machine contchidsc01:</p><p><font color="#0000ff" face="Courier New">Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Service -Wait -Verbose -Force</font></p><p><font color="#0000ff" face="Courier New"></font><a href="https://lh3.googleusercontent.com/-UyqsZT2G0wA/Wasr862XzEI/AAAAAAAACv4/GcyvUq95YwYSE9nO8wto3dqn7yjEKELwwCHMYCw/s1600-h/image%255B47%255D"><img width="504" height="180" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-_kvhcp4PUkM/Wasr9ynVX7I/AAAAAAAACv8/4kQz8ivR5hcAXioc64MDUpTctzUhEBrugCHMYCw/image_thumb%255B15%255D?imgmax=800" border="0"></a><br>
</p><p>……and then we confirm that our target machine matches the configuration:</p><p><font color="#0000ff" face="Courier New">Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Service</font><br>
</p><p><a href="https://lh3.googleusercontent.com/-6y_zViDOePc/Wasr-RZx3FI/AAAAAAAACwA/aCZ_lRCWa8ooHo_sSTOVcLCaDzTctl-mwCHMYCw/s1600-h/image%255B50%255D"><img width="504" height="65" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-sjDEPG8L3kI/Wasr_c1iQuI/AAAAAAAACwE/fFx-kZZhJxMhJbyMdUVrKUGTGc2iwRhbQCHMYCw/image_thumb%255B16%255D?imgmax=800" border="0"></a></p><p>We can also check the service to make sure it’s started and start up is automatic:</p><p><font color="#0000ff" face="Courier New">Get-Service Audiosrv | fl *</font></p><p><a href="https://lh3.googleusercontent.com/-8Oa52RLZ-TU/WassAPd2k-I/AAAAAAAACwI/Xq2X-xNRsQsJf21AHULT3-AaC7oudvmSACHMYCw/s1600-h/image%255B56%255D"><img width="504" height="343" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-lHxJZfdFNfo/WassBF5lIGI/AAAAAAAACwM/NYq60oHCQRc8JZvNA20OC6wc7iKnZ_cTwCHMYCw/image_thumb%255B18%255D?imgmax=800" border="0"></a></p><h1>Archive DSC Resource Example</h1><p>This allows you to extract a zip file from a location into a location on the target machine. See the example below:</p><ul><li>Source zip file: <a href="file://\\contchisql01\Software\Docker.zip">\\contchisql01\Software\Docker.zip</a></li><li>Destination folder: C:\Software\Docker</li></ul><p><font color="#0000ff" face="Courier New">configuration Archive <br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> Archive Unzip<br> {<br> Destination = 'C:\Software\Docker'<br> Path = '\\contchisql01\Software\Docker.zip'<br> Checksum = 'SHA-256'<br> Validate = $true<br> Force = $true<br> Ensure = 'Present'<br> }<br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">Archive -OutputPath C:\DSC\Archive<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Archive -Wait -Verbose -Force<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Archive</font></p><p><a href="https://lh3.googleusercontent.com/-6pXaDcuoWLo/WassBjFuamI/AAAAAAAACwQ/cGW-2UpVrS0T_p_DOfyU1BsLLF61IdBSACHMYCw/s1600-h/image%255B59%255D"><img width="504" height="190" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-s2ZdgGKRz70/WassCfYzH2I/AAAAAAAACwU/cYfPlrgoJHE2V2DRHAQ4jnZ8WPJKcwr1ACHMYCw/image_thumb%255B19%255D?imgmax=800" border="0"></a></p><h1>Environment DSC Resource Example</h1><p>This DSC resource adds environment variables. In this case, it creates a new variable called NewVar and gives it a value of ‘Value to store’.</p><p><font color="#0000ff" face="Courier New">configuration Environment <br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> Environment NewVar<br> {<br> Name = 'MYNEWVAR'<br> Value = 'Value to store'<br> Ensure = 'Present'<br> }<br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">Environment -OutputPath C:\DSC\Environment<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Environment -Wait -Verbose -Force<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Environment</font></p><p><a href="https://lh3.googleusercontent.com/-9k4IWH0qN9g/WassDA65atI/AAAAAAAACwY/rXPGOg2sLEMTPrNDKjC1tPIY7TOCyoTGACHMYCw/s1600-h/image%255B62%255D"><img width="504" height="156" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-XdHYf0D_9CQ/WassD4nBj8I/AAAAAAAACwc/nzJkueHbjMUqbpfsL6vRmYqTs6ZV-QbDACHMYCw/image_thumb%255B20%255D?imgmax=800" border="0"></a></p><h1>Group DSC Resource Example</h1><p>This DSC resource creates a local group and can set the members for it too. This example creates a group called TestGroup and makes Administrator a member of it. </p><p><font color="#0000ff" face="Courier New">configuration GroupConfig<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> Group TestGroup<br> {<br> Ensure = 'Present'<br> GroupName = 'TestGroup'<br> Description = 'This is a DSC test group'<br> Members = 'administrator'<br> } <br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">GroupConfig -OutputPath C:\DSC\Group<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Group -Wait -Verbose -Force<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Group</font></p><p><a href="https://lh3.googleusercontent.com/-zDrrFvODARE/WassFPOrEuI/AAAAAAAACwg/NxWNb2rZdQ0cTedQNandFTYMwZTjZg6vACHMYCw/s1600-h/image%255B65%255D"><img width="504" height="176" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-KbbvZhMymqM/WassF2_XcQI/AAAAAAAACwk/prJhdN7pM1QNKNAkbwZ40nPCn-sxoNzegCHMYCw/image_thumb%255B21%255D?imgmax=800" border="0"></a></p><h1>Process DSC Resource Example</h1><p>This DSC resource starts or stops a particular process. You can also specify the arguments for the process too. This example ensures that notepad.exe is running.</p><p><font color="#0000ff" face="Courier New">configuration ProcessConfig<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> WindowsProcess MSPaint <br> {<br> Path = 'notepad.exe'<br> Arguments = ''<br> }<br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">ProcessConfig -OutputPath C:\DSC\Process<br>
Start-DscConfiguration -Computername contchidsc01 -Path C:\DSC\Process -Wait -Verbose -Force<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Process</font></p><p><a href="https://lh3.googleusercontent.com/-TB70xQZH9SY/WassGkN7-oI/AAAAAAAACwo/hwhWrH-zJp8JElxmt2b9wFdGqHUkDpGNwCHMYCw/s1600-h/image%255B68%255D"><img width="504" height="153" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-Zd6jkX3hJ48/WassHV87KzI/AAAAAAAACws/5sDwxKBzqB4lBX2G2lJqNE7brzN_rnB8QCHMYCw/image_thumb%255B22%255D?imgmax=800" border="0"></a></p><h1>Registry DSC Resource Example</h1><p>You can use this DSC resource to create, delete or set registry keys and values. This example creates a registry key 'HKEY_Local_Machine\Software\DSCTest' with the below value:</p><ul><li>Name: DSCTestGood </li><li>Value: True</li><li>Type: REG_SZ (string)</li></ul><p><font color="#0000ff" face="Courier New">configuration RegistryConfig<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration<br> Node contchidsc01<br> { <br> Registry CreateReg <br> {<br> Key = 'HKEY_Local_Machine\Software\DSCTest'<br> ValueName = 'DSCTestGood'<br> ValueType = 'string'<br> ValueData = 'True'<br> } <br> }<br>
}</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New">RegistryConfig -OutputPath C:\DSC\Registry<br>
Start-DscConfiguration -Computername contchidsc01 </font><font color="#0000ff" face="Courier New">-Path C:\DSC\Registry -Wait -Verbose -Force<br>
Test-DscConfiguration -ComputerName contchidsc01 -Path C:\DSC\Registry</font></p><p><a href="https://lh3.googleusercontent.com/-PJcikF8VubM/WassH6zNwMI/AAAAAAAACww/PSctHpuVMhA4HBFqMwA2VZeRkrhfcl4MQCHMYCw/s1600-h/image%255B71%255D"><img width="504" height="170" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-ZHXlaqptyzY/WassI3WGgkI/AAAAAAAACw0/4um6kIXdG7shV2gn46k_yZpeKNvGE-NOwCHMYCw/image_thumb%255B23%255D?imgmax=800" border="0"></a></p><h1>Conclusion</h1><p>As you can see, you can do a lot with PowerShell DSC and these are just a few of the built in DSC resources you can use. There’s a lot more on GitHub and we’ll come to this in part 4. Stay tuned for <a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-3.html">part 3</a> where we’ll start using parameters and a setting called DependsOn.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-77821619361362498992017-08-28T22:18:00.001+01:002017-12-23T15:32:42.223+00:00Learn PowerShell DSC - Part 1<h1>
Introduction</h1><p>
PowerShell DSC. What’s that? DSC stands for Dynamic State Configuration. It sounds like it could get a little complicated but if you’re just starting out using PowerShell to deploy configurations to machines then you’ll probably be lost in long scripts which check whether your configuration is correct then takes the steps to correct it.</p><p>To go to other parts of this series, see below:</p><ul><li><a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-2.html">Learn PowerShell DSC Part 2</a></li><li><a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-3.html">Learn PowerShell DSC Part 3</a></li><li><a href="https://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-4.html">Learn PowerShell DSC Part 4</a></li><li><a href="http://markgossa.blogspot.co.uk/2017/10/learn-powershell-dsc-part-5.html">Learn PowerShell DSC Part 5</a></li><li><a href="https://markgossa.blogspot.com/2017/11/learn-powershell-dsc-part-6.html">Learn PowerShell DSC Part 6</a></li><li><a href="https://markgossa.blogspot.co.uk/2017/11/learn-powershell-dsc-part-7.html">Learn PowerShell DSC Part 7</a><br></li></ul>
<p>You would have to write out the check statements and then write out all the logic to install the feature or copy the file etc. <br>
</p><p>With PowerShell DSC, you just state what you want your configuration to look like and DSC just “makes it so” and that’s the beauty of DSC. <br>
</p><p><a href="https://lh3.googleusercontent.com/-Kk8bJOYG_Ic/WaHStawiWZI/AAAAAAAACug/8JVqb8OdFTYvfSClFhXi7kHX-Elth93AQCHMYCw/s1600-h/image%255B42%255D"><img width="504" height="203" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-7KHGDoOFPPU/WaHStjHMflI/AAAAAAAACuk/GsC4gY0wZt0Akc4aUBXnK5KITz2QeFNKwCHMYCw/image_thumb%255B13%255D?imgmax=800" border="0"></a><br>
</p><h1>
Advantages of PowerShell DSC</h1><p>
As explained above, you need to write less code. That’s great but there’s more. <br></p>
<h3>
1) You can read through your code easier</h3><p>
This is called a configuration document. Rather than having a long script with if statements and lots of logic, you now just have a simpler script which states what you want the configuration to look like.<br></p>
<h3>
2) Look for configuration drift</h3><p>
DSC allows you to check a server against a configuration document to make sure there hasn’t been any changes.<br></p>
<h3>
3) Auto-remediation</h3><p>
DSC periodically checks a server’s configuration against the configuration document and then can be set to automatically restore the configuration to what it should be<br></p>
<h3>
4) Remote execution</h3><p>
You can deploy a configuration to remote machines and you can apply the same configuration to many machines<br></p>
<h3>
5) Centralised repository</h3><p>
You can configure your servers to pull their configuration from a central repository. This saves you having to copy scripts around and helps you manage versioning.<br></p>
<h3>
6) Works with workgroup servers</h3><p>
You’re not tied down to Kerberos authentication! You can deploy configurations to remote machines which are not on the domain.<br></p>
<h3>
7) Different teams can manage different configurations</h3><p>
This is called partial configurations. For example it allows your DBAs to manage the SQL related configuration while your systems team can manage the networking and your developers manage IIS.<br></p>
<h3>
8) One to many deployment</h3><p>
You can deploy the same configuration to more than one server at a time.<br>
</p><p>As you can see, DSC is really the best thing since sliced bread! It saves so much time and is a very elegant and efficient way to deploy configurations. <br></p>
<h1>
PowerShell DSC Example</h1><p>
Let’s take a look at a quick example. Let’s say we just want to make sure that an install file is copied to C:\Software on our server.<br></p>
<ul>
<li>Server to configure: contlonsql01</li>
<li>Source file: \\contchisql01\Software\Installer.msi</li>
<li>Destination file: C:\Software\Installer.msi</li>
</ul><p>
Here’s what we’d write out to make this happen. Things to note: <br></p>
<ul>
<li><strong>configuration</strong>. This specifies that this is a PowerShell DSC configuration and the name is <strong>Configuration1</strong>. </li>
<li><strong>Import-DscResource -ModuleName PSDesiredStateConfiguration</strong>. Perhaps you guessed it already but this imports the DSC resources from the DSC module. We’ll go into resources and modules another time so don’t worry about this line for now.</li>
<li><strong>node</strong> is an array of servers we want to configure.</li>
<li><strong>File</strong>. This specifies that we will be asking DSC to do a file or folder operation and we tell it what we want - i.e. we want to ensure that <strong>installer.msi </strong>is present which means it needs to be copied from the source location to the destination location.</li></ul><p><br></p><ul>
</ul><p><a href="https://lh3.googleusercontent.com/-vjbouglMHpI/WaHSBWZ4dkI/AAAAAAAACtk/rFhVi-KXFtcvBV4aDyqZIkcqHRq0KabFwCHMYCw/s1600-h/image%255B20%255D"><img width="504" height="122" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-UKlj9_GBRdM/WaHSB4Q1jDI/AAAAAAAACto/P7jDxqI8Ww4H0AFVmA-Qn7FF-VOAH9uMQCHMYCw/image_thumb%255B6%255D?imgmax=800" border="0"></a><br>
<span style="color: blue; font-family: courier new;"></span></p><p><span style="color: blue; font-family: courier new;">configuration Configuration1 #Configuration1 is the name of the configuration<br>
{<br> Import-DscResource -ModuleName PSDesiredStateConfiguration #Imports the DSC module</span><br>
<span style="color: blue; font-family: courier new;">
</span>
<span style="color: blue; font-family: courier new;"> node ("contlonsql01") #List the servers you'll be targeting. It'll deploy the settings within node {}<br> {<br> File InstallerFile #File is a DSC Resource<br> {<br> Ensure = "Present"<br> SourcePath = "\\contchisql01\Software\Installer.msi"<br> DestinationPath = "C:\Software\Installer.msi" <br> }<br> }<br>
}</span><br>
<span style="color: black;"></span></p><p><span style="color: black;">There is no output from this. It’s like when you define a function:</span></p><p><span style="color: black;"></span><br>
<a href="https://lh3.googleusercontent.com/-r_yy-iDzeN4/WaHSCfK53II/AAAAAAAACts/tDk5cuwZLpsn2jkwIqKKy999O63Vipm1wCHMYCw/s1600-h/image%255B23%255D"><img width="504" height="141" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-fzM3UKEVPQ0/WaHSC0Jb7MI/AAAAAAAACtw/K-dr49VUy7Yw0tazQ3pJ857s03ltq6AHwCHMYCw/image_thumb%255B7%255D?imgmax=800" border="0"></a><br>
</p><h1>
Push a DSC configuration </h1><p>
Now we need to push the configuration to the machine. To do this we need to create a Management Object File or MOF file and we simply run the configuration and specify an output path for the MOF file:</p><p><span style="color: blue; font-family: courier new;">Configuration1 -OutputPath C:\DS</span></p><p><a href="https://lh3.googleusercontent.com/-4GorqIq3vwg/WaHSDOvqtqI/AAAAAAAACt0/nh9VI624NW4Exo2YHQim9sjjBXFxQlN8ACHMYCw/s1600-h/image%255B26%255D"><img width="504" height="129" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-8o_4KQtXZ20/WaHSDi5xRGI/AAAAAAAACt4/cOR3hSVy_RMYU4PeUQUoJkeHAGdXt31cgCHMYCw/image_thumb%255B8%255D?imgmax=800" border="0"></a><br>
</p><p>Let’s take a look at the contents of C:\DSC<br>
</p><p><a href="https://lh3.googleusercontent.com/-FNQR89V4WB8/WaHSEDoG2yI/AAAAAAAACt8/jgsXHBGKbyEUDPyjx3gO-eBaWzbGL-3OgCHMYCw/s1600-h/image%255B30%255D"><img width="504" height="155" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-Qjrz4xMQPic/WaHSEgb8ydI/AAAAAAAACuA/XaPnqNT80u8wAJS_4-TUt0ZSC1cLU4EygCHMYCw/image_thumb%255B9%255D?imgmax=800" border="0"></a><br>
</p><p>Note that the MOF file is named after the node specified in the configuration. If you have specified more than one node then you’ll get one MOF file per node. <br>
We then deploy the configuration by using <strong>Start-DscConfiguration</strong><br>
<span style="color: blue; font-family: courier new;"></span></p><p><span style="color: blue; font-family: courier new;">Start-DscConfiguration -Path C:\DSC</span><br>
</p><p><a href="https://lh3.googleusercontent.com/-tBqOQJRNzDU/WaHSFF3GnDI/AAAAAAAACuE/IIOiICiRn_sbEsDhlh7NuMr-xxv30FluQCHMYCw/s1600-h/image%255B33%255D"><img width="504" height="81" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-YV3T9reJCZk/WaHSFimTreI/AAAAAAAACuI/hLOTU4i46Y03uMls1sryzFG-BLhvc5wmwCHMYCw/image_thumb%255B10%255D?imgmax=800" border="0"></a><br>
</p><p>Note that you don’t really get much output here. You just see that a job’s been started. if you want to get the output of the job, you can run use Get-Job:<br>
<span style="color: blue; font-family: courier new;"></span></p><p><span style="color: blue; font-family: courier new;">Get-Job 11</span><br>
</p><p><a href="https://lh3.googleusercontent.com/-CkwiF-nI3YU/WaHSGFBVkrI/AAAAAAAACuM/snURy7fkQe8yLYTj32mfHasBXsA1mwE5QCHMYCw/s1600-h/image%255B36%255D"><img width="504" height="70" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-r2k8P7nLUaY/WaHSG_3iPWI/AAAAAAAACuQ/TR6x5UfqSbYqeoGi6TeI6HEvInWXZLKFwCHMYCw/image_thumb%255B11%255D?imgmax=800" border="0"></a><br>
</p><p>So, it’s completed and we can confirm our install.msi file has been copied over:<br>
</p><p><a href="https://lh3.googleusercontent.com/-aWCDfKVgQiQ/WaHSHfNfgLI/AAAAAAAACuU/LiyAFn1cIkQCZPC749STUBlS47HBC0r7QCHMYCw/s1600-h/image%255B39%255D"><img width="504" height="195" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-Pk6QzQ42upc/WaHSHzkJWcI/AAAAAAAACuY/PkFuFLCgf6YlnnDcXl6onqEMch_PRKYcQCHMYCw/image_thumb%255B12%255D?imgmax=800" border="0"></a></p><p>We can also use Test-DscConfiguration to check our target machine configuration against the configuration we deployed to it:</p><p><font color="#0000ff" face="Courier New">Test-DscConfiguration -Path C:\DSC</font></p><p><a href="https://lh3.googleusercontent.com/-kkaCzaIfeMg/WasL_05xV6I/AAAAAAAACu0/AwmfURAl7_wUo7bVnmBsLKGlhCykdu5RgCHMYCw/s1600-h/image%255B2%255D"><img width="504" height="116" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/--1RVPv8Y-rM/WasMA8gVBUI/AAAAAAAACu4/0cpKfBIdqFULqWJ0F-xhL82b09-HPBuywCHMYCw/image_thumb?imgmax=800" border="0"></a><br></p>
<h1>
Conclusion</h1><p>
So, that’s just a quick intro into PowerShell DSC. It’s such a great way to configure your servers and definitely the way of the future. In the next post, I’ll talk through DSC resources - these define what types of configuration settings you can make e.g. file, windows features, registry changes etc. Click <a href="http://markgossa.blogspot.com/2017/09/learn-powershell-dsc-part-2.html">here</a> for part 2 to continue the DSC journey.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-38564789742480248372017-08-26T19:10:00.000+01:002017-08-26T19:13:32.795+01:00PowerShell functions with -Verbose and -Debug<h1>Introduction</h1><p>So, another rather standard day but made a little more interesting with some new tips on getting your PowerShell functions to provide some more feedback. We’re going to look at how to get your script to use the <strong>-Verbose </strong>and <strong>-Debug </strong>parameters.</p><h1>Simple function</h1><p>Okay, so our simple function is below. It just takes a <strong>Message </strong>parameter of and outputs <strong>Welcome <message> </strong>in green<strong>.</strong></p><p><a href="https://lh3.googleusercontent.com/-pTvBh9Zcl84/WaG5Z_eJyWI/AAAAAAAACsg/pSTnadcIkyER7IypCGPnT-QHRHn8osCPwCHMYCw/s1600-h/image%255B9%255D"><img width="489" height="127" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-KVRqnZIFlMQ/WaG5a4uoxHI/AAAAAAAACsk/mm_igDKSQCs0mlWuEbMZQfBx4IFj7wdHgCHMYCw/image_thumb%255B2%255D?imgmax=800" border="0"></a><strong><br></strong></p><p><font color="#0000ff" face="Courier New" size="2">function Welcome<br> {<br> param(<br> [string]$Message<br> ) </font></p><font color="#0000ff" face="Courier New" size="2">
</font><p><font color="#0000ff" face="Courier New" size="2"> Write-Host Welcome $message -ForegroundColor Green<br> }</font></p><p>We can run the function as below:</p><p><font color="#0000ff" face="Courier New">Welcome -Message "to my blog!"</font></p><p><a href="https://lh3.googleusercontent.com/-aU7UkTopIE0/WaG5bS_g9nI/AAAAAAAACso/pNdStNJdWfEFrIPOIcLnKRDzSE5gwzvxgCHMYCw/s1600-h/image%255B27%255D"><img width="504" height="145" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-f3XzNwO8AMs/WaG5b62sKhI/AAAAAAAACss/vPtJdXNjBgw8304hfvOrn5WT0f-YD6LeACHMYCw/image_thumb%255B8%255D?imgmax=800" border="0"></a></p><p>Nothing really that interesting here. Let’s move on.</p><h1>Add -Verbose and -Debug to a PowerShell function</h1><p>Here I’m adding another part to the script - <strong>[cmdletbinding()]</strong>. This automatically adds the <strong>-Verbose</strong> and <strong>-Debug</strong> parameters to the script and does all the logic behind it. By default, <strong>Write-Verbose</strong> doesn’t actually produce an output.</p><p><a href="https://lh3.googleusercontent.com/-Fw7sQOJXhHU/WaG5cdQod_I/AAAAAAAACsw/ycZNxvuyKsAtIMxw6OsIAY-4MctAfZTpACHMYCw/s1600-h/image%255B12%255D"><img width="504" height="152" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-WPEUoOXUdKU/WaG5dI7p6SI/AAAAAAAACs0/PH1WVrtbJFYO-DyYXCpaWkdkyJ1woshLgCHMYCw/image_thumb%255B3%255D?imgmax=800" border="0"></a></p><p><font color="#0000ff" face="Courier New">function Welcome<br> {<br> [cmdletbinding()] #This provides the function with the -Verbose and -Debug parameters<br> param(<br> [string]$Message<br> ) </font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> #Verbose - this is only shown if the -Verbose switch is used<br> Write-Verbose -Message "This is verbose output"</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> #Debug - this causes the script to halt at this point<br> Write-Debug "This is debugging information"</font></p><font color="#0000ff" face="Courier New">
</font><p><font color="#0000ff" face="Courier New"> #Actual function<br> Write-Host Welcome $message -ForegroundColor Green<br> }</font></p><p>We can now run the function and specify the <strong>-Verbose </strong>parameter and we can see we’re now getting the output from Write-Verbose:</p><p><font color="#0000ff" face="Courier New">Welcome -Message "to my blog!" -Verbose</font></p><p><a href="https://lh3.googleusercontent.com/-h_YG8UVXahI/WaG5dibu8yI/AAAAAAAACs4/sm6IQsW7EFoLaU0WXYNwHyWRIzVbz_8QACHMYCw/s1600-h/image%255B24%255D"><img width="504" height="145" title="image" style="display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-n7KsYwahv0Y/WaG5ePtypdI/AAAAAAAACs8/grvaLMuB3zUqRDQQ63GW7Wv_hggV73QowCHMYCw/image_thumb%255B7%255D?imgmax=800" border="0"></a></p><p>Let’s test out <strong>-Debug</strong> now. Debug is useful for when you’re debugging your script (who would have thought). Basically, it outputs <strong>Write-Debug</strong>, pauses the script and asks for you to either continue running it or to halt it. <strong>Write-Debug </strong>could contain more than just text. For example, if you want to check the value of a variable before it’s used, you can use <strong>Write-Debug </strong>to output the variable and then prompt you to either continue or halt the script.</p><p><font color="#0000ff" face="Courier New">Welcome -Message "to my blog!" -Debug</font><font face="Courier New"><br></font></p><p><a href="https://lh3.googleusercontent.com/-TYf-9VWaF0Y/WaG5ekQc6dI/AAAAAAAACtA/LWCphyh4U4YTxsxNEeNCA-KPWE5yPoisACHMYCw/s1600-h/image%255B33%255D"><img width="504" height="165" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-cjd5ENU3xiw/WaG5fKAAD4I/AAAAAAAACtE/vP-yKQFCorsjAE9eQGhNPhlsVb6qaetMQCHMYCw/image_thumb%255B10%255D?imgmax=800" border="0"></a></p><p>I selected Y and so it continued running the rest of the script:</p><p><a href="https://lh3.googleusercontent.com/-rDqIcw7kmcU/WaG5fhBdpkI/AAAAAAAACtI/5OejNKoxKFIs8Y2IfCacQYjwg5CJ2aR8wCHMYCw/s1600-h/image%255B30%255D"><img width="504" height="165" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://lh3.googleusercontent.com/-B5NNrcaBt_4/WaG5gBOeL1I/AAAAAAAACtM/xzOQG7Iq1S0ByHuYOo1Ab7bRkw3bwQ5WQCHMYCw/image_thumb%255B9%255D?imgmax=800" border="0"></a></p><p>So, there you have it. How to add <strong>-Verbose </strong>and <strong>-Debug </strong>into your functions.</p>Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-26956169966170388492017-08-22T10:12:00.000+01:002017-08-22T10:12:41.499+01:00VMware to Hyper-V migration with Veeam<h1>
Problem</h1>
Okay, so here’s the problem. You want to migrate VMs from VMware vSphere 5 or 6 or whatever to Hyper-V 2016 but you can’t find a tool to use because you want near-zero downtime. You search around and find some options:<br />
<h2>
Sysinternals Disk2Vhd</h2>
Great tool and free! The problem is that you need a lot of downtime because it converts the entire disk and you cannot sync changes after the conversion is done so you need downtime from the time you start the conversion.<br />
<h2>
Microsoft Virtual Machine Converter</h2>
Another good tool but no longer supports the later versions of vSphere or Hyper-V. In fact, the tool itself is not supported as of June 3rd 2017. See more <a href="https://blogs.technet.microsoft.com/scvmm/2016/06/04/important-update-regarding-microsoft-virtual-machine-converter-mvmc/" target="_blank">here</a>. However, even if you do use it, you still cannot do the incremental sync that you need.<br />
<h2>
Third party tools to migrate VMware to Hyper-V</h2>
There’s some very useful tools that you can use but these come at a cost but will literally do near-zero downtime conversions. Have a look at Quest, Double-Take or PlateSpin.<br />
<h1>
Solution</h1>
So, I found a neat little workaround for this. Basically, use Veeam. Now, you need both Veeam Agent for Windows and Veeam Backup and Replication (and you can get free trials for both). The steps are below:<br />
<ol>
<li>Install Veeam Agent for Windows on your VM </li>
<li>Install Veeam Backup and Replication on a backup server </li>
<li>Add your host into Veeam Backup and Replication </li>
<li>Create a backup repository in Veeam Backup and Replication </li>
<li>Back up your VM to a Veeam Repository on the backup server using Veeam Agent for Windows </li>
<li>Prevent users accessing the server to make changes </li>
<li>Do an incremental backup of your VM and shut it down </li>
<li>Use Veeam Backup and Replication to rescan the repository </li>
<li>Use Veeam Backup and Replication to do an Instant Restore of your VM onto a Hyper-V host and select to power on the VM </li>
<li>Re-enable user access </li>
<li>Use Veeam Backup and Replication to migrate the VM onto production storage (using the Instant Restore wizard)</li>
</ol>
The advantages of doing this are that you minimize downtime by doing incremental backups and then doing an instant restore. If you’re not familiar with this, Veeam Backup and Replication creates dummy VHD and VM configuration files on the Hyper-V storage which actually reference the backup server storage and the VM runs off the backup server storage. To improve performance, you may want to add faster disks and use 10Gb networking on your backup servers.<br />
If you are a hosting provider then you really don’t want tenant VMs with access to the backup server so you can use the Veeam Cloud Connect Gateway (part of the Veeam Cloud Connect suite). This only requires a single port to be open from the tenant network - it’s generally used to back up VMs over the internet so it was designed with that security in mind. <br />
I hope this helps people out as it looks like MS aren’t really providing a solution to do this just yet. Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-25141190367665981892017-03-04T13:25:00.000+00:002017-03-04T13:25:57.128+00:00Enable key archival in Server 2012 R2<h1>
Overview</h1>
So, you get an escalated call from the helpdesk saying someone’s lost their private key. So, we only had one copy of that. Now what?<br />
Well, here’s where key archival comes into play. You configure your CA to enable key archival and then you specify that your certificate templates have key archival enabled and now your private keys are copied to your CA so you can recover them when needed!<br />
<h1>
How to enable key archival</h1>
Identify a user to serve as the key recovery agent. In this case, we'll use the account <strong>LITWARE\Administrator</strong>.<br />
<br />
Open your <strong>Certification Authority </strong>snap-in, right click <strong>Certificate Templates </strong>and click <strong>Manage</strong>. You now see a list of certificate templates:<br />
<br />
<a href="https://lh3.googleusercontent.com/-IaJVhHW8YFw/WLq7FZhMTqI/AAAAAAAACnk/azp3RdHrEFE/s1600-h/clip_image001%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image001[6]" border="0" height="396" src="https://lh3.googleusercontent.com/-Vw1-YcjpcNo/WLq7FsqZWCI/AAAAAAAACno/Wh9bD_nURJA/clip_image001%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image001[6]" width="504" /></a> <br />
<br />
Duplicate the <strong>Key Recovery Agent </strong>certificate template and give it a name: <strong>Key Recovery Agent 2</strong><br />
<strong><br /></strong>
<a href="https://lh3.googleusercontent.com/-3Hmsu5cacQQ/WLq7GHQHp0I/AAAAAAAACns/L1ViYqm2tI4/s1600-h/clip_image002%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image002[6]" border="0" height="571" src="https://lh3.googleusercontent.com/-r_5fGEP66Zg/WLq7GQUojmI/AAAAAAAACnw/WRxCgk6L4bM/clip_image002%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image002[6]" width="418" /></a> <br />
<br />
Configure the <strong>key recovery agent </strong>certificate template with <strong>Read </strong>and <strong>Enroll </strong>permissions for the <strong>key recovery agent</strong> (<strong>LITWARE\Administrator</strong>). You do this on the <strong>Security </strong>tab:<br />
<br />
<a href="https://lh3.googleusercontent.com/-rG_9lsQwrVM/WLq7Gz2sWNI/AAAAAAAACn0/SlB3bbD2SWY/s1600-h/clip_image003%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image003[6]" border="0" height="571" src="https://lh3.googleusercontent.com/-zZ43kHkOx7Q/WLq7Hal1i9I/AAAAAAAACn4/-w7lgu3nO1k/clip_image003%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image003[6]" width="418" /></a> <br />
<br />
Now we need to configure the CA to use issue the new certificate template. Right click <strong>Certificate Templates</strong>, click <strong>New</strong> then click <strong>Certificate Templates</strong> to Issue<br />
<br />
<a href="https://lh3.googleusercontent.com/-q2ejEajQIl4/WLq7Hu7ihjI/AAAAAAAACn8/9nOjRcljivQ/s1600-h/clip_image004%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image004[6]" border="0" height="345" src="https://lh3.googleusercontent.com/-4ZvIBBVEJBQ/WLq7IP9ma5I/AAAAAAAACoA/aNnxnnepa2Y/clip_image004%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image004[6]" width="504" /></a> <br />
<br />
Select your new <strong>Key Recovery Agent 2 </strong>certificate and click <strong>OK</strong><br />
<strong><br /></strong>
<a href="https://lh3.googleusercontent.com/-ppiTSrjcUxI/WLq7IewcINI/AAAAAAAACoE/yYHeBVPGBkk/s1600-h/clip_image005%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image005[6]" border="0" height="322" src="https://lh3.googleusercontent.com/-x2z5S6h1Fmg/WLq7IxqAiEI/AAAAAAAACoI/ddYmsxAkHWI/clip_image005%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image005[6]" width="504" /></a> <br />
<br />
Now we need to enroll the Administrator account for the <strong>Key Recovery Agent 2 </strong>certificate. To do this, open up <strong>certmgr.msc</strong> and click on <strong>Personal</strong><br />
<strong><br /></strong>
<strong>Click on Action > All Tasks > Request New Certificate</strong><br />
<strong><br /></strong>
<a href="https://lh3.googleusercontent.com/-780vAz28bUo/WLq7JDkU8kI/AAAAAAAACoM/Tgsp3jb1u6M/s1600-h/clip_image006%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image006[6]" border="0" height="366" src="https://lh3.googleusercontent.com/--ilD6tD3dGs/WLq7JVRjxII/AAAAAAAACoQ/CZz-deBe86k/clip_image006%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image006[6]" width="504" /></a> <br />
<br />
Click <strong>next</strong><br />
<br />
<a href="https://lh3.googleusercontent.com/-Z_mrNvDu46g/WLq7J6TtMxI/AAAAAAAACoU/rBydo_atp8s/s1600-h/clip_image007%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image007[6]" border="0" height="366" src="https://lh3.googleusercontent.com/-JiCy_ZK-H_o/WLq7KDax4MI/AAAAAAAACoY/DhUVfwLptVs/clip_image007%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image007[6]" width="504" /></a> <br />
<br />
Click to select the <strong>Key Recovery Agent 2</strong> certificate and then click <strong>Enroll </strong>to finish the wizard:<br />
<br />
<a href="https://lh3.googleusercontent.com/-yjYKgsSGMAU/WLq7KW3uDMI/AAAAAAAACoc/iG2742xvFD4/s1600-h/clip_image008%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image008[6]" border="0" height="366" src="https://lh3.googleusercontent.com/-evSilBVOJsc/WLq7K9SBQYI/AAAAAAAACog/OBmNrQJbeAM/clip_image008%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image008[6]" width="504" /></a> <br />
<br />
<a href="https://lh3.googleusercontent.com/-0atbVt5wxKk/WLq7LJlMkKI/AAAAAAAACok/JQqq0K0MVks/s1600-h/clip_image009%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image009[6]" border="0" height="366" src="https://lh3.googleusercontent.com/-cxlQpvV5jds/WLq7LZ9XSvI/AAAAAAAACoo/wYGV0CQ0Z9Y/clip_image009%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image009[6]" width="504" /></a> <br />
<br />
Note that it didn't issue the certificate - the status is <strong>Enrollment pending</strong>. Now, go back to your <strong>CA snap-in </strong>and click on <strong>Pending Requests</strong>. You should see a pending request for the certificate you just enrolled.<br />
<br />
<a href="https://lh3.googleusercontent.com/--2hQNsEj1nc/WLq7L7tp1bI/AAAAAAAACos/Yqv8eSPD3Pc/s1600-h/clip_image010%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image010[6]" border="0" height="163" src="https://lh3.googleusercontent.com/-5ZMkVO14Xt4/WLq7MP1ASNI/AAAAAAAACow/YpKnnMgW790/clip_image010%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image010[6]" width="504" /></a> <br />
<br />
Right click the certificate, click on <strong>All Tasks </strong>and then <strong>Issue</strong>. The certificate is now issued.<br />
Now, right click the CA and go to <strong>Properties </strong>and select the <strong>Recovery Agents </strong>tab. Select <strong>Archive the key</strong>, select the <strong>Number of recovery agents to use </strong>(one in our case):<br />
<br />
<a href="https://lh3.googleusercontent.com/-jwRHnskk_bY/WLq7MS9uq1I/AAAAAAAACo0/n8OimLpm1ec/s1600-h/clip_image011%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image011[6]" border="0" height="548" src="https://lh3.googleusercontent.com/-6xjY-oQtFmM/WLq7My7bRyI/AAAAAAAACo4/xy_FRKPXcM0/clip_image011%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image011[6]" width="418" /></a> <br />
<br />
Click <strong>Add</strong> and select the certificate which was issued to your chosen user:<br />
<br />
<a href="https://lh3.googleusercontent.com/-C6rdJKzJv0w/WLq7NJTcUPI/AAAAAAAACo8/W40AQZ_ioFw/s1600-h/clip_image012%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image012[6]" border="0" height="404" src="https://lh3.googleusercontent.com/-bJsLGqtmmxQ/WLq7NmyofSI/AAAAAAAACpA/as7FTfFMFvg/clip_image012%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image012[6]" width="443" /></a> <br />
<br />
Click <strong>OK </strong>twice and you're then prompted to restart the AD CS services so go ahead and click <b>Yes</b><br />
<br />
<a href="https://lh3.googleusercontent.com/-n2oYHxXQ9_I/WLq7N_8x_WI/AAAAAAAACpE/ogKw5KtcJCg/s1600-h/clip_image013%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image013[6]" border="0" height="176" src="https://lh3.googleusercontent.com/-WiMUVYZyqn4/WLq7OPWl7CI/AAAAAAAACpI/91wB3QfksPs/clip_image013%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image013[6]" width="501" /></a> <br />
<br />
So, we've now created our <strong>Key Recovery Agent </strong>certificate template, issued it to our <strong>Key Recovery Agent </strong>and configured the CA to use a <strong>Key Recovery Agent</strong>. We're not protected against key loss just yet because the certificate templates that are issued out need to have key archival enabled.<br />
Right click on a certificate template which you need to enable key archival for, duplicate it, give it a name, go to <strong>Properties</strong> and then to the <strong>Request Handling</strong> tab. Tick <strong>Archive subject's encryption private key</strong>:<br />
<br />
<a href="https://lh3.googleusercontent.com/-iY_1zwBmlVo/WLq7Ol1YcYI/AAAAAAAACpM/yejULIHDz-c/s1600-h/clip_image014%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image014[6]" border="0" height="571" src="https://lh3.googleusercontent.com/-H-jBNqnSlbs/WLq7O_Tp1WI/AAAAAAAACpQ/Te9LuQADo9E/clip_image014%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image014[6]" width="418" /></a> <br />
<br />
On the <strong>Superseded Templates </strong>tab, add all the certificate templates that you want to be replaced by your new one then click OK:<br />
<br />
<a href="https://lh3.googleusercontent.com/-U_raXJMHDO4/WLq7PSXYuJI/AAAAAAAACpU/dUzRwEMEDnk/s1600-h/clip_image015%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image015[6]" border="0" height="571" src="https://lh3.googleusercontent.com/-qwFmSidjUck/WLq7PkSMcbI/AAAAAAAACpY/Aq0s-7FQOFA/clip_image015%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image015[6]" width="418" /></a> <br />
<br />
This doesn't protect against loss of private keys for certificates which have already been issued so in this case, you need to get the clients to reenroll these. Right click on your original certificate and select <strong>Reenroll All Certificate Holders:</strong><br />
<strong><br /></strong>
<a href="https://lh3.googleusercontent.com/-CO3eZUczRTs/WLq7QDkw8yI/AAAAAAAACpc/duoJ77rR3j0/s1600-h/clip_image016%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image016[6]" border="0" height="150" src="https://lh3.googleusercontent.com/-JFT3027hwQk/WLq7Qdg85FI/AAAAAAAACpg/9_Ku3KQXgz4/clip_image016%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image016[6]" width="504" /></a> <br />
<br />
Go for an 8hr coffee break or just sit and stare at the screen…….<br />
<br />
Go to <strong>Issued Certificates</strong> in the CA snap-in and add the <strong>Archived Key </strong>column. Eventually, you should start to see new certificates issued and you can see that the key is archived:<br />
<br />
<a href="https://lh3.googleusercontent.com/-9XYiYWGSigY/WLq7QhuqvdI/AAAAAAAACpk/5S2Xz76prmg/s1600-h/clip_image017%25255B6%25255D%25255B2%25255D.png"><img alt="clip_image017[6]" border="0" height="533" src="https://lh3.googleusercontent.com/-RUL5lD2nBjc/WLq7RGN_qgI/AAAAAAAACpo/m2LG6KSXFwA/clip_image017%25255B6%25255D_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image017[6]" width="504" /></a> <br />
<br />
So, there you have it. That’s how you enable key archival in AD CS!<br />
<br />
If you need to recover a key then see <a href="http://markgossa.blogspot.com/2017/03/recover-lost-private-key-key-archival.html">here</a>.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-29082267739908106942017-03-04T13:23:00.000+00:002017-03-04T13:23:45.403+00:00Recover lost private key (Key Archival)<h1>
Overview</h1>
If you have Key Archival enabled then you can recover private keys. If you don’t have Key Archival enabled then click <a href="http://http//markgossa.blogspot.com/2017/03/enable-key-archival-in-server-2012-r2.html">here</a> for instructions. <br />
In this post, I’ll demonstrate how to recover a lost private key <br />
<h1>
How to recover a lost private key</h1>
You need to be logged in with one of your <strong>Key Recovery Agents</strong> that you specified when you configured <strong><a href="http://markgossa.blogspot.co.uk/2017/03/enable-key-archival-in-server-2012-r2.html">Key Archival</a></strong>. <br />
Firstly, locate your certificate in the <strong>Issued Certificates</strong> section using the CA snap-in: <br />
<a href="https://lh3.googleusercontent.com/-dv0W4jQs_kw/WLq_mKfHbnI/AAAAAAAACp0/tRni3j3ItMw/s1600-h/clip_image001%25255B3%25255D.png"><img alt="clip_image001" border="0" height="596" src="https://lh3.googleusercontent.com/-ZHaxkUBWlog/WLq_mjy3CRI/AAAAAAAACp4/LQQqbYfwZ00/clip_image001_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image001" width="504" /></a> <br />
You then need to get the serial number so you can just double click it, go to details and select <strong>Serial Number</strong>: <br />
<a href="https://lh3.googleusercontent.com/-crWcHy4M3eI/WLq_m2pKv_I/AAAAAAAACp8/M4f1fuf7Ns8/s1600-h/clip_image002%25255B3%25255D.png"><img alt="clip_image002" border="0" height="526" src="https://lh3.googleusercontent.com/-zxMflpXFnO0/WLq_naIOM6I/AAAAAAAACqA/aWmOyonZd-w/clip_image002_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image002" width="423" /></a> <br />
Remove the spaces from the <strong>Serial Number</strong>: <br />
1a00000042af62922b38431f48000100000042 <br />
Use <strong>certutil </strong>to get the key: <br />
<em>certutil -getkey 1a00000042af62922b38431f48000100000042 C:\Temp\key.key</em> <br />
<a href="https://lh3.googleusercontent.com/-SV6YaSRNj4Y/WLq_nsEf23I/AAAAAAAACqE/HW5afbRiWZo/s1600-h/clip_image003%25255B3%25255D.png"><img alt="clip_image003" border="0" height="97" src="https://lh3.googleusercontent.com/-TfX4X9J64OA/WLq_n1pKsvI/AAAAAAAACqI/TVtSRJQ4n5E/clip_image003_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image003" width="504" /></a> <br />
You then use <strong>certutil </strong>again to recover the private key: <br />
<em>certutil -recoverkey C:\Temp\key.key c:\temp\cert.pfx</em> <br />
<a href="https://lh3.googleusercontent.com/-tC8Pc8-0qRY/WLq_oUcImBI/AAAAAAAACqM/SLXcqHI_45w/s1600-h/clip_image004%25255B3%25255D.png"><img alt="clip_image004" border="0" height="97" src="https://lh3.googleusercontent.com/-EQVx_UmD0BY/WLq_okSJKiI/AAAAAAAACqQ/-EvuyTKL8dU/clip_image004_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image004" width="504" /></a> <br />
You now have a <strong>.pfx </strong>file and you can import this back onto your client using certmgr.msc<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-2440690713954087192017-03-04T12:52:00.000+00:002017-03-04T12:52:42.875+00:00How to enable certificate autoenrollment<h1>
Introduction</h1>
Welcome back! In this post, we’ll do a quick demo of how you can enable certificate autoenrollment for a computer certificate. This means that the computer (or server) will get its own certificate……eventually……and you don’t (really) need to do anything.<br />
<h1>
How to enable certificate autoenrollment</h1>
Okay, so you have to do something! The first step is to open the <strong>Certification Authority </strong>snap-in on your CA or management computer, right click on <strong>Certificate Templates </strong>and click <strong>Manage</strong>.<br />
<a href="https://lh3.googleusercontent.com/-XI2ssK0ZEls/WLnQ14JQ8gI/AAAAAAAACkI/b-COSxBVR1I/s1600-h/clip_image001%25255B3%25255D.png"><img alt="clip_image001" border="0" height="352" src="https://lh3.googleusercontent.com/-VZzGxoXEfk0/WLnQ2XRXqzI/AAAAAAAACkM/bEoiLg3-RZk/clip_image001_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image001" width="504" /></a><br />
You should now see a list of certificate templates you can configure:<br />
<a href="https://lh3.googleusercontent.com/-ehL564OaEVo/WLnQ2yCyt3I/AAAAAAAACkQ/E5U-7Ln1LZ0/s1600-h/image%25255B2%25255D.png"><img alt="image" border="0" height="396" src="https://lh3.googleusercontent.com/-gRsuWT5Pl1M/WLnQ3ef24pI/AAAAAAAACkU/FOnclbliRBk/image_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="504" /></a><br />
Right click the <strong>Computer </strong>certificate template and duplicate it. Call your new certificate <strong>Computer 2 </strong>and change any settings you need to change (e.g. validity period)<br />
<a href="https://lh3.googleusercontent.com/-U4sVaXw3Y9s/WLnQ3rXAbzI/AAAAAAAACkY/LpDQ7mv_3Qc/s1600-h/clip_image002%25255B3%25255D.png"><img alt="clip_image002" border="0" height="571" src="https://lh3.googleusercontent.com/-a_oTpF0-fbE/WLnQ4DGKZYI/AAAAAAAACkc/lmbCKbS1Dl0/clip_image002_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image002" width="418" /></a> <br />
Click on the <strong>Security </strong>tab and grant <strong>Enroll </strong>and <strong>Autoenroll </strong>permissions for <strong>Domain Computers</strong> (or whatever group of computers you need to configure autoenrollment for)<br />
<a href="https://lh3.googleusercontent.com/-6yohRVVXVyI/WLnQ4h2YaZI/AAAAAAAACkg/UrYR8QkHRtM/s1600-h/clip_image003%25255B3%25255D.png"><img alt="clip_image003" border="0" height="571" src="https://lh3.googleusercontent.com/-uFKdhB6lqG4/WLnQ5B1FCtI/AAAAAAAACkk/1UiBcHOldt0/clip_image003_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image003" width="418" /></a><br />
Create a Group Policy Object which is linked to the domain and go to <strong>Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies\Certificate Services Client - Auto-Enrollment</strong>. Select <strong>Enable </strong>and tick <strong>Renew expired certificates </strong>and tick <strong>Update certificates that use templates</strong>. Although we link the GPO to the domain, we are in fact only allowing the group with permissions on the computer certificate to actually autoenroll and get the certificate<br />
<a href="https://lh3.googleusercontent.com/-ArOsjp-x2_0/WLnQ5XtSV-I/AAAAAAAACko/9Na9lpwg-rA/s1600-h/clip_image004%25255B3%25255D.png"><img alt="clip_image004" border="0" height="515" src="https://lh3.googleusercontent.com/-0-Q_Ui4SNJw/WLnQ5_JK0GI/AAAAAAAACks/dFktBhW7TAw/clip_image004_thumb.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image004" width="418" /></a> <br />
Now, to get your clients to actually autoenroll for a certificate, you can either wait a while or restart or run force the clients to autoenroll immediately with <strong>certutil /pulse.</strong><br />
This creates a certificate in the Local Machine personal store:<br />
<a href="https://lh3.googleusercontent.com/-mFHupZRPS7w/WLnRcSr6e5I/AAAAAAAACkw/YMhqgnTmp6g/s1600-h/image%25255B5%25255D.png"><img alt="image" border="0" height="359" src="https://lh3.googleusercontent.com/-vZ_h5OCwCZc/WLnRc0LobPI/AAAAAAAACk0/Z1otrnfu-Ys/image_thumb%25255B1%25255D.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="504" /></a><br />
………and it has a common name which matches the FQDN of the client (litcli01.litware.com in our case):<br />
<a href="https://lh3.googleusercontent.com/-XFywjElSp5o/WLnRdXUjItI/AAAAAAAACk4/XT7TCyXdEVM/s1600-h/image%25255B8%25255D.png"><img alt="image" border="0" height="526" src="https://lh3.googleusercontent.com/-x_R1D793BjA/WLnRdt6xG7I/AAAAAAAACk8/dCxj-opifbg/image_thumb%25255B2%25255D.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="423" /></a><br />
<br />
Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0tag:blogger.com,1999:blog-6018791258441928308.post-78547883359632241682017-02-11T13:13:00.000+00:002017-02-11T13:15:11.748+00:00Offline standalone root CA install, Server 2012 R2 - Part 1<h1>
Overview</h1>
In this post, we’ll look at how to set up an offline standalone root CA in Windows Server 2012 R2. This is the most secure way to set up your CA because it means you can set up subordinate issuing CAs and power off the root CA when not required to issue subordinate CA certificates. <br />
Having a powered off server means you cannot possibly have it compromised (unless someone has physical access to it or you decide to store the CA private key on an unencrypted USB key and gave it to a friend to get some movies but that’s beside the point!).<br />
<br />
<h1>
How to install an offline standalone root CA</h1>
Before we start, make sure you have a clean build of Windows Server 2012 R2 without any other roles installed. Make sure your server is not joined to a domain. The server in this example is called LITCA01 (our root CA in the Litware organization).<br />
<ul>
<li>Install AD CS role and select Certificate Authority role service: <ul>
<li>Either user Powershell</li>
</ul>
<em>Install-WindowsFeature AD-Certificate,ADCS-Cert-Authority</em><br />
<ul>
<li>Or use the GUI:</li>
</ul>
</li>
</ul>
<a href="https://lh3.googleusercontent.com/-Rx1Bojwne5A/WJ8D87skBGI/AAAAAAAAChw/dcFQDkW7pcM/s1600-h/clip_image0013.png"><img alt="clip_image001" border="0" height="358" src="https://lh3.googleusercontent.com/-1Kkp7-DL3Ng/WJ8D9l7EJuI/AAAAAAAACh0/PMY88R3Riws/clip_image001_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image001" width="504" /></a> <br />
<a href="https://lh3.googleusercontent.com/-nEgMsZA4PcA/WJ8D94Eer3I/AAAAAAAACh4/ZFVYRuJJJIg/s1600-h/clip_image0023.png"><img alt="clip_image002" border="0" height="358" src="https://lh3.googleusercontent.com/-GRit70m2gB0/WJ8D-Un2ayI/AAAAAAAACh8/L2LgGRUj0rc/clip_image002_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image002" width="504" /></a> <br />
<a href="https://lh3.googleusercontent.com/-e8baCk1BlC0/WJ8D-7zlhXI/AAAAAAAACiA/zYKvUDsVMSQ/s1600-h/clip_image0033.png"><img alt="clip_image003" border="0" height="358" src="https://lh3.googleusercontent.com/-K_8ndGknIGs/WJ8D_Smr0XI/AAAAAAAACiE/-WYNcefQjTE/clip_image003_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image003" width="504" /></a> <br />
<ul>
<li>Select Active Directory Certificate Services</li>
</ul>
<a href="https://lh3.googleusercontent.com/-h7ztjs32IsE/WJ8D_4Lsk_I/AAAAAAAACiI/e2zKTgVR2FQ/s1600-h/clip_image0043.png"><img alt="clip_image004" border="0" height="358" src="https://lh3.googleusercontent.com/-ka86vOtLlBE/WJ8EAYqY2gI/AAAAAAAACiM/XNEzshiKmgY/clip_image004_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image004" width="504" /></a> <br />
<ul>
<li>Click next</li>
</ul>
<a href="https://lh3.googleusercontent.com/-wXdNiGeCyKc/WJ8EA8bvueI/AAAAAAAACiQ/_tX9Wv8XYtU/s1600-h/clip_image0053.png"><img alt="clip_image005" border="0" height="358" src="https://lh3.googleusercontent.com/-LlHIs_ipcaY/WJ8EBaPVlLI/AAAAAAAACiU/SnEuqgFejkA/clip_image005_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image005" width="504" /></a><br />
<ul>
<li>Click next</li>
</ul>
<a href="https://lh3.googleusercontent.com/-mragE0xrqOA/WJ8EB369sFI/AAAAAAAACiY/e3j6Ka5-wgI/s1600-h/clip_image0063.png"><img alt="clip_image006" border="0" height="358" src="https://lh3.googleusercontent.com/-AzPuzJKJWq8/WJ8ECcdgYBI/AAAAAAAACic/OzPvj4nEkAI/clip_image006_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image006" width="504" /></a><br />
<ul>
<li>Select Certificate Authority</li>
</ul>
<a href="https://lh3.googleusercontent.com/-IEp37KNF4vk/WJ8EDKpyZII/AAAAAAAACig/xayER_nbdK8/s1600-h/clip_image0073.png"><img alt="clip_image007" border="0" height="358" src="https://lh3.googleusercontent.com/-NSf5PkGAFZE/WJ8EDkzt_GI/AAAAAAAACik/yMTtzQv8CI8/clip_image007_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image007" width="504" /></a><br />
<ul>
<li>Click next</li>
</ul>
<a href="https://lh3.googleusercontent.com/-s7V1il-MaxM/WJ8ED_0yHxI/AAAAAAAACio/zXXWiKYOLwA/s1600-h/clip_image0083.png"><img alt="clip_image008" border="0" height="358" src="https://lh3.googleusercontent.com/-JRCQgAp7_kY/WJ8EEebPoPI/AAAAAAAACis/f1qekLRF-7Q/clip_image008_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image008" width="504" /></a> <br />
<ul>
<li>Configure CA and select standalone CA:</li>
</ul>
<a href="https://lh3.googleusercontent.com/-Hv32o14C0ag/WJ8EEzdkznI/AAAAAAAACiw/9IJqM22GqaQ/s1600-h/clip_image0093.png"><img alt="clip_image009" border="0" height="370" src="https://lh3.googleusercontent.com/-i0K28VFdvis/WJ8EFREn_RI/AAAAAAAACi0/Qwgg2GY792I/clip_image009_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image009" width="504" /></a><br />
<ul>
<li>After installation, the wizard prompts you to configure the CA. If you used PowerShell then you can continue CA configuration by opening up Server Manager. </li>
<li>Click through the wizard and select defaults and then when prompted, for a CA type, select root CA:</li>
</ul>
<a href="https://lh3.googleusercontent.com/-DbTMIHma2V8/WJ8EF0Z26oI/AAAAAAAACi4/pU6b_MUnU2A/s1600-h/clip_image0103.png"><img alt="clip_image010" border="0" height="370" src="https://lh3.googleusercontent.com/-MCCEwkZW58M/WJ8EGfHapAI/AAAAAAAACi8/E8MLRRHM7as/clip_image010_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="clip_image010" width="504" /></a><br />
<ul>
<li>Create certificate or use an existing one (if you have one already). In our case, we don't already have one so we create a new one. </li>
<li>Accept defaults and complete the wizard. You now have a standalone Certificate Authority.</li>
</ul>
<h1>
</h1>
<h1>
Conclusion</h1>
Your standalone CA is now set up. So, that’s great! How do I make sure things will work when it’s offline? How do you get a certificate from an offline CA? How will domain joined clients autoenroll certificates? Well, we’ll need a subordinate CA but first we need to configure our CA and prepare it for a subordinate CA. We’ll go through this in <a href="http://markgossa.blogspot.com/2017/02/offline-standalone-root-ca-install-server-2012-r2-part-2.html" target="">part 2</a>.<br />
<br />
<br />
<br />
<br />Mark Gossahttp://www.blogger.com/profile/12935906012968295161noreply@blogger.com0