PS C:\Users\Administrator> # 加载必要程序集
PS C:\Users\Administrator> Add-Type -AssemblyName System.Net.Http -ErrorAction Stop
PS C:\Users\Administrator>
PS C:\Users\Administrator> function Invoke-EnhancedCurlRequest {
>> [CmdletBinding()]
>> param(
>> [Parameter(Mandatory=$true)]
>> [string]$Uri,
>> [ValidateSet('GET','POST','PUT','DELETE','PATCH','HEAD','OPTIONS')]
>> [string]$Method = 'GET',
>> [hashtable]$Headers = @{},
>> [object]$Body,
>> [int]$Timeout = 30,
>> [switch]$SkipCertificateCheck,
>> [switch]$UseGzipCompression
>> )
>>
>> $resultTemplate = [PSCustomObject]@{
>> StatusCode = 0
>> StatusMessage = "NotExecuted"
>> Headers = [ordered]@{}
>> Content = $null
>> IsSuccess = $false
>> Technology = "None"
>> ErrorMessage = $null
>> ElapsedMs = 0
>> }
>>
>> $timer = [System.Diagnostics.Stopwatch]::StartNew()
>> $result = $resultTemplate.PSObject.Copy()
>> $result.Technology = "HttpClient"
>>
>> $handler = $null
>> $client = $null
>> $request = $null
>> $response = $null
>>
>> try {
>> # 创建 HttpClientHandler
>> $handler = New-Object System.Net.Http.HttpClientHandler
>>
>> # 修复证书验证 - 兼容所有 .NET 版本
>> if ($SkipCertificateCheck) {
>> # 方法1: 使用反射设置回调(兼容旧版 .NET)
>> $handlerType = $handler.GetType()
>> $prop = $handlerType.GetProperty("ServerCertificateCustomValidationCallback")
>>
>> if ($null -ne $prop) {
>> $callback = {
>> param($sender, $cert, $chain, $sslPolicyErrors)
>> return $true
>> }
>> $prop.SetValue($handler, $callback)
>> }
>> # 方法2: 使用全局设置(备用方案)
>> else {
>> $originalCallback = [System.Net.ServicePointManager]::ServerCertificateValidationCallback
>> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
>> param($sender, $cert, $chain, $sslPolicyErrors)
>> return $true
>> }
>> }
>> }
>>
>> if ($UseGzipCompression) {
>> $handler.AutomaticDecompression = [System.Net.DecompressionMethods]::GZip
>> }
>>
>> # 创建 HttpClient
>> $client = New-Object System.Net.Http.HttpClient($handler)
>> $client.Timeout = [System.TimeSpan]::FromSeconds($Timeout)
>>
>> # 创建请求方法对象
>> $httpMethod = [System.Net.Http.HttpMethod]::new($Method)
>> if (-not $httpMethod) {
>> $httpMethod = New-Object System.Net.Http.HttpMethod($Method)
>> }
>>
>> # 创建请求消息
>> $request = New-Object System.Net.Http.HttpRequestMessage($httpMethod, $Uri)
>>
>> # 添加默认 User-Agent
>> if (-not $Headers.ContainsKey('User-Agent')) {
>> $request.Headers.TryAddWithoutValidation("User-Agent", "PowerShell-HTTPClient/1.0")
>> }
>>
>> # 添加自定义头
>> foreach ($key in $Headers.Keys) {
>> if (-not $request.Headers.TryAddWithoutValidation($key, $Headers[$key])) {
>> if (-not $request.Content) {
>> $request.Content = New-Object System.Net.Http.StringContent("")
>> }
>> $request.Content.Headers.TryAddWithoutValidation($key, $Headers[$key])
>> }
>> }
>>
>> # 处理请求体
>> if ($Body -and @('POST','PUT','PATCH') -contains $Method) {
>> if ($Body -is [byte[]]) {
>> $request.Content = New-Object System.Net.Http.ByteArrayContent($Body)
>> }
>> elseif ($Body -is [hashtable] -or $Body -is [System.Collections.IDictionary]) {
>> $jsonBody = $Body | ConvertTo-Json -Depth 5 -Compress
>> $request.Content = New-Object System.Net.Http.StringContent(
>> $jsonBody,
>> [System.Text.Encoding]::UTF8,
>> "application/json"
>> )
>> }
>> elseif ($Body -is [string]) {
>> $request.Content = New-Object System.Net.Http.StringContent(
>> $Body,
>> [System.Text.Encoding]::UTF8
>> )
>> }
>> else {
>> throw "Unsupported body type: $($Body.GetType().Name)"
>> }
>> }
>>
>> # 发送请求
>> $response = $client.SendAsync($request).GetAwaiter().GetResult()
>>
>> # 解析响应
>> $result.StatusCode = [int]$response.StatusCode
>> $result.StatusMessage = $response.ReasonPhrase
>> $result.IsSuccess = $response.IsSuccessStatusCode
>>
>> $result.Headers = [ordered]@{}
>> foreach ($header in $response.Headers) {
>> $result.Headers[$header.Key] = $header.Value -join ", "
>> }
>>
>> foreach ($header in $response.Content.Headers) {
>> $result.Headers[$header.Key] = $header.Value -join ", "
>> }
>>
>> $result.Content = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
>> return $result
>> }
>> catch [System.Threading.Tasks.TaskCanceledException] {
>> $result.ErrorMessage = "Request timed out after $Timeout seconds"
>> $result.StatusCode = 408
>> $result.StatusMessage = "Timeout"
>> return $result
>> }
>> catch [System.Net.Http.HttpRequestException] {
>> # 处理特定HTTP请求异常
>> $ex = $_.Exception
>> $result.ErrorMessage = $ex.ToString()
>>
>> if ($ex.InnerException -is [System.Net.Sockets.SocketException]) {
>> $result.StatusCode = 0
>> $result.StatusMessage = "DNSResolutionFailed"
>> }
>> else {
>> $result.StatusCode = 500
>> $result.StatusMessage = "HttpRequestError"
>> }
>>
>> return $result
>> }
>> catch {
>> # 通用错误处理
>> $result.ErrorMessage = $_.Exception.ToString()
>> $result.StatusCode = 500
>> $result.StatusMessage = "InternalError"
>> return $result
>> }
>> finally {
>> $timer.Stop()
>> $result.ElapsedMs = $timer.ElapsedMilliseconds
>>
>> # 安全清理资源
>> if ($response -is [IDisposable]) { $response.Dispose() }
>> if ($request -is [IDisposable]) { $request.Dispose() }
>> if ($client -is [IDisposable]) { $client.Dispose() }
>> if ($handler -is [IDisposable]) { $handler.Dispose() }
>>
>> # 恢复全局证书验证设置
>> if ($SkipCertificateCheck -and $null -ne $originalCallback) {
>> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $originalCallback
>> }
>> }
>> }
>>
PS C:\Users\Administrator> # 使用反射设置回调(兼容旧版 .NET)
PS C:\Users\Administrator> $handlerType = $handler.GetType()
不能对 Null 值表达式调用方法。
所在位置 行:1 字符: 1
+ $handlerType = $handler.GetType()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [],RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PS C:\Users\Administrator> $prop = $handlerType.GetProperty("ServerCertificateCustomValidationCallback")
不能对 Null 值表达式调用方法。
所在位置 行:1 字符: 1
+ $prop = $handlerType.GetProperty("ServerCertificateCustomValidationCa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [],RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PS C:\Users\Administrator> if ($null -ne $prop) {
>> $callback = { param($sender, $cert, $chain, $sslPolicyErrors) return $true }
>> $prop.SetValue($handler, $callback)
>> }
>> # 备用方案:全局设置
>> else {
>> $originalCallback = [System.Net.ServicePointManager]::ServerCertificateValidationCallback
>> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
>> param($sender, $cert, $chain, $sslPolicyErrors) return $true
>> }
>> }
>>
PS C:\Users\Administrator> catch [System.Net.Http.HttpRequestException] {
>> $ex = $_.Exception
>> if ($ex.InnerException -is [System.Net.Sockets.SocketException]) {
>> $result.StatusCode = 0
>> $result.StatusMessage = "DNSResolutionFailed"
>> }
>> }
>>
catch : 无法将“catch”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正
确,然后再试一次。
所在位置 行:1 字符: 1
+ catch [System.Net.Http.HttpRequestException] {
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (catch:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Users\Administrator> finally {
>> # 恢复全局证书验证设置
>> if ($SkipCertificateCheck -and $null -ne $originalCallback) {
>> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $originalCallback
>> }
>> }
>>
finally : 无法将“finally”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路
径正确,然后再试一次。
所在位置 行:1 字符: 1
+ finally {
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (finally:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Users\Administrator> # 创建模块目录
PS C:\Users\Administrator> $moduleDir = "$env:ProgramFiles\WindowsPowerShell\Modules\PSHttpClient"
PS C:\Users\Administrator> New-Item -Path $moduleDir -ItemType Directory -Force | Out-Null
PS C:\Users\Administrator>
PS C:\Users\Administrator> # 生成并保存模块文件
PS C:\Users\Administrator> $fixedModuleCode = @'
>> # 将上面修复后的完整函数代码复制到这里
>> '@
>>
PS C:\Users\Administrator> $fixedModuleCode | Out-File "$moduleDir\PSHttpClient.psm1" -Encoding UTF8 -Force
PS C:\Users\Administrator>
PS C:\Users\Administrator> # 重新加载模块
PS C:\Users\Administrator> Remove-Module PSHttpClient -ErrorAction SilentlyContinue
PS C:\Users\Administrator> Import-Module PSHttpClient -Force -PassThru
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 1.3 PSHttpClient
PS C:\Users\Administrator>
PS C:\Users\Administrator> # 测试自签名证书网站
PS C:\Users\Administrator> $result = Invoke-EnhancedCurlRequest -Uri "https://self-signed.badssl.com/" -SkipCertificateCheck
PS C:\Users\Administrator>
PS C:\Users\Administrator> if ($result.IsSuccess) {
>> Write-Host "✅ 自签名证书网站访问成功" -ForegroundColor Green
>> } else {
>> Write-Host "❌ 自签名证书网站访问失败: $($result.ErrorMessage)" -ForegroundColor Red
>> }
>>
❌ 自签名证书网站访问失败: System.Management.Automation.MethodInvocationException: 使用“2”个参数调用“SetValue”时发生异常:“类型“System.Management.Automation.ScriptBlock”的对象无法转换为类型“System.Func`5[System.Net.Http.HttpRequestMessage,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Chain,System.Net.Security.SslPolicyErrors,System.Boolean]”。” ---> System.ArgumentException: 类型“System.Management.Automation.ScriptBlock”的对象无法转换为类型“System.Func`5[System.Net.Http.HttpRequestMessage,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Chain,System.Net.Security.SslPolicyErrors,System.Boolean]”。
在 System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
在 System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
在 System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
在 System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
在 CallSite.Target(Closure , CallSite , Object , Object , Object )
--- 内部异常堆栈跟踪的结尾 ---
在 System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
在 System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
在 System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
在 System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
PS C:\Users\Administrator> # 测试无效域名
PS C:\Users\Administrator> $result = Invoke-EnhancedCurlRequest -Uri "https://invalid.domain.abc/"
PS C:\Users\Administrator>
PS C:\Users\Administrator> if ($result.StatusCode -eq 0) {
>> Write-Host "✅ DNS错误处理成功" -ForegroundColor Green
>> } else {
>> Write-Host "❌ DNS错误处理失败: $($result.StatusCode)" -ForegroundColor Red
>> }
>>
❌ DNS错误处理失败: 500
PS C:\Users\Administrator>