Private/Import-AtwsDiskCache.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<#
    .COPYRIGHT
    Copyright (c) ECIT Solutions AS. All rights reserved. Licensed under the MIT license.
    See https://github.com/ecitsolutions/Autotask/blob/master/LICENSE.md for license information.
#>

Function Import-AtwsDiskCache {
    <#
            .SYNOPSIS
                This function reads the cachefile into memory.
            .DESCRIPTION
                This function determines the correct paths to cache files and creates any
                missing path if necessary. If there isn't any cache for the current Autotask
                tenant available this function creates it, starting with a supplied cache
                file from the module.
            .INPUTS
                Nothing.
            .OUTPUTS
                Nothing, but the cache property of the SOAP Client object is filled.
            .EXAMPLE
                Import-AtwsDiskCache
                Loads the cache from disk
            .NOTES
                NAME: Import-AtwsDiskCache
            .LINK
                Export-AtwsDiskCache
    #>

    [CmdLetBinding()]
  
    Param()

    begin {
        Write-Verbose -Message ('{0}: trying to determine correct location for dynamic module cache.' -F $MyInvocation.MyCommand.Name)    
    
        # Get the current module name
        $myModule = (Get-Command -Name $MyInvocation.MyCommand.Name).Module
    
        $cacheFile = 'AutotaskFieldInfoCache.xml'
    
        # Use join-path to be platform agnostic on slashes in paths
        $centralCache = Join-Path $(Join-Path $myModule.ModuleBase 'Private') $cacheFile

        Write-Verbose -Message ('{0}: Module cache location is {1}' -F $MyInvocation.MyCommand.Name, $centralCache)  
        
    }
  
    process {
        # Do not check for existence of personal cache if asked to load module without it
        # This function should not be called from a context where this is necessary, but
        # better be on the safe side
        if ($Script:Atws.Configuration.UseDiskCache) { 
            # On Windows we store the cache in the WindowsPowerhell folder in My documents
            # On macOS and Linux we use a dot-folder in the users $HOME folder as is customary
            if ([Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([Runtime.InteropServices.OSPlatform]::Windows)) {  
                $PersonalCacheDir = Join-Path $([environment]::GetFolderPath('MyDocuments')) 'WindowsPowershell\Cache' 
            }
            else {
                $PersonalCacheDir = Join-Path $([environment]::GetFolderPath('MyDocuments')) '.config\powershell\atwsCache' 
            }

            # Add tenant id to path
            $PersonalCacheDir = Join-Path $PersonalCacheDir $Script:Atws.CI

            # Add module version to cache path (join-path only takes a single childpath parameter)
            $PersonalCacheDir = Join-Path $PersonalCacheDir $My.ModuleVersion.ToString()
        
            # Save the cache path to the module information
            $Script:Atws.DynamicCache = $PersonalCacheDir  
        
            $PersonalCache = Join-Path $PersonalCacheDir $CacheFile

            Write-Verbose -Message ('{0}: Personal cache location is {1}.' -F $MyInvocation.MyCommand.Name, $PersonalCache)  

            if (-not (Test-Path $personalCache)) {
                Write-Verbose -Message ('{0}: There is no personal cache. Creating from central location.' -F $MyInvocation.MyCommand.Name)
      
                # Create Personalcache directory if it doesn't exist
                if (-not (Test-Path $personalCacheDir)) {
                    New-Item -Path $personalCacheDir -ItemType Directory
                }
      
                # Copy the cache
                Copy-Item -Path $centralCache -Destination $personalCache -Force
           
            }
    
            # This should work now!
            if (Test-Path $personalCache) {
                Write-Verbose -Message ('{0}: Reading cache from disk.' -F $MyInvocation.MyCommand.Name)
      
                $Script:Atws.Cache = Import-Clixml -Path $personalCache
  
            }
            else {
                Throw [System.Exception] "Coult not create a cache file."
            }
      
            # Nested testing to make sure the structure is OK
            if ($Script:Atws.Cache -is [Hashtable]) {
                if ($Script:Atws.Cache.ContainsKey('00')) {
                    if ($Script:Atws.Cache['00'] -is [PSCustomObject]) {
                        if ([bool]($Script:Atws.Cache['00'].PSobject.Properties.name -match "FieldInfoCache")) {
                            if (-not ($Script:Atws.Cache['00'].FieldInfoCache.Count -gt 0)) {

                                Write-Warning ('{0}: Personal disk cache is broken! Deleting cache and trying again!' -F $MyInvocation.MyCommand.Name)
                                # Delete ceache
                                $null = Remove-Item -Path $personalCache -Force -ErrorAction SilentlyContinue
                                # Restart import
                                Import-AtwsDiskCache
                        
                                # Do not process rest of script
                                return
                            }
                        }
                    }
                }
            }
        }
        else {
            Write-Verbose -Message ('{0}: Running with -NoDiskCache. Initializing memory-only cache with data supplied with module ({1}).' -F $MyInvocation.MyCommand.Name, $centralCache)
            
            # Initialize memory only cache from module directory
            $Script:Atws.Cache = Import-Clixml -Path $centralCache      
        }
    
        # We must be connected to know the customer identity number
        if ($Script:Atws.CI) {
            # If the current connection is for a new Autotask tenant, copy the blank
            # cache from the included pre-cache
            if (-not ($Script:Atws.Cache.ContainsKey($Script:Atws.CI))) {
                Write-Debug -Message ('{0}: Cache does not contain information about Autotask tenant {1}. Initializing.' -F $MyInvocation.MyCommand.Name, $Script:Atws.CI )
                
                # Create a cache object to store API version along with the cache
                $Script:Atws.Cache[$Script:Atws.CI] = New-Object -TypeName PSObject -Property @{
                    ApiVersion    = $Script:Atws.Cache['00'].ApiVersion
                    ModuleVersion = [Version]$My.ModuleVersion
                }
                # Use Add-Member on the Hashtable, or the propertyvalue will be set to typename only
                # Copy the hashtable to a new object. We do NOT want a referenced copy!
                $newHashTable = Copy-PSObject -InputObject $Script:Atws.Cache['00'].FieldInfoCache
                Add-Member -InputObject $Script:Atws.Cache[$Script:Atws.CI] -MemberType NoteProperty -Name FieldInfoCache -Value $newHashTable

            }

            # Initialize the $Script:FieldInfoCache shorthand
            $Script:FieldInfoCache = $Script:Atws.Cache[$Script:Atws.CI].FieldInfoCache
      
      
            # If the API version has been changed at the Autotask end we unfortunately have to reload all
            # entities from scratch
            $currentApiVersion = $Script:Atws.GetWsdlVersion($Script:Atws.IntegrationsValue)
            if ($Script:Atws.Cache[$Script:Atws.CI].ApiVersion -ne $currentApiVersion -or [Version]$My.ModuleVersion -ne $Script:Atws.Cache[$Script:Atws.CI].ModuleVersion) {
        
                # Write-Warning to inform user that an update of static functions is due
                if ($Script:Atws.Cache[$Script:Atws.CI].ApiVersion -ne $currentApiVersion) { 
                    Write-Warning ('{0}: API version has been updated. You need to run "Update-AtwsFunctions -FunctionSet static" with writepermissions to the module directory or update the module.' -F $MyInvocation.MyCommand.Name) 
                }
        
                # Call the import-everything function
                Update-AtwsDiskCache
        
            }
      
        }
        else {
            Write-Debug -Message ('{0}: No connection to Autotask or running with -NoDiskCache. Loading using module supplied data for Get-AtwsFieldInfo.' -F $MyInvocation.MyCommand.Name )
          
            # Initialize the $Script:FieldInfoCache shorthand for base entity info
            $Script:FieldInfoCache = $Script:Atws.Cache['00'].FieldInfoCache
        }
    }
  
    end {
        Write-Verbose ('{0}: End of function' -F $MyInvocation.MyCommand.Name)    
    }
}