Functions/AzureDevOps/Get-ADOAuditLog.ps1

function Get-ADOAuditLog {
<#
    .SYNOPSIS
        Gets the Azure DevOps Audit Log
    .DESCRIPTION
        Gets the Azure DevOps Audit Log for a Given Organization
    .EXAMPLE
        Get-ADOAuditLog
    .LINK
        https://docs.microsoft.com/en-us/rest/api/azure/devops/audit/audit-log/query
    
#>

    
    param(
# The Organization
[Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='https://auditservice.dev.azure.com/{Organization}/_apis/audit/auditlog')]
[string]
$Organization,
# The size of the batch of audit log entries.
    [Parameter(ValueFromPipelineByPropertyName)]
    [int]
    $BatchSize,
# The start time.
    [Parameter(ValueFromPipelineByPropertyName)]
    [DateTime]
    $StartTime,
# The end time.
    [Parameter(ValueFromPipelineByPropertyName)]
    [DateTime]
    $EndTime,
# The api-version. By default, 7.1-preview.1
    [Parameter(ValueFromPipelineByPropertyName)]    
    [ComponentModel.DefaultBindingProperty("api-version")]
    [string]
    $ApiVersion = '7.1-preview.1'
    )
    dynamicParam { . $GetInvokeParameters -DynamicParameter 
}
    begin {
        #region Copy Invoke-ADORestAPI parameters
        $invokeParams = . $getInvokeParameters $PSBoundParameters
        $invokeParams.ExpandProperty = 'decoratedAuditLogEntries'
        $invokeParams.PSTypeName    = "ADO.AuditLog.Entry"
        #endregion Copy Invoke-ADORestAPI parameters
    
    # Declare a Regular Expression to match URL variables.
    $RestVariable = [Regex]::new(@'
# Matches URL segments and query strings containing variables.
# Variables can be enclosed in brackets or curly braces, or preceeded by a $ or :
(?> # A variable can be in a URL segment or subdomain
    (?<Start>[/\.]) # Match the <Start>ing slash|dot ...
    (?<IsOptional>\?)? # ... an optional ? (to indicate optional) ...
    (?:
        \{(?<Variable>\w+)\}| # ... A <Variable> name in {} OR
        \[(?<Variable>\w+)\]| # A <Variable> name in [] OR
        \<(?<Variable>\w+)\>| # A <Variable> name in <> OR
        \:(?<Variable>\w+) # A : followed by a <Variable>
    )
|
    (?<IsOptional> # If it's optional it can also be
        [{\[](?<Start>/) # a bracket or brace, followed by a slash
    )
    (?<Variable>\w+)[}\]] # then a <Variable> name followed by } or ]
| # OR it can be in a query parameter:
    (?<Start>[?&]) # Match The <Start>ing ? or & ...
    (?<Query>[\w\-]+) # ... the <Query> parameter name ...
    = # ... an equals ...
    (?<IsOptional>\?)? # ... an optional ? (to indicate optional) ...
    (?:
        \{(?<Variable>\w+)\}| # ... A <Variable> name in {} OR
        \[(?<Variable>\w+)\]| # A <Variable> name in [] OR
        \<(?<Variable>\w+)\>| # A <Variable> name in <> OR
        \:(?<Variable>\w+) # A : followed by a <Variable>
    )
)
'@
, 'IgnoreCase,IgnorePatternWhitespace')
    
    # Next declare a script block that will replace the rest variable.
    $ReplaceRestVariable = {
        param($match)
        if ($uriParameter -and $uriParameter[$match.Groups["Variable"].Value]) {
            return $match.Groups["Start"].Value + $(
                    if ($match.Groups["Query"].Success) { $match.Groups["Query"].Value + '=' }
                ) +
                ([Web.HttpUtility]::UrlEncode(
                    $uriParameter[$match.Groups["Variable"].Value]
                ))
        } else {
            return ''
        }
    }
        $myCmd = $MyInvocation.MyCommand
        function ConvertRestInput {
                    param([Collections.IDictionary]$RestInput = @{}, [switch]$ToQueryString)
                    foreach ($ri in @($RestInput.GetEnumerator())) {
                        $RestParameterAttributes = @($myCmd.Parameters[$ri.Key].Attributes)
                        $restParameterName  = $ri.Key
                        $restParameterValue = $ri.Value
                        foreach ($attr in $RestParameterAttributes) {
                            if ($attr -is [ComponentModel.AmbientValueAttribute] -and 
                                $attr.Value -is [ScriptBlock]) {
                                $_ = $this = $ri.Value
                                $restParameterValue = & $attr.Value
                            }
                            if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) {
                                $restParameterName = $attr.Name
                            }
                        }
                        $restParameterValue = 
                            if ($restParameterValue -is [DateTime]) {
                                $restParameterValue.Tostring('o')
                            }
                            elseif ($restParameterValue -is [switch]) {
                                $restParameterValue -as [bool]
                            }
                            else {
                                if ($ToQueryString -and 
                                    $restParameterValue -is [Array] -and 
                                    $JoinQueryValue) {
                                    $restParameterValue -join $JoinQueryValue
                                } else {
                                    $restParameterValue
                                }
                                
                            }
                        
                        if ($restParameterValue -is [Collections.IDictionary]) {
                            $RestInput.Remove($ri.Key)
                            foreach ($kv in $restParameterValue.GetEnumerator()) {
                                $RestInput[$kv.Key] = $kv.Value
                            }
                        } elseif ($restParameterName -ne $ri.Key) {
                            $RestInput.Remove($ri.Key)
                            $RestInput[$restParameterName] = $restParameterValue
                        } else {
                            $RestInput[$ri.Key] = $restParameterValue
                        }
                    }
                    $RestInput
                
        }
    
}
process {
    $InvokeCommand       = 'Invoke-ADORestAPI'
    $invokerCommandinfo  = 
        $ExecutionContext.SessionState.InvokeCommand.GetCommand('Invoke-ADORestAPI', 'All')
    $method              = ''
    $contentType         = ''
    $bodyParameterNames  = @('')
    $queryParameterNames = @('BatchSize','StartTime','EndTime','ApiVersion')
    $joinQueryValue      = ''
    $uriParameterNames   = @('Organization')
    $endpoints           = @("https://auditservice.dev.azure.com/{Organization}/_apis/audit/auditlog")
    $ForEachOutput = {
        
    }
    if ($ForEachOutput -match '^\s{0,}$') {
        $ForEachOutput = $null
    }    
    if (-not $invokerCommandinfo) {
        Write-Error "Unable to find invoker '$InvokeCommand'"
        return        
    }
    if (-not $psParameterSet) { $psParameterSet = $psCmdlet.ParameterSetName}
    if ($psParameterSet -eq '__AllParameterSets') { $psParameterSet = $endpoints[0]}    
    $originalUri = "$psParameterSet"
    if (-not $PSBoundParameters.ContainsKey('UriParameter')) {
        $uriParameter = [Ordered]@{}
    }
    foreach ($uriParameterName in $uriParameterNames) {
        if ($psBoundParameters.ContainsKey($uriParameterName)) {
            $uriParameter[$uriParameterName] = $psBoundParameters[$uriParameterName]
        }
    }
    $uri = $RestVariable.Replace($originalUri, $ReplaceRestVariable)
    $invokeSplat = @{}
    $invokeSplat.Uri = $uri
    if ($method) {
        $invokeSplat.Method = $method
    }
    if ($ContentType -and $invokerCommandInfo.Parameters.ContentType) {        
        $invokeSplat.ContentType = $ContentType
    }
    if ($InvokeParams -and $InvokeParams -is [Collections.IDictionary]) {
        $invokeSplat += $InvokeParams
    }
    $QueryParams = [Ordered]@{}
    foreach ($QueryParameterName in $QueryParameterNames) {
        if ($PSBoundParameters.ContainsKey($QueryParameterName)) {
            $QueryParams[$QueryParameterName] = $PSBoundParameters[$QueryParameterName]            
        } else {
            $queryDefault = $ExecutionContext.SessionState.PSVariable.Get($QueryParameterName).Value
            if ($null -ne $queryDefault) {
                $QueryParams[$QueryParameterName] = $queryDefault
            }
        }
    }
    $queryParams = ConvertRestInput $queryParams -ToQueryString
    if ($invokerCommandinfo.Parameters['QueryParameter'] -and 
        $invokerCommandinfo.Parameters['QueryParameter'].ParameterType -eq [Collections.IDictionary]) {
        $invokeSplat.QueryParameter = $QueryParams
    } else {
        $queryParamStr = 
            @(foreach ($qp in $QueryParams.GetEnumerator()) {
                $qpValue = $qp.value                
                if ($JoinQueryValue -eq '&') {
                    foreach ($qVal in $qpValue -split '&') {
                        "$($qp.Key)=$([Web.HttpUtility]::UrlEncode($qValue).Replace('+', '%20'))"    
                    }
                } else {
                    "$($qp.Key)=$([Web.HttpUtility]::UrlEncode($qpValue).Replace('+', '%20'))"
                }
            }) -join '&'
        if ($invokeSplat.Uri.Contains('?')) {
            $invokeSplat.Uri = "$($invokeSplat.Uri)" + '&' + $queryParamStr
        } else {
            $invokeSplat.Uri = "$($invokeSplat.Uri)" + '?' + $queryParamStr
        }
    }
    Write-Verbose "$($invokeSplat.Uri)"
    if ($ForEachOutput) {
        if ($ForEachOutput.Ast.ProcessBlock) {
            & $invokerCommandinfo @invokeSplat | & $ForEachOutput
        } else {
            & $invokerCommandinfo @invokeSplat | ForEach-Object -Process $ForEachOutput
        }        
    } else {
        & $invokerCommandinfo @invokeSplat
    }
}
}