我正在使用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