{"id":5491,"date":"2008-09-14T11:04:00","date_gmt":"2008-09-14T11:04:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2008\/09\/14\/rdp-file-generationuse-of-here-strings\/"},"modified":"2019-02-18T13:13:01","modified_gmt":"2019-02-18T20:13:01","slug":"rdp-file-generationuse-of-here-strings","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/rdp-file-generationuse-of-here-strings\/","title":{"rendered":"RDP File Generation\/Use of HERE-Strings"},"content":{"rendered":"<p>Over on the <a href=\"http:\/\/everydaynerd.com\/\">Everyday Nerd<\/a> blog, I found a great blog entry you should read:&#160; <a href=\"http:\/\/everydaynerd.com\/microsoft\/create-multiple-rdp-files-with-powershell\">Create multiple RDP files with PowerShell<\/a>.&#160; He describes his environment where he has to manage a large set of servers using Remote Desktop (RDP).&#160; Having to configure the RDP settings each time he connects to the server, he decided to automate the process by writing a script which generates the RDP files for him.&#160; <\/p>\n<p>The script itself is cool but the think I wanted to highlight was that the script is a great illustration of a very powerful scripting design pattern.&#160; It uses:<\/p>\n<ol>\n<li>A Template file which defines the structure of the output <\/li>\n<li>A Script which takes input, applies it to the template and generates output <\/li>\n<li>A CSV file which drives the script<\/li>\n<\/ol>\n<p>This pattern has a number of advantages including:<\/p>\n<ul>\n<li>You can change the template file without touching the code.&#160; \n<ul>\n<li>If the script is digitally signed, you can change the template without affecting the digital signature.&#160; <\/li>\n<li>The person updating the template might not have any programming skills<\/li>\n<\/ul>\n<\/li>\n<li>Using a CSV file allows you to have this script driven using the IT Pro&#8217;s favorite input editor:&#160; EXCEL.<\/li>\n<\/ul>\n<p>I have a couple of suggestions for how to improve the script.<\/p>\n<p><strong><u>Use HERE-strings<\/u><\/strong><\/p>\n<p>I continue to see scripts which use lots of string processing which look difficult to create and maintain and are fragile because they are complex.&#160; Here is the example from the script:<\/p>\n<p><font face=\"Courier New\" size=\"2\">&#160;<font face=\"Consolas\">&#160;&#160; # Begin building RDP file       <br \/>&#160;&#160;&#160; $temp = &quot;`nfull address:s:&quot; + $Entry.IP         <br \/>&#160; <br \/>&#160;&#160;&#160; switch ($resolution) {        <br \/>&#160;&#160;&#160;&#160;&#160; <br \/>&#160;&#160;&#160;&#160;&#160; &quot;1024&#215;768&quot; {        <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`nscreen mode id:i:1&quot;        <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`ndesktopwidth:i:1024&quot;        <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`ndesktopheight:i:768&quot;        <br \/>&#160; $temp = $temp + &quot;`nusername:s:&quot; + $Entry.USER        <br \/>&#160;&#160;&#160;&#160;&#160; }<\/font><\/font><\/p>\n<p><font face=\"Consolas\" size=\"2\">&#160;&#160;&#160;&#160;&#160; &quot;1152&#215;864&quot; {      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`nscreen mode id:i:1&quot;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`ndesktopwidth:i:1152&quot;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $temp = $temp + &quot;`ndesktopheight:i:864&quot;      <br \/>&#160; $temp = $temp + &quot;`nusername:s:&quot; + $Entry.USER      <br \/>&#160;&#160;&#160;&#160;&#160; }      <br \/>&#160;&#160;&#160; }<\/font>    <\/p>\n<p>This is exactly the sort of code we hoped to eliminate by providing <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/pstips\/jun07\/pstip0629.mspx\">HERE-strings<\/a>.&#160; HERE-Strings allow you to easily create multi-line strings (with or without variable expansion and command substitution).&#160; HERE-Strings are NOT an advanced topic &#8211; <strong>every PowerShell scripter should take the time to learn how to use HERE-Strings<\/strong>.&#160; Advanced scripters should use them because they are incredibly powerful.&#160; Beginner scripters should use them because they are incredibly easy and reduce the complexity and fragility of your scripts.<\/p>\n<p>Here is the same logic refactored and written with HERE-Strings:<\/p>\n<p><font face=\"Consolas\" size=\"2\">&#160;&#160;&#160; # Begin building RDP file     <br \/>&#160;&#160;&#160; $temp = &quot;`nfull address:s:&quot; + $Entry.IP       <br \/>&#160; <br \/>&#160;&#160;&#160; switch ($resolution) {      <br \/>&#160;&#160;&#160;&#160;&#160; <br \/>&#160;&#160;&#160;&#160;&#160; &quot;1024&#215;768&quot; {      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $width = 1024      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $height = 768      <br \/>&#160;&#160;&#160;&#160;&#160; }<\/font><\/p>\n<p><font face=\"Consolas\" size=\"2\">&#160;&#160;&#160;&#160;&#160; &quot;1152&#215;864&quot; {      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $width = 1152      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; $height = 864      <br \/>&#160;&#160;&#160;&#160;&#160; }      <br \/>&#160;&#160;&#160; }      <br \/>&#160;&#160;&#160; $temp = $temp + @&quot;      <br \/>screen mode id:i:1      <br \/>desktopwidth:i:$width      <br \/>desktopheight:i:$height      <br \/>username:s: $($Entry.USER)      <br \/>&quot;@<\/font>    <\/p>\n<p>In this example I used double quotes which allow variable expansion (Notice the use of $width and $Height) and command substitution (notice the use of $($Entry.USER) [you could put any command or command sequence within $() and we&#8217;ll run it and substitute it&#8217;s output into the string]).<\/p>\n<p><strong><u><\/u><\/strong><\/p>\n<p><strong><u>Use Verb-Noun naming and Proper Verbs<\/u><\/strong><\/p>\n<p>CreateRDP should be New-RDP or New-RDPFile.&#160; What we are trying to do is to achieve a world where people will be able to guess and type and have it be right.&#160; At the beginning, those patterns are not yet established so it might seem like &quot;create&quot; is the same as &quot;new&quot;.&#160; The problem is that if we aren&#8217;t hardcore on this then 50 verbs will become 500 which will become 5,000 and we&#8217;ll have an incoherent world where your guesses are useless and have ourselves to blame. I know what is going on here because it happens with me all the time &#8211; you are so focused on solving the problem, you don&#8217;t want to spend the energy on getting the naming right.&#160; At some point, that pattern will be well established and you won&#8217;t have to think about it &#8211; you&#8217;ll need a new name and you&#8217;ll naturally pick the right ones.&#160; Until then, you need to adopt a practice of reviewing and fixing the naming any script that you share with others.&#160; When you share a script, you&#8217;ll either be enforcing or destroying the pattern for people.&#160; Be a force of good.<\/p>\n<p>The community is the ultimate controller of whether this pattern will emerge or we&#8217;ll have chaos.&#160; I&#8217;ll do whatever I can do to ensure that the artifacts that we produce enforce the pattern but the bulk of scripts are going to come from the community.&#160; The community needs to politely self police itself.&#160; When you see someone share a script that doesn&#8217;t follow the correct naming, you need to leave a comment pointing it out and ask that the post be corrected.&#160; <\/p>\n<p>Let&#8217;s be clear, that includes US.&#160; If (when) you see use posting scripts that don&#8217;t follow the pattern, call us on it and we&#8217;ll get it fixed.<\/p>\n<p>&#160;<\/p>\n<p><u><strong>Use Pipelining Features (when available in PS V2)<\/strong><\/u><\/p>\n<p>One of the problems with the script is that it is hardwired to a CSV file.&#160; It would be more flexible to declare your data requirements and then be flexible with how those data requirements are satisfied.&#160; We are redoing the interfaces to this for the next version of the CTP so I want go into detail here but I didn&#8217;t want to let the point pass either.&#160; What you&#8217;ll be able to do is to specify the parameters and then specify that their values can be retrieved from the properties of a pipelined object.&#160; What that means is that users can create any object they want as long as it has the right property names and then pipeline that object to your command.&#160; This is a TON more powerful\/flexible then hardwiring to CSV files.&#160; Wha\nt this means is you&#8217;d be able to do things like:<\/p>\n<p>PS&gt; Import-CSV RDPLIST.CSV | New-RDPFile   <br \/>PS&gt; Invoke-Database -Query &lt;something&gt; | New-RDPFile    <br \/>PS&gt; Invoke-WebServer -Parameter &lt;something&gt; | New-RDPFile    <br \/>etc<\/p>\n<p>&#160;<\/p>\n<p>Enjoy!<\/p>\n<p>Jeffrey Snover [MSFT]   <br \/>Windows Management Partner Architect    <br \/>Visit the Windows PowerShell Team blog at:&#160;&#160;&#160; <a href=\"http:\/\/blogs.msdn.com\/PowerShell\">http:\/\/blogs.msdn.com\/PowerShell<\/a>    <br \/>Visit the Windows PowerShell ScriptCenter at:&#160; <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/hubs\/msh.mspx\">http:\/\/www.microsoft.com\/technet\/scriptcenter\/hubs\/msh.mspx<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over on the Everyday Nerd blog, I found a great blog entry you should read:&#160; Create multiple RDP files with PowerShell.&#160; He describes his environment where he has to manage a large set of servers using Remote Desktop (RDP).&#160; Having to configure the RDP settings each time he connects to the server, he decided to [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5491","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"blog_post_summary":"<p>Over on the Everyday Nerd blog, I found a great blog entry you should read:&#160; Create multiple RDP files with PowerShell.&#160; He describes his environment where he has to manage a large set of servers using Remote Desktop (RDP).&#160; Having to configure the RDP settings each time he connects to the server, he decided to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/5491","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=5491"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/5491\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=5491"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=5491"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=5491"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}