合并Rest API结果,合并/组合PowerShell对象

时间:2017-07-21 07:36:57

标签: powershell

我正在使用PowerShell中的Rest API从OMS Service Map导出数据。但是,Rest API仅限于导出数据的一小时时间窗口。

我知道我可以在每小时块(比如ForEach)中循环更长的时间跨度,但是如何合并每个结果,所以我没有得到重复,只有更改或添加添加到现有数据

 # Call to get everything in a service map
$mapRequest = @{'startTime' = $ScriptStartTime
                'endTime'= $ScriptEndTime
                'kind' = 'map:single-machine-dependency'
                'machineId' = $machineId} | ConvertTo-Json

### Post Header Creation
$enc = New-Object "System.Text.ASCIIEncoding"
$byteArray = $enc.GetBytes($mapRequest)
$contentLength = $byteArray.Length
$PostHeader = PostHeader $contentLength

### OMS Service Map API - per machine
$apicall = "$myAPIPath/features/serviceMap/generateMap?api-version=2015-11-01-preview"
$Uri = "{0}{1}" -f $APIURL, $apicall

$serverdep = Invoke-RestMethod -Method Post -Headers $PostHeader -Body $mapRequest -Uri $uri 

下面是完整的脚本,它使用默认的一小时窗口来抓取数据....

##########################################################################################
##################################     Credentials     ###################################
##########################################################################################


#region Logon to Azure & choose Azure subscription

### Log into Azure with an organisational account

$secpasswd = ConvertTo-SecureString 'MyPasssword' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("0db3d52f-0976-40f7-bee3-745da7f2fe7d", $secpasswd)
$TenantId = 'Tennant-ID'
Login-AzureRmAccount -Credential $cred -ServicePrincipal -TenantId $TenantId

$Subscription = (Get-AzureRmSubscription | Out-GridView -Title "Choose a Source & Target Subscription ..." -PassThru)
Select-AzureRmSubscription -SubscriptionId $Subscription.Id

#endregion

$ResourceGroupName = "azureroadmaprg"
$WorkSpaceName = "AzureRoadMap"
$SubscriptionId = $Subscription.Id

##########################################################################################
###################################    Functions     #####################################
##########################################################################################

Function RestAPI-UPN-AuthToken {

    $Username = $Cred.Username
    $Password = $Cred.Password
    $TenantId = $Subscription.TenantId

    # Load ADAL Azure AD Authentication Library Assemblies
    $adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
    $adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
    $null = [System.Reflection.Assembly]::LoadFrom($adal)
    $null = [System.Reflection.Assembly]::LoadFrom($adalforms)

    $adTenant = $Subscription.TenantId
    # Client ID for Azure PowerShell
    $clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
    # Set redirect URI for Azure PowerShell
    $redirectUri = "urn:ietf:wg:oauth:2.0:oob"
    # Set Resource URI to Azure Service Management API | @marckean
    $resourceAppIdURIARM = "https://management.azure.com/"

    # Authenticate and Acquire Token

    # Set Authority to Azure AD Tenant
    $authority = "https://login.microsoftonline.com/common/$TenantId"
    # Build up the credentials
    $ClientCred = [Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential]::new($UserName, $Password)
    # Create Authentication Context tied to Azure AD Tenant
    $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
    # Acquire token
    $global:Token = $authContext.AcquireTokenAsync($resourceAppIdURIARM,$clientId,$ClientCred)
    }

Function RestAPI-SPN-AuthToken {

    $Username = $Cred.Username
    $Password = $Cred.Password
    $TenantId = $Subscription.TenantId

    # Set Resource URI to Azure Service Management API
    $resourceAppIdURI = 'https://management.core.windows.net/'

    # Set Authority to Azure AD Tenant
    $authority = "https://login.windows.net/$TenantId"

    # Build up the credentials
    $ClientCred = [Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential]::new($UserName, $Password)
    # Acquire token
    $authContext = [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext]::new($authority)
    $global:Token = $authContext.AcquireTokenAsync($resourceAppIdURI,$ClientCred)
}

Function RequestHeader {

  # Create Authorization Header
  $authHeader = $global:Token.Result.CreateAuthorizationHeader()
  # Set HTTP request headers to include Authorization header | @marckean
  $requestHeader = @{
    "x-ms-version" = "2014-10-01"; #'2014-10-01'
    "Authorization" = $authHeader
  }
  return $RequestHeader
}

Function PostHeader ($contentLength) {

  # Create Authorization Header
  $authHeader = $global:Token.Result.CreateAuthorizationHeader()
  # Set HTTP request headers to include Authorization header | @marckean
  $PostHeader = @{
    "x-ms-version" = "2014-10-01"; #'2014-10-01'
    "x-ms-date" = ([DateTime]::UtcNow | Get-Date)
    "Authorization" = $authHeader
    "Content-Type" = "application/json"
    "Content-Length"= $contentLength
  }
  return $PostHeader
}

##########################################################################################
#####################################     Token     ######################################
##########################################################################################

RestAPI-SPN-AuthToken # To Logon to Rest and get an an auth key

##########################################################################################
################################    Rest API metadata    #################################
##########################################################################################

$APIURL = 'https://management.azure.com'
$myAPIPath = "/subscriptions/$SubscriptionId/resourcegroups/$ResourceGroupName/providers/microsoft.operationalinsights/workspaces/$WorkSpaceName"

##########################################################################################
#########################     OMS Service Map Rest API calls     #########################
##########################################################################################

[string]$server = '*'
$endTime = ([DateTime]::UtcNow | Get-Date -Format s)
$startTime = ([DateTime]::UtcNow.AddHours(-1) | Get-Date -Format s)

$startTime = '2017-07-19T21:08:17'
$endTime = '2017-07-19T22:08:17'

# Get all machines in OMS $machines
$apicall = "$myAPIPath/features/serviceMap/machines?api-version=2015-11-01-preview&st=$startTime&et=$endTime"
$Uri = "{0}{1}" -f $APIURL, $apicall
$RequestHeader = RequestHeader
$AllMachines = Invoke-RestMethod -Method Get -Headers $RequestHeader -Uri $uri

$csvContents = @() # Create the empty array that will eventually be the CSV file
#[ref]$csvContents

# Get all Machine Groups via API
$apicall = "$myAPIPath/features/serviceMap/machineGroups?api-version=2015-11-01-preview"
$Uri = "{0}{1}" -f $APIURL, $apicall
$RequestHeader = RequestHeader
$MachineGroups = Invoke-RestMethod -Method Get -Headers $RequestHeader -Uri $uri

$ObjectResult = @()
# For each Machine
foreach($machine in ($Allmachines.value)
{
  if ($machine.properties.displayName -like $server)
  {
    $machineFound = $true
    $machineId = $machine.id

    # Call to get everything in a service map
    $mapRequest = @{'startTime' = $startTime
                    'endTime'= $endTime
                    'kind' = 'map:single-machine-dependency'
                    'machineId' = $machineId} | ConvertTo-Json

    ### Post Header Creation
    $enc = New-Object "System.Text.ASCIIEncoding"
    $byteArray = $enc.GetBytes($mapRequest)
    $contentLength = $byteArray.Length
    $PostHeader = PostHeader $contentLength

    ### OMS Service Map API - per machine
    $apicall = "$myAPIPath/features/serviceMap/generateMap?api-version=2015-11-01-preview"
    $Uri = "{0}{1}" -f $APIURL, $apicall

    $serverdep = Invoke-RestMethod -Method Post -Headers $PostHeader -Body $mapRequest -Uri $uri
    $SMconnections = $serverdep.map.edges.connections
    $SMacceptors = $serverdep.map.edges.acceptors
    $SMClientGroups = $serverdep.map.nodes.clientGroups
    $SMprocesses = $serverdep.map.nodes.processes
    $SMmachines = $serverdep.map.nodes.machines
    $SMports = $serverdep.map.nodes.ports
    # Prosesses on remote machines
    $ExternalProcesses = $SMProcesses | ? {$_.properties.machine.id -ne $Machine.id}

##########################################################################################
#########################     Client Groups Per Hour and Per Machine
##########################################################################################

    ### OMS Client Groups - per machine
    $ClientGroupObject = @()
    foreach($SMClientGroup in $SMClientGroups)
    {

     # Client Group API
      $apicall = "$myAPIPath/features/serviceMap/clientGroups/$($SMClientGroup.name)/members?api-version=2015-11-01-preview&st=$startTime&et=$endTime"
      $Uri = "{0}{1}" -f $APIURL, $apicall
      $RequestHeader = RequestHeader
      $ClientGroupMembersAPI = Invoke-RestMethod -Method Get -Headers $RequestHeader -Uri $Uri
      Start-Sleep -Seconds 1

      $CGMembers = @()
      0..(($ClientGroupMembersAPI.value).count -1) |
      % {$CGMembers += '{0} ({1})' -f ($ClientGroupMembersAPI.value)[$_].properties.ipAddress, ($ClientGroupMembersAPI.value)[$_].properties.port.properties.portNumber}

    # Custom Object
      $cgm = [PSCustomObject]@{

      #Connection = $connection.name
      ID = $SMClientGroup.id
      Name = $SMClientGroup.name
      Members = ($CGMembers -join ', ')
      MachineID = $machine.id
      ProcessName = ($SMprocesses | ? {$_.id -eq $SMClientGroup.properties.clientsOf.id}).properties.DisplayName
      ProcessID = ($SMprocesses | ? {$_.id -eq $SMClientGroup.properties.clientsOf.id}).id
    }

    $ClientGroupObject += $cgm

    }

##########################################################################################
#########################     ForEach Process - Per Machine Per Hour
##########################################################################################

    #nodes - The nodes (entities) of a map
    #Ports - Port resources
    #machines
    #processes
    #clientGroups
    #edges - The edges (relationships) of a map
    #connections - Network Connections
    #acceptors - Processes accepting on a port

    # Processes (Monitored) (not discovered, e.g. a discovered process is Port 443 (https))

    # Find inbound connections processes ID
      $InboundConnectionProcessIDs = ($SMconnections | ? {$_.properties.source.properties.machine -and $_.properties.destination.properties.machine.id -eq $machine.id}).properties.source.id
    foreach ($process in ($SMprocesses | ? {$_.properties.monitoringState -eq 'monitored' -and $ExternalProcesses.id -notcontains $_.id})) 
    {
      # -and $InboundConnectionProcessIDs -notcontains $_.id
      # -and $_.id -eq '/subscriptions/e390d230-7e20-466b-8350-5666b87f9dfb/resourceGroups/azureroadmaprg/providers/Microsoft.OperationalInsights/workspaces/AzureRoadMap/features/serviceMap/machines/m-0c14c199-5439-4b62-80ea-1f06dca736ae/processes/p-1f9551d7b5bab1947ac798affec7b0d52763d924'


      ##########################################################################################
      #########################     Network Details Clean-Up
      ##########################################################################################

          $ipv4s = @()
          foreach($interface in $machine.properties.networking.ipv4interfaces) {
            $ipv4s += $interface.ipAddress
          }

          $ipv6s = @()
          foreach($interface in $machine.properties.networking.ipv6interfaces) {
            $ipv6s += $interface.ipAddress
          }

      ##########################################################################################
      #########################     Outbound Connections - based on process
      ##########################################################################################
    # Outbound Connections - based on process
    $OutboundConnectionAgg = @(); $ConnectionMachineName = $null; $ConnectionPort = $null;$OutboundConnection = $null
    $obc1Result = @()
    foreach ($conn in ($SMconnections | ? {$_.properties.source.id -eq $process.id})){
    # Check to see if the destination doesn't contain the current machine's process and that destination machine is not the current machine

    $monitoringState = ($SMprocesses | ? {$_.id -eq $conn.properties.destination.id}).properties.monitoringState
    $monitoringState
    # Discovered Connections
    if($monitoringState -eq 'discovered' -and $conn.properties.destination.id -ne $process.id){

        $ConnectionPort = $conn.properties.serverPort.properties.portNumber
        $MachineID = $conn.properties.destination.properties.machine.id
        $ConnectionMachineName = ($SMmachines | ? {$_.id -eq $MachineID}).properties.displayName
        $DestinationPortID = ($SMports | ? {$_.id -eq $conn.properties.serverPort.id}).id
        $ipAddress = ($SMports | ? {$_.id -eq $DestinationPortID}).properties.ipAddress
        $FailureState = $conn.properties.failureState

        # Custom Object
        $obc1 = new-object psObject | select TargetMachineName,ServerPort,DestinationProcessName,FailureState

        $obc1.TargetMachineName = $ConnectionMachineName
        $obc1.ServerPort = $ConnectionPort
        $obc1.DestinationProcessName = $ipAddress
        $obc1.FailureState = $FailureState

        $obc1Result += $obc1
            }
        }


    # External Process
    $obc2Result = @() 
    if($monitoringState -eq 'monitored' -and $conn.properties.destination.id -ne $process.id){

    $SourceProcessname = ($SMprocesses | ? {$_.id -eq $conn.properties.source.id}).properties.displayName
    $SourceProcessID = ($SMprocesses | ? {$_.id -eq $conn.properties.source.id}).id
    $SourceProcessVersionName = ($SMprocesses | ? {$_.id -eq $conn.properties.source.id}).properties.details.productVersion
    $DestinationProcessName = ($SMprocesses | ? {$_.id -eq $conn.properties.destination.id}).properties.displayName
    $DestinationProcessID = ($SMprocesses | ? {$_.id -eq $conn.properties.destination.id}).id
    $DestinationProcessVersionName = ($SMprocesses | ? {$_.id -eq $conn.properties.destination.id}).properties.details.productVersion
    $TargetMachineID = ($SMmachines | ? {$_.id -eq $conn.properties.destination.properties.machine.id}).id
    $TargetMachineName = ($SMmachines | ? {$_.id -eq $TargetMachineID}).properties.displayName
    $ServerPortID = $SMports | ? {$_.id -eq $conn.properties.serverPort.id}
    $ServerPort = $ServerPortID.properties.portNumber
    $FailureState = $conn.properties.failureState

        # Custom Object
        $obc2 = new-object psObject | select TargetMachineName,ServerPort,DestinationProcessName,FailureState

        $obc2.TargetMachineName = $TargetMachineName
        $obc2.ServerPort = $ServerPort
        $obc2.DestinationProcessName = $DestinationProcessName
        $obc2.FailureState = $FailureState

        $obc2Result += $obc2
       }    

      ##########################################################################################
      #########################     Inbound Connections - based on process
      ##########################################################################################
      # Outbound Connections - based on process
      $ibc1Result = @();$ibc2Result = @()
      $InboundConnection = $null; $InboundConnectionAgg = @(); $ConnectionMachineName = $null; $ConnectionPort = $null
      if(($SMconnections) | ? {$_.properties.destination.id -eq $process.id})
      {

        # Client Groups
          # Match the connection destination to a source client group
        if($ClientGroupObject.Processid -contains $process.id)
          {

            # Client Group Members            
            foreach ($obj in ($ClientGroupObject | ? {$_.Processid -eq $process.id -and $_.ProcessName})){

            $members = $obj.Members
            $ConnectionMachineName = "ClientGroup{0}" -f (Get-Random -Minimum 1111 -Maximum 9999999)

            # Custom Object
            $ibc1 = new-object psObject | select ConnectionMachineName,ProcessName

            $ibc1.ConnectionMachineName = $ConnectionMachineName
            $ibc1.ProcessName = $members

            $ibc1Result += $ibc1

            }
          }

        foreach ($conn in ($SMconnections | ? {$_.properties.destination.id -eq $process.id -and $_.properties.source.type -notmatch 'workspaces/features/clientGroups'})) {

              $ProcessID = $conn.properties.destination.id
              $ProcessName = ($SMprocesses | ? {$_.id -eq $conn.properties.source.id}).properties.displayName
              $MachineID = ($SMmachines | ? {$_.id -eq $conn.properties.source.properties.machine.id}).id
              $ConnectionMachineName = ($SMmachines | ? {$_.id -eq $conn.properties.source.properties.machine.id}).properties.displayName

            # Custom Object
            $ibc2 = new-object psObject | select ConnectionMachineName,ProcessName

            $ibc2.ConnectionMachineName = $ConnectionMachineName
            $ibc2.ProcessName = $ProcessName

            $ibc2Result += $ibc2
                }
          }

      ##########################################################################################
      #########################     Machine Group Membership
      ##########################################################################################                    
          # Get Machine Group Membership
          $MachineGroupMembership = @()
          foreach($MachineGroup in $MachineGroups.value){
            if($MachineGroup.properties.machines.properties.displayNameHint -contains $machine.properties.displayName){
              $MachineGroupMembership += $MachineGroup.properties.displayName
            }
          }

      ##########################################################################################
      #########################     Custom Object
      ##########################################################################################  

$inboundConnections = (($ibc1Result + $ibc2Result) | % {('({0}, {1})' -f $_.ConnectionMachineName, $_.ProcessName)}) -join ', '
$outboundConnections = (($obc1Result + $obc2Result) | % {('({0}, {1}, {2}, {3})' -f $_.TargetMachineName, $_.ServerPort, $_.DestinationProcessName, $_.FailureState)}) -join ', '

        # Custom Object
        $s = [PSCustomObject]@{

            #Connection = $connection.name
            ServerName = $machine.properties.displayName
            MachineGroupMembership = $MachineGroupMembership -join ' '
            Ipv4s = ([system.String]::Join(", ", $ipv4s))
            Ipv6s = ([system.String]::Join(", ", $ipv6s))
            OsFamily = $machine.properties.operatingsystem.family
            OsName = $machine.properties.operatingsystem.fullName
            Memory = $machine.properties.resources.physicalmemory
            Cpus = $machine.properties.resources.cpus
            CpuSpeed = $machine.properties.resources.cpuSpeed
            VmType = $machine.properties.virtualMachine.virtualMachineType
            #ClientMachine = (. ( {"client"},{$clientMachine.properties.displayName})[$clientMachine.properties.displayName -ne $null])
            #InboundConnections = (@(($InboundConnection) -join ',') | Out-String).Trim()
            InboundConnections = $inboundConnections
            Process = (. ( {"n/a"},{$Process.properties.displayName})[$Process.properties.displayName -ne $null])
            OutboundConnection = $outboundConnections

        }
        $ObjectResult += $s

        }
    }
}




$csvName = "Migration_" + [DateTime]::Now.ToString("yyyyMMdd_HHmmss") + ".html"
#$csvName = "output.csv"

$ObjectResult | Sort-Object Process | ConvertTo-Html | Set-Content -Path $csvName

# Write CSV
$ObjectResult | Select-Object @{name="multistring";Expression={$_.InboundConnections -join ';'}} | Export-CSV -NoTypeInformation -Path $csvName

0 个答案:

没有答案