Public/Initialize-LMPOVSetup.ps1
<# .SYNOPSIS This function initializes the Logic Monitor (POV) setup for SEs by automating various tasks required during POV setup. .DESCRIPTION The Initialize-LMPOVSetup function sets up various components of the Logic Monitor POV. It can set up the website, portal metrics, alert analysis, and LM container. The setup for each component can be controlled individually or all at once. .PARAMETER Website The name of the website to be set up. This parameter is used in both 'All' and 'Individual' parameter sets. .PARAMETER WebsiteHttpType The HTTP type of the website. Defaults to "https". This parameter is used in both 'All' and 'Individual' parameter sets. .PARAMETER PortalMetricsAPIUsername The username for the Portal Metrics API. Defaults to "lm_portal_metrics". This parameter is used in both 'All' and 'Individual' parameter sets. .PARAMETER LogsAPIUsername The username for the Logs API. Defaults to "lm_logs". This parameter is used in both 'All' and 'Individual' parameter sets. .PARAMETER SetupWebsite A switch to control the setup of the website. This parameter is used in the 'Individual' parameter set. .PARAMETER SetupPortalMetrics A switch to control the setup of the portal metrics. This parameter is used in the 'Individual' parameter set. .PARAMETER SetupAlertAnalysis A switch to control the setup of the alert analysis. This parameter is used in the 'Individual' parameter set. .PARAMETER SetupLMContainer A switch to control the setup of the LM container. This parameter is used in the 'Individual' parameter set. .PARAMETER LMContainerAPIUsername The username for the LM Container API. Defaults to "lm_container". This parameter is used in both 'All' and 'Individual' parameter sets. .EXAMPLE Initialize-LMPOVSetup -RunAll -IncludeDefaults -Website example.com This command runs all setup processes including default options and creates a webcheck for example.com. .INPUTS The function does not accept input from the pipeline. .OUTPUTS The function does not return any output. .NOTES The function throws an error if it fails to set up any component. #> Function Initialize-LMPOVSetup { [CmdletBinding(DefaultParameterSetName = 'Individual')] Param ( [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [String]$Website, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [String]$WebsiteHttpType = "https", [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [string]$PortalMetricsAPIUsername = "lm_portal_metrics", [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [string]$LogsAPIUsername = "lm_logs", [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupWebsite, [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupPortalMetrics, [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupAlertAnalysis, [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupLMContainer, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [string]$LMContainerAPIUsername = "lm_container", [Parameter(ParameterSetName = 'Individual')] [Switch]$MoveMinimalMonitoring, [Parameter(ParameterSetName = 'Individual')] [Switch]$CleanupDynamicGroups, [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupWindowsLMLogs, [Parameter(ParameterSetName = 'Individual')] [Parameter(ParameterSetName = 'All')] [Switch]$IncludeDefaults, [Parameter(ParameterSetName = 'PostPOV-Readonly')] [Switch]$ReadOnlyMode, [Parameter(ParameterSetName = 'PostPOV-RevertReadonly')] [Switch]$RevertReadOnlyMode, [Parameter(ParameterSetName = 'Individual')] [Switch]$SetupCollectorServiceInsight, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'Individual')] [String]$WindowsLMLogsEventChannels = "Application,System", [Parameter(ParameterSetName = 'All')] [Switch]$RunAll ) #Check if we are logged in and have valid api creds Begin { #Check for newer version of Logic.Monitor module Update-LogicMonitorSEModule -CheckOnly } Process { $PortalInfo = Get-LMAccountStatus If ($($PortalInfo)) { $PortalName = $PortalInfo.Portal $DeviceName = "$PortalName.logicmonitor.com" #Generate hastable of new dynamic groups to create $DynamicGroupList = @{ "All Devices" = 'true()' "AWS Resources" = 'isAWSService()' "Azure Resources" = 'isAzureService()' "GCP Resources" = 'isGCPService()' "K8s Resources" = 'system.devicetype == "8"' "Dead Devices" = 'system.hoststatus == "dead" || system.hoststatus == "dead-collector" || system.gcp.status == "TERMINATED" || system.azure.status == "PowerState/stopped" || system.aws.stateName == "terminated"' "Palo Alto" = 'hasCategory("PaloAlto")' "Cisco ASA" = 'hasCategory("CiscoASA")' "Logs Enabled Devices" = 'hasPushModules("LogUsage")' "Netflow Enabled Devices" = 'isNetflow()' "Cisco UCS" = 'hasCategory("CiscoUCSFabricInterconnect") || hasCategory("CiscoUCSManager")' "Oracle" = 'hasCategory("OracleDB")' "Domain Controllers" = 'hasCategory("MicrosoftDomainController")' "Exchange Servers" = 'hasCategory("MSExchange")' "IIS" = 'hasCategory("MicrosoftIIS")' "Citrix XenApp" = 'hasCategory("CitrixBrokerActive") || hasCategory("CitrixMonitorServiceV2") || hasCategory("CitrixLicense") || hasCategory("CitrixEUEM")' } $GitubURI = "https://raw.githubusercontent.com/stevevillardi" #If readonly mode, siwtch all users to readonly and record previous role permissions for role back If($ReadOnlyMode){ $Users = Get-LMUser | Where-Object {$_.apionly -eq $False -and $_.username -ne "lmsupport"} Foreach($User in $Users){ If($User.Note -notlike "Previous Roles:*"){ $PreviousRoles = $User.roles.Name -Join(",") $UpdatedUser = Set-LMUser -Id $User.Id -RoleNames @("readonly") -Note "Previous Roles: $PreviousRoles" If($UpdatedUser){ Write-Host "[INFO]: Previous role info ($($User.roles.Name -Join(","))) stored for user $($User.username), successfully converted to readonly role." -ForegroundColor Yellow } } Else{ Write-Host "[INFO]: User $($User.username) previously converted, skipping processing." -ForegroundColor Gray } } } #Revert any previous set readonly roles back to their original state If($RevertReadOnlyMode){ $Users = Get-LMUser | Where-Object {$_.apionly -eq $False -and $_.username -ne "lmsupport"} Foreach($User in $Users){ $PreviousRoles = ($User.Note -Split "Previous Roles: ")[1] -Split (",") If($PreviousRoles){ $UpdatedUser = Set-LMUser -Id $User.Id -RoleNames $PreviousRoles -Note " " If($UpdatedUser){ Write-Host "[INFO]: Previous role info ($(($User.Note -Split "Previous Roles: ")[1])) found for user $($User.username), successfully reverted readonly role." -ForegroundColor Yellow } } Else{ Write-Host "[WARN]: No previous role info found for user $($User.username), skipping role revert for user." -ForegroundColor Yellow } } } #Create example collector service insight If($SetupCollectorServiceInsight -or $RunAll){ $ServiceInsightProps = @{ device = @( @{ deviceGroupFullPath = "Devices by Type/Collectors"; deviceDisplayName = "*"; deviceProperties = @() } ) } | ConvertTo-Json -Depth 3 #Create new SI resource $ServiceInsightResource = Get-LMDevice -name "LogicMonitorCollectorHealth" If(!$ServiceInsightResource){ $ServiceInsightResource = New-LMDevice -name "LogicMonitorCollectorHealth" -DisplayName "LogicMonitor: Collector Health" -PreferredCollectorId -4 -DeviceType 6 -Properties @{"predef.bizservice.members"=$ServiceInsightProps;"predef.bizService.evalMembersInterval"="30"} If($ServiceInsightResource){ Write-Host "[INFO]: Successfully created service insight resource (LogicMonitor: Collector Health)" #Upload SI datasource from xml Try{ $SIDatasource = (Invoke-WebRequest -Uri "$GitubURI/LogicMonitor-Dashboards/main/POV/LogicMonitor_Collector_Health.xml" -UseBasicParsing).Content Import-LMLogicModule -File $SIDatasource -Type datasource -ErrorAction Stop } Catch{ #Oops Write-Host "[ERROR]: Unable to import SI template from source: $_" -ForegroundColor Red } } Else{ #Oops Write-Host "[ERROR]: Failed to create service insight resource (LogicMonitor: Collector Health), review error message and try again." -ForegroundColor Red } } Else{ Write-Host "[INFO]: Service insight resource (LogicMonitor: Collector Health) already exists, skipping creation" -ForegroundColor Gray #Upload SI datasource from xml If(!$(Get-LMDatasource -DisplayName "LogicMonitor Collector Health")){ Try{ $SIDatasource = (Invoke-WebRequest -Uri "$GitubURI/LogicMonitor-Dashboards/main/POV/LogicMonitor_Collector_Health.xml").Content Import-LMLogicModule -File $SIDatasource -Type datasource -ErrorAction Stop } Catch{ #Oops Write-Host "[WARN]: Unable to import SI template from source: $_" -ForegroundColor Yellow } } Else{ Write-Host "[INFO]: Service insight aggregate datasource (LogicMonitor Collector Health) already exists, skipping import" -ForegroundColor Gray } } } #Create readonly API use for Portal Metrics If ($SetupPortalMetrics -or $RunAll) { $CheckAPIUser = Get-LMUser -Name "$PortalMetricsAPIUsername" $CheckPortalDevice = Get-LMDevice -Name $DeviceName If(!$CheckAPIUser -and !$CheckPortalDevice){ Write-Host "[INFO]: Setting up API user: $PortalMetricsAPIUsername" $APIUser = New-LMAPIUser -Username "$PortalMetricsAPIUsername" -note "Auto provisioned for use with LM Portal Metrics Datasources" -RoleNames @("readonly") If ($APIUser) { Write-Host "[INFO]: Successfully setup API user: $PortalMetricsAPIUsername" Write-Host "[INFO]: Creating readonly API token for user: $PortalMetricsAPIUsername" $APIInfo = New-LMAPIToken -id $APIUser.id -Note "Auto provisioned for use with LM Portal Metrics Datasource" } #Setup portal mertics device if we have a valid API token If ($APIInfo) { Write-Host "[INFO]: Successfully created API token for user: $PortalMetricsAPIUsername | $($APIInfo.accessId) | $($APIInfo.accessKey)" If ($PortalName) { $PortalDeviceGroup = New-LMDeviceGroup -Name "LogicMonitor Portal Metrics" -AppliesTo "hasCategory(`"LogicMonitorPortal`")" -ParentGroupName "Devices by Type" If ($PortalDeviceGroup) { Write-Host "[INFO]: Created Portal Metrics dynamic group in Devices by Type: $($PortalDeviceGroup.name)" } $CollectorId = (Get-LMCollector | Where-Object {$_.collectorSize -ne "n/a"} | Select-Object -Last 1).id Write-Host "[INFO]: Creating Portal Metrics resource: $DeviceName" $PortalDevice = New-LMDevice -Name $DeviceName -DisplayName $DeviceName -Description "Auto provisioned resource to collect LM Portal Metrics" -Properties @{"lmaccess.id" = $APIInfo.accessId; "lmaccess.key" = $APIInfo.accessKey; "lmaccount" = $PortalName } -PreferredCollectorId $CollectorId If ($PortalDevice) { Write-Host "[INFO]: Successfully created Portal Metrics resource: $DeviceName" } } } } Else{ Write-Host "[INFO]: API User ($PortalMetricsAPIUsername) or portal metrics device ($DeviceName) already exists in portal, skipping setup for portal metrics" -ForegroundColor Gray } } #Setup Company Website If (($SetupWebsite -or $RunAll) -and $Website) { Write-Host "[INFO]: Setting up external webcheck for: $Website" $Website = $Website.split("//")[-1] #Make sure http/https is not in the entered site name $WebsiteResult = New-LMWebsite -Webcheck -Name $Website -HttpType $WebsiteHttpType -WebsiteDomain $Website If ($WebsiteResult) { Write-Host "[INFO]: Successfully setup external webcheck for: $Website" } } #Move minimal monitoring folder into devices by type If ($MoveMinimalMonitoring -or $RunAll) { $DeviceFolderId = (Get-LMDeviceGroup -Name "Devices by Type").id $MinimalFolderId = (Get-LMDeviceGroup -Name "Minimal Monitoring").id If ($DeviceFolderId -and $MinimalFolderId) { Write-Host "[INFO]: Moving minimal monitoring folder into Devices by Type" $MinimalFolderGroup = Set-LMDeviceGroup -id $MinimalFolderId -ParentGroupId $DeviceFolderId If ($MinimalFolderGroup) { Write-Host "[INFO]: Successfully moved minimal monitoring folder into Devices by Type" } $MinimalFolderAppliesTo = (Get-LMDeviceGroup -Name "Minimal Monitoring").appliesTo If ($MinimalFolderAppliesTo) { Write-Host "[INFO]: Updating Minimal Monitoring folder to exclude Meraki and Portal Metrics resources" $MinimalFolderAppliesTo = "system.sysinfo == `"`" && system.sysoid == `"`" && isDevice() && !(system.virtualization) && (monitoring != `"basic`") && system.devicetype != `"8`" && !hasCategory(`"LogicMonitorPortal`") && !hasCategory(`"MerakiAPIOrg`") && !hasCategory(`"MerakiAPINetwork`")" $MinimalFolder = Set-LMDeviceGroup -Id $MinimalFolderId -AppliesTo $MinimalFolderAppliesTo If ($MinimalFolder) { Write-Host "[INFO]: Successfully updated minimal monitoring appliesTo query" } } } } #Cleanup dynamic groups will add Linux_SSH to the Linux folder and delete the Misc folder If ($CleanupDynamicGroups -or $RunAll) { Write-Host "[INFO]: Cleaning up default dynamic groups" $LinuxDeviceGroupId = (Get-LMDeviceGroup -Name "Linux Servers" | Where-Object {$_.fullPath -like "Devices by Type*"}).id $MiscDeviceGroupId = (Get-LMDeviceGroup -Name "Misc").id If(!$DeviceFolderId){ $DeviceFolderId = (Get-LMDeviceGroup -Name "Devices by Type").id } If ($LinuxDeviceGroupId) { $ModifedLinuxGroup = Set-LMDeviceGroup -Id $LinuxDeviceGroupId -AppliesTo "isLinux() || hasCategory(`"Linux_SSH`")" If ($ModifedLinuxGroup) { Write-Host "[INFO]: Updated Linux Servers group to include Linux_SSH devices" } } If ($MiscDeviceGroupId) { $MiscDeviceGroup = Remove-LMDeviceGroup -Id $MiscDeviceGroupId If ($ModifedLinuxGroup) { Write-Host "[INFO]: Removed Misc devices group from Devices by Type" } } Write-Host "[INFO]: Creating additional default dynamic groups" Foreach($Group in $DynamicGroupList.GetEnumerator()){ If(!$(Get-LMDeviceGroup -Name $Group.Name)){ $NewGroup = New-LMDeviceGroup -Name $Group.Name -ParentGroupId $DeviceFolderId -AppliesTo $Group.Value If($NewGroup){ Write-Host "[INFO]: Created new dynamic group: $($Group.Name)" } } Else{ Write-Host "[INFO]: Dynamic group: $($Group.Name) already exists, skipping creation" -ForegroundColor Gray } } } #Add k8s role with proper permissions If($RunAll -or $SetupLMContainer){ $LMContainerAPIRoleName = "lm-container" $LMContainerAPIUser = Get-LMUser -Name "$LMContainerAPIUsername" $LMContainerAPIRole = Get-LMRole -Name $LMContainerAPIRoleName If(!$LMContainerAPIRole){ Write-Host "[INFO]: Setting up LM Container API Role: $LMContainerAPIRoleName" $LMContainerAPIRole = New-LMRole -Name $LMContainerAPIRoleName -ResourcePermission manage -LogsPermission manage -DashboardsPermission manage -SettingsPermission manage-collectors -Description "Auto provisioned to allow for API token creation for use with lm-container" If($LMContainerAPIRole){ Write-Host "[INFO]: Successfully setup API role: $LMContainerAPIRoleName" } } Else{ Write-Host "[INFO]: LM Container API Role ($LMContainerAPIRoleName) already exists in portal, skipping setup" -ForegroundColor Gray } If(!$LMContainerAPIUser){ Write-Host "[INFO]: Setting up LM Container API user: $LMContainerAPIUsername" $LMContainerAPIUser = New-LMAPIUser -Username "$LMContainerAPIUsername" -note "Auto provisioned for use with LM Container" -RoleNames @($LMContainerAPIRoleName) If ($LMContainerAPIUser) { Write-Host "[INFO]: Successfully setup API user: $LMContainerAPIUsername" } } } If($SetupWindowsLMLogs -or $RunAll){ $LogsAPIRoleName = "lm-logs-ingest" $LogsAPIUser = Get-LMUser -Name "$LogsAPIUsername" $LogsAPIRole = Get-LMRole -Name $LogsAPIRoleName If(!$LogsAPIRole){ Write-Host "[INFO]: Setting up LM Logs API Role: $LogsAPIRoleName" $LogsAPIRole = New-LMRole -Name $LogsAPIRoleName -ResourcePermission view -LogsPermission manage -Description "Auto provisioned to allow for windows events ingest via datasource" If($LogsAPIRole){ Write-Host "[INFO]: Successfully setup API role: $LogsAPIRoleName" } } Else{ Write-Host "[INFO]: LM Logs API Role ($LogsAPIRoleName) already exists in portal, skipping setup" -ForegroundColor Gray } If(!$LogsAPIUser){ Write-Host "[INFO]: Setting up LM Logs API user: $LogsAPIUsername" $LogsAPIUser = New-LMAPIUser -Username "$LogsAPIUsername" -note "Auto provisioned for use with Windows LM Logs Datasource" -RoleNames @($LogsAPIRoleName) If ($LogsAPIUser) { Write-Host "[INFO]: Successfully setup API user: $LogsAPIUsername" Write-Host "[INFO]: Creating administrator API token for user: $LogsAPIUsername" $LMLogsAPIINfo = New-LMAPIToken -id $LogsAPIUser.id -Note "Auto provisioned for use with Windows LM Logs Datasource" } #Import Datasource and apply properties to windows server group If ($LMLogsAPIINfo) { Write-Host "[INFO]: Successfully created API token for user: $LogsAPIUsername | $($LMLogsAPIINfo.accessId) | $($LMLogsAPIINfo.accessKey)" $WindowsServerDeviceGroup = Get-LMDeviceGroup -Name "Windows Servers" | Where-Object {$_.fullPath -like "Devices by Type*"} If ($WindowsServerDeviceGroup) { Write-Host "[INFO]: Adding API properties to Windows Server device group" $UpdatedWindowsServerDeviceGroup = Set-LMDeviceGroup -Id $WindowsServerDeviceGroup.Id -Properties @{"lmaccess.id" = $LMLogsAPIINfo.accessId; "lmaccess.key" = $LMLogsAPIINfo.accessKey; "lmaccount" = $PortalName; "lmlogs.winevent.channels" = $WindowsLMLogsEventChannels; "lmlogs.winevent.detailed_message" = "false" } If ($UpdatedWindowsServerDeviceGroup) { Write-Host "[INFO]: Successfully updated Windows Server device group for LM Logs" } } } } Else{ Write-Host "[INFO]: LM Logs API User ($LogsAPIUsername) already exists in portal, skipping setup" -ForegroundColor Gray } #Import LM Logs Datasource $LogsDatasource = Get-LMDatasource -Name "Windows_Events_LMLogs" If(!$LogsDatasource){ Import-LMExchangeModule -LMExchangeId "2cb0a988-487a-48a6-b332-62003ef3b3dc" #core module Start-Sleep -Seconds 5 #Added manual pause to ensure datasource is available after importing from the exchange $LogsDatasource = Set-LMDatasource -Name Windows_Events_LMLogs -appliesTo "isWindows() && lmlogs.winevent.channels && lmaccess.id && lmaccess.key && lmaccount" If($LogsDatasource){ Write-Host "[INFO]: Successfully added core module (Windows_Events_LMLogs) and updated appliesto logic" } Else{ Write-Host "[WARN]: Successfully added core module (Windows_Events_LMLogs) but was unable to modify the appliesTo criteria, please manually set the appliesTo criteria for the datasource to apply: 'isWindows() && lmlogs.winevent.channels && lmaccess.id && lmaccess.key && lmaccount'" -ForegroundColor Yellow } } Else{ Write-Host "[INFO]: LM Logs core logicmodule ($($LogsDatasource.displayname)) already exists in portal, skipping setup" -ForegroundColor Gray } } If($IncludeDefaults -or $SetupAlertAnalysis){ #Deploy AlertDuration dashboard Write-Host "[INFO]: Setting up Alert Analysis Dashboard and LogicModules from repo." $CheckPortalDevice = Get-LMDevice -Name $DeviceName If($CheckPortalDevice){ #Setup alert analysis package #Import default DSes $ModuleList = @( @{ name = "LogicMonitor_Device_Alert_Statistics.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/Suites/Alert%20Duration" }, @{ name = "LogicMonitor_DeviceGroup_Alert_Statistics.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/Suites/Alert%20Duration" }, @{ name = "LogicMonitor_Portal_Alert_Statistics_Cache.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/Suites/Alert%20Duration" }, @{ name = "LogicMonitor_Portal_Alert_Statistics.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/Suites/Alert%20Duration" } ) Foreach($Module in $ModuleList){ $ModuleName = $Module.name.Split(".")[0] $LogicModule = Get-LMDataSource -name $ModuleName If(!$LogicModule){ Try{ $LogicModule = (Invoke-WebRequest -Uri "$GitubURI/$($Module.repo)/$($Module.name)").Content Import-LMLogicModule -File $LogicModule -Type $Module.type -ErrorAction Stop Write-Host "[INFO]: Successfully imported $ModuleName datasource" } Catch{ #Oops Write-Host "[ERROR]: Unable to import $ModuleName LogicModule from source: $_" -ForegroundColor Red } } Else{ Write-Host "[INFO]: LogicModule $ModuleName already exists, skipping import" -ForegroundColor Gray } } $AlertAnalysisProps = @{ "alert.analysis.period"="7" "alert.analysis.excludeUnACKedAlerts"="false" "alert.analysis.excludeSDTedAlerts"="false" "alert.analysis.datasourceList"="*" "alert.analysis.minimumTimeInSeconds"="0" } Set-LMDevice -Id $CheckPortalDevice.Id -Properties $AlertAnalysisProps | Out-Null $AlertDurationRootFolder = (Get-LMDashboardGroup -Name "LogicMonitor").Id If(!$AlertDurationRootFolder){$AlertDurationRootFolder = 1} Try{ $AlertDurationDashboardFile = (Invoke-WebRequest -Uri "$GitubURI/LogicMonitor-Dashboards/main/Suites/Alert%20Duration/Alert_Analysis_Overview.json").Content $AlertDurationDashboard = Get-LMDashboard -Name "Alert Analysis Overview" If(!$AlertDurationDashboard){ $ImportAlertDurationDashboard = Import-LMDashboard -File $AlertDurationDashboardFile -ParentGroupId $AlertDurationRootFolder Write-Host "[INFO]: Successfully imported Alert Analysis Dashboard" } Else{ Write-Host "[INFO]: Alert Analysis Dashboard already exists, skipping import" -ForegroundColor Gray } } Catch{ #Oops Write-Host "[ERROR]: Unable to import Alert Analysis dashboard from source: $_" -ForegroundColor Red } } Else{ Write-Host "[WARN]: Unable to import Alert Analysis dashboard template: PortalMetrics device not found, please deploy before attempting to deploy" -ForegroundColor Yellow } } #Setup common default options/imports If($IncludeDefaults){ #Setup new user welcome message $MessageSubject = "LogicMonitor Account Created - (##USER##)" #Message Template $MessageTemplate = "PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQvc3RyaWN0LmR0ZCI+PEhUTUw+PEhFQUQ+PFRJVExFPjwvVElUTEU+PC9IRUFEPjxCT0RZPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSI1IiBjZWxsc3BhY2luZz0iNSIgc3R5bGU9ImhlaWdodDo0MDBweDsgd2lkdGg6NTUwcHgiPgoJPHRib2R5PgoJCTx0cj4KCQkJPHRkPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+QSBMb2dpY01vbml0b3IgYWNjb3VudCBoYXMgYmVlbiBjcmVhdGVkIGZvciB5b3UuIEhlcmUmIzM5O3Mgd2hhdCB5b3UgbmVlZCB0byBrbm93IHRvIGdldCBzdGFydGVkOjwvc3Bhbj4KCQkJPGRpdj48YnIgLz4KCQkJPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5Mb2dnaW5nIGluOjwvc3Bhbj4KCQkJPHVsPgoJCQkJPGxpPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+WW91IGNhbiBsb2cgaW4gdG8geW91ciBhY2NvdW50IGF0Jm5ic3A7PGEgaHJlZj0iaHR0cDovLyMjQ09NUEFOWSMjIyNET01BSU4jIy8iIHRhcmdldD0iX2JsYW5rIj4jI0NPTVBBTlkjIyMjRE9NQUlOIyM8L2E+PC9zcGFuPjwvbGk+CgkJCQk8bGk+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5Zb3UgbXVzdCBsb2cgaW4gd2l0aCB0aGUgdXNlciAmcXVvdDs8c3Ryb25nPiMjVVNFUiMjPC9zdHJvbmc+JnF1b3Q7IGFuZCB0aGUgcGFzc3dvcmQgY3JlYXRlZCZuYnNwO2ZvciB5b3VyIHVzZXIgYWNjb3VudDwvc3Bhbj48L2xpPgoJCQk8L3VsPgoKCQkJPHA+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48c3Ryb25nPk5vdGU6PC9zdHJvbmc+Jm5ic3A7SXQgaXMgcG9zc2libGUgdGhpcyBhY2NvdW50IHdhcyBnZW5lcmF0ZWQgYnkgeW91ciBMb2dpY01vbml0b3IgYWRtaW5pc3RhdG9yLCBpZiB5b3UgZG8gbm90IGtub3cgdGhlIHBhc3N3b3JkLCB5b3UgY2FuIHJlc2V0IHRoZSBwYXNzd29yZCBieSB2aXNpdGluZzogPGEgaHJlZj0iaHR0cDovLyMjQ09NUEFOWSMjIyNET01BSU4jIy8iIHRhcmdldD0iX2JsYW5rIj4jI0NPTVBBTlkjIyMjRE9NQUlOIyM8L2E+Jm5ic3A7YW5kIGNob29zaW5nICZxdW90OzxzdHJvbmc+SSBmb3Jnb3QgbXkgcGFzc3dvcmQ8L3N0cm9uZz4mcXVvdDs8L3NwYW4+PC9wPgoJCQk8L2Rpdj4KCgkJCTxkaXY+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5MZWFybmluZyBhYm91dCBMb2dpY01vbml0b3I6PC9zcGFuPgoKCQkJPHVsPgoJCQkJPGxpPgoJCQkJPHA+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5Mb2cgaW50byB5b3VyIHBvcnRhbCBhbmQgY2xpY2sgdGhlIFRyYWluaW5nIGxpbmsgaW4gdGhlIHVwcGVyIHJpZ2h0IGhhbmQgY29ybmVyLiBZb3Ugd2lsbCBmaW5kIGEgJnF1b3Q7R2V0dGluZyBTdGFydGVkIHdpdGggTG9naWNNb25pdG9yJnF1b3Q7IGNvdXJzZSB0aGVyZSB0byBoZWxwIHlvdSBiZWdpbiB5b3VyIExvZ2ljTW9uaXRvciBqb3VybmV5PC9zcGFuPjwvcD4KCQkJCTwvbGk+CgkJCQk8bGk+CgkJCQk8cD48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPlJlYWQgb3VyIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxvZ2ljbW9uaXRvci5jb20vc3VwcG9ydC9nZXR0aW5nLXN0YXJ0ZWQvaS1qdXN0LXNpZ25lZC11cC1mb3ItbG9naWNtb25pdG9yLW5vdy13aGF0LzEtYWJvdXQtdGhlLWxvZ2ljbW9uaXRvci1zb2x1dGlvbi8iPkdldHRpbmcgU3RhcnRlZCBHdWlkZTwvYT48L3NwYW4+PC9wPgoJCQkJPC9saT4KCQkJCTxsaT4KCQkJCTxwPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+U2lnbiB1cCBmb3IgYSA8YSBocmVmPSJodHRwczovL3d3dy5sb2dpY21vbml0b3IuY29tL2xpdmUtdHJhaW5pbmctd2ViaW5hcnMvIj53ZWJpbmFyPC9hPiBvciByZXZpZXcgb3VyIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxvZ2ljbW9uaXRvci5jb20vYWNhZGVteS8iPm90aGVyIGF2YWlsYWJsZSByZXNvdXJjZXM8L2E+Jm5ic3A7PC9zcGFuPiZuYnNwOzwvcD4KCQkJCTwvbGk+CgkJCQk8bGk+CgkJCQk8cD48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPkNoZWNrIG91dCBvdXIgPGEgaHJlZj0iaHR0cHM6Ly93d3cubG9naWNtb25pdG9yLmNvbS9zdXBwb3J0LyI+c3VwcG9ydCBjZW50ZXI8L2E+PC9zcGFuPjwvcD4KCQkJCTwvbGk+CgkJCQk8bGk+CgkJCQk8cD48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPlN1YnNjcmliZSB0byBvdXIgPGEgaHJlZj0iaHR0cHM6Ly93d3cubG9naWNtb25pdG9yLmNvbS9yZWxlYXNlLW5vdGVzLyI+cmVsZWFzZSBub3RlczwvYT48L3NwYW4+PC9wPgoJCQkJPC9saT4KCQkJPC91bD4KCQkJPC9kaXY+CgoJCQk8ZGl2PjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+SWYgeW91IG5lZWQgaGVscDo8L3NwYW4+CgoJCQk8dWw+CgkJCQk8bGk+CgkJCQk8cD48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPkNvbnRhY3QgPGEgaHJlZj0iaHR0cHM6Ly9zdXBwb3J0LmxvZ2ljbW9uaXRvci5jb20vaGMvZW4tdXMvcmVxdWVzdHMvbmV3LyI+c3VwcG9ydDwvYT48L3NwYW4+PC9wPgoJCQkJPC9saT4KCQkJCTxsaT4KCQkJCTxwPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+U2lnbiB1cCBmb3IgYSA8YSBocmVmPSJodHRwczovL3d3dy5sb2dpY21vbml0b3IuY29tL3N1cHBvcnQvY2VydGlmaWNhdGlvbi9sb2dpY21vbml0b3ItY2VydGlmaWNhdGlvbi1wcm9ncmFtcy8iPmNlcnRpZmljYXRpb24gY291cnNlPC9hPiBvciBmaW5kIGEgY2VydGlmaWVkIGluZGl2aWR1YWwgd2l0aGluIHlvdXIgY29tcGFueTwvc3Bhbj48L3A+CgkJCQk8L2xpPgoJCQk8L3VsPgoJCQk8L2Rpdj4KCgkJCTxkaXY+PGJyIC8+CgkJCTxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+SGFwcHkgTW9uaXRvcmluZyE8L3NwYW4+PGJyIC8+CgkJCTxzcGFuIHN0eWxlPSJmb250LXNpemU6MTNweCI+VGhlIExvZ2ljTW9uaXRvciB0ZWFtPC9zcGFuPjwvZGl2PgoJCQk8L3RkPgoJCTwvdHI+Cgk8L3Rib2R5Pgo8L3RhYmxlPgo8L0JPRFk+PC9IVE1MPg==" $MessageTemplate = [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($MessageTemplate)) Try{ $MessageResult = Set-LMNewUserMessage -MessageBody $MessageTemplate -MessageSubject $MessageSubject -ErrorAction Stop Write-Host "[INFO]: Successfully updated new user welcome email template" } Catch{ Write-Host "[ERROR]: Unable to modify new user welcome email template: $_" -ForegroundColor Red } #Set SSL_Cert DS to only alert on non self signed certs $SSLDatasourceName = "SSL_Certificates" $SSLDatasource = Get-LMDatasource -name $SSLDatasourceName If($SSLDatasource){ If($SSLDatasource.dataPoints.name.IndexOf("Alerting_DaysRemainingIfNotSelfSigned") -ne 1 -and $SSLDatasource.dataPoints.name.IndexOf("DaysRemaining") -ne 1){ Try{ $SSLDatasource.dataPoints[$SSLDatasource.dataPoints.name.IndexOf("Alerting_DaysRemainingIfNotSelfSigned")].alertExpr = "< 28 7 2" $SSLDatasource.dataPoints[$SSLDatasource.dataPoints.name.IndexOf("DaysRemaining")].alertExpr = $null $SSLResult = Set-LMDatasource -Id $SSLDatasource.id -Datapoints $SSLDatasource.datapoints -ErrorAction Stop Write-Host "[INFO]: Successfully updated default alert thresholds on LogicModule ($SSLDatasourceName)" } Catch{ Write-Host "[ERROR]: Unable to modify default alert thresholds on LogicModule ($SSLDatasourceName): $_" -ForegroundColor Red } } Else{ #Unable to find required datapoints for modification Write-Host "[ERROR]: Unable to modify default alert thresholds on LogicModule ($SSLDatasourceName), expected datapoints not found" -ForegroundColor Red } } Else{ #Unable to find SSL_Certificates DS Write-Host "[ERROR]: Unable to locate LogicModule ($SSLDatasourceName), skipping alert threshold modification" -ForegroundColor Red } #Import default DSes $ModuleList = @( @{ name = "Microsoft_Windows_Services_AD.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/POV" }, @{ name = "LogicMonitor_Collector_Configurations.xml" type = "configsource" repo = "LogicMonitor-Dashboards/main/POV" }, @{ name = "NoData_Metrics.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/POV" }, @{ name = "NoData_Tasks_By_Type_v2.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/POV" }, @{ name = "NoData_Tasks_Overall_v2.xml" type = "datasource" repo = "LogicMonitor-Dashboards/main/POV" }, @{ name = "NoData_Tasks_Discovery_v2.json" type = "propertyrules" repo = "LogicMonitor-Dashboards/main/POV" } ) Foreach($Module in $ModuleList){ $ModuleName = $Module.name.Split(".")[0] $LogicModule = Switch($Module.type){ "datasource" {Get-LMDataSource -name $ModuleName} "configsource" {Get-LMConfigSource -name $ModuleName} "propertyrules" {Get-LMPropertySource -name $ModuleName} default {Get-LMDataSource -name $ModuleName} } If(!$LogicModule){ Try{ $LogicModule = (Invoke-WebRequest -Uri "$GitubURI/$($Module.repo)/$($Module.name)").Content Import-LMLogicModule -File $LogicModule -Type $Module.type -ErrorAction Stop Write-Host "[INFO]: Successfully imported $ModuleName datasource" } Catch{ #Oops Write-Host "[ERROR]: Unable to import $ModuleName LogicModule from source: $_" -ForegroundColor Red } } Else{ Write-Host "[INFO]: LogicModule $ModuleName already exists, skipping import" -ForegroundColor Gray } } #Deploy Dynamic Dashboards $DashboardList = @( @{ name = "Dynamic_Dashboard_-_Network_Performance.json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" }, @{ name = "Dynamic_Dashboard_-_Windows.json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" }, @{ name = "Dynamic_Dashboard_-_Windows_(Textbox_Selector).json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" }, # @{ # name = "Dynamic_Dashboard_-_vCenter_VMs.json" # repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" # }, @{ name = "Dynamic_Server-at-a-Glance__Linux(SNMP).json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" }, @{ name = "Dynamic_Server-at-a-Glance__Linux(SSH).json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" }, @{ name = "Dynamic_Server-at-a-Glance__Windows.json" repo = "LogicMonitor-Dashboards/main/Dynamic%20Dashboards" } ) #Generate API Key and Role $DashboardAPIRoleName = "lm-dynamic-dashboards" $DashboardAPIUserName = "lm_dynamic_dashboards" $DashboardAPIRole = Get-LMRole -Name $DashboardAPIRoleName $DashboardAPIUser = Get-LMUser -Name $DashboardAPIUserName If(!$DashboardAPIRole){ $DashboardAPIRole = New-LMRole -Name $DashboardAPIRoleName -ResourcePermission view -DashboardsPermission manage -Description "Auto provisioned for use with dynamic dashboards" Write-Host "[INFO]: Successfully generated required API role ($DashboardAPIRoleName) for dynamic dashboards" } If(!$DashboardAPIUser){ $DashboardAPIUser = New-LMAPIUser -Username "$DashboardAPIUserName" -note "Auto provisioned for use with dynamic dashboards" -RoleNames @($DashboardAPIRoleName) Write-Host "[INFO]: Successfully generated required API user ($DashboardAPIUserName) for dynamic dashboards" } If($DashboardAPIRole -and $DashboardAPIUser){ $APIToken = New-LMAPIToken -Username $DashboardAPIUserName -Note "Auto provisioned for use with dynamic dashboards" If($APIToken){ Write-Host "[INFO]: Successfully generated required API token for dynamic dashboards for user: $DashboardAPIUserName" } } Else{ Write-Host "Unable to generate required API token for dynamic dashboards, manually update the required tokens to use dynamic dashboards" } Write-Host "[INFO]: Importing dynamic dashboards from repo." $DynamicDashboardGroup = (Get-LMDashboardGroup -Name "Dynamic Dashboards").Id If(!$DynamicDashboardGroup){ $DynamicDashboardGroup = (New-LMDashboardGroup -Name "Dynamic Dashboards" -ParentGroupId 1).Id } Foreach($Dashboard in $DashboardList){ Try{ $DashboardFile = (Invoke-WebRequest -Uri "$GitubURI/$($Dashboard.repo)/$($Dashboard.name)").Content If(!$(Get-LMDashboard -Name $(($DashboardFile | ConvertFrom-Json).Name))){ $ImportedDashboard = Import-LMDashboard -File $DashboardFile -ReplaceAPITokensOnImport -APIToken $APIToken -ParentGroupId $DynamicDashboardGroup -ErrorAction Stop } Else{ Write-Host "[INFO]: Dashboard $($Dashboard.name) already exists, skipping import" -ForegroundColor Gray } } Catch{ #Oops Write-Host "[ERROR]: Unable to import $($Dashboard.name) template from source: $_" -ForegroundColor Red } } } } Else { Write-Error "Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again." } } End {} } |