系统管理员的 Powershell URI 构建器

问题描述 投票:0回答:3

请原谅我的无知 - 我正在尝试编写一个 powershell cmdlet,它接受用户输入并为 API 构建一个查询 uri(一个强制,3 个选择) - 我有一个大概的想法,我需要使用哈希表作为字典查询字符串和参数。

我正在尝试构建

$baseurl + $querystring + '=' + $parameter + '&' + $querystring + '=' $value (if not null)

例如

https://example.com/api?param1=value&param2=value

到目前为止 - 这非常粗糙,完全不起作用:

            Function Get-commonURI{ #takes 4 params from user
                [CmdletBinding()]
                Param(
                    [Parameter(Mandatory=$true,
                                ValueFromPipeline=$true,
                                ValueFromPipelineByPropertyName=$true)]

                                [String[]]$value1

                                [Parameter(Mandatory=$false,
                                ValueFromPipeline=$true,
                                ValueFromPipelineByPropertyName=$true)]

                                [String[]]$value2,
                                [String[]]$value3,
                                [String[]]$value4 

                ) #end param 
            }
        #put the input into a paramter hash table with the query strings

        $Parameters = @{
            query = 'querysting1', 'querystring2', 'querystring3', 'querystring4'
            values = $value1,$value2.$value2, $value4
        }

        uri = https://example.com/api?

    $HttpValueCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty)

    foreach ($Item in $Parameters.GetEnumerator()) {
#I want to append each query passed in on the cli

foreach ($Value in $Item.Value) {
      $ParameterName = $Item.value

      $HttpValueCollection.Add($ParameterName, $Value)}

$Request  = [System.UriBuilder]($Uri)
$Request.Query = $HttpValueCollection.ToString()

invoke-webrequest $Request.Uri

}

我写了类似的东西,但它不起作用 - 我是否走在正确的轨道上? - 我确信这已经被执行了一百万次,但甚至不知道要谷歌什么 - 有些东西告诉我我不应该用变量设置哈希表。感谢您的关注。

powershell
3个回答
17
投票

我一直不喜欢重新发明轮子:

$ub = new-object System.UriBuilder -argumentlist 'http', 'myhost.com', 80, 'mypath/query.aspx', '?param=value'
$ub.Uri.AbsoluteUri
>>>> http://myhost.com/mypath/query.aspx?param=value

更新:

这是一个内置的 .NET 类,具有许多构造函数。上面的接受协议、主机、端口号、路径和查询字符串。它似乎处理空或空查询字符串,因此无需自己处理。有关信息,可以在here查看该类的构造函数。为了检索用户的输入,您可以使用 Read-Host,例如:

[String] $Local:strServer = '';
[String] $Local:strPath   = '';
[String] $Local:strQuery  = '';
[String] $Local:strUri    = '';

while ( $strServer -eq '' ) {
    $strServer = Read-Host -Prompt 'Please enter a server name';
    } #while
while ( $strPath -eq '' ) {
    $strPath   = Read-Host -Prompt 'Please enter a path';
    } #while

# Get query string and ensure it begins with a "?".
$strQuery  = Read-Host -Prompt 'Please enter a query string';
if ( ($strQuery -ne '') -and (! $strQuery.StartsWith('?')) ) { $strQuery = '?' + $strQuery; } 

try {
    $strUri = [System.UriBuilder]::new( 'http', $strServer, 80, $strPath, $strQuery );
    Write-Host -Object ( 'URI is {0}' -f $strUri );
    } #try
catch [System.ArgumentException] {
    # Something went wrong.
    } #catch

0
投票

最后,我将其编写为一个 cmdlet,它接受管道输入,并且可以从其他脚本调用 - 它可以在浏览器中打开 uri,将 xml 保存为文档,或将文档转换为 xml 类型对象 - 这是非常方便,因为您可以使用点分符号而不是 xPath 选择 xml 对象属性(xml 节点、属性),并且 Powershells 智能感知使用制表符补全,因此您可以在命令行或 Powershell ISE 中循环浏览 xml 节点。

我还使用powershell社区扩展模块 https://pscx.codeplex.com/ 因为它是明智的连接字符串 cmdlet。

Add-Type -AssemblyName System.Web
$authparam = '&auth='
$baseURI = 'https://example.com/restapi?'
$password = 'plaintextpassword'

Function Get-APICommon
{
    #takes 4 params and auth key
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $false,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true)]
        [String[]]$param1,
        [String[]]$Param2,
        [String[]]$Param3,
        [String[]]$Param4

    ) #end param 

    Begin { }
    process
    {

        $Parameters = [ordered] @{
            Query1 = $Param1
            Query2 = $Param2
            Query3 = $Param3
            Query4 = $Param4
        }
        #This particular API needs to have query parameters separated by ':' and hashed as part of the authentication parameter i.e param1:param2:param3:param4:password
        $preauth = ($Parameters.GetEnumerator() | % { "$($_.Value)" }) -join ':'

        $prehash = Join-String $preauth, ':', $password
        $hash = $prehash | Get-Hash -Algorithm SHA1 -StringEncoding ascii


        foreach ($item in $Parameters.GetEnumerator())
        {

            if ($item.value -ne $null)
            {

                $query =[System.Web.HttpUtility]::ParseQueryString($uriBuilder.Query)
                $query[$item.key] = $item.Value

                $uriBuilder = [System.UriBuilder]::new($baseURI)
                $uriBuilder.Query = $query.ToString()
                $baseURI = $uriBuilder.ToString()
            }



        }

        $queryURI = Join-String $baseURI, $authparam, $hash
        Write-Host $queryURI


    $Resultfile = Join-String $($Parameters.Query1),'-Result.xml'

    $Resultxml = [xml](Invoke-WebRequest -Uri $queryURI | Select-Object -ExpandProperty content | Out-File $Resultfile)

    $Parameters.Clear()


        $Browser = new-object -com internetexplorer.application

        $Browser.navigate2("$queryURI")

        $Browser.visible = $true


    }


}

使用示例

get-APICommon -param1 查询字符串

get-APICommon -param1 查询值1 -param2 查询值2

结果示例

https://example.com/restapi?&query1=queryvalue&query2=queryvalue2&auth=JSJAUJQJALF09OLQLS34LLK

0
投票

在添加查询参数时,

System.UriBuilder
类非常简洁。对于除了最简单的查询之外的任何查询,这都会将查询生成的所有复杂性都推入代码中,这会很快将其变成意大利面条。幸运的是,Powershell 类允许我们扩展
System.UriBuilder
来处理复杂性。

在高级场景中,您可能希望添加具有相同键的多个参数,将值数组转换为键/值对的字符串,或者仅在表示值的变量计算结果为 true 时添加参数(即 Exists/不为空)。

请参阅评论标题中的示例了解如何使用它。

<#
.SYNOPSIS
    Updated version of the System.UriBuilder class with improved support for query params.
.EXAMPLE
    Add simple key/value pair.

    $Builder = [UriBuilderPro]::new('https://this.example.com')
    $Builder.AddParameter('one', 'two')
    $Builder.Parameters  # Display Parameters
    $Builder.Query       # Display Query

.EXAMPLE
    Add parameters based on predicate logic, either a constant
    or scriptblock that resolves to True/False.

    $Builder = [UriBuilderPro]::new('https://this.example.com')
    $exists = 'exists'
    $Builder.AddParameter('exists', $exists, $exists)  # Evals true and added
    $Builder.AddParameter('notExists', $notexists, $notexists)  # Evals false and not added
    $Builder.AddParameter('mayExist', $notexists, { $exists -eq 'notexists' })  # Evals false and not added
    $Builder.Parameters  # Display Parameters
    $Builder.Query       # Display Query

.EXAMPLE
    Add parameter with array values

    $Builder = [UriBuilderPro]::new('https://this.example.com')
    $Builder.AddParameter('foo', @('foo', 'fubar'))  # Implicit conversion of array value into multiple key=value pairs.
    $Builder.AddParameter('bar', @('bar', 'barfu'), $True, ',')  # Join array on string value. Pass $True just to satisfy overload.
    $Builder.Parameters  # Display Parameters
    $Builder.Query       # Display Query
#>
class UriBuilderPro : System.UriBuilder {
    [hashtable] $Parameters = @{}

    UriBuilderPro() : base() { }

    UriBuilderPro([string] $Uri) : base([string] $Uri) {}

    UriBuilderPro([uri] $uri) : base($args) {}

    UriBuilderPro([string] $schemeName, [string] $hostName) :
        base([string] $schemeName, [string] $hostName) {}

    UriBuilderPro([string] $scheme, [string] $hostname, [int] $portNumber) :
        base([string] $scheme, [string] $hostname, [int] $portNumber) {}

    UriBuilderPro([string] $scheme, [string] $hostname, [int] $port, [string] $pathValue) :
        base($args) {
            [string] $scheme, [string] $hostname, [int] $port, [string] $pathValue
        }

    UriBuilderPro([string] $scheme, [string] $hostname, [int] $port, [string] $path, [string] $extraValue) :
        base([string] $scheme, [string] $hostname, [int] $port, [string] $path, [string] $extraValue) {}

    AddParameter([string] $Key, [object] $Value) {
        if ($this.Parameters.ContainsKey($Key)) {
            throw [System.IO.InvalidDataException] "Cannot add duplicate key '$Key'"
        }
        $this.Parameters[$Key] = $Value
        $this.UpdateQuery()
    }

    AddParameter([string] $Key, [object] $Value, [string] $Join) {
        $this.AddParameter($Key, ($Value -join $Join))
    }

    AddParameter([string] $Key, [object] $Value, [object] $Predicate) {
        if ($null -ne $Predicate -and
            $Predicate.GetType().Name -eq "Scriptblock" -and
            $Predicate.InvokeReturnAsIs()
        ) {
            $this.AddParameter($Key, $Value)
        }
    }

    AddParameter([string] $Key, [object] $Value, [object] $Predicate, [string] $Join) {
        if ($null -ne $Predicate -and
            $Predicate.GetType().Name -eq "Scriptblock" -and
            $Predicate.InvokeReturnAsIs()
        ) {
            $this.AddParameter($Key, $Value, $Join)
        } elseif ($Predicate) {
            $this.AddParameter($Key, $Value, $Join)
        }
    }

    UpdateQuery() {
        $TempQuery = ''
        foreach($Param in $this.Parameters.GetEnumerator()) {
            foreach ($Value in $Param.Value) {
                $TempQuery += "{0}={1}&" -f $Param.Key, [uri]::EscapeDataString($Value).Replace('(', '%28').Replace(')', '%29')
            }
        }
        # UriBuilder implicitly adds a leading ? mark when setting Query
        $this.Query = $TempQuery.TrimEnd('&')
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.