├── .devcontainer ├── devcontainer.json └── Dockerfile ├── examples ├── application-bulk-import.csv ├── archive-flows-to-vrli │ ├── config.json │ ├── vrealize-log-insight.ps1 │ └── vrni-archive-flows-to-vrli.ps1 ├── datasource-bulk-set-snmp.csv ├── export-flows.ps1 ├── get-bandwidth-usage-per-ip.ps1 ├── datasource-bulk-set-snmp.ps1 ├── datasource-bulk-import.csv ├── application-bulk-import.ps1 ├── cmdb-import-from-itop.ps1 ├── datasource-bulk-import.ps1 └── cmdb-import-from-servicenow.ps1 ├── ToDo.md ├── .vscode └── settings.json ├── extract-example-metadata.sh ├── publish ├── Publish.ps1 ├── Include.ps1 └── psgallery │ └── PowervRNI │ └── PowervRNI.psd1 ├── EXAMPLES.md ├── ChangeLog.md ├── README.md ├── PowervRNI.psd1 └── LICENSE.md /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PowervRNI Development Container", 3 | "dockerFile": "Dockerfile", 4 | "postCreateCommand": "pwsh", 5 | "extensions": [ 6 | "ms-vscode.powershell" 7 | ] 8 | } -------------------------------------------------------------------------------- /examples/application-bulk-import.csv: -------------------------------------------------------------------------------- 1 | Application;Tier;Security Group;VM Names 2 | App01;Web;;App01-VM1-Web,App01-VM2-Web 3 | App01;App;SG-3Tier-App;App01-VM*-App 4 | App01;DB;SG-App01-DB; 5 | App02;NoTier;SG-App02; 6 | App03;Web;;App03-Web* 7 | App03;DB;;App03-DB* -------------------------------------------------------------------------------- /examples/archive-flows-to-vrli/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "vrni_server": "my-vrni-platform.lab", 3 | "vrni_credentials_file": "credentials.xml", 4 | "vrni_domain": "local", 5 | "vrli_server": "my-vrli-server", 6 | "cache_file": "flow-cache.json", 7 | "last_flows_ts": 1579273407 8 | } 9 | -------------------------------------------------------------------------------- /examples/datasource-bulk-set-snmp.csv: -------------------------------------------------------------------------------- 1 | Nickname;NewSnmpCommunity 2 | cat3k.lab.local;public 3 | cat45k.lab.local;public 4 | cat65k.lab.local;public 5 | n5k.lab.local;public 6 | n7k.lab.local;public 7 | n9k.lab.local;public 8 | arista.lab.local;public 9 | dellf10mlx10.lab.local;public 10 | dellp8024.lab.local;public 11 | dell54048.lab.local;public 12 | dell29100.lab.local;public 13 | dell56000.lab.local;public 14 | brocade.lab.local;public 15 | juniper.lab.local;public 16 | ucs.lab.local;public -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell:ubuntu16.04 2 | 3 | # Set working directory so stuff doesn't end up in / 4 | WORKDIR /root 5 | 6 | # Configure apt 7 | ENV DEBIAN_FRONTEND=noninteractive 8 | RUN apt-get update && apt-get -y install --no-install-recommends apt-utils 2>&1 9 | 10 | # Install git, process tools, lsb-release (common in install instructions for CLIs) 11 | RUN apt-get -y install git procps lsb-release 12 | 13 | # Trust PSGallery 14 | SHELL [ "pwsh", "-command" ] 15 | RUN Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 16 | 17 | CMD ["/usr/bin/pwsh"] 18 | -------------------------------------------------------------------------------- /ToDo.md: -------------------------------------------------------------------------------- 1 | ## ToDo items/ideas 2 | 3 | - \[enhancement] improve cmdlets that take `-StartTime` / `-EndTime` parameters to take actual `DateTime` objects to improve the user experience (they can pass the more "natural"-in-PowerShell `Get-Date "13 Jun 2017"` as a value, instead of needing to pass a "seconds since 01 Jan 1970" value, or even think about less-legible epoch-based time) 4 | - \[enhancement] add `-WhatIf` support to Set-, Remove-, etc. cmdlets (via `SupportsShouldProcess` directive in `CmdletBinding` and `$PSCmdlet.ShouldProcess()` in the body), and maybe add `ConfirmImpact` of `High` to destructive cmdlets (`Remove-vRNI*`, for example), as described at [https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.confirmimpact?view=powershellsdk-1.1.0](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.confirmimpact?view=powershellsdk-1.1.0) 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.formatOnSave": true, 4 | "files.trimTrailingWhitespace": true, 5 | "editor.tabSize": 2, 6 | "editor.insertSpaces": true, 7 | "editor.detectIndentation": false, 8 | "[markdown]": { 9 | "files.trimTrailingWhitespace": false, 10 | }, 11 | "yaml.customTags": [ 12 | "!And", 13 | "!And sequence", 14 | "!If", 15 | "!If sequence", 16 | "!Not", 17 | "!Not sequence", 18 | "!Equals", 19 | "!Equals sequence", 20 | "!Or", 21 | "!Or sequence", 22 | "!FindInMap", 23 | "!FindInMap sequence", 24 | "!Base64", 25 | "!Join", 26 | "!Join sequence", 27 | "!Cidr", 28 | "!Ref", 29 | "!Sub", 30 | "!Sub sequence", 31 | "!GetAtt", 32 | "!GetAZs", 33 | "!ImportValue", 34 | "!ImportValue sequence", 35 | "!Select", 36 | "!Select sequence", 37 | "!Split", 38 | "!Split sequence" 39 | ] 40 | } -------------------------------------------------------------------------------- /extract-example-metadata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "# PowervRNI - Examples" > EXAMPLES.md 4 | 5 | EXAMPLE_FILES="examples/*.ps1 examples/archive-flows-to-vrli/*.ps1" 6 | for example in $EXAMPLE_FILES 7 | do 8 | #echo "Processing $example file..." 9 | # see if example header is present 10 | LINE=`grep "Example:" $example` 11 | if [ -n "$LINE" ] 12 | then 13 | EXAMPLE_NAME=`echo $LINE | sed -e 's/^# Example:\ *//'` 14 | echo "## ${example}" >> EXAMPLES.md 15 | echo "### ${EXAMPLE_NAME}" >> EXAMPLES.md 16 | 17 | # sed -n '1!p' = cut first line ("START Description") 18 | # sed '$d' = cut last line ("END Description") 19 | # sed 's/^..//' = remove the comments "# " 20 | EXAMPLE_DESC=`sed -n '/START Description/,/END Description/p' $example | sed -n '1!p' | sed '$d' | sed 's/^..//'` 21 | echo $EXAMPLE_DESC >> EXAMPLES.md 22 | 23 | example_file=`echo $example | sed -e 's/^examples\/\ *//'` 24 | 25 | #echo "" 26 | #echo " ${example_file}" 27 | #echo " ${EXAMPLE_NAME}" 28 | #echo " ${EXAMPLE_DESC}" 29 | #echo "" 30 | fi 31 | done -------------------------------------------------------------------------------- /examples/export-flows.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Exporting network flows 4 | # 5 | # START Description 6 | # This script outputs flows in a certain time range. 7 | # END Description 8 | # 9 | # Martijn Smit (@smitmartijn) 10 | # msmit@vmware.com 11 | # Version 1.0 12 | 13 | param ( 14 | [parameter(Mandatory = $false, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 15 | [ValidateNotNullOrEmpty()] 16 | [int]$StartTime = ([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s")) - 60), # default to an hour window 17 | [parameter(Mandatory = $false, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 18 | [ValidateNotNullOrEmpty()] 19 | [int]$EndTime = [Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s")), 20 | [parameter(Mandatory = $false, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 21 | [ValidateNotNullOrEmpty()] 22 | [int]$Limit = 9999 23 | ) 24 | 25 | if ($null -eq $defaultvRNIConnection) { 26 | Write-Host "Please connect to a Network Insight instance, using Connect-vRNIServer or Connect-NIServer!" 27 | exit; 28 | } 29 | 30 | $flows = Get-vRNIFlow -StartTime $StartTime -EndTime $EndTime -Limit $Limit -Debug 31 | $flows 32 | $flows.Count 33 | 34 | foreach ($flow in $flows) { 35 | } 36 | 37 | if ($Limit -lt $flows.Count) { 38 | Write-Host -ForegroundColor "red" "The current limit ($Limit) is lower than the amount of flows in the system. Consider raising the limit." 39 | } -------------------------------------------------------------------------------- /publish/Publish.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Publishing: 2 | # 3 | # - Generate a new manifest 4 | # - Publish it to PowerShell Gallery 5 | # 6 | # Martijn Smit (@smitmartijn) 7 | # msmit@vmware.com 8 | # Version 1.0 9 | 10 | param ( 11 | # Required API key to upload to PowerShell Gallery. 12 | [Parameter (Mandatory = $true)] 13 | [string]$NuGetApiKey 14 | ) 15 | 16 | # Source the Include.ps1 file for settings 17 | . ./Include.ps1 18 | 19 | # Append the current build number on the version number. For this, we need git. 20 | # The build number is correlated on how many commits there are. 21 | 22 | # Check if we have git 23 | try { if (Get-Command git) { <# we have git, so continue! #> } } 24 | catch { throw "For this script to run, we need git. I couldn't find git." } 25 | 26 | # Get build number 27 | $BuildNumber = (git log --oneline).Count 28 | # Format version number 29 | $PowervRNI_Version = $PowervRNI_Version + '.' + $BuildNumber.ToString().Trim() 30 | # Test version 31 | if (-not ($PowervRNI_Version -as [version])) { 32 | throw "$PowervRNI_Version is not a valid version number. Try again." 33 | } 34 | # Add the version to the manifest options 35 | $Manifest_Common.Add("ModuleVersion", $PowervRNI_Version) 36 | 37 | # Get current working directory 38 | $currentPath = split-path $MyInvocation.MyCommand.Path 39 | 40 | # Generate new manifest file 41 | New-ModuleManifest -Path "$currentPath/../PowervRNI.psd1" -PowerShellVersion '6.0' @Manifest_Common 42 | # Convert to UTF8 43 | $content = Get-Content "$currentPath/../PowervRNI.psd1" 44 | [System.IO.File]::WriteAllLines("$currentPath/../PowervRNI.psd1", $content) 45 | 46 | # Copy module file to publish directory 47 | Copy-Item -Path "$currentPath/../PowervRNI.psm1" "$currentPath/psgallery/PowervRNI/" 48 | # Copy manifest file to publish directory 49 | Copy-Item -Path "$currentPath/../PowervRNI.psd1" "$currentPath/psgallery/PowervRNI/" 50 | 51 | Publish-Module -NuGetApiKey $NuGetApiKey -Path "$currentPath/psgallery/PowervRNI" -ReleaseNotes $Manifest_Common.ReleaseNotes 52 | 53 | Write-Host -ForegroundColor Yellow "PowervRNI $PowervRNI_Version is now published to the PowerShell Gallery! Also push the new files to GitHub." 54 | -------------------------------------------------------------------------------- /EXAMPLES.md: -------------------------------------------------------------------------------- 1 | # PowervRNI - Examples 2 | ## examples/application-bulk-import.ps1 3 | ### Adding applications in bulk 4 | This script uses an input CSV (example: application-bulk-import.csv) to add multiple vRealize Network Insight Applications. Modify application-bulk-import.csv to contain your applications and application tiers, along with either the NSX Security Group or the VM names. Then run this script with the param -ApplicationsCSV to your CSV. 5 | ## examples/cmdb-import-from-itop.ps1 6 | ### Import Applications from iTop 7 | Retrieves applications from the CMDB iTop, and imports them into vRNI. 8 | ## examples/cmdb-import-from-servicenow.ps1 9 | ### Import Applications from ServiceNow 10 | Retrieves applications from the CMDB ServiceNow, and imports them into vRNI. Note: is now a native vRNI feature, the script is still here to serve as an example. 11 | ## examples/datasource-bulk-import.ps1 12 | ### Adding datasources in bulk 13 | This script uses an input CSV (example: datasource-bulk-import.csv) to add multiple vRealize Network Insight Data Sources. Modify datasource-bulk-import.csv to contain your own data sources (vCenters, NSX, switches, firewalls) and run this script with the param -DatasourcesCSV to your CSV. 14 | ## examples/datasource-bulk-set-snmp.ps1 15 | ### Changing SNMP configs of multiple switch devices 16 | This script uses an input CSV (example: datasource-bulk-snmp.csv) to configure multiple vRealize Network Insight Data Sources SNMP Values. Modify datasource-bulk-snmp.csv to contain your own data sources and run this script with the param -DatasourcesCSV to your CSV. Based off Martijn Smit bulk data source import script. 17 | ## examples/export-flows.ps1 18 | ### Exporting network flows 19 | This script outputs flows in a certain time range. 20 | ## examples/get-bandwidth-usage-per-ip.ps1 21 | ### Billing Use Case 22 | Gets a list of IPs with their respective bandwidth usage, which can be used for billing purposes (ISPs). 23 | ## examples/archive-flows-to-vrli/vrni-archive-flows-to-vrli.ps1 24 | ### Archiving vRealize Network Insight flows to vRealize Log Insight 25 | This script connects to vRNI, retrieves the flows within a time window (the last time this script was run and now), then checks whether the flow is located in the cache (more info in comments of cache code), and if not, gathers metadata (VM & L2 network name), and finally sends the flow to vRLI using Send-vRLIMessage from vrealize-log-insight.ps1 26 | -------------------------------------------------------------------------------- /examples/get-bandwidth-usage-per-ip.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Billing Use Case 4 | # 5 | # START Description 6 | # Gets a list of IPs with their respective bandwidth usage, which can be used for billing purposes (ISPs). 7 | # END Description 8 | # 9 | # Martijn Smit (@smitmartijn) 10 | # msmit@vmware.com 11 | # Version 1.0 12 | 13 | 14 | param ( 15 | [Parameter (Mandatory = $false)] 16 | # The epoch timestamp of when to start looking up records 17 | [int]$StartTime = ([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s")) - 86400), # default to a day window 18 | [Parameter (Mandatory = $false)] 19 | # The epoch timestamp of when to stop looking up records 20 | [int]$EndTime = [Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s")) 21 | ) 22 | 23 | # If we want to select flows in a time slot, make sure the end time is later then the start time 24 | if ($StartTime -gt $EndTime) { 25 | throw "Param StartTime cannot be greater than EndTime" 26 | } 27 | 28 | if (!$defaultvRNIConnection) { 29 | throw "Use Connect-vRNIServer or Connect-NIServer to connect to Network Insight first!" 30 | } 31 | 32 | # Loop through these IPs and get their download/upload bytes 33 | $IPs_to_lookup = @("10.8.20.20", "10.8.20.66") 34 | foreach ($ip_address in $IPs_to_lookup) { 35 | # Get download bytes first 36 | $requestBody = @{ 37 | entity_type = 'Flow' 38 | filter = "destination_ip.ip_address = '$ip_address'" 39 | aggregations = @( @{ 40 | field = "flow.totalBytes.delta.summation.bytes" 41 | aggregation_type = "SUM" 42 | } ) 43 | start_time = $StartTime 44 | end_time = $EndTime 45 | } 46 | 47 | $listParams = @{ 48 | Connection = $defaultvRNIConnection 49 | Method = 'POST' 50 | Uri = "/api/ni/search/aggregation" 51 | Body = ($requestBody | ConvertTo-Json) 52 | } 53 | 54 | $result = Invoke-vRNIRestMethod @listParams 55 | $download_bytes = $result.aggregations.value 56 | 57 | # Now get upload bytes 58 | $requestBody = @{ 59 | entity_type = 'Flow' 60 | filter = "source_ip.ip_address = '$ip_address'" 61 | aggregations = @( @{ 62 | field = "flow.totalBytes.delta.summation.bytes" 63 | aggregation_type = "SUM" 64 | } ) 65 | start_time = $StartTime 66 | end_time = $EndTime 67 | } 68 | 69 | $listParams = @{ 70 | Connection = $defaultvRNIConnection 71 | Method = 'POST' 72 | Uri = "/api/ni/search/aggregation" 73 | Body = ($requestBody | ConvertTo-Json) 74 | } 75 | 76 | $result = Invoke-vRNIRestMethod @listParams 77 | $upload_bytes = $result.aggregations.value 78 | 79 | Write-Host "IP: $ip_address - Download bytes: $download_bytes - Upload bytes: $upload_bytes" 80 | } 81 | -------------------------------------------------------------------------------- /examples/datasource-bulk-set-snmp.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Changing SNMP configs of multiple switch devices 4 | # 5 | # START Description 6 | # This script uses an input CSV (example: datasource-bulk-snmp.csv) to configure multiple vRealize Network Insight 7 | # Data Sources SNMP Values. Modify datasource-bulk-snmp.csv to contain your own data sources and run this script 8 | # with the param -DatasourcesCSV to your CSV. Based off Martijn Smit bulk data source import script. 9 | # END Description 10 | 11 | param ( 12 | [parameter(Mandatory = $true, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 13 | [ValidateNotNullOrEmpty()] 14 | [string]$DatasourcesCSV 15 | ) 16 | 17 | # Test CSV existance 18 | if (!(Test-Path $DatasourcesCSV)) { 19 | throw "[$(Get-Date)] CSV with data sources not found! ($DatasourcesCSV)" 20 | } 21 | 22 | if (!$defaultvRNIConnection) { 23 | throw "[$(Get-Date)] Please connect to vRealize Network Insight [Cloud] first! (Connect-vRNIServer or Connect-NIServer)" 24 | } 25 | 26 | # Put all datasources into a hash array first 27 | Write-Host "[$(Get-Date)] Getting a list of all data sources first.." 28 | $datasources = @{} 29 | $datasources_raw = Get-vRNIDataSource -DataSourceType ciscoswitch # If you want to speed this up, add i.e. -DatasourceType ciscoswitch for only Cisco switches. 30 | Write-Host "[$(Get-Date)] Found $($datasources_raw.Count) data sources!" -ForegroundColor "green" 31 | 32 | # Save the datasources in a hash, using the nickname as a key to identify it against the CSV 33 | foreach ($ds in $datasources_raw) { 34 | $datasources.Add($ds.nickname, $ds) 35 | } 36 | 37 | $updates_failed = @{} 38 | # Read the CSV into memory (using delimiter ';' so you can use Excel to modify it) 39 | $csvList = Import-CSV $DatasourcesCSV -Delimiter ';' 40 | $successfully_updated = 0 41 | Write-Host "[$(Get-Date)] The CSV has $($csvList.Count) data sources, starting to update those.." 42 | foreach ($csvLine in $csvList) { 43 | Write-Host "[$(Get-Date)] Setting SNMP for Data Source with Nickname of $($csvLine.Nickname).." 44 | 45 | if (!$datasources.ContainsKey($csvLine.Nickname)) { 46 | Write-Host "Datasource with nickname $($csvLine.Nickname) not found; skipping!" -ForegroundColor "red" 47 | continue 48 | } 49 | 50 | # TODO: SNMPv3 support 51 | # Run! 52 | try { 53 | $ds = $datasources.Item($csvLine.Nickname) 54 | $result = ($ds | Set-vRNIDataSourceSNMPConfig -Enabled $true -Community $csvLine.NewSnmpCommunity) 55 | $successfully_updated++ 56 | Write-Host "Done updating $($csvLine.Nickname)!" -ForegroundColor "green" 57 | } 58 | catch { 59 | Write-Host "Error updating $($csvLine.Nickname): $($_)" -ForegroundColor "red" 60 | $updates_failed.Add($csvLine.Nickname, $_) 61 | } 62 | } 63 | 64 | Write-Host "Sucessfully updated $($successfully_updated) data sources!" -ForegroundColor "green" 65 | if ($updates_failed.Count -gt 0) { 66 | Write-Host "Error updating these datasources:" -ForegroundColor "red" 67 | $updates_failed.Keys | % { Write-Host " - $($_) with error: $($updates_failed.Item($_))" -ForegroundColor "red" } 68 | } -------------------------------------------------------------------------------- /examples/datasource-bulk-import.csv: -------------------------------------------------------------------------------- 1 | DatasourceType;IP;Username;Password;Nickname;NSX_ENABLE_CENTRAL_CLI;NSX_ENABLE_IPFIX;NSX_VCENTER_NICKNAME;CISCO_SWITCHTYPE;DELL_SWITCHTYPE;SnmpCommunity 2 | vcenter;172.16.0.11;administrator@vsphere.local;MyPassword;vcenter.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;"" 3 | nsxv;172.16.0.11;admin;MyPassword;nsx.lab.local;TRUE;TRUE;vcenter.lab.local;onlyusedforCisco;onlyusedforDell;"" 4 | ciscoswitch;172.16.0.11;admin;MyPassword;cat3k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;CATALYST_3000;onlyusedforDell;public 5 | ciscoswitch;172.16.0.11;admin;MyPassword;cat45k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;CATALYST_4500;onlyusedforDell;public 6 | ciscoswitch;172.16.0.11;admin;MyPassword;cat65k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;CATALYST_6500;onlyusedforDell;public 7 | ciscoswitch;172.16.0.11;admin;MyPassword;n5k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;NEXUS_5K;onlyusedforDell;public 8 | ciscoswitch;172.16.0.11;admin;MyPassword;n7k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;NEXUS_7K;onlyusedforDell;public 9 | ciscoswitch;172.16.0.11;admin;MyPassword;n9k.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;NEXUS_9K;onlyusedforDell;public 10 | aristaswitch;172.16.0.11;admin;MyPassword;arista.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;public 11 | dellswitch;172.16.0.11;admin;MyPassword;dellf10mlx10.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;FORCE_10_MXL_10;public 12 | dellswitch;172.16.0.11;admin;MyPassword;dellp8024.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;POWERCONNECT_8024;public 13 | dellswitch;172.16.0.11;admin;MyPassword;dell54048.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;S4048;public 14 | dellswitch;172.16.0.11;admin;MyPassword;dell29100.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;Z9100;public 15 | dellswitch;172.16.0.11;admin;MyPassword;dell56000.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;S6000;public 16 | brocadeswitch;172.16.0.11;admin;MyPassword;brocade.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;public 17 | juniperswitch;172.16.0.11;admin;MyPassword;juniper.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;public 18 | ciscoucs;172.16.0.11;admin;MyPassword;ucs.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;public 19 | hponeview;172.16.0.11;admin;MyPassword;hponeview.prod.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell; 20 | hpvcmanager;172.16.0.11;admin;MyPassword;hpvc.lab.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;"" 21 | checkpointfirewall;172.16.0.11;admin;MyPassword;checkpoint.prod.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;"" 22 | panfirewall;172.16.0.11;admin;MyPassword;pan.prod.local;onlyusedforNSX;onlyusedforNSX;onlyusedforNSX;onlyusedforCisco;onlyusedforDell;"" -------------------------------------------------------------------------------- /examples/application-bulk-import.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Adding applications in bulk 4 | # 5 | # START Description 6 | # This script uses an input CSV (example: application-bulk-import.csv) to add multiple vRealize Network Insight 7 | # Applications. Modify application-bulk-import.csv to contain your applications and application tiers, along with 8 | # either the NSX Security Group or the VM names. Then run this script with the param -ApplicationsCSV to your CSV. 9 | # END Description 10 | # 11 | # Martijn Smit (@smitmartijn) 12 | # msmit@vmware.com 13 | # Version 1.0 14 | 15 | param ( 16 | [parameter(Mandatory = $true, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 17 | [ValidateNotNullOrEmpty()] 18 | [string]$ApplicationsCSV 19 | ) 20 | 21 | # Test CSV existance 22 | if (!(Test-Path $ApplicationsCSV)) { 23 | Write-Host "[$(Get-Date)] CSV with applications not found! ($ApplicationsCSV)" -ForegroundColor "red" 24 | Exit 25 | } 26 | 27 | # Cache for new application entity ids 28 | $new_apps = @{} 29 | 30 | # Read the CSV into memory (using delimiter ';' so you can use Excel to modify it) 31 | $csvList = Import-CSV $ApplicationsCSV -Delimiter ';' 32 | $csvLineNo = 0 33 | foreach ($csvLine in $csvList) { 34 | $csvLineNo += 1 35 | 36 | Write-Host "[$(Get-Date)] Processing application $($csvLine.Application).." -ForegroundColor "green" 37 | 38 | # First, see if the application exists (otherwise create it) 39 | if ($new_apps.ContainsKey($csvLine.Application)) { 40 | $application = $new_apps[$csvLine.Application] 41 | } 42 | else { 43 | $application = Get-vRNIApplication $csvLine.Application 44 | } 45 | 46 | if ($application -eq $null) { 47 | Write-Host "[$(Get-Date)] Application $($csvLine.Application) not found, so creating it.." -ForegroundColor "green" 48 | $application = New-vRNIApplication $csvLine.Application 49 | $new_apps.Add($csvLine.Application, $application) 50 | } 51 | 52 | # Format the filter 53 | $filters = @() 54 | 55 | # Is there a Security Group provided? If yes, get the entity id 56 | if ($csvLine."Security Group" -ne "") { 57 | $security_group_id = (Get-vRNISecurityGroup $csvLine."Security Group").entity_id 58 | if ($security_group_id -eq $null) { 59 | Write-Host "[$(Get-Date)] Wanted to use Security Group $($csvLine."Security Group"), but it doesn't exist - so skipping this rule!" -ForegroundColor "yellow" 60 | } 61 | else { 62 | $filters += "security_groups.entity_id = '$($security_group_id)'" 63 | } 64 | } 65 | 66 | # Are there VM Names provided? If yes, go through them and add them to the filter 67 | if ($csvLine."VM Names" -ne "") { 68 | $filter_vm = "" 69 | # Split VMs by comma and go through the list to add them to the filter string 70 | $vms = $csvLine."VM Names".Split(",") 71 | foreach ($vm in $vms) { 72 | $filter_vm += "name = '$($vm)' or " 73 | } 74 | # Remove last " or " 75 | $filter_vm = $filter_vm.Substring(0, $filter_vm.Length - 4) 76 | # Add it to the filter that will be passed to New-vRNIApplicationTier 77 | $filters += $filter_vm 78 | } 79 | 80 | # Make sure the filters aren't empty (non existing security group and no VM names provided), otherwise skip this tier 81 | if ($filters.Length -eq 0) { 82 | Write-Host "[$(Get-Date)] Skipping Tier '$($csvLine.Tier)' in application '$($csvLine.Application)' because filters are empty!" -ForegroundColor "red" 83 | Continue 84 | } 85 | 86 | # Add the tier! 87 | $tier = New-vRNIApplicationTier -Application $application -Name $csvLine.Tier -Filters $filters 88 | Write-Host "[$(Get-Date)] Added Tier '$($csvLine.Tier)' to application '$($csvLine.Application)' with filters: $($filters)" -ForegroundColor "green" 89 | 90 | # Sleep for a second, so we don't hit the API rate limiter 91 | Start-Sleep 1 92 | } 93 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## ChangeLog 2 | 3 | ### v6.5 - 2022-01-28 4 | 5 | @smitmartijn: 6 | 7 | - \[new] Match PowervRNI version to indicate support for vRNI versions 8 | - \[new] Support for NSXALB Data Source (NSX Advanced Load Balancer) 9 | - \[new] New message groups for the databus subscriber: flows, metrics, VMs, hosts, NICs, switchports 10 | - \[new] Get-vRNISDDCGroup 11 | - \[new] Get-vRNIVMCDirectConnect 12 | - \[new] Get-vRNIVMCDirectConnectInterface 13 | - \[new] Get-vRNISwitchPort 14 | - \[new] Get-vRNILogicalRouter 15 | - \[new] Get-vRNIVMwareTransitGateway 16 | - \[new] Get-vRNINSXTIPsecVPNSessions 17 | - \[new] Get-vRNISettingsLoginBanner 18 | - \[new] Set-vRNISettingsLoginBanner 19 | - \[new] Remove-vRNISettingsLoginBanner 20 | 21 | ### v2.0 - 2021-10-05 22 | 23 | @smitmartijn: 24 | 25 | - \[new] Connect-NIServer: Add support for vRNI Cloud locations by adding the -Location parameter 26 | - \[new] New-vRNIDataSource: Add support for Cisco ASR and ISR models (types: CISCOASRISR, CISCOASR1000, CISCOISR4000) 27 | - \[new] Get-vRNISDDC: New cmdlet to retrieve SDDC objects 28 | - \[new] Get-vRNIDatabusSubscriber: New cmdlet to retrieve all databus subscribers 29 | - \[new] New-vRNIDatabusSubscriber: New cmdlet to create a databus subscriber 30 | - \[new] Remove-vRNIDatabusSubscriber: New cmdlet to remove a databus subscriber 31 | 32 | ### v1.9 - 2021-07-09 33 | 34 | @smitmartijn: 35 | 36 | - \[new] Add cmdlet Update-vRNIDataSource to update data source details (credentials, nickname, notes) 37 | - \[new] Add cmdlet Invoke-vRNISearch to run search queries. Example: Invoke-vRNISearch -Query “VM where CPU Count > 2” 38 | - \[new] Add data source support for: AWS, Mellanox, Cisco ASR/XR, VMware HCX, HPE Switches 39 | - \[new] Add support for Custom polling intervals 40 | - \[new] Add support for Enabling IPFIX on vCenter VDS when adding 41 | - \[new] Add support for Platform Backup Management. New cmdlets: Get-vRNIBackup, Get-vRNIBackupStatus, Remove-vRNIBackup, Enable-vRNIBackup, Disable-vRNIBackup, Set-vRNIBackup 42 | - \[new] Add support for License Management. New cmdlets: Get-vRNILicensing, Test-vRNILicensing, Install-vRNILicensing, Remove-vRNILicensing 43 | 44 | ### v1.4 - 2018-10-13 45 | 46 | @smitmartijn: 47 | 48 | - \[new] Add cmdlet Get-vRNIRecommendedRulesNsxBundle to download a zip file with the recommended firewall rules which can be used by the Importer Tool to send the firewall rules to NSX 49 | - \[bug-fix] Fix a random connection issue to on-prem vRNI by fixing the on-prem vs SaaS detection 50 | 51 | ### v1.3 52 | 53 | @smitmartijn: 54 | 55 | - \[new] Add Connect-NIServer to connect to the Network Insight as a Service on the VMware Cloud Services. 56 | 57 | ### v1.2 58 | 59 | @smitmartijn: 60 | 61 | - \[new] Add Get-vRNIDataSourceSNMPConfig and Set-vRNIDataSourceSNMPConfig to retrieve and configure SNMP settings for certain data sources 62 | - \[fix] Fixed New-vRNIDataSource when using a Cisco or Dell switch type (it didn't add the required switch type API value) 63 | 64 | ### v1.1 65 | 66 | @smitmartijn: 67 | 68 | - \[new] Execute Get-vRNIAPIVersion when using Connect-vRNIServer and store API version for further use 69 | - \[new] Use the /entities/fetch endpoint when API v1.1.0 is available to significantly speed up entity results 70 | - \[new] Use the /groups/applications/fetch endpoint when API v1.1.0 is available to significantly speed up application results (5500% faster on 400 applications) 71 | - \[enhancement] Use the /search endpoint when looking for a single entity (not just VMs), speeding up the execution time 72 | - \[enhancement] Make sure Invoke-vRNIRestMethod takes a 100ms break before running to prevent API throttling (error 429) 73 | 74 | @awickham10: 75 | 76 | - \[enhancement] Use /search endpoint when looking for a single VM, speeding up the execution time 77 | 78 | @mtboren: 79 | - \[enhancement] Added a bit to some ErrorMessage output in `Invoke-vRNIRestMethod`, and updated to throw actual `ErrorRecord` object in catch situation (to enable deeper debugging by user) 80 | - \[bugfix] Updated remaining functions that take value from pipeline to handle multiple objects from pipeline (`Remove-vRNIApplication`, `New-vRNIApplicationTier`, `Remove-vRNIApplicationTier`, `Disable-vRNIDataSource`, `Enable-vRNIDataSource`, `Remove-vRNIDataSource`) 81 | 82 | -------------------------------------------------------------------------------- /publish/Include.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # This file is used by Publish.ps1 to generate the manifest and publish PowervRNI 3 | # to the PowerShell Gallery. 4 | # 5 | # Add any new cmdlets in this file, otherwise they won't get published in the module 6 | # 7 | 8 | # This is the version of PowervRNI. The publish script will also append ".build number", 9 | # put this in a "major.minor" format 10 | $PowervRNI_Version = "6.51" 11 | 12 | $FunctionsToExport = @( 13 | 'Connect-vRNIServer', 14 | 'Connect-NIServer', 15 | 'Disable-vRNIDataSource', 16 | 'Disconnect-vRNIServer', 17 | 'Enable-vRNIDataSource', 18 | 'Get-vRNIAPIVersion', 19 | 'Get-vRNIApplication', 20 | 'Get-vRNIApplicationTier', 21 | 'Get-vRNIDataSource', 22 | 'Get-vRNIDatastore', 23 | 'Get-vRNIDistributedSwitch', 24 | 'Get-vRNIDistributedSwitchPortGroup', 25 | 'Get-vRNIEntity', 26 | 'Get-vRNIEntityName', 27 | 'Get-vRNIFirewallRule', 28 | 'Get-vRNIFlow', 29 | 'Get-vRNIHost', 30 | 'Get-vRNIHostVMKNic', 31 | 'Get-vRNIIPSet', 32 | 'Get-vRNIL2Network', 33 | 'Get-vRNINodes', 34 | 'Get-vRNINSXManager', 35 | 'Get-vRNIProblem', 36 | 'Get-vRNIRecommendedRules', 37 | 'Get-vRNIRecommendedRulesNsxBundle', 38 | 'Get-vRNISecurityGroup', 39 | 'Get-vRNISecurityTag', 40 | 'Get-vRNIService', 41 | 'Get-vRNIServiceGroup', 42 | 'Get-vRNIvCenter', 43 | 'Get-vRNIvCenterCluster', 44 | 'Get-vRNIvCenterDatacenter', 45 | 'Get-vRNIvCenterFolder', 46 | 'Get-vRNIVM', 47 | 'Get-vRNIVMvNIC', 48 | 'Get-vRNIDataSourceSNMPConfig', 49 | 'Get-vRNISDDC', 50 | 'Invoke-vRNIRestMethod', 51 | 'New-vRNIApplication', 52 | 'New-vRNIApplicationTier', 53 | 'New-vRNIDataSource', 54 | 'Remove-vRNIApplication', 55 | 'Remove-vRNIApplicationTier', 56 | 'Remove-vRNIDataSource', 57 | 'Set-vRNIDataSourceSNMPConfig', 58 | 'New-vRNISubnetMapping', 59 | 'Get-vRNISubnetMapping', 60 | 'Get-vRNIEastWestIP', 61 | 'Add-vRNIEastWestIP', 62 | 'Remove-vRNIEastWestIP', 63 | 'Get-vRNINorthSouthIP', 64 | 'Add-vRNINorthSouthIP', 65 | 'Remove-vRNINorthSouthIP', 66 | 'Get-vRNISettingsVIDM', 67 | 'Set-vRNISettingsVIDM', 68 | 'Get-vRNISettingsUserGroup', 69 | 'Set-vRNISettingsUserGroup', 70 | 'Remove-vRNISettingsUserGroup', 71 | 'Get-vRNISettingsUser', 72 | 'Set-vRNISettingsUser', 73 | 'Remove-vRNISettingsUser', 74 | 'Get-vRNIAuditLogs', 75 | 'Get-vRNIApplicationMemberVM', 76 | 'Set-vRNIUserPassword', 77 | 'Get-vRNIKubernetesServices', 78 | 'Update-vRNIDataSourceData', 79 | 'Update-vRNINSXvControllerClusterPassword', 80 | 'Get-vRNIEntityNames', 81 | 'Invoke-vRNISearch', 82 | 'Get-vRNILicensing', 83 | 'Test-vRNILicensing', 84 | 'Install-vRNILicensing', 85 | 'Remove-vRNILicensing', 86 | 'Get-vRNIBackup', 87 | 'Get-vRNIBackupStatus', 88 | 'Remove-vRNIBackup', 89 | 'Enable-vRNIBackup', 90 | 'Disable-vRNIBackup', 91 | 'Set-vRNIBackup', 92 | 'Get-vRNIDatabusSubscriber', 93 | 'New-vRNIDatabusSubscriber', 94 | 'Remove-vRNIDatabusSubscriber', 95 | 'Get-vRNISDDCGroup', 96 | 'Get-vRNIVMCDirectConnect', 97 | 'Get-vRNIVMCDirectConnectInterface', 98 | 'Get-vRNISwitchPort', 99 | 'Get-vRNILogicalRouter', 100 | 'Get-vRNIVMwareTransitGateway', 101 | 'Get-vRNINSXTIPsecVPNSessions', 102 | 'Get-vRNISettingsLoginBanner', 103 | 'Set-vRNISettingsLoginBanner', 104 | 'Remove-vRNISettingsLoginBanner' 105 | ) 106 | 107 | # Manifest settings 108 | $Manifest_Common = @{ 109 | RootModule = 'PowervRNI.psm1' 110 | GUID = 'a34be6be-3dc1-457a-aea3-d4263481ed79' 111 | Author = 'Martijn Smit' 112 | CompanyName = 'VMware' 113 | Copyright = 'Copyright 2022 VMware. All rights reserved.' 114 | Description = 'A PowerShell module to talk to the vRealize Network Insight API' 115 | DotNetFrameworkVersion = '4.0' 116 | FunctionsToExport = $FunctionsToExport 117 | CmdletsToExport = '*' 118 | VariablesToExport = '*' 119 | AliasesToExport = '*' 120 | LicenseUri = 'https://github.com/PowervRNI/powervrni/blob/master/LICENSE.md' 121 | ProjectUri = 'https://github.com/PowervRNI/powervrni' 122 | ReleaseNotes = '### v6.5.1 - 2022-03-07 123 | - \[fixed] Change the application page size to 100 to fix seeing an error about a hard limit in vRNI 6.5.1' 124 | } 125 | -------------------------------------------------------------------------------- /examples/cmdb-import-from-itop.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Import Applications from iTop 4 | # 5 | # START Description 6 | # Retrieves applications from the CMDB iTop, and imports them into vRNI. 7 | # END Description 8 | # 9 | # Martijn Smit (@smitmartijn) 10 | # msmit@vmware.com 11 | # Version 1.0 12 | 13 | $CONFIG_URL = "http://itop.lab/webservices/rest.php?version=1.3" 14 | $CONFIG_USER = "api" 15 | $CONFIG_PASS = "VMware1!" 16 | $CONFIG_VRNI_HOST = "network-insight.platform.lab" 17 | $CONFIG_VRNI_USER = "admin@local" 18 | $CONFIG_VRNI_PASS = "VMware1!" 19 | 20 | $vrni_connection = Connect-vRNIServer -Server $CONFIG_VRNI_HOST -User $CONFIG_VRNI_USER -Password ($CONFIG_VRNI_PASS | ConvertTo-SecureString -AsPlainText -Force) 21 | Write-Host -ForegroundColor 'Green' "Connected to Network Insight with PowervRNI!" 22 | Write-Host "Connecting to CMDB to get a list of applications..." 23 | 24 | # Select all applications from the iTop API 25 | $app_request_json = @{ 26 | 'operation' = 'core/get' ; 27 | 'class' = 'ApplicationSolution' ; 28 | 'key' = "SELECT ApplicationSolution" ; 29 | 'output_fields' = '*' 30 | } | ConvertTo-Json 31 | 32 | # Format the POST payload 33 | $postParams = @{ 34 | auth_user = $CONFIG_USER; 35 | auth_pwd = $CONFIG_PASS; 36 | json_data = $app_request_json; 37 | } 38 | 39 | # Execute web request and translate the incoming result to a PowerShell object 40 | $res = Invoke-WebRequest -Uri $CONFIG_URL -Method POST -Body $postParams -UseBasicParsing 41 | # The actual content is hidden is key 'Content' (surprise!) 42 | $json = ConvertFrom-Json $res.Content 43 | 44 | # Go through all applications 45 | foreach ($info in $json.objects.PSObject.Properties) { 46 | $appName = $info.Value.fields.name 47 | Write-Host -ForegroundColor 'Magenta' "Found Application: $($appName)" 48 | $fields = $info.Value 49 | 50 | # First, see if the application exists (otherwise create it) 51 | $application = Get-vRNIApplication -Name $appName -Connection $vrni_connection 52 | 53 | # Application doesn't exist in vRNI, create it 54 | if ($null -eq $application) { 55 | Write-Host "Application $($appName) not found in Network Insight, so creating it.." -ForegroundColor "Yellow" 56 | $application = New-vRNIApplication -Name $appName 57 | Write-Host "Application $($appName) created!" -ForegroundColor "Green" 58 | } 59 | 60 | # Array for holding the tier/VM combo 61 | $appTiers = @{} 62 | 63 | Write-Host "Looking for VMs attached to this application..." 64 | # This is only going to supply us with the VM name and ID 65 | foreach ($field in $info.Value.fields.functionalcis_list) { 66 | Write-Host -ForegroundColor 'Magenta' "Found a VM attached to $($appName): " 67 | #Write-Host "VM: $($field.functionalci_name)" 68 | 69 | # ..so we need to request more details around this VM. 70 | $vm_request_json = @{ 71 | 'operation' = 'core/get' ; 72 | 'class' = 'VirtualMachine' ; 73 | 'key' = "SELECT VirtualMachine WHERE id = $($field.functionalci_id)" ; 74 | 'output_fields' = '*' 75 | } | ConvertTo-Json 76 | 77 | $postParams = @{ 78 | auth_user = $CONFIG_USER; 79 | auth_pwd = $CONFIG_PASS; 80 | json_data = $vm_request_json 81 | } 82 | # Execute the VM info request and translate the output to 83 | $res = Invoke-WebRequest -Uri $CONFIG_URL -Method POST -Body $postParams -UseBasicParsing 84 | 85 | $json = ConvertFrom-Json $res.Content 86 | foreach ($info in $json.objects.PSObject.Properties) { 87 | $fields = $info.Value 88 | $tier = $($fields.fields.description) 89 | 90 | if ($null -eq $appTiers.$tier) { 91 | $appTiers.$tier = @() 92 | } 93 | $appTiers.$tier += $fields.fields.name 94 | Write-Host "VM: $($fields.fields.name) - Tier: $($tier)" 95 | #Write-Host "OS: $($fields.fields.osfamily_name) - $($fields.fields.osversion_name)" 96 | #Write-Host "IP Address: $($fields.fields.managementip)" 97 | } 98 | } 99 | 100 | Write-Host "Adding tiers and VMs to Network Insight.." 101 | 102 | foreach ($tier in $appTiers.Keys) { 103 | $filters = @() 104 | $filter_vm = "" 105 | foreach ($vm in $appTiers.$tier) { 106 | $filter_vm += "name = '$($vm)' or " 107 | } 108 | $filter_vm = $filter_vm.Substring(0, $filter_vm.Length - 4) 109 | $filters += $filter_vm 110 | 111 | $vrni_tier = New-vRNIApplicationTier -Application $application -Name $tier -Filters $filters 112 | Write-Host "Added Tier '$($tier)' to application '$($appname)' to Network Insight!" -ForegroundColor "green" 113 | 114 | } 115 | } 116 | 117 | Write-Host "All done." 118 | -------------------------------------------------------------------------------- /examples/archive-flows-to-vrli/vrealize-log-insight.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | function Send-vRLIMessage 4 | { 5 | <# 6 | .SYNOPSIS 7 | Sends a message to vRealize Log Insight over the CFAPI. Allows usage of fields (tags). 8 | 9 | .EXAMPLE 10 | PS C:\> Send-vRLIMessage -Server vrli.lab.local -Message "testing powershell function!" 11 | 12 | Sends a plain message 13 | 14 | .EXAMPLE 15 | PS C:\> Send-vRLIMessage -Server vrli.lab.local -Message "testing powershell function!" -Fields @{ tag1 = "value1"; tag2 = "value2"; } 16 | 17 | Sends a message, including fields/tags and their values 18 | #> 19 | 20 | param ( 21 | # Destination vRLI server that message is to be sent to. 22 | [Parameter(Mandatory = $true)] 23 | [ValidateNotNullOrEmpty()] 24 | [String] 25 | $Server, 26 | # Destination vRLI server port that message is to be sent to. Defaults to 9543 27 | [Parameter(Mandatory = $false)] 28 | [ValidateNotNullOrEmpty()] 29 | [Int] 30 | $Port = 9543, 31 | # Log/event message 32 | [Parameter(Mandatory = $true)] 33 | [ValidateNotNullOrEmpty()] 34 | [String] 35 | $Message, 36 | # Timestamp of the message. Defaults to current time. 37 | [Parameter(Mandatory = $false)] 38 | [ValidateNotNullOrEmpty()] 39 | [Int] 40 | $Timestamp = [DateTimeOffset]::Now.ToUnixTimeSeconds(), 41 | # Log/event message 42 | [Parameter(Mandatory = $false)] 43 | [ValidateNotNullOrEmpty()] 44 | [hashtable] 45 | $Fields = @{} 46 | ) 47 | 48 | 49 | # Build the vRLI URL 50 | $URL = "https://$($Server):$($Port)/api/v1/events/ingest/0" 51 | 52 | # Build the event message that will be passed to vRLI 53 | $event = @{ 54 | text = $Message 55 | timestamp = $Timestamp 56 | } 57 | 58 | # Iterate through the provides fields, if any are given 59 | if($Fields) 60 | { 61 | $event.fields = @() 62 | foreach($field_name in $Fields.keys) 63 | { 64 | # Build a temporary array that can be added to the fields value. 65 | $field_tmp = @{ 66 | name = $field_name 67 | content = $Fields[$field_name] 68 | } 69 | $event.fields += $field_tmp 70 | } 71 | } 72 | 73 | # Build the request body. The API call supports multiple messages/events at the same time, that's why it's a list. 74 | $requestBody = @{ 75 | events = @( $event ) 76 | } 77 | $jsonBody = $requestBody | ConvertTo-Json -Depth 4 78 | 79 | Write-Debug "$(Get-Date -format s) Sent JSON: $($jsonBody)" 80 | 81 | # Energize! 82 | try 83 | { 84 | $response = Invoke-RestMethod $URL -Method POST -Body $jsonBody -ContentType 'application/json' 85 | } 86 | # If its a webexception, we may have got a response from the server with more information... 87 | # Even if this happens on PoSH Core though, the ex is not a webexception and we cant get this info :( 88 | catch [System.Net.WebException] { 89 | #Check if there is a response populated in the response prop as we can return better detail. 90 | $response = $_.exception.response 91 | if ( $response ) { 92 | $responseStream = $response.GetResponseStream() 93 | $reader = New-Object system.io.streamreader($responseStream) 94 | $responseBody = $reader.readtoend() 95 | ## include ErrorDetails content in case therein lies juicy info 96 | $ErrorString = "$($MyInvocation.MyCommand.Name) : The API response received indicates a failure. $($response.StatusCode.value__) : $($response.StatusDescription) : Response Body: $($responseBody)`nErrorDetails: '$($_.ErrorDetails)'" 97 | 98 | # Log the error with response detail. 99 | Write-Warning -Message $ErrorString 100 | ## throw the actual error, so that the consumer can debug via the actuall ErrorRecord 101 | Throw $_ 102 | } 103 | else 104 | { 105 | # No response, log and throw the underlying ex 106 | $ErrorString = "$($MyInvocation.MyCommand.Name) : Exception occured calling invoke-restmethod. $($_.exception.tostring())" 107 | Write-Warning -Message $_.exception.tostring() 108 | ## throw the actual error, so that the consumer can debug via the actuall ErrorRecord 109 | Throw $_ 110 | } 111 | } 112 | catch { 113 | # Not a webexception (may be on PoSH core), log and throw the underlying ex string 114 | $ErrorString = "$($MyInvocation.MyCommand.Name) : Exception occured calling invoke-restmethod. $($_.exception.tostring())" 115 | Write-Warning -Message $ErrorString 116 | ## throw the actual error, so that the consumer can debug via the actuall ErrorRecord 117 | Throw $_ 118 | } 119 | 120 | Write-Debug "$(Get-Date -format s) Invoke-RestMethod Result: $response" 121 | 122 | # Return result 123 | if($response) { $response } 124 | } 125 | -------------------------------------------------------------------------------- /examples/datasource-bulk-import.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Adding datasources in bulk 4 | # 5 | # START Description 6 | # This script uses an input CSV (example: datasource-bulk-import.csv) to add multiple vRealize Network Insight 7 | # Data Sources. Modify datasource-bulk-import.csv to contain your own data sources (vCenters, NSX, switches, firewalls) 8 | # and run this script with the param -DatasourcesCSV to your CSV. 9 | # END Description 10 | # 11 | # More info: https://lostdomain.org/2018/11/19/integrating-servicenow-with-network-insight/ 12 | # 13 | # Martijn Smit (@smitmartijn) 14 | # msmit@vmware.com 15 | # Version 1.0 16 | 17 | 18 | param ( 19 | [parameter(Mandatory = $true, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 20 | [ValidateNotNullOrEmpty()] 21 | [string]$DatasourcesCSV 22 | ) 23 | 24 | # Test CSV existance 25 | if (!(Test-Path $DatasourcesCSV)) { 26 | Write-Host "[$(Get-Date)] CSV with data sources not found! ($DatasourcesCSV)" -ForegroundColor "red" 27 | Exit 28 | } 29 | 30 | # Look up collector ID. This assumes you only have 1 collector in play 31 | $collectorId = (Get-vRNINodes | Where { $_.node_type -eq "PROXY_VM" } | Select -ExpandProperty id) 32 | 33 | # Read the CSV into memory (using delimiter ';' so you can use Excel to modify it) 34 | $csvList = Import-CSV $DatasourcesCSV -Delimiter ';' 35 | $csvLineNo = 0 36 | foreach ($csvLine in $csvList) { 37 | $csvLineNo += 1 38 | 39 | Write-Host "[$(Get-Date)] Adding a $($csvLine.DatasourceType) Data Source with IP $($csvLine.IP).." -ForegroundColor "green" 40 | 41 | # Build up the params we're going to give to New-vRNIDataSource 42 | $cmdParams = @{ 43 | "DataSourceType" = $csvLine.DatasourceType; 44 | "Username" = $csvLine.Username; 45 | "Password" = ($csvLine.Password | ConvertTo-SecureString -AsPlainText -Force); 46 | "IP" = $csvLine.IP; 47 | "Nickname" = $csvLine.Nickname; 48 | "CollectorVMId" = $collectorId; 49 | } 50 | 51 | # sort out NSX-V specific parameters 52 | if ($csvLine.DatasourceType -eq "nsxv") { 53 | if ($csvLine.NSX_ENABLE_CENTRAL_CLI -eq "TRUE") { 54 | $cmdParams.Add("NSXEnableCentralCLI", $True) 55 | } 56 | else { 57 | $cmdParams.Add("NSXEnableCentralCLI", $False) 58 | } 59 | if ($csvLine.NSX_ENABLE_IPFIX -eq "TRUE") { 60 | $cmdParams.Add("NSXEnableIPFIX", $True) 61 | } 62 | else { 63 | $cmdParams.Add("NSXEnableIPFIX", $False) 64 | } 65 | 66 | # Retrieve the vCenter Entity ID by doing a lookup with it's nickname 67 | $vcId = (Get-vRNIDataSource | Where { $_.nickname -eq $csvLine.NSX_VCENTER_NICKNAME } | Select -ExpandProperty entity_id) 68 | $cmdParams.Add("NSXvCenterID", $vcId) 69 | } 70 | 71 | # add a -CiscoSwitchType param when the datasource type is a cisco switch 72 | if ($csvLine.DatasourceType -eq "ciscoswitch") { 73 | # Sanity check on the input 74 | if (($csvLine.CISCO_SWITCHTYPE -eq "CATALYST_3000") -Or 75 | ($csvLine.CISCO_SWITCHTYPE -eq "CATALYST_4500") -Or 76 | ($csvLine.CISCO_SWITCHTYPE -eq "CATALYST_6500") -Or 77 | ($csvLine.CISCO_SWITCHTYPE -eq "NEXUS_5K") -Or 78 | ($csvLine.CISCO_SWITCHTYPE -eq "NEXUS_7K") -Or 79 | ($csvLine.CISCO_SWITCHTYPE -eq "NEXUS_9K")) { 80 | $cmdParams.Add("CiscoSwitchType", $csvLine.CISCO_SWITCHTYPE) 81 | } 82 | else { 83 | Write-Host "[$(Get-Date)] Invalid CISCO_SWITCHTYPE ($($csvLine.CISCO_SWITCHTYPE)) given on line $($csvLineNo), skipping.." -ForegroundColor "yellow" 84 | } 85 | } 86 | 87 | # add a -DellSwitchType param when the datasource type is a dell switch 88 | if ($csvLine.DatasourceType -eq "dellswitch") { 89 | # Sanity check on the input 90 | if (($csvLine.DELL_SWITCHTYPE -eq "FORCE_10_MXL_10") -Or 91 | ($csvLine.DELL_SWITCHTYPE -eq "POWERCONNECT_8024") -Or 92 | ($csvLine.DELL_SWITCHTYPE -eq "S4048") -Or 93 | ($csvLine.DELL_SWITCHTYPE -eq "Z9100") -Or 94 | ($csvLine.DELL_SWITCHTYPE -eq "S6000")) { 95 | $cmdParams.Add("DellSwitchType", $csvLine.DELL_SWITCHTYPE) 96 | } 97 | else { 98 | Write-Host "[$(Get-Date)] Invalid DELL_SWITCHTYPE ($($csvLine.DELL_SWITCHTYPE)) given on line $($csvLineNo), skipping.." -ForegroundColor "yellow" 99 | } 100 | } 101 | 102 | # Execute! 103 | try { 104 | $newDs = New-vRNIDataSource @cmdParams 105 | } 106 | catch { 107 | # If 1 data source addition fails because the data source itself times out or is unavailable, make a note and move on to the next data source 108 | Write-Host "[$(Get-Date)] Unable to add data source with parameters:" -ForegroundColor "red" 109 | $cmdParams 110 | Write-Host "[$(Get-Date)] Exception:" -ForegroundColor "red" 111 | $_.Exception 112 | # Don't even bother with SNMP, continue to the next data source 113 | continue 114 | } 115 | 116 | 117 | # Set SNMP community after adding - just SNMP v2c support right now 118 | if ($csvLine.SnmpCommunity -ne "" -And ($csvLine.DataSourceType -eq "ciscoswitch" -Or $csvLine.DataSourceType -eq "aristaswitch" -Or $csvLine.DataSourceType -eq "dellos10switch" -Or $csvLine.DataSourceType -eq "ciscoucs")) { 119 | try { 120 | ($newDs | Set-vRNIDataSourceSNMPConfig -Enabled $true -Community $csvLine.SnmpCommunity | Out-Null) 121 | } 122 | catch { 123 | Write-Host "Unable to add snmp config to:" 124 | $newDs 125 | Write-Host "Exception:" 126 | $_.Exception 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowervRNI 2 | 3 | *A PowerShell module for vRealize Network Insight* 4 | 5 | Starting vRealize Network Insight (vRNI) 3.6, the platform has a public API. PowervRNI is a PowerShell module that takes advantage of those public APIs and provides you with the option to look at vRNI data using PowerShell. 6 | 7 | 8 | This module is _not supported_ by VMware, and comes with no warranties express or implied. Please test and validate its functionality before using this product in a production environment. 9 | 10 | ## Installing PowervRNI 11 | 12 | 13 | There are 2 ways of installing PowervRNI. An easy one through PowerShell Gallery where everything is taken care of for you, or a slightly harder one where you download the module and load it up manually. 14 | 15 | ### PowerShell Gallery 16 | 17 | ``` 18 | PS C:\> Install-Module PowervRNI 19 | PS C:\> Import-Module PowervRNI 20 | ``` 21 | 22 | That's it, you're off the the races. 23 | 24 | ### Manual Download 25 | 26 | Right now, PowervRNI is a simple two-file module. To install it, download it to a PowerShell enabled machine and load it. PowervRNI is supported for PowerShell Desktop & Core, so Windows, MacOS and Linux. Here is an example on how to load it: 27 | 28 | ``` 29 | PS C:\> Invoke-WebRequest -Uri "https://raw.githubusercontent.com/powervrni/powervrni/master/PowervRNI.psm1" -OutFile "PowervRNI.psm1" 30 | PS C:\> Invoke-WebRequest -Uri "https://raw.githubusercontent.com/powervrni/powervrni/master/PowervRNI.psd1" -OutFile "PowervRNI.psd1" 31 | PS C:\> Import-Module .\PowervRNI.psd1 32 | ``` 33 | 34 | ## Usage 35 | 36 | A more elaborate usage guide will follow, but here's a quick example on how to get started. 37 | 38 | ### Connecting to the vRNI Platform VM 39 | 40 | The API of vRNI requires you to login to the Platform VM first. Here's how: 41 | 42 | ``` 43 | PS C:\> $creds = Get-Credential 44 | PS C:\> Connect-vRNIServer -Server vrni-platform.lab -Credential $creds 45 | ``` 46 | 47 | or, if you'd like the system to ask you for your credentials 48 | 49 | ``` 50 | PS C:\> Connect-vRNIServer -Server vrni-platform.lab 51 | ``` 52 | 53 | ### Connecting to vRNI Cloud 54 | 55 | If you're using vRNI Cloud, use `Connect-NIServer` to authenticate. First, generate a [CSP Refresh Token](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-E2A3B1C1-E9AD-4B00-A6B6-88D31FCDDF7C.html). 56 | 57 | ``` 58 | PS C:\> Connect-NIServer -RefreshToken xxx-xxx-xxx-xxx -Location UK 59 | ``` 60 | 61 | Use the `-Location` parameter to indicate where the vRNI Cloud service is hosted. A list of regions can be found using `Get-Help Connect-NIServer -Examples` 62 | 63 | ### Getting Started 64 | 65 | After logging in and starting a session, you can start doing information calls to vRNI. To see what kind of cmdlets PowervRNI offers and what information you can get out of vRNI with it, use the following command: 66 | 67 | ``` 68 | PS C:\> Get-Command -Module PowervRNI ``` 69 | ``` 70 | 71 | You'll see that there are a bunch of cmdlets you can use. To give you an example of what kind of output PowervRNI produces, here's an example from my lab: 72 | 73 | ``` 74 | PS C:\> Get-vRNIHost 75 | 76 | entity_id : 14207:4:204319385 77 | name : esxi03.lab 78 | entity_type : Host 79 | vmknics : {@{entity_id=14307:17:1822450329; entity_type=Vmknic}, @{entity_id=14307:17:1827250360; entity_type=Vmknic}, @{entity_id=14307:17:1827250298; entity_type=Vmknic}} 80 | cluster : @{entity_id=14307:66:1217795335; entity_type=Cluster} 81 | vcenter_manager : @{entity_id=14307:8:5696601749271539863; entity_type=VCenterManager} 82 | vm_count : 20 83 | datastores : {@{entity_id=14307:80:1083140774; entity_type=Datastore}, @{entity_id=14307:80:1082389334; entity_type=Datastore}, @{entity_id=14307:80:1860142552; entity_type=Datastore}} 84 | service_tag : 85 | vendor_id : host-2921 86 | nsx_manager : @{entity_id=14307:7:1483719682; entity_type=NSXVManager} 87 | maintenance_mode : NOTINMAINTENANCEMODE 88 | connection_state : CONNECTED 89 | 90 | entity_id : 14307:4:1142332887 91 | ``` 92 | 93 | More examples are available in the examples/ directory and [here](https://lostdomain.org/tag/powervrni/) 94 | 95 | 96 | ## Contact 97 | 98 | Currently, [@smitmartijn](https://twitter.com/smitmartijn) started this project and will keep maintaining it. Reach out to me via twitter or the [Issues Page](https://github.com/powervrni/powervrni/issues) here on GitHub. If you want to contribute, also get in touch with me. 99 | 100 | 101 | ## Is PowervRNI supported by VMware? 102 | 103 | No. This is an opensource project started by [@smitmartijn](https://twitter.com/smitmartijn) and not supported by VMware. Please test and validate its functionality before using in a production environment. 104 | 105 | 106 | ## License 107 | 108 | PowervRNI is licensed under GPL v2. 109 | 110 | This program is free software: you can redistribute it and/or modify it under 111 | the terms of the GNU General Public License version 2, as published by the Free Software Foundation. 112 | 113 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 114 | WARRANTY; without even the implied warranty of MERCHANTIBILITY or FITNESS 115 | FOR A PARTICULAR PURPOSE. See the GNU General Public License version 2 for more details. 116 | 117 | You should have received a copy of the General Public License version 2 along with this program. 118 | If not, see https://www.gnu.org/licenses/gpl-2.0.html. 119 | 120 | The full text of the General Public License 2.0 is provided in the COPYING file. 121 | Some files may be comprised of various open source software components, each of which 122 | has its own license that is located in the source code of the respective component. -------------------------------------------------------------------------------- /PowervRNI.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PowervRNI' 3 | # 4 | # Generated by: Martijn Smit 5 | # 6 | # Generated on: 3/7/2022 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PowervRNI.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '6.51.185' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'a34be6be-3dc1-457a-aea3-d4263481ed79' 22 | 23 | # Author of this module 24 | Author = 'Martijn Smit' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'VMware' 28 | 29 | # Copyright statement for this module 30 | Copyright = 'Copyright 2022 VMware. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'A PowerShell module to talk to the vRealize Network Insight API' 34 | 35 | # Minimum version of the PowerShell engine required by this module 36 | PowerShellVersion = '6.0' 37 | 38 | # Name of the PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | DotNetFrameworkVersion = '4.0' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # ClrVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = 'Connect-vRNIServer', 'Connect-NIServer', 'Disable-vRNIDataSource', 73 | 'Disconnect-vRNIServer', 'Enable-vRNIDataSource', 74 | 'Get-vRNIAPIVersion', 'Get-vRNIApplication', 75 | 'Get-vRNIApplicationTier', 'Get-vRNIDataSource', 'Get-vRNIDatastore', 76 | 'Get-vRNIDistributedSwitch', 'Get-vRNIDistributedSwitchPortGroup', 77 | 'Get-vRNIEntity', 'Get-vRNIEntityName', 'Get-vRNIFirewallRule', 78 | 'Get-vRNIFlow', 'Get-vRNIHost', 'Get-vRNIHostVMKNic', 'Get-vRNIIPSet', 79 | 'Get-vRNIL2Network', 'Get-vRNINodes', 'Get-vRNINSXManager', 80 | 'Get-vRNIProblem', 'Get-vRNIRecommendedRules', 81 | 'Get-vRNIRecommendedRulesNsxBundle', 'Get-vRNISecurityGroup', 82 | 'Get-vRNISecurityTag', 'Get-vRNIService', 'Get-vRNIServiceGroup', 83 | 'Get-vRNIvCenter', 'Get-vRNIvCenterCluster', 84 | 'Get-vRNIvCenterDatacenter', 'Get-vRNIvCenterFolder', 'Get-vRNIVM', 85 | 'Get-vRNIVMvNIC', 'Get-vRNIDataSourceSNMPConfig', 'Get-vRNISDDC', 86 | 'Invoke-vRNIRestMethod', 'New-vRNIApplication', 87 | 'New-vRNIApplicationTier', 'New-vRNIDataSource', 88 | 'Remove-vRNIApplication', 'Remove-vRNIApplicationTier', 89 | 'Remove-vRNIDataSource', 'Set-vRNIDataSourceSNMPConfig', 90 | 'New-vRNISubnetMapping', 'Get-vRNISubnetMapping', 91 | 'Get-vRNIEastWestIP', 'Add-vRNIEastWestIP', 'Remove-vRNIEastWestIP', 92 | 'Get-vRNINorthSouthIP', 'Add-vRNINorthSouthIP', 93 | 'Remove-vRNINorthSouthIP', 'Get-vRNISettingsVIDM', 94 | 'Set-vRNISettingsVIDM', 'Get-vRNISettingsUserGroup', 95 | 'Set-vRNISettingsUserGroup', 'Remove-vRNISettingsUserGroup', 96 | 'Get-vRNISettingsUser', 'Set-vRNISettingsUser', 97 | 'Remove-vRNISettingsUser', 'Get-vRNIAuditLogs', 98 | 'Get-vRNIApplicationMemberVM', 'Set-vRNIUserPassword', 99 | 'Get-vRNIKubernetesServices', 'Update-vRNIDataSourceData', 100 | 'Update-vRNINSXvControllerClusterPassword', 'Get-vRNIEntityNames', 101 | 'Invoke-vRNISearch', 'Get-vRNILicensing', 'Test-vRNILicensing', 102 | 'Install-vRNILicensing', 'Remove-vRNILicensing', 'Get-vRNIBackup', 103 | 'Get-vRNIBackupStatus', 'Remove-vRNIBackup', 'Enable-vRNIBackup', 104 | 'Disable-vRNIBackup', 'Set-vRNIBackup', 'Get-vRNIDatabusSubscriber', 105 | 'New-vRNIDatabusSubscriber', 'Remove-vRNIDatabusSubscriber', 106 | 'Get-vRNISDDCGroup', 'Get-vRNIVMCDirectConnect', 107 | 'Get-vRNIVMCDirectConnectInterface', 'Get-vRNISwitchPort', 108 | 'Get-vRNILogicalRouter', 'Get-vRNIVMwareTransitGateway', 109 | 'Get-vRNINSXTIPsecVPNSessions', 'Get-vRNISettingsLoginBanner', 110 | 'Set-vRNISettingsLoginBanner', 'Remove-vRNISettingsLoginBanner' 111 | 112 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 113 | CmdletsToExport = '*' 114 | 115 | # Variables to export from this module 116 | VariablesToExport = '*' 117 | 118 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 119 | AliasesToExport = '*' 120 | 121 | # DSC resources to export from this module 122 | # DscResourcesToExport = @() 123 | 124 | # List of all modules packaged with this module 125 | # ModuleList = @() 126 | 127 | # List of all files packaged with this module 128 | # FileList = @() 129 | 130 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 131 | PrivateData = @{ 132 | 133 | PSData = @{ 134 | 135 | # Tags applied to this module. These help with module discovery in online galleries. 136 | # Tags = @() 137 | 138 | # A URL to the license for this module. 139 | LicenseUri = 'https://github.com/PowervRNI/powervrni/blob/master/LICENSE.md' 140 | 141 | # A URL to the main website for this project. 142 | ProjectUri = 'https://github.com/PowervRNI/powervrni' 143 | 144 | # A URL to an icon representing this module. 145 | # IconUri = '' 146 | 147 | # ReleaseNotes of this module 148 | ReleaseNotes = '### v6.5.1 - 2022-03-07 149 | - \[fixed] Change the application page size to 100 to fix seeing an error about a hard limit in vRNI 6.5.1' 150 | 151 | # Prerelease string of this module 152 | # Prerelease = '' 153 | 154 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 155 | # RequireLicenseAcceptance = $false 156 | 157 | # External dependent modules of this module 158 | # ExternalModuleDependencies = @() 159 | 160 | } # End of PSData hashtable 161 | 162 | } # End of PrivateData hashtable 163 | 164 | # HelpInfo URI of this module 165 | # HelpInfoURI = '' 166 | 167 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 168 | # DefaultCommandPrefix = '' 169 | 170 | } 171 | 172 | -------------------------------------------------------------------------------- /publish/psgallery/PowervRNI/PowervRNI.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PowervRNI' 3 | # 4 | # Generated by: Martijn Smit 5 | # 6 | # Generated on: 3/7/2022 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PowervRNI.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '6.51.185' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'a34be6be-3dc1-457a-aea3-d4263481ed79' 22 | 23 | # Author of this module 24 | Author = 'Martijn Smit' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'VMware' 28 | 29 | # Copyright statement for this module 30 | Copyright = 'Copyright 2022 VMware. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'A PowerShell module to talk to the vRealize Network Insight API' 34 | 35 | # Minimum version of the PowerShell engine required by this module 36 | PowerShellVersion = '6.0' 37 | 38 | # Name of the PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | DotNetFrameworkVersion = '4.0' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # ClrVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = 'Connect-vRNIServer', 'Connect-NIServer', 'Disable-vRNIDataSource', 73 | 'Disconnect-vRNIServer', 'Enable-vRNIDataSource', 74 | 'Get-vRNIAPIVersion', 'Get-vRNIApplication', 75 | 'Get-vRNIApplicationTier', 'Get-vRNIDataSource', 'Get-vRNIDatastore', 76 | 'Get-vRNIDistributedSwitch', 'Get-vRNIDistributedSwitchPortGroup', 77 | 'Get-vRNIEntity', 'Get-vRNIEntityName', 'Get-vRNIFirewallRule', 78 | 'Get-vRNIFlow', 'Get-vRNIHost', 'Get-vRNIHostVMKNic', 'Get-vRNIIPSet', 79 | 'Get-vRNIL2Network', 'Get-vRNINodes', 'Get-vRNINSXManager', 80 | 'Get-vRNIProblem', 'Get-vRNIRecommendedRules', 81 | 'Get-vRNIRecommendedRulesNsxBundle', 'Get-vRNISecurityGroup', 82 | 'Get-vRNISecurityTag', 'Get-vRNIService', 'Get-vRNIServiceGroup', 83 | 'Get-vRNIvCenter', 'Get-vRNIvCenterCluster', 84 | 'Get-vRNIvCenterDatacenter', 'Get-vRNIvCenterFolder', 'Get-vRNIVM', 85 | 'Get-vRNIVMvNIC', 'Get-vRNIDataSourceSNMPConfig', 'Get-vRNISDDC', 86 | 'Invoke-vRNIRestMethod', 'New-vRNIApplication', 87 | 'New-vRNIApplicationTier', 'New-vRNIDataSource', 88 | 'Remove-vRNIApplication', 'Remove-vRNIApplicationTier', 89 | 'Remove-vRNIDataSource', 'Set-vRNIDataSourceSNMPConfig', 90 | 'New-vRNISubnetMapping', 'Get-vRNISubnetMapping', 91 | 'Get-vRNIEastWestIP', 'Add-vRNIEastWestIP', 'Remove-vRNIEastWestIP', 92 | 'Get-vRNINorthSouthIP', 'Add-vRNINorthSouthIP', 93 | 'Remove-vRNINorthSouthIP', 'Get-vRNISettingsVIDM', 94 | 'Set-vRNISettingsVIDM', 'Get-vRNISettingsUserGroup', 95 | 'Set-vRNISettingsUserGroup', 'Remove-vRNISettingsUserGroup', 96 | 'Get-vRNISettingsUser', 'Set-vRNISettingsUser', 97 | 'Remove-vRNISettingsUser', 'Get-vRNIAuditLogs', 98 | 'Get-vRNIApplicationMemberVM', 'Set-vRNIUserPassword', 99 | 'Get-vRNIKubernetesServices', 'Update-vRNIDataSourceData', 100 | 'Update-vRNINSXvControllerClusterPassword', 'Get-vRNIEntityNames', 101 | 'Invoke-vRNISearch', 'Get-vRNILicensing', 'Test-vRNILicensing', 102 | 'Install-vRNILicensing', 'Remove-vRNILicensing', 'Get-vRNIBackup', 103 | 'Get-vRNIBackupStatus', 'Remove-vRNIBackup', 'Enable-vRNIBackup', 104 | 'Disable-vRNIBackup', 'Set-vRNIBackup', 'Get-vRNIDatabusSubscriber', 105 | 'New-vRNIDatabusSubscriber', 'Remove-vRNIDatabusSubscriber', 106 | 'Get-vRNISDDCGroup', 'Get-vRNIVMCDirectConnect', 107 | 'Get-vRNIVMCDirectConnectInterface', 'Get-vRNISwitchPort', 108 | 'Get-vRNILogicalRouter', 'Get-vRNIVMwareTransitGateway', 109 | 'Get-vRNINSXTIPsecVPNSessions', 'Get-vRNISettingsLoginBanner', 110 | 'Set-vRNISettingsLoginBanner', 'Remove-vRNISettingsLoginBanner' 111 | 112 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 113 | CmdletsToExport = '*' 114 | 115 | # Variables to export from this module 116 | VariablesToExport = '*' 117 | 118 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 119 | AliasesToExport = '*' 120 | 121 | # DSC resources to export from this module 122 | # DscResourcesToExport = @() 123 | 124 | # List of all modules packaged with this module 125 | # ModuleList = @() 126 | 127 | # List of all files packaged with this module 128 | # FileList = @() 129 | 130 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 131 | PrivateData = @{ 132 | 133 | PSData = @{ 134 | 135 | # Tags applied to this module. These help with module discovery in online galleries. 136 | # Tags = @() 137 | 138 | # A URL to the license for this module. 139 | LicenseUri = 'https://github.com/PowervRNI/powervrni/blob/master/LICENSE.md' 140 | 141 | # A URL to the main website for this project. 142 | ProjectUri = 'https://github.com/PowervRNI/powervrni' 143 | 144 | # A URL to an icon representing this module. 145 | # IconUri = '' 146 | 147 | # ReleaseNotes of this module 148 | ReleaseNotes = '### v6.5.1 - 2022-03-07 149 | - \[fixed] Change the application page size to 100 to fix seeing an error about a hard limit in vRNI 6.5.1' 150 | 151 | # Prerelease string of this module 152 | # Prerelease = '' 153 | 154 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 155 | # RequireLicenseAcceptance = $false 156 | 157 | # External dependent modules of this module 158 | # ExternalModuleDependencies = @() 159 | 160 | } # End of PSData hashtable 161 | 162 | } # End of PrivateData hashtable 163 | 164 | # HelpInfo URI of this module 165 | # HelpInfoURI = '' 166 | 167 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 168 | # DefaultCommandPrefix = '' 169 | 170 | } 171 | 172 | -------------------------------------------------------------------------------- /examples/cmdb-import-from-servicenow.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Import Applications from ServiceNow 4 | # 5 | # START Description 6 | # Retrieves applications from the CMDB ServiceNow, and imports them into vRNI. 7 | # Note: is now a native vRNI feature, the script is still here to serve as an example. 8 | # END Description 9 | # 10 | # More info: https://lostdomain.org/2018/11/19/integrating-servicenow-with-network-insight/ 11 | # 12 | # Martijn Smit (@smitmartijn) 13 | # msmit@vmware.com 14 | # Version 1.0 15 | 16 | 17 | ## Start editing here ## 18 | 19 | # ServiceNow configuration; login credentials & URL 20 | $CONFIG_SNOW_USER = "admin" 21 | $CONFIG_SNOW_PASS = "VMware!" 22 | $CONFIG_SNOW_URL = "https://myinstance.service-now.com" 23 | 24 | # vRealize Network Insight config; login credentials & URL 25 | $CONFIG_vRNI_SERVER = "platform.networkinsight.lab.local" 26 | $CONFIG_vRNI_USER = "admin@local" 27 | $CONFIG_vRNI_PASS = "VMware1!" 28 | 29 | # We're using a filter to find only applications in ServiceNow with this in its name 30 | $APP_FILTER = "VMworld" 31 | 32 | ## Stop editing here ## 33 | 34 | # ServiceNow basic auth setup 35 | $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $CONFIG_SNOW_USER, $CONFIG_SNOW_PASS))) 36 | 37 | # Check if PowervRNI is installed. If not, throw an error, if yes, load it. 38 | if (!(Get-Module -ListAvailable -Name PowervRNI)) { 39 | throw "Please install PowervRNI (http://github.com/PowervRNI/powervrni) first by running: Install-Module PowervRNI" 40 | } 41 | Import-Module PowervRNI 42 | 43 | # This function is used to discover dependancies of configuration items (CIs) and loop through them to find any virtual machines 44 | # attached to the application. This function is called multiple times 45 | function get_children($outbound_relations, $depth) { 46 | # Outbound relations is an array of CI IDs that SNOW returns that have a relation with the current CI. 47 | foreach ($relation in $outbound_relations) { 48 | # The values are the actual CI IDs that we should use to request more information on the CI (and see if it's a VM) 49 | foreach ($val in $relation.target.value) { 50 | # Request details of CI ID 51 | $url = "$($CONFIG_SNOW_URL)/api/now/cmdb/instance/cmdb_ci/$($val)" 52 | $info = Invoke-RestMethod -Uri $url -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -UseBasicParsing 53 | 54 | # Is it a VM? If yes, then save the details 55 | if ($info.result.attributes.sys_class_name -eq "cmdb_ci_vmware_instance") { 56 | # I'm using the first bit of the VM name as the tier name. For instance: App-VM01 will be translated to tier: App 57 | $vm_name = $info.result.attributes.name 58 | # Split the VM name on "-" and grab the second to last element (App-VM01 = App) for the tier name 59 | $vm_name_pieces = $vm_name.Split("-") 60 | $tier_name = $vm_name_pieces[-2] 61 | 62 | # Initialise the tier array to save the VM names to 63 | if ($null -eq $Script:tier_list[$tier_name]) { 64 | $Script:tier_list[$tier_name] = @() 65 | $Script:number_of_tiers++ 66 | } 67 | 68 | # If the tier does not already contain this VM (maybe from another CI relation), save it to memory 69 | if (!($Script:tier_list[$tier_name].Contains($vm_name))) { 70 | $Script:tier_list[$tier_name] += $vm_name 71 | $Script:number_of_vms++ 72 | 73 | Write-Host -Foreground Yellow "VM '$($vm_name)' found for tier '$($tier_name)'" 74 | } 75 | 76 | # This is a special one; the correlation field on a CI is a text field that you can fill out in SNOW. 77 | # I'm using that field to couple a load balancing IP address to the VM. That means the VM is behind a load 78 | # balancer with that specific IP address. Save that IP address to also put in the vRNI Application, so connections 79 | # to the load balancer are also put into the vRNI Application context. 80 | # Note: you can also put any load balancer VM (i.e. NSX Edge) into the SNOW CI as a regular VM and this script will 81 | # also pick it up. 82 | if ($info.result.attributes.correlation_id -ne "") { 83 | $tier_name = "LB-$($tier_name)" 84 | if ($null -eq $Script:tier_list[$tier_name]) { 85 | $Script:tier_list[$tier_name] = @() 86 | $Script:number_of_tiers++ 87 | } 88 | 89 | $vm_name = $info.result.attributes.correlation_id 90 | if (!($Script:tier_list[$tier_name].Contains($vm_name))) { 91 | $Script:tier_list[$tier_name] += $vm_name 92 | Write-Host -Foreground Yellow "IP Address '$($vm_name)' found for tier '$($tier_name)'" 93 | } 94 | } 95 | } 96 | 97 | # See if the CI has outbound relations to other CIs and if so, have get_children dive into those relations. 98 | if ($info.result.outbound_relations -ne "") { 99 | get_children($info.result.outbound_relations, ($depth + 1)) 100 | } 101 | } 102 | } 103 | } 104 | 105 | # Connect PowervRNI 106 | Write-Host "Connecting PowervRNI to Network Insight.." 107 | $conn = Connect-vRNIServer -Server $CONFIG_vRNI_SERVER -User $CONFIG_vRNI_USER -Password ($CONFIG_VRNI_PASS | ConvertTo-SecureString -AsPlainText -Force) 108 | if (!$conn) { 109 | throw "Connection to Network Insight failed! Stopping." 110 | } 111 | 112 | # Execute a SNOW API call to get all defined application constructs 113 | Write-Host "Connecting to ServiceNow to retrieve CMDB application list.." 114 | $url = "$($CONFIG_SNOW_URL)/api/now/table/cmdb_ci_appl" 115 | $result = Invoke-RestMethod -Uri $url -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -UseBasicParsing 116 | 117 | # Go through all top-level applications that were returned 118 | foreach ($app in $result.result) { 119 | # We're limiting our import by using a name filter. If you want to import everything, comment this if statement out. 120 | if ($app.name.Contains($APP_FILTER)) { 121 | # Initialise a couple of variables to save the application info too 122 | $Script:tier_list = @{} 123 | $Script:number_of_tiers = 0 124 | $Script:number_of_vms = 0 125 | 126 | Write-Host -ForegroundColor green "Found an application with $($APP_FILTER) in it: $($app.name)" 127 | 128 | # Dig into the found application by retrieving the app details and then having get_children dive into the outbound relations 129 | $url = "$($CONFIG_SNOW_URL)/api/now/cmdb/instance/cmdb_ci/$($app.sys_id)" 130 | $result = Invoke-RestMethod -Uri $url -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -UseBasicParsing 131 | Write-Host "Looking for CIs inside '$($app.name)'.." 132 | get_children($result.result.outbound_relations, 1); 133 | 134 | # Considering get_children loops itself until it has discovered all VMs linked to an app, by now we have fully filled variables with the tiers and VMs 135 | Write-Host -ForegroundColor green "Found $($Script:number_of_vms) VMs in $($Script:number_of_tiers) tiers. Adding them to Network Insight via PowervRNI.." 136 | 137 | # Create Application container in vRNI 138 | $vrniApp = New-vRNIApplication -Name $app.name 139 | Write-Host -ForegroundColor Magenta "New-vRNIApplication -Name '$($app.name)'" 140 | 141 | # Now go through the discovered tiers and VMs 142 | foreach ($tier in $Script:tier_list.Keys) { 143 | # Get the list of VMs for this tier and go through them 144 | $vm_list = $($Script:tier_list.Item($tier)) 145 | $vm_filter_list = "" 146 | $ip_filter_list = @() 147 | foreach ($vm in $vm_list) { 148 | # Test if the name is an IP address; if so, use an IP Filter instead of a VM Name filter 149 | if (($vm -As [IPAddress]) -As [Bool]) { 150 | $ip_filter_list += $vm 151 | } 152 | else { 153 | # This is a VM Name filter, add it to the VM Name filter string (and add an 'or' if this is not the first VM) 154 | if ($vm_filter_list -ne "") { 155 | $vm_filter_list += " or " 156 | } 157 | $vm_filter_list += "name = '$($vm)'" 158 | } 159 | } 160 | 161 | # If this is a VM Name filter, add that to vRNI using PowervRNI 162 | if ($vm_filter_list -ne "") { 163 | $new_tier = ($vrniApp | New-vRNIApplicationTier -Name $tier -VMFilters ("$($vm_filter_list)")) 164 | Write-Host -ForegroundColor Magenta "New-vRNIApplicationTier -Name $tier -VMFilters ("$($vm_filter_list)")" 165 | } 166 | else { 167 | # This is an IP filter, add that to vRNI 168 | $new_tier = ($vrniApp | New-vRNIApplicationTier -Name $tier -IPFilters $ip_filter_list) 169 | Write-Host -ForegroundColor Magenta "New-vRNIApplicationTier -Name $($tier) -IPFilters $($ip_filter_list)" 170 | } 171 | } 172 | 173 | Write-Host -ForegroundColor green "Application '$($app.name)' added to Network Insight!" 174 | Write-Host "----------------------" 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The GNU General Public License, Version 2, June 1991 (GPLv2) 2 | ============================================================ 3 | 4 | > Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | > 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license 8 | document, but changing it is not allowed. 9 | 10 | 11 | Preamble 12 | -------- 13 | 14 | The licenses for most software are designed to take away your freedom to share 15 | and change it. By contrast, the GNU General Public License is intended to 16 | guarantee your freedom to share and change free software--to make sure the 17 | software is free for all its users. This General Public License applies to most 18 | of the Free Software Foundation's software and to any other program whose 19 | authors commit to using it. (Some other Free Software Foundation software is 20 | covered by the GNU Lesser General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not price. Our 24 | General Public Licenses are designed to make sure that you have the freedom to 25 | distribute copies of free software (and charge for this service if you wish), 26 | that you receive source code or can get it if you want it, that you can change 27 | the software or use pieces of it in new free programs; and that you know you can 28 | do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid anyone to deny 31 | you these rights or to ask you to surrender the rights. These restrictions 32 | translate to certain responsibilities for you if you distribute copies of the 33 | software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether gratis or for a 36 | fee, you must give the recipients all the rights that you have. You must make 37 | sure that they, too, receive or can get the source code. And you must show them 38 | these terms so they know their rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and (2) offer 41 | you this license which gives you legal permission to copy, distribute and/or 42 | modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain that 45 | everyone understands that there is no warranty for this free software. If the 46 | software is modified by someone else and passed on, we want its recipients to 47 | know that what they have is not the original, so that any problems introduced by 48 | others will not reflect on the original authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software patents. We wish 51 | to avoid the danger that redistributors of a free program will individually 52 | obtain patent licenses, in effect making the program proprietary. To prevent 53 | this, we have made it clear that any patent must be licensed for everyone's free 54 | use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and modification 57 | follow. 58 | 59 | 60 | Terms And Conditions For Copying, Distribution And Modification 61 | --------------------------------------------------------------- 62 | 63 | **0.** This License applies to any program or other work which contains a notice 64 | placed by the copyright holder saying it may be distributed under the terms of 65 | this General Public License. The "Program", below, refers to any such program or 66 | work, and a "work based on the Program" means either the Program or any 67 | derivative work under copyright law: that is to say, a work containing the 68 | Program or a portion of it, either verbatim or with modifications and/or 69 | translated into another language. (Hereinafter, translation is included without 70 | limitation in the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not covered by 73 | this License; they are outside its scope. The act of running the Program is not 74 | restricted, and the output from the Program is covered only if its contents 75 | constitute a work based on the Program (independent of having been made by 76 | running the Program). Whether that is true depends on what the Program does. 77 | 78 | **1.** You may copy and distribute verbatim copies of the Program's source code 79 | as you receive it, in any medium, provided that you conspicuously and 80 | appropriately publish on each copy an appropriate copyright notice and 81 | disclaimer of warranty; keep intact all the notices that refer to this License 82 | and to the absence of any warranty; and give any other recipients of the Program 83 | a copy of this License along with the Program. 84 | 85 | You may charge a fee for the physical act of transferring a copy, and you may at 86 | your option offer warranty protection in exchange for a fee. 87 | 88 | **2.** You may modify your copy or copies of the Program or any portion of it, 89 | thus forming a work based on the Program, and copy and distribute such 90 | modifications or work under the terms of Section 1 above, provided that you also 91 | meet all of these conditions: 92 | 93 | * **a)** You must cause the modified files to carry prominent notices stating 94 | that you changed the files and the date of any change. 95 | 96 | * **b)** You must cause any work that you distribute or publish, that in whole 97 | or in part contains or is derived from the Program or any part thereof, to 98 | be licensed as a whole at no charge to all third parties under the terms of 99 | this License. 100 | 101 | * **c)** If the modified program normally reads commands interactively when 102 | run, you must cause it, when started running for such interactive use in the 103 | most ordinary way, to print or display an announcement including an 104 | appropriate copyright notice and a notice that there is no warranty (or 105 | else, saying that you provide a warranty) and that users may redistribute 106 | the program under these conditions, and telling the user how to view a copy 107 | of this License. (Exception: if the Program itself is interactive but does 108 | not normally print such an announcement, your work based on the Program is 109 | not required to print an announcement.) 110 | 111 | These requirements apply to the modified work as a whole. If identifiable 112 | sections of that work are not derived from the Program, and can be reasonably 113 | considered independent and separate works in themselves, then this License, and 114 | its terms, do not apply to those sections when you distribute them as separate 115 | works. But when you distribute the same sections as part of a whole which is a 116 | work based on the Program, the distribution of the whole must be on the terms of 117 | this License, whose permissions for other licensees extend to the entire whole, 118 | and thus to each and every part regardless of who wrote it. 119 | 120 | Thus, it is not the intent of this section to claim rights or contest your 121 | rights to work written entirely by you; rather, the intent is to exercise the 122 | right to control the distribution of derivative or collective works based on the 123 | Program. 124 | 125 | In addition, mere aggregation of another work not based on the Program with the 126 | Program (or with a work based on the Program) on a volume of a storage or 127 | distribution medium does not bring the other work under the scope of this 128 | License. 129 | 130 | **3.** You may copy and distribute the Program (or a work based on it, under 131 | Section 2) in object code or executable form under the terms of Sections 1 and 2 132 | above provided that you also do one of the following: 133 | 134 | * **a)** Accompany it with the complete corresponding machine-readable source 135 | code, which must be distributed under the terms of Sections 1 and 2 above on 136 | a medium customarily used for software interchange; or, 137 | 138 | * **b)** Accompany it with a written offer, valid for at least three years, to 139 | give any third party, for a charge no more than your cost of physically 140 | performing source distribution, a complete machine-readable copy of the 141 | corresponding source code, to be distributed under the terms of Sections 1 142 | and 2 above on a medium customarily used for software interchange; or, 143 | 144 | * **c)** Accompany it with the information you received as to the offer to 145 | distribute corresponding source code. (This alternative is allowed only for 146 | noncommercial distribution and only if you received the program in object 147 | code or executable form with such an offer, in accord with Subsection b 148 | above.) 149 | 150 | The source code for a work means the preferred form of the work for making 151 | modifications to it. For an executable work, complete source code means all the 152 | source code for all modules it contains, plus any associated interface 153 | definition files, plus the scripts used to control compilation and installation 154 | of the executable. However, as a special exception, the source code distributed 155 | need not include anything that is normally distributed (in either source or 156 | binary form) with the major components (compiler, kernel, and so on) of the 157 | operating system on which the executable runs, unless that component itself 158 | accompanies the executable. 159 | 160 | If distribution of executable or object code is made by offering access to copy 161 | from a designated place, then offering equivalent access to copy the source code 162 | from the same place counts as distribution of the source code, even though third 163 | parties are not compelled to copy the source along with the object code. 164 | 165 | **4.** You may not copy, modify, sublicense, or distribute the Program except as 166 | expressly provided under this License. Any attempt otherwise to copy, modify, 167 | sublicense or distribute the Program is void, and will automatically terminate 168 | your rights under this License. However, parties who have received copies, or 169 | rights, from you under this License will not have their licenses terminated so 170 | long as such parties remain in full compliance. 171 | 172 | **5.** You are not required to accept this License, since you have not signed 173 | it. However, nothing else grants you permission to modify or distribute the 174 | Program or its derivative works. These actions are prohibited by law if you do 175 | not accept this License. Therefore, by modifying or distributing the Program (or 176 | any work based on the Program), you indicate your acceptance of this License to 177 | do so, and all its terms and conditions for copying, distributing or modifying 178 | the Program or works based on it. 179 | 180 | **6.** Each time you redistribute the Program (or any work based on the 181 | Program), the recipient automatically receives a license from the original 182 | licensor to copy, distribute or modify the Program subject to these terms and 183 | conditions. You may not impose any further restrictions on the recipients' 184 | exercise of the rights granted herein. You are not responsible for enforcing 185 | compliance by third parties to this License. 186 | 187 | **7.** If, as a consequence of a court judgment or allegation of patent 188 | infringement or for any other reason (not limited to patent issues), conditions 189 | are imposed on you (whether by court order, agreement or otherwise) that 190 | contradict the conditions of this License, they do not excuse you from the 191 | conditions of this License. If you cannot distribute so as to satisfy 192 | simultaneously your obligations under this License and any other pertinent 193 | obligations, then as a consequence you may not distribute the Program at all. 194 | For example, if a patent license would not permit royalty-free redistribution of 195 | the Program by all those who receive copies directly or indirectly through you, 196 | then the only way you could satisfy both it and this License would be to refrain 197 | entirely from distribution of the Program. 198 | 199 | If any portion of this section is held invalid or unenforceable under any 200 | particular circumstance, the balance of the section is intended to apply and the 201 | section as a whole is intended to apply in other circumstances. 202 | 203 | It is not the purpose of this section to induce you to infringe any patents or 204 | other property right claims or to contest validity of any such claims; this 205 | section has the sole purpose of protecting the integrity of the free software 206 | distribution system, which is implemented by public license practices. Many 207 | people have made generous contributions to the wide range of software 208 | distributed through that system in reliance on consistent application of that 209 | system; it is up to the author/donor to decide if he or she is willing to 210 | distribute software through any other system and a licensee cannot impose that 211 | choice. 212 | 213 | This section is intended to make thoroughly clear what is believed to be a 214 | consequence of the rest of this License. 215 | 216 | **8.** If the distribution and/or use of the Program is restricted in certain 217 | countries either by patents or by copyrighted interfaces, the original copyright 218 | holder who places the Program under this License may add an explicit 219 | geographical distribution limitation excluding those countries, so that 220 | distribution is permitted only in or among countries not thus excluded. In such 221 | case, this License incorporates the limitation as if written in the body of this 222 | License. 223 | 224 | **9.** The Free Software Foundation may publish revised and/or new versions of 225 | the General Public License from time to time. Such new versions will be similar 226 | in spirit to the present version, but may differ in detail to address new 227 | problems or concerns. 228 | 229 | Each version is given a distinguishing version number. If the Program specifies 230 | a version number of this License which applies to it and "any later version", 231 | you have the option of following the terms and conditions either of that version 232 | or of any later version published by the Free Software Foundation. If the 233 | Program does not specify a version number of this License, you may choose any 234 | version ever published by the Free Software Foundation. 235 | 236 | **10.** If you wish to incorporate parts of the Program into other free programs 237 | whose distribution conditions are different, write to the author to ask for 238 | permission. For software which is copyrighted by the Free Software Foundation, 239 | write to the Free Software Foundation; we sometimes make exceptions for this. 240 | Our decision will be guided by the two goals of preserving the free status of 241 | all derivatives of our free software and of promoting the sharing and reuse of 242 | software generally. 243 | 244 | 245 | No Warranty 246 | ----------- 247 | 248 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR 249 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE 250 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM 251 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 252 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 253 | PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 254 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 255 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 256 | 257 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 258 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 259 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 260 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR 261 | INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA 262 | BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 263 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER 264 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 265 | -------------------------------------------------------------------------------- /examples/archive-flows-to-vrli/vrni-archive-flows-to-vrli.ps1: -------------------------------------------------------------------------------- 1 | # PowervRNI Examples 2 | # 3 | # Example: Archiving vRealize Network Insight flows to vRealize Log Insight 4 | # 5 | # START Description 6 | # This script connects to vRNI, retrieves the flows within a time window (the last time this script was run and now), 7 | # then checks whether the flow is located in the cache (more info in comments of cache code), and if not, 8 | # gathers metadata (VM & L2 network name), and finally sends the flow to vRLI using Send-vRLIMessage from vrealize-log-insight.ps1 9 | # END Description 10 | # 11 | # Start by filling out config.json with these values: 12 | # 13 | # "vrni_server": "your vRNI platform IP or hostname", 14 | # "vrni_credentials_file": "credentials.xml", <-- See below 15 | # "vrni_domain": "local", <-- Only change this if the vRNI user is using LDAP 16 | # "vrli_server": "your vRLI IP or hostname", 17 | # "cache_file": "flow-cache.json", <-- Leave this 18 | # "last_flows_ts": 1579273407 <-- leave this 19 | # 20 | # # credentials.xml 21 | # In order to login to vRNI, this script needs credentials. And let's not store these in plain text, so credentials.xml is a file with 22 | # masked credentials. Here's how to generate it: 23 | # 24 | # Open a PowerShell window and do this: 25 | # 26 | # PS > $credential = Get-Credential -Title "vRealize Network Insight Login" 27 | # PS > $credential | Export-CliXml -Path credentials.xml 28 | # 29 | # After generating the credentials.xml and configuring config.json, you can run this script by running: 30 | # 31 | # PS > ./vrni-archive-flows-to-vrli.ps1 -Config_JSON config.json 32 | # 33 | # Martijn Smit (@smitmartijn) 34 | # msmit@vmware.com 35 | # Version 1.0 36 | 37 | param ( 38 | [parameter(Mandatory = $true, ValueFromPipeLine = $true, ValueFromPipeLineByPropertyName = $true)] 39 | [ValidateNotNullOrEmpty()] 40 | [string]$Config_JSON 41 | ) 42 | 43 | # Test config existance 44 | if (!(Test-Path $Config_JSON)) { 45 | Throw "[$(Get-Date)] Configuration file not found! ($Config_JSON)" 46 | } 47 | 48 | # Include for Send-vRLIMessage function 49 | . "$PSScriptRoot\vrealize-log-insight.ps1" 50 | 51 | # Retrieve config and convert to object 52 | $Config = Get-Content -Path $Config_JSON | ConvertFrom-Json 53 | 54 | 55 | # Test for required params 56 | if (([bool]$Config.vrni_server -eq $False) -Or ([bool]$Config.vrni_credentials_file -eq $False) -Or ([bool]$Config.vrli_server -eq $False) -Or ([bool]$Config.cache_file -eq $False)) { 57 | Throw "[$(Get-Date)] Configuration file ($Config_JSON) needs to contain keys cache_file, vrli_server, vrni_server, and vrni_credentials_file!" 58 | } 59 | 60 | # Figure out the last_flow_ts variable; now-1hour when the ts is 0, use the timestamp otherwise 61 | $last_flow_ts = ([DateTimeOffset]::Now.ToUnixTimeSeconds() - 3600) 62 | if ($Config.last_flows_ts -ne 0) { 63 | $last_flow_ts = $Config.last_flows_ts 64 | } 65 | $new_flow_ts = ([DateTimeOffset]::Now.ToUnixTimeSeconds()) 66 | 67 | # Connect to vRNI using the credentials file 68 | $creds = Import-CliXml -Path $Config.vrni_credentials_file 69 | Connect-vRNIServer -Server $Config.vrni_server -Credential $creds -Domain $Config.vrni_domain 70 | 71 | # Retrieve flows for the time window we need 72 | $max_flow_count = 250000 73 | Write-Host "[$(Get-Date)] Gettings flows from vRNI (this could take a while)" 74 | $raw_flows = Get-vRNIFlow -StartTime $last_flow_ts -EndTime $new_flow_ts -Limit $max_flow_count 75 | Write-Host "[$(Get-Date)] Found $($raw_flows.count) flows" 76 | 77 | if ($max_flow_count -eq $raw_flows.count) { 78 | Write-Host -ForegroundColor "yellow" "[$(Get-Date)] Warning: the number of flows returned is equal to max_flow_count $($max_flow_count). Please up the limit." 79 | } 80 | 81 | # Flows can exist for a long time; as long as the connection isn't shut down, or re-used, the flow record inside vRNI will stick around. 82 | # To prevent logging the same flow over and over again, we keep a local cache file and make sure to remove any flows here that are in that 83 | # cache file. 84 | 85 | # See if cache file exists, otherwise we'll start with an empty cache 86 | $flow_cache = @{} 87 | if (Test-Path $Config.cache_file) { 88 | $flow_cache = Get-Content -Path $Config.cache_file | ConvertFrom-Json -AsHashtable 89 | } 90 | 91 | # Home of the new cache 92 | $new_flow_cache = @{} 93 | 94 | # This will store the flows we'll submit to vRLI 95 | $flows = @() 96 | 97 | # Deduplicate flows with cache in mind 98 | foreach ($flow in $raw_flows) { 99 | # unique key is: src ip - dst ip - port - protocol 100 | # value will be the timestamp it's last seen, to be able to compare the time 101 | $key_name = ("{0}-{1}-{2}-{3}" -f $flow.source_ip.ip_address, $flow.destination_ip.ip_address, $flow.port.display, $flow.protocol) 102 | 103 | # if the flow is in the cache, check if it's older than 1 week. 104 | if ($flow_cache.ContainsKey($key_name)) { 105 | Write-Debug "Found flow in cache: $($key_name)" 106 | # If it is older than 1 week; don't remove it and repeat it to vRLI (safeguard) 107 | if (($new_flow_ts - $flow_cache[$key_name]) -gt (60 * 60 * 24 * 7)) { 108 | $flows += $flow 109 | Write-Debug " - Adding flow to queue because it's older than 1 week: $($key_name)" 110 | } 111 | } 112 | else { 113 | Write-Debug "Flow not found in cache: $($key_name)" 114 | # if the flow is not in the cache, it's a new one; add it! 115 | $flows += $flow 116 | } 117 | 118 | # update new cache 119 | if ($new_flow_cache.ContainsKey($key_name)) { 120 | $flow_cache[$key_name] = $new_flow_ts 121 | } 122 | else { 123 | $new_flow_cache.Add($key_name, $new_flow_ts) 124 | } 125 | } 126 | 127 | # Write new cache file 128 | Write-Debug "Saving new cache file" 129 | ($new_flow_cache | ConvertTo-Json | Out-File $Config.cache_file) 130 | 131 | # Go through the entity IDs related to the flows and get names for them 132 | 133 | # Start with VMs 134 | Write-Debug "Looking up VMs names" 135 | $vm_names = @{} 136 | $tmp_entity_lookup = @{} 137 | $tmp_entity_lookup.Add("entity_ids", @()) 138 | $tmp_entity_count = 0 139 | foreach ($flow in $flows) { 140 | if ([bool]$flow.source_vm -ne $False) { 141 | # Only add it when the VM has not been discovered before 142 | if (!($vm_names.ContainsKey($flow.source_vm.entity_id))) { 143 | # Store entity id in tmp buffer, to be looked up at 100 entities, or in the last flow 144 | $tmp_entity_lookup.entity_ids += $flow.source_vm 145 | $tmp_entity_count++ 146 | } 147 | } 148 | if ([bool]$flow.destination_vm -ne $False) { 149 | # Only add it when the VM has not been discovered before 150 | if (!($vm_names.ContainsKey($flow.destination_vm.entity_id))) { 151 | # Store entity id in tmp buffer, to be looked up at 100 entities, or in the last flow 152 | $tmp_entity_lookup.entity_ids += $flow.destination_vm 153 | $tmp_entity_count++ 154 | } 155 | } 156 | 157 | # Do entity lookup with a 100 entities, or when it's the last flow 158 | if ($tmp_entity_count -eq 100 -Or $flow -eq $flows[-1]) { 159 | # Send a request to entities/fetch in order to bulk fetch the names of the VMs 160 | $requestBody = ConvertTo-Json $tmp_entity_lookup 161 | $entity_info = Invoke-vRNIRestMethod -Method POST -URI "/api/ni/entities/fetch" -Body $requestBody 162 | # Go through results and store the VM names 163 | foreach ($entity in $entity_info.results) { 164 | if (!($vm_names.ContainsKey($entity.entity_id))) { 165 | $vm_names.Add($entity.entity_id, @{name = $entity.entity.name; vc_id = $entity.entity.vendor_id; region = $entity.entity.region; type = $entity.entity_type }) 166 | } 167 | } 168 | # Reset the tmp buffers 169 | $tmp_entity_lookup = @{} 170 | $tmp_entity_lookup.Add("entity_ids", @()) 171 | $tmp_entity_count = 0 172 | } 173 | } 174 | 175 | # Also resolve L2 network names 176 | Write-Debug "Looking up L2 network names" 177 | $l2_names = @{} 178 | $tmp_entity_lookup = @{} 179 | $tmp_entity_lookup.Add("entity_ids", @()) 180 | $tmp_entity_count = 0 181 | foreach ($flow in $flows) { 182 | 183 | if ([bool]$flow.source_l2_network -ne $False) { 184 | # Only add it when the L2 network has not been discovered before 185 | if (!($l2_names.ContainsKey($flow.source_l2_network.entity_id))) { 186 | # Store entity id in tmp buffer, to be looked up at 100 entities, or in the last flow 187 | # Work around a bug in the vRNI API - not all L2 network types has its entity_type set (like Azure VNets) 188 | if ([bool]$flow.source_l2_network.entity_type -eq $True) { 189 | $tmp_entity_lookup.entity_ids += $flow.source_l2_network 190 | $tmp_entity_count++ 191 | } 192 | } 193 | } 194 | if ([bool]$flow.destination_l2_network -ne $False) { 195 | # Only add it when the L2 network has not been discovered before 196 | if (!($l2_names.ContainsKey($flow.destination_l2_network.entity_id))) { 197 | # Store entity id in tmp buffer, to be looked up at 100 entities, or in the last flow 198 | # Work around a bug in the vRNI API - not all L2 network types has its entity_type set (like Azure VNets) 199 | if ([bool]$flow.destination_l2_network.entity_type -eq $True) { 200 | $tmp_entity_lookup.entity_ids += $flow.destination_l2_network 201 | $tmp_entity_count++ 202 | } 203 | } 204 | } 205 | 206 | # Do entity lookup with a 100 entities, or when it's the last flow 207 | if (($tmp_entity_count -eq 100 -Or $flow -eq $flows[-1]) -And $tmp_entity_count -gt 0) { 208 | # Send a request to entities/fetch in order to bulk fetch the names of the VMs 209 | $requestBody = ConvertTo-Json $tmp_entity_lookup 210 | $entity_info = Invoke-vRNIRestMethod -Method POST -URI "/api/ni/entities/fetch" -Body $requestBody 211 | # Go through results and store the VM names 212 | foreach ($entity in $entity_info.results) { 213 | if (!($l2_names.ContainsKey($entity.entity_id))) { 214 | $l2_names.Add($entity.entity_id, @{name = $entity.entity.name; vlan_id = $entity.entity.vlan_id; type = $entity.entity_type }) 215 | } 216 | } 217 | # Reset the tmp buffers 218 | $tmp_entity_lookup = @{} 219 | $tmp_entity_lookup.Add("entity_ids", @()) 220 | $tmp_entity_count = 0 221 | } 222 | } 223 | 224 | Write-Host "[$(Get-Date)] Looping through results and sending to vRLI" 225 | $flows_sent = 0 226 | foreach ($flow in $flows) { 227 | $flowDate = (Get-Date 01.01.1970) + ([System.TimeSpan]::fromseconds($flow.time)) 228 | 229 | $log_message = "vRNI-FLOW $($flowDate.ToString('r')) $(($flow.firewall_action).ToUpper()) $($flow.protocol) $($flow.name)" 230 | $log_fields = @{} 231 | 232 | $log_fields.Add("__vrni_flow_firewall_action", $flow.firewall_action) 233 | $log_fields.Add("__vrni_flow_traffic_type", $flow.traffic_type) 234 | $log_fields.Add("__vrni_flow_tag", $flow.flow_tag) 235 | $log_fields.Add("__vrni_flow_source_ip", $flow.source_ip.ip_address) 236 | $log_fields.Add("__vrni_flow_destination_ip", $flow.destination_ip.ip_address) 237 | $log_fields.Add("__vrni_flow_port", $flow.port.display) 238 | $log_fields.Add("__vrni_flow_port_name", $flow.port.iana_name) 239 | $log_fields.Add("__vrni_flow_protocol", $flow.protocol) 240 | $log_fields.Add("__vrni_flow_timestamp", $flowDate) 241 | 242 | Write-Debug "Flow.name: $($flow.name)" 243 | Write-Debug "Flow.date: $($flowDate)" 244 | Write-Debug "Flow.firewall_action: $($flow.firewall_action)" 245 | Write-Debug "Flow.traffic_type: $($flow.traffic_type)" 246 | Write-Debug "Flow.flow_tag: $($flow.flow_tag)" 247 | Write-Debug "Flow.source_ip: $($flow.source_ip.ip_address)" 248 | Write-Debug "Flow.destination_ip: $($flow.destination_ip.ip_address)" 249 | Write-Debug "Flow.port: $($flow.port.display)" 250 | Write-Debug "Flow.port.name: $($flow.port.iana_name)" 251 | Write-Debug "Flow.protocol: $($flow.protocol)" 252 | 253 | # There are conditional fields, like when the flow contains a source or destination VM, or L2 network. 254 | # Below is checks whether these fields are present and adds them to the vRLI payload, if so. 255 | if ([bool]$flow.source_vm -ne $False) { 256 | $entity_id = $flow.source_vm.entity_id 257 | if ([bool]$vm_names[$entity_id].name -ne $False) { 258 | Write-Debug "Flow.source_vm: $($vm_names[$entity_id].name)" 259 | $log_fields.Add("__vrni_flow_source_vm", $vm_names[$entity_id].name) 260 | } 261 | if ([bool]$vm_names[$entity_id].type -ne $False) { 262 | Write-Debug "Flow.source_vm.type: $($vm_names[$entity_id].type)" 263 | $log_fields.Add("__vrni_flow_source_vm_type", $vm_names[$entity_id].type) 264 | } 265 | if ([bool]$vm_names[$entity_id].vc_id -ne $False) { 266 | Write-Debug "Flow.source_vm.vc_id: $($vm_names[$entity_id].vc_id)" 267 | $log_fields.Add("__vrni_flow_source_vm_vc_id", $vm_names[$entity_id].vc_id) 268 | } 269 | if ([bool]$vm_names[$entity_id].region -ne $False) { 270 | Write-Debug "Flow.source_vm.region: $($vm_names[$entity_id].region)" 271 | $log_fields.Add("__vrni_flow_source_vm_region", $vm_names[$entity_id].region) 272 | } 273 | } 274 | if ([bool]$flow.destination_vm -ne $False) { 275 | $entity_id = $flow.destination_vm.entity_id 276 | if ([bool]$vm_names[$entity_id].name -ne $False) { 277 | Write-Debug "Flow.destination_vm: $($vm_names[$entity_id].name)" 278 | $log_fields.Add("__vrni_flow_destination_vm", $vm_names[$entity_id].name) 279 | } 280 | if ([bool]$vm_names[$entity_id].type -ne $False) { 281 | Write-Debug "Flow.destination_vm.type: $($vm_names[$entity_id].type)" 282 | $log_fields.Add("__vrni_flow_destination_vm_type", $vm_names[$entity_id].type) 283 | } 284 | if ([bool]$vm_names[$entity_id].vc_id -ne $False) { 285 | Write-Debug "Flow.destination_vm.vc_id: $($vm_names[$entity_id].vc_id)" 286 | $log_fields.Add("__vrni_flow_destination_vm_vc_id", $vm_names[$entity_id].vc_id) 287 | } 288 | if ([bool]$vm_names[$entity_id].region -ne $False) { 289 | Write-Debug "Flow.destination_vm.region: $($vm_names[$entity_id].region)" 290 | $log_fields.Add("__vrni_flow_destination_vm_region", $vm_names[$entity_id].region) 291 | } 292 | } 293 | 294 | if ([bool]$flow.source_l2_network -ne $False) { 295 | $entity_id = $flow.source_l2_network.entity_id 296 | if ($l2_names.ContainsKey($entity_id)) { 297 | if ([bool]$l2_names[$entity_id].name -ne $False) { 298 | Write-Debug "Flow.source_l2_network.name: $($l2_names[$entity_id].name)" 299 | $log_fields.Add("__vrni_flow_source_l2_network", $l2_names[$entity_id].name) 300 | } 301 | if ([bool]$l2_names[$entity_id].vlan_id -ne $False) { 302 | Write-Debug "Flow.source_l2_network.vlan_id: $($l2_names[$entity_id].vlan_id)" 303 | $log_fields.Add("__vrni_flow_source_l2_network_vlan_id", $l2_names[$entity_id].vlan_id) 304 | } 305 | } 306 | } 307 | if ([bool]$flow.destination_l2_network -ne $False) { 308 | $entity_id = $flow.destination_l2_network.entity_id 309 | if ($l2_names.ContainsKey($entity_id)) { 310 | if ([bool]$l2_names[$entity_id].name -ne $False) { 311 | Write-Debug "Flow.destination_l2_network.name: $($l2_names[$entity_id].name)" 312 | $log_fields.Add("__vrni_flow_destination_l2_network", $l2_names[$entity_id].name) 313 | } 314 | if ([bool]$l2_names[$entity_id].vlan_id -ne $False) { 315 | Write-Debug "Flow.destination_l2_network.vlan_id: $($l2_names[$entity_id].vlan_id)" 316 | $log_fields.Add("__vrni_flow_destination_l2_network_vlan_id", $l2_names[$entity_id].vlan_id) 317 | } 318 | } 319 | } 320 | 321 | Write-Debug "=================" 322 | 323 | # Send log message to vRLI! 324 | $output = Send-vRLIMessage -Server $Config.vrli_server -Message $log_message -Fields $log_fields 325 | $output | Out-Null 326 | $flows_sent++ 327 | } 328 | 329 | # Save new timestamp to the configuration file 330 | ($Config.PSObject.Properties.Remove('last_flows_ts') | Out-Null) 331 | ($Config | Add-Member 'last_flows_ts' $new_flow_ts | Out-Null) 332 | ($Config | ConvertTo-Json | Out-File $Config_JSON) 333 | 334 | # Disconnect from vRNI to release the auth token 335 | Disconnect-vRNIServer 336 | 337 | Write-Host "[$(Get-Date)] Archived $($flows_sent) flows to vRealize Log Insight" --------------------------------------------------------------------------------