{"id":16741,"date":"2010-10-22T00:01:00","date_gmt":"2010-10-22T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/10\/22\/make-windows-powershell-your-web-client\/"},"modified":"2010-10-22T00:01:00","modified_gmt":"2010-10-22T00:01:00","slug":"make-windows-powershell-your-web-client","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/make-windows-powershell-your-web-client\/","title":{"rendered":"Make Windows PowerShell Your Web Client"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p><span style=\"font-size: small\"><b>Summary:<\/b> Interact with websites from Windows PowerShell with this how-to post that wraps .NET Framework classes.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Question\" border=\"0\" title=\"Hey, Scripting Guy! Question\" \/><span style=\"font-size: small\">Hey, Scripting Guy! I would like to be able to download files and things from the Internet via Windows PowerShell. Is there an easy way to do this? I have not been able to find a Windows PowerShell cmdlet, and I would like to share whatever I come up with other users. <\/span><\/p>\n<p>&#8212; BR<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Answer\" border=\"0\" title=\"Hey, Scripting Guy! Answer\" \/><span style=\"font-size: small\">Hello BR, <\/span><\/p>\n<p><span style=\"font-size: small\">Microsoft Scripting Guy Ed Wilson here. James Brundage began talking about wrapping .NET Framework classes to work with the web in yesterday&rsquo;s Hey, Scripting Guy! post. That post is a great introduction to wrapping .NET Framework classes to work with the Internet. Let&rsquo;s let him complete the discussion. <\/span><\/p>\n<p><span style=\"font-size: small\">James Brundage is the founder of Start-Automating (<\/span><a href=\"http:\/\/www.start-automating.com\/\"><span style=\"font-size: small\">http:\/\/www.start-automating.com<\/span><\/a><span style=\"font-size: small\">), a company dedicated to saving people time and money by helping them automate. Start-Automating offers Windows PowerShell training and custom Windows PowerShell and .NET Framework development. James formerly worked on the Windows PowerShell team at Microsoft and is the author of the <\/span><a href=\"http:\/\/code.msdn.microsoft.com\/PowerShellPack\"><span style=\"font-size: small\">PowerShellPack<\/span><\/a><span style=\"font-size: small\">, a collection of Windows PowerShell scripts to enable building user interfaces, interact with RSS feeds, retrieve system information, and more. You can follow James on Twitter @JamesBru. <\/span><\/p>\n<p>&nbsp;<\/p>\n<h3>A Series on Splatting (and Stuff)<\/h3>\n<h4>Part 5: Splatting .NET Framework conclusion<\/h4>\n<p><span style=\"font-size: small\">In previous posts, we have covered how to build commands that wrap other commands with splatting and building bridges between two commands with splatting.&nbsp; Yesterday we looked at improving a Windows PowerShell script that invoked a .NET command. Today, we will learn how to apply those skills to make some usable Windows PowerShell scripts to replace some hard-to-use .NET.<\/span><\/p>\n<p><span style=\"font-size: small\">Great! Let&rsquo;s take the <b>New-WebClient<\/b> function that was developed <\/span><a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2010\/10\/21\/packaging-net-framework-classes-into-windows-powershell-functions.aspx\"><span style=\"font-size: small\">yesterday<\/span><\/a><span style=\"font-size: small\">, because we can think of the next command we will write as bridging <b>New-WebClient<\/b> and a quick function to invoke the method.&nbsp; <\/span><\/p>\n<p><span style=\"font-size: small\">Our begin block will also contain this <b>New-WebClient<\/b> function and a helper function called <b>Invoke-Method<\/b> that lets us invoke .NET methods in a Windows PowerShell syntax.<\/span><\/p>\n<p><span style=\"font-size: small\">The <b>$BeginBlock<\/b> variable will contain the two helper commands, and nothing else.&nbsp; If these helper commands were going to be used by a larger group of commands, I&rsquo;d put them into the same <\/span><a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/tags\/getting+started\/modules\/default.aspx\"><span style=\"font-size: small\">module<\/span><\/a><span style=\"font-size: small\"> as the command I&rsquo;m working on. However, you can also embed a private command this way. The <b>$BeginBlock<\/b> and its two functions are seen here. <\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">$BeginBlock = {<br \/>&nbsp;&nbsp;&nbsp; function New-WebClient<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding(DefaultParameterSetName=&#8221;Easy&#8221;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [string]$BaseAddress,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Hard&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Net.ICredentials]$Credentials,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Easy&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Management.Automation.PSCredential]$Credential,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Hard&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Net.WebHeaderCollection]$Headers,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Easy&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Hashtable]$Header,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Hard&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Collections.Specialized.NameValueCollection]$QueryString,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Easy&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Hashtable]$Query,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Hard&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [bool]$UseDefaultCredentials,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;Easy&#8217;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]$Anonymous&nbsp;&nbsp; &nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; process {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($psCmdlet.ParameterSetName -eq &#8220;Hard&#8221;) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; New-Object Net.Webclient -Property $psBoundParameters<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters = @{} + $psBoundParameters<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters.UseDefaultCredentials = -not $Anonymous<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.Remove(&#8220;Anonymous&#8221;)<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($newWebClientParameters.Credential) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters.Credentials = $newWebClientParameters.Credential.GetNetworkCredential()<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.Remove(&#8220;Credential&#8221;)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($newWebClientParameters.Header) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters.Headers = New-Object Net.WebHeadercollection<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($headerPair in $newWebClientParameters.Header.GetEnumerator()) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.Headers.Add($headerPair.Key, $headerPair.Value)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.Remove(&#8220;Header&#8221;)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($newWebClientParameters.Query) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters.QueryString = New-Object Collections.Specialized.NameValueCollection<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($QueryPair in $newWebClientParameters.Query.GetEnumerator()) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.QueryString.Add($QueryPair.Key, $QueryPair.Value)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $newWebClientParameters.Remove(&#8220;Query&#8221;)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; New-WebClient @newWebclientParameters<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; function Invoke-Method<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param($Object, [string]$Method, $Parameters)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;process {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $realMethod =$object.&#8221;${method}&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($realMethod) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $realMethod.Invoke($Parameters)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">The parameter block is next.&nbsp; Remember how we said that most of what you do in .NET can be expressed as creating a class, setting lots of properties, and running lots of methods? The begin block took care of the first two.&nbsp; The parameter block and process block will handle the rest.<\/span><\/p>\n<p><span style=\"font-size: small\">You can think of any Windows PowerShell command as one or more things that you can do.&nbsp; Each parameter set may be a small variation on the thing.&nbsp; Many commands actually contain many related operations in one, with each parameter set representing a different operation.<\/span><\/p>\n<p><span style=\"font-size: small\">When wrapping something from .NET in Windows PowerShell, it is easy to go down the list and turn methods into parameter sets.<\/span><\/p>\n<p><span style=\"font-size: small\">Here are the .NET methods we want to wrap:<\/span><\/p>\n<ul>\n<li>\n<div class=\"BullList\"><strong># string DownloadString(System.Uri address)<\/strong><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># byte[] DownloadData(System.Uri address)<\/strong> <\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># void DownloadFile(System.Uri address, string file)<\/strong><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># byte[] UploadData(System.Uri address, string method, byte[] data)<\/strong><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># byte[] UploadFile(System.Uri address, string method, string file)<\/strong><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># byte[] UploadString(System.Uri address, string method, string string)<\/strong> <\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><strong># byte[] UploadValues(System.Uri address, string method, NameValueCollection values)<\/strong><\/div>\n<\/li>\n<\/ul>\n<p><span style=\"font-size: small\">Turning these into parameters is tedious, but easy.&nbsp; Here is a list of guidelines that describe how we&#8217;ll do it. <\/span><\/p>\n<ul>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Each method becomes a parameter set.<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Each parameter becomes a mandatory parameter for that parameter set.<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Any parameter that is in multiple methods will be in multiple parameter sets (it is easy, just add another [Parameter()] attribute).<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Make sure that you give common parameters a position (i.e. address and method).<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">If there is a case in which the only way the methods are different is by the type of data that they return, make an <strong>-AsTYPE<\/strong> parameter to let the user decide (i.e. <strong>DownloadString<\/strong> and <strong>DownloadData<\/strong>).<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Select the most common operation as the default parameter set.<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Add comments for user help.<\/span><\/div>\n<\/li>\n<li>\n<div class=\"BullList\"><span style=\"font-size: small\">Add the <strong>ValueFromPipelineByPropertyName<\/strong> attribute to each parameter (unless you have a good reason not to, it opens up some interesting possibilities if you do).<\/span><\/div>\n<\/li>\n<\/ul>\n<p><span style=\"font-size: small\">If you are writing one of these from scratch in the Windows PowerShell Integrated Scripting Environment (ISE), you might want to try using the <b>Add-Parameter<\/b> function from IsePack (part of PowerShellPack) because it simplifies some repetitive typing.&nbsp; The <b>Add-Parameter<\/b> function has several switches that let you add mandatory parameters, select a parameter set, create the parameter from the <\/span><a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/winpsh\/manual\/pipe.mspx\"><span style=\"font-size: small\">pipeline<\/span><\/a><span style=\"font-size: small\"> or from the pipeline by property name.<\/span><\/p>\n<p><span style=\"font-size: small\">Here is the parameter block for <b>Send-WebRequest<\/b>, which combines the &rdquo;Easy&rdquo; parameter set of <b>New-WebClient<\/b> and the parameters that match each newly added operation.<\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">$paramBlock = {<br \/>&nbsp;&nbsp;&nbsp; &lt;#<br \/>&nbsp;&nbsp;&nbsp; .Synopsis<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sends web requests to download or upload information from the web<br \/>&nbsp;&nbsp;&nbsp; .Description<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Uses the System.Net.WebClient class to download or upload information from the web<br \/>&nbsp;&nbsp;&nbsp; .Example<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Send-WebRequest &#8220;http:\/\/www.start-automating.com\/&#8221;<br \/>&nbsp;&nbsp;&nbsp; #&gt;<br \/>&nbsp;&nbsp;&nbsp; [CmdletBinding(DefaultParameterSetName=&#8221;DownloadString&#8221;)]<br \/>&nbsp;&nbsp;&nbsp; param(<br \/>&nbsp;&nbsp;&nbsp; # The Uri to download or upload<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;DownloadData&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;DownloadString&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;DownloadFile&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadData&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadFile&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadString&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadValues&#8217;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position=0,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mandatory=$true,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Uri]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; $Address,<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # The method used to send an upload request (i.e. Get or Post)<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadData&#8217;,Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadFile&#8217;,Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadString&#8217;,Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadValues&#8217;,Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [string]$Method = &#8220;Get&#8221;,<\/p>\n<p>&nbsp;&nbsp;&nbsp; # The data to upload&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadData&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Byte[]]$UploadData,<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # The file to upload<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadFile&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [string]$UploadFile,<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # The string to upload<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadString&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)] &nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp; [string]$UploadString,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # The string to upload<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;UploadValues&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Hashtable]$UploadValue,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # If set, the information will be returned as Data<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;DownloadData&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Switch]$ASData,<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # If set, the infromation will be downloaded to a file<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ParameterSetName=&#8217;DownloadFile&#8217;,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [String]<br \/>&nbsp;&nbsp;&nbsp; $ToFile,<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; # The Base Address.&nbsp;&nbsp; The Uri will be appended to this address<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [string]$BaseAddress,<\/p>\n<p>&nbsp;&nbsp;&nbsp; # The Credential used to send the web request<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Management.Automation.PSCredential]$Credential,<\/p>\n<p>&nbsp;&nbsp;&nbsp; # A collection of header information&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; [Parameter(ValueFrom&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Hashtable]$Header,<\/p>\n<p>&nbsp;&nbsp;&nbsp; # A set of data for GET or POST query<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Hashtable]$Query,<\/p>\n<p>&nbsp;&nbsp;&nbsp; # If this is set, then the connection will be anonymous.&nbsp; Otherwise, the default credentials will be used.<br \/>&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName=$true)]<br \/>&nbsp;&nbsp;&nbsp; [Switch]$Anonymous<br \/>&nbsp;&nbsp;&nbsp; )<br \/>}<\/p>\n<p><\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">It&rsquo;s a piece of cake right? (Well maybe the kind that Marie Antoinette would serve).<\/span><\/p>\n<p><span style=\"font-size: small\">The process block is less tedious, but follows a similar pattern.&nbsp; The start of the command becomes a bit of common code (creating the web request) followed by either a switch statement (if you prefer readability) or lots of else-ifs (if you prefer speed) that set up the input for the method, followed by a calling the method.<\/span><\/p>\n<p><span style=\"font-size: small\">Because the parameter set name is the method name, and the webclient is always the object, the only thing that has to be in the switch statement is the part that determines the arguments.&nbsp; Here&rsquo;s what our process block looks like. <\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\" style=\"padding-left: 30px\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">$processBlock = {<br \/>&nbsp;&nbsp;&nbsp; # Create the web client<br \/>&nbsp;&nbsp;&nbsp; $newWebClientParameters = @{}&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; foreach ($p in &#8220;BaseAddress&#8221;, &#8220;Credential&#8221;, &#8220;Header&#8221;, &#8220;Query&#8221;, &#8220;Anonymous&#8221;) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($psBoundParameters[$p]) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $newWebClientParameters[$p] = $psBoundParameters[$p]<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; $webClient = New-WebClient @newWebClientParameters<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; $parameters = @()<br \/>&nbsp;&nbsp;&nbsp; switch ($psCmdlet.ParameterSetName)<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DownloadString {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters = $Address<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DownloadData {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters = $Address<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DownloadFile {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $unresolvedFile = $psCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($ToFile)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters = $Address, $unresolvedFile <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UploadData {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;$parameters = $Address, $Method, $UploadData<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UploadFile {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $resolvedFile = $psCmdlet.SessionState.Path.GetResolvedProviderPathFromPSPath($uploadFile)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters =&nbsp; $Address, $Method, $resolvedFile<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;UploadString {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters = $Address, $Method, $UploadString <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UploadValues {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $nameValueCollection = New-Object Collections.Specialized.NameValueCollection<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($pair in $value.GetEnumerator()) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = $nameValueCollection.Add($Pair.Key, $Pair.Value)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $parameters = $Address, $Method, $nameValueCollection<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; $invokeMethodParameters = @{<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object = $webClient<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Method = $psCmdlet.ParameterSetName<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Parameters = $parameters<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; Invoke-Method @invokeMethodParameters<br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">Now let&#8217;s create our function from the three different parts we just finished making. The <b>Send-WebRequest<\/b> function is seen here. <\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">$functionDefinition = &#8220;function Send-WebRequest {<br \/>&nbsp;&nbsp;&nbsp; $paramBlock<br \/>&nbsp;&nbsp;&nbsp; <br \/>&nbsp;&nbsp;&nbsp; begin {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $beginBlock<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; process {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $processBlock<br \/>&nbsp;&nbsp;&nbsp; }<br \/>}<br \/>&#8220;<\/p>\n<p>$functionDefinition | Set-Content .\\Send-WebRequest.ps1<br \/>. .\\Send-WebRequest.ps1<\/p>\n<p>Let&rsquo;s try downloading the Hey, Scripting Guy blog:<br \/>$rss = Send-WebRequest &#8220;http:\/\/blogs.technet.com\/b\/heyscriptingguy\/rss.aspx&#8221;<br \/>$rss = [xml]$rss<br \/>$rss.rss.channel.item | Select-Object Title, PubDate<br \/><\/span><br \/><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">It even has help! Cool! <\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">Get-Help Send-WebRequest &ndash;Full<\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">The complete <b>Send-WebRequest<\/b> function can be downloaded from the <\/span><a href=\"http:\/\/gallery.technet.microsoft.com\/ScriptCenter\/en-us\/7e7b6bf2-d067-48c3-96b3-b38f26a1d143\"><span style=\"font-size: small\">Scripting Guys Script Repository<\/span><\/a><span style=\"font-size: small\">. You can paste the function into the Windows PowerShell ISE, run the script, and then use the code seen here to download the RSS feed for the Hey, Scripting Guy! Blog. <\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">$rss = Send-WebRequest &#8220;http:\/\/blogs.technet.com\/b\/heyscriptingguy\/rss.aspx&#8221;<br \/>$rss = [xml]$rss<br \/>$rss.rss.channel.item | Select-Object Title, PubDate<\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">When you run this code, the output shown in the following image appears.<\/span><\/p>\n<p>&nbsp;<img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/prod.evol.blogs.technet.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/00\/76\/18\/4722.HSG-10-22-10-01.JPG\" border=\"0\" \/><\/p>\n<p><span style=\"font-size: small\">If you save the <b>Send-WebRequest<\/b> function to a Windows PowerShell script file, you can dot-source it into your new script. This is seen in the <b>UseSendWebRequestFunction.ps1<\/b> script.<\/span><\/p>\n<blockquote>\n<p class=\"CodeBlockScreenedHead\"><strong><span style=\"font-size: small\">UseSendWebRequestFunction.ps1<\/span><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span style=\"font-family: Lucida Sans Typewriter\"><span style=\"font-size: small\">. C:\\fso\\Send-WebRequestFunction.ps1<br \/>$rss = Send-WebRequest &#8220;http:\/\/blogs.technet.com\/b\/heyscriptingguy\/rss.aspx&#8221;<br \/>$rss = [xml]$rss<br \/>$rss.rss.channel.item | Select-Object Title, PubDate<\/span><\/span><\/p>\n<\/blockquote>\n<p><span style=\"font-size: small\">BR, that is all there is to using Windows PowerShell to wrap .NET Framework commands. Guest blogger week has ended. Thank you James for all this information and scripts. &nbsp;Join us tomorrow for the <\/span><a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/tags\/weekend+scripter\/\"><span style=\"font-size: small\">Weekend Scripter<\/span><\/a><span style=\"font-size: small\">. <\/span><\/p>\n<p><span style=\"font-size: small\">We invite you to follow us on <\/span><a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingguystwitter\"><span style=\"font-size: small\">Twitter<\/span><\/a><span style=\"font-size: small\"> or <\/span><a href=\"http:\/\/bit.ly\/scriptingguysfacebook\"><span style=\"font-size: small\">Facebook<\/span><\/a><span style=\"font-size: small\">. If you have any questions, send email to us at <\/span><a target=\"_blank\" href=\"mailto:scripter@microsoft.com\"><span style=\"font-size: small\">scripter@microsoft.com<\/span><\/a><span style=\"font-size: small\"> or post them on the <\/span><a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en\/ITCG\/threads\/\"><span style=\"font-size: small\">Official Scripting Guys Forum.<\/span><\/a><span style=\"font-size: small\">. See you tomorrow. Until then, peace.<\/span><\/p>\n<p><span style=\"font-size: small\">&nbsp;<\/span><\/p>\n<p><b><span style=\"font-size: small\">Ed Wilson and Craig Liebendorfer, Scripting Guys<\/span><\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Summary: Interact with websites from Windows PowerShell with this how-to post that wraps .NET Framework classes. &nbsp; Hey, Scripting Guy! I would like to be able to download files and things from the Internet via Windows PowerShell. Is there an easy way to do this? I have not been able to find a Windows [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[51,56,184,3,4,170,45],"class_list":["post-16741","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-getting-started","tag-guest-blogger","tag-james-brundage","tag-scripting-guy","tag-scripting-techniques","tag-splatting","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Summary: Interact with websites from Windows PowerShell with this how-to post that wraps .NET Framework classes. &nbsp; Hey, Scripting Guy! I would like to be able to download files and things from the Internet via Windows PowerShell. Is there an easy way to do this? I have not been able to find a Windows [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/16741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=16741"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/16741\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=16741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=16741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=16741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}