This discussion has been locked. The information referenced herein may be inaccurate due to age, software updates, or external references.
You can no longer post new replies to this discussion. If you have a similar question you can start a new discussion in this forum.

Export Network Atlas Maps from Orion [PowerShell]

UPDATE: Updated to 1.0.1 to fix exports of User Graphics Files

Because I'm constantly creating and destroying Orion instances in my currently capacity, I sometimes forget to export everything before I start working on the next instance.  To that end, I started playing around with the Orion SDK and seeing if there was a way that I could rapidly export some content.  The first thing time that I had this was when I stood up a new server and wanted to use my existing Network Path Troubleshooting map.  I started to dig around a little bit and what to my wondering eyes should appear?  No, not reindeer, but a 'table' called MapStudioFiles.

Then I broke out my PoSH hat and started tinkering.  This is what I came up with:


<#

------------------------------------------------------------------------------------------------------

File Name:    Export-OrionMapFiles.ps1

Author:      Kevin M.  Sparenberg (https://thwack.solarwinds.com/people/KMSigma)

------------------------------------------------------------------------------------------------------

Purpose:

  This script will  export the Orion Maps (and associated files) from an active Orion System.  By

default this script will export ALL maps and associated files  (including images).  To change it to

only export hte OrionMap files comment out or remove the "Exports only the Maps" region.

  Export Path is to the  current user's desktop.  This can be  modified within the "Setup Variables &

Connect to the SolarWinds Information Service (SWIS)"  region.

IMPORTANT NOTE:

This version is set to use the "username/password"  authentication process.  This can be  changed to

AD-credentials with some minor tweaking (TBD).

Prerequisites:

  You must have OrionSDK Installed (Link:  https://thwack.solarwinds.com/community/labs_tht/orion-sdk)

  (tested with version 1.10)

Version History: [P = Past, C = Current, F = Future]

  (P) 1.0.0 - Initial  Release (2015-07-22)

  (C) 1.0.1 - Update  the path check for custom icons (2015-08-10)

  (F) 1.1.0 -  Conversion to a PowerShell Function (TBD)

  (F) 1.2.0 - Allow for  Multiple Authentication Types (TBD)

Tested against:

  Orion Platform  2015.1.2

  SAM 6.2.1

  DPA 9.2.0

  QoE 2.0

  IPAM 4.3

  NCM 7.4

  NPM 11.5.2

  NTA 4.1.1

  OGS 1.0.10

  WPM 2.2.0

  SRM 6.1.11

  Toolset 11.0.1

  UDT 3.2.2

  IVIM 2.1.0

  VNQM 4.2.2

------------------------------------------------------------------------------------------------------

#>

#region Setup Variables & Connect to the SolarWinds  Information Service (SWIS)

Add-PSSnapin -Name SwisSnapin -ErrorAction SilentlyContinue

# The username for a user with admin  level permissions

$SwisUsername = "admin"

# The poassword for said user (in plain text)

$SwisPassword = "@ppStack1"

# The IP, machine name, or alias for the associated Orion  Instance

$SwisHost    = "orionweb.demo.lab"

$SwisCredentails = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $SwisUsername, ( ConvertTo-SecureString $SwisPassword -AsPlainText -Force )

# Export Path for the Files

$ExportPath = "$env:userprofile\Desktop\OrionMapFiles"

#endregion

#region Exports the Maps Only‌

$SwqlQuery = @"

SELECT FileName, FileData

FROM Orion.MapStudioFiles

WHERE FileType = 0 AND IsDeleted = False

ORDER BY FileName

"@

#endregion

#region Exports the Maps and any associated files

$SwqlQuery = @"

SELECT FileName, FileData

FROM Orion.MapStudioFiles

WHERE IsDeleted = False

ORDER BY FileName

"@

#endregion

#region Collect the files to a local object

$SwisConnection  = Connect-Swis -Hostname $SwisHost -Credential $SwisCredentails

$OrionMapFiles = Get-SwisData -SwisConnection $SwisConnection -Query $SwqlQuery

$SwisConnection.Close()

$SwisConnection.Dispose()

Remove-Variable -Name SwisConnection -Force -Confirm:$false -ErrorAction SilentlyContinue

$TotalMapFiles = $OrionMapFiles.Count

#endregion

#region Check for Path Existence.  If the path doesn't exist, then it's created.

if ( -not ( Test-Path -Path $ExportPath -ErrorAction SilentlyContinue ) )

{

    Write-Host "Path: '$ExportPath' does not  exist.`nCreating Export  Folder..." -ForegroundColor Yellow

    New-Item -ItemType Directory -Path $ExportPath | Out-Null

}

#endregion

#region Cycle through each file and export to the file system

For ( $i = 0; $i -lt $TotalMapFiles; $i++ )

{

    Write-Progress -Activity "Exporting  Orion Map Files" -CurrentOperation "Exporting $( $OrionMapFiles[$i].FileName )" -Status "Exporting $( $OrionMapFiles[$i].FileData.Length ) bytes" -PercentComplete ( ( $i / $TotalMapFiles ) * 100 )

    #region Added  for verison 1.0.1 for Custom Icons

    # Check for  the "Full Path" and create it, if it doesn't exist.

    $ExportFullPath = ( Join-Path -Path $ExportPath -ChildPath $OrionMapFiles[$i].FileName )

    $ExportDirectory = Split-Path -Path $ExportFullPath -Parent

    if ( -not ( Test-Path -Path $ExportDirectory -ErrorAction SilentlyContinue ) )

    {

        Write-Warning "Creating [$( $ExportDirectory )] Folder"

        New-Item -Path $ExportDirectory -ItemType Directory | Out-Null

    }

    #endregion

    $OrionMapFiles[$i].FileData | Set-Content -Path ( Join-Path -Path $ExportPath -ChildPath $OrionMapFiles[$i].FileName ) -Encoding Byte -Force

}

Remove-Variable OrionMapFiles

Write-Progress -Activity "Exporting Orion Map Files" -Completed

#endregion


I'd love feedback from the community on what you think about this and what you think of my plans going forward.

  • Hi Kevin,

    nice script looks good, worked first time for me so always a plus! A few suggestions if I may:

    • instead of the write-host I'd use the write-warning (I'm nit-picking here,I see you used it in other places). As Jeffrey says, write-host is bademoticons_devil.png
    • I think the SWQLQuery variable is declared twice. It runs fine, not sure if you had planned a switch for those?
    • Haven't checked it, but is the $exportdirectory variable the same as the $exportpath (haven't tested it, just wondering out loud, so to speak)

    Please +1 conversion to a function emoticons_wink.png

  • Thanks Michael.  I'm working towards these changes in all of my free time (read "no time whatsoever").  I want to address your points.

    • I'm actually a fan of Write-Host because it's not part of an object - I only use it for "informational" notes.  And I know that Jeff doesn't like it, but I find it useful for just reporting information back to the screen.  I will probable change that with Write-Verbose when I convert it to a function.
    • The variable is defined twice.  The first only exports the Maps, the second exports the maps and all referenced files (custom icons, background images, etc.).  I left it this way so that you can comment out the second one if you want to export only the maps.  (Actually, there is a typo in my script which I will fix without incrementing the version information.  You finding this helped me find it.  Thanks!)
    • You are correct.  I've just re-used a name and declared the same variable twice for no good reason.

    Converting this to a function would be great, but then the error trapping needs to be rock-solid.  All the try..catch..finally blocks would no doubt drive me batty, but it's the best way to do it.  The better way to do it would probably entail creating a "Get-OrionMapFiles" function and allowing that to be piped to an "Export-OrionMapFiles" function.  What's the point of building a file of functions if there's only one function, right?

    Insofar as function conversion, what do you think would be good for parameters?  I was thinking:

    • [string] $SwisServer = $env:COMPUTERNAME (default to the local machine)
    • [System.Management.Automation.PSCredentials] $SwisCredentials (or [string] $SwisUsername and [string ]$SwisPassword )
    • [string] $ExportPath = Get-Location (and checking to make sure that it is of type "FileSystem")
    • [switch] $MapsOnly = $false (Export everything, not just the OrionMap files)
    • [switch] $IncludeDeleted = $false (otherwise include deleted files - will probably prepend a "DELETED_" before the file name or something)
    • [switch] $Force = $false (Overwrite existing files if they exist)
    • Support for the common parameters (WhatIf, Verbose, Debug).

    Then the only question is: what do I return from the function.  I was thinking of returning a complete list (similar to Get-ChildItem) of all files that have been exported.  Whatcha think?

  • Yeah, figuring out what to return in a lot of functions I've written is pretty tricky: I've a HUGE list of things I want to re-write for proper pipelining, and to make use of try/catch etc <cough> PowerOrion  </cough> emoticons_wink.png. But in this case an array of the files returned definitely makes sense.

    The one thing that would be really great is if we could figure out a better way to handle the $swis variables. The only thing I've done so far is pass it as a parameter, but I would like to have more robust type checking around it. Ideally it would be great if we could just set it as a global variable somewhere, but not sure how the best approach to that is.

  • Well - Microsoft does something like that with the Exchange Console, so there has to be a way.  I haven't looked at the scripts recently, but it should work.  I remember once trying to export the a set of credentials as a CLIXML and then re-importing it later.  But no-go.  I'm actually thinking of just (by default) using the trusted credentials to start when I begin converting this to a function.

  • What file format do the maps get saved as?

    I would prefer to download the files with a curl request, any idea how to do this?

  • The maps are exported as "OrionMap" files.  This is the native type if you save a map out of Network Atlas.

  • This script is great and we are going to use it to backup our maps.  I wished it worked on v10.7 as we are currently upgrading now to 11.5.3 and haven't fully completed it.  It works great on v11.5.3 though.  Has anyone tested it on v12.X?  Also, does anyone know of a way to identify what view the maps are on?  I was looking through SQL but couldn't find anything.  Thanks much!

  • I'm not sure on which version this schema took over, but this works for me:

    SELECT [Views].[ViewID]       ,[ViewKey]       ,[ViewTitle]       ,[ViewType]       ,[System]       ,[Customizable]       ,[LimitationID]       ,[ViewGroup]       ,[ViewIcon]       ,[ViewGroupPosition]       ,[ViewGroupName]       ,[NOCView]       ,[NOCViewRotationInterval]   FROM [dbo].[Views]   INNER JOIN [Resources]     ON [Views].ViewID = [Resources].ViewID WHERE ResourceName = 'Map'
  • Thanks for the info KMSigma!  I apologize for not being more specific in my request.  Is there anyway to identify the name of the map assigned to the map resources above?  Your script above tells me what views contain map resources but it doesn't tell me the actual name of the map assigned to the resource.  Is there anyway to get that information?  The reason I ask is because our Database team has informed us that we have database inconsistency issues in our MapStudioFiles table and they want to correct it.  We are concerned that once they do, we may lose maps.  We have captured all the maps available on the system, we've backed them up on our v11.5.3 systems using your script (THANKS!) and have even taken screen captures of the maps just in case when we go to restore a file and can't open the .orionmap file in Atlas.  What I don't know though is which maps are assigned to the map resources.  I performed a test and determined that if a map that is assigned to a resource is deleted and recreated with the same name, the map will not magically reappear so I need to know which views and resources the map is assigned to so I can go back and reassign it.

    Hope this makes more sense and thanks so much for the help!

  • Well, then you need to do some clever linkage:

    SELECT        [Views].ViewID,

                  [Views].ViewKey,

                  [Views].ViewTitle,

                  [Views].ViewType,

                  [Views].System,

                  [Views].Customizable,

                  [Views].LimitationID,

                  [Views].ViewGroup,

                  [Views].ViewIcon,

                  [Views].ViewGroupPosition,

                  [Views].ViewGroupName,

                  [Views].NOCView,

                  [Views].NOCViewRotationInterval,

         Maps.[FileName]

    FROM          [Views]

    INNER JOIN Resources

       ON [Views].ViewID = Resources.ViewID

    INNER JOIN ResourceProperties

       ON ResourceProperties.ResourceID = Resources.ResourceID

    INNER JOIN ( SELECT CONVERT(nvarchar(50), [FileId]) + '.OrionMap' AS [FileID]

                      ,[FileName]

                 FROM [SolarWindsOrion_2017Q4].[dbo].[MapStudioFiles]

                 WHERE FileType = 0 ) AS Maps

       ON Maps.FileID = ResourceProperties.PropertyValue

    WHERE        ( Resources.ResourceName = 'Map' )

             AND ( ResourceProperties.PropertyName = 'selectedMapId' )