Autotask.psm1
<#
.COPYRIGHT Copyright (c) Office Center Hønefoss AS. All rights reserved. Licensed under the MIT license. See https://github.com/officecenter/Autotask/blob/master/LICENSE.md for license information. #> [CmdletBinding()] Param( [Parameter( Position = 0 )] [pscredential] $Credential = $Global:AtwsCredential, [Parameter( Position = 1 )] [String] $ApiTrackingIdentifier = $Global:AtwsApiTrackingIdentifier, [Parameter( Position = 2, ValueFromRemainingArguments = $True )] [String[]] $EntityName = $Global:AtwsRefreshCachePattern ) Write-Debug ('{0}: Start of module import' -F $MyInvocation.MyCommand.Name) # Special consideration for -Verbose, as there is no $PSCmdLet context to check if Import-Module was called using -Verbose # and $VerbosePreference is not inherited from Import-Module for some reason. # Remove comments $ParentCommand = ($MyInvocation.Line -split '#')[0] # Store Previous preference $OldVerbosePreference = $VerbosePreference If ($ParentCommand -like '*-Verbose*') { Write-Debug ('{0}: Verbose preference detected. Verbose messages ON.' -F $MyInvocation.MyCommand.Name) $VerbosePreference = 'Continue' } $OldDebugPreference = $DebugPreference If ($ParentCommand -like '*-Debug*') { Write-Debug ('{0}: Debug preference detected. Debug messages ON.' -F $MyInvocation.MyCommand.Name) $DebugPreference = 'Continue' } # Read our own manifest to access configuration data $ManifestFileName = $MyInvocation.MyCommand.Name -replace 'pdm1$','psd1' $ManifestDirectory = Split-Path $MyInvocation.MyCommand.Path -Parent Write-Debug ('{0}: Loading Manifest file {1} from {2}' -F $MyInvocation.MyCommand.Name, $ManifestFileName, $ManifestDirectory) Import-LocalizedData -BindingVariable My -FileName $ManifestFileName -BaseDirectory $ManifestDirectory # Get all function files as file objects # Private functions can only be called internally in other functions in the module $PrivateFunction = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Found {1} script files in {2}\Private' -F $MyInvocation.MyCommand.Name, $PrivateFunction.Count, $PSScriptRoot) # Public functions will be exported with Prefix prepended to the Noun of the function name $PublicFunction = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Found {1} script files in {2}\Public' -F $MyInvocation.MyCommand.Name, $PublicFunction.Count, $PSScriptRoot) # Static functions will be exported with Prefix prepended to the Noun of the function name $StaticFunction = @( Get-ChildItem -Path $PSScriptRoot\Static\*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Found {1} script files in {2}\Static' -F $MyInvocation.MyCommand.Name, $StaticFunction.Count, $PSScriptRoot) # Static functions will be exported with Prefix prepended to the Noun of the function name $DynamicFunction = @( Get-ChildItem -Path $PSScriptRoot\Dynamic\*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Found {1} script files in {2}\Dynamic' -F $MyInvocation.MyCommand.Name, $DynamicFunction.Count, $PSScriptRoot) Write-Verbose ('{0}: Importing {1} Private and {2} Public functions.' -F $MyInvocation.MyCommand.Name, $PrivateFunction.Count, $PublicFunction.Count) # Loop through all script files and source them foreach ($Import in @($PrivateFunction + $PublicFunction)) { Write-Debug ('{0}: Importing {1}' -F $MyInvocation.MyCommand.Name, $Import) try { . $Import.fullname } catch { throw "Could not import function $($Import.fullname): $_" } } # If they tried to pass any variables If (($Credential) -or ($ApiTrackingIdentifier)) { Write-Verbose ('{0}: Credentials detected. Connecting to Autotask API' -F $MyInvocation.MyCommand.Name) # Remove Global variables (if used) for security If (Get-Variable -Name AtwsCredential -Scope Global -ErrorAction SilentlyContinue) { Write-Debug ('{0}: Credentials for {1} detected.' -F $MyInvocation.MyCommand.Name, $AtwsCredential.UserName) # Remove Global Object, credentials are now stored in a variable internal to the module Remove-Variable -Name AtwsCredential -Scope Global } If (Get-Variable -Name AtwsApiTrackingIdentifier -Scope Global -ErrorAction SilentlyContinue) { Write-Debug ('{0}: API tracking identifier for {1} detected.' -F $MyInvocation.MyCommand.Name, $AtwsCredential.UserName) # Remove Global Object, credentials are now stored in a variable internal to the module Remove-Variable -Name AtwsApiTrackingIdentifier -Scope Global } If (Get-Variable -Name AtwsRefreshCachePattern -Scope Global -ErrorAction SilentlyContinue) { Write-Debug ('{0}: Refreshing disk cache by force' -F $MyInvocation.MyCommand.Name) # Remove Global Object Remove-Variable -Name AtwsRefreshCachePattern -Scope Global } If (Get-Variable -Name AtwsNoDiskCache -Scope Global -ErrorAction SilentlyContinue) { Write-Debug ('{0}: Force No disk cache detected. All functions are loaded from the scripts supplied by the module.' -F $MyInvocation.MyCommand.Name) Write-Verbose ('{0}: Force No disk cache detected. All functions are loaded from the scripts supplied by the module.' -F $MyInvocation.MyCommand.Name) # Remove Global Object, credentials are now stored in a variable internal to the module Remove-Variable -Name AtwsNoDiskCache -Scope Global # Connect to the API using required, additional parameters, using internal function name . Connect-AtwsWebServices -Credential $Credential -ApiTrackingIdentifier $ApiTrackingIdentifier -NoDiskCache } Else { # Connect to the API using required, additional parameters, using internal function name . Connect-AtwsWebServices -Credential $Credential -ApiTrackingIdentifier $ApiTrackingIdentifier $DynamicCache = '{0}\WindowsPowershell\Cache\{1}\Dynamic' -f $([environment]::GetFolderPath('MyDocuments')), $Script:Atws.CI If (Test-Path $DynamicCache) { $FunctionCount = $DynamicFunction.Count $DynamicFunction = @( Get-ChildItem -Path $DynamicCache\*atws*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Personal disk cache: Found {1} script files in {2}' -F $MyInvocation.MyCommand.Name, $DynamicFunction.Count, $DynamicCache) $VersionString = "#Version {0}" -F $My.ModuleVersion $ScriptVersion = Select-String -Pattern $VersionString -Path $DynamicFunction.FullName If ($ScriptVersion.Count -ne $FunctionCount) { Write-Debug ('{0}: Personal disk cache: Wrong number of script files or scripts are not the right version in {1}, refreshing all entities.' -F $MyInvocation.MyCommand.Name, $DynamicCache) # Clear out old cache, it will be recreated $Null = Remove-Item -Path $DynamicFunction.fullname -Force -ErrorAction SilentlyContinue # Refresh ALL dynamic entities. $EntityName = '*' } $OldFunctions = @(Get-ChildItem -Path $DynamicCache\*.ps1 -Exclude *Atws* -ErrorAction SilentlyContinue) If ($OldFunctions.Count -gt 0) { Write-Debug ('{0}: Personal disk cache: Found {1} old script files in {2}. Deleting.' -F $MyInvocation.MyCommand.Name, $OldFunctions.Count, $DynamicCache) $Null = Remove-Item -Path $OldFunctions.fullname -Force -ErrorAction SilentlyContinue } } Else { Write-Debug ('{0}: Personal disk cache {1} does not exist. Forcing load of all dynamic entities.' -F $MyInvocation.MyCommand.Name, $DynamicCache) # No personal dynamic cache. Refresh ALL dynamic entities. $EntityName = '*' } # Refresh any entities the caller has ordered # We only consider entities that are dynamic $Entities = Get-AtwsFieldInfo -Dynamic $EntitiesToProcess = @() Write-Debug ('{0}: {1} dynamic entities are eligible for refresh.' -F $MyInvocation.MyCommand.Name, $DynamicCache) Foreach ($String in $EntityName) { Write-Debug ('{0}: Selecting entities that match pattern "{1}"' -F $MyInvocation.MyCommand.Name, $String) $EntitiesToProcess += $Entities.GetEnumerator().Where({$_.Key -like $String}) } # Prepare Index for progressbar $Index = 0 $ProgressParameters = @{ Activity = 'Updating diskcache for requested entities.' Id = 10 } # Make sure we only check each possible entity once $EntitiesToProcess = $EntitiesToProcess | Sort-Object -Property Name -Unique Write-Debug ('{0}: {1} entities have been selected for refresh' -F $MyInvocation.MyCommand.Name, $EntitiesToProcess.Count) Foreach ($EntityToProcess in $EntitiesToProcess) { $Index++ $PercentComplete = $Index / $EntitiesToProcess.Count * 100 # Add parameters for @splatting $ProgressParameters['PercentComplete'] = $PercentComplete $ProgressParameters['Status'] = 'Entity {0}/{1} ({2:n0}%)' -F $Index, $EntitiesToProcess.Count, $PercentComplete $ProgressParameters['CurrentOperation'] = 'Getting fieldinfo for {0}' -F $EntityToProcess.Name Write-Progress @ProgressParameters $null = Get-AtwsFieldInfo -Entity $EntityToProcess.Key -UpdateCache } If ($EntitiesToProcess.Count -gt 0) { Write-Debug ('{0}: Calling Import-AtwsCmdLet with {1} entities to process' -F $MyInvocation.MyCommand.Name, $EntitiesToProcess.Count) # Recreate functions that have been updated Import-AtwsCmdLet -Entities $EntitiesToProcess # Re-read Dynamic functions $DynamicFunction = @( Get-ChildItem -Path $DynamicCache\*atws*.ps1 -ErrorAction SilentlyContinue ) Write-Debug ('{0}: Personal disk cache: Found {1} script files in {2}' -F $MyInvocation.MyCommand.Name, $DynamicFunction.Count, $DynamicCache) } } Write-Verbose ('{0}: Importing {1} Static and {2} Dynamic functions.' -F $MyInvocation.MyCommand.Name, $StaticFunction.Count, $DynamicFunction.Count) # Loop through all script files and source them foreach ($Import in @($StaticFunction + $DynamicFunction)) { Write-Debug ('{0}: Importing {1}' -F $MyInvocation.MyCommand.Name, $Import) try { . $Import.fullname } catch { throw "Could not import function $($Import.fullname): $_" } } # Explicitly export public functions Write-Debug ('{0}: Exporting {1} Public functions.' -F $MyInvocation.MyCommand.Name, $PublicFunction.Count) Export-ModuleMember -Function $PublicFunction.Basename # Explicitly export static functions Write-Debug ('{0}: Exporting {1} Static functions.' -F $MyInvocation.MyCommand.Name, $StaticFunction.Count) Export-ModuleMember -Function $StaticFunction.Basename # Explicitly export dynamic functions Write-Debug ('{0}: Exporting {1} Dynamic functions.' -F $MyInvocation.MyCommand.Name, $DynamicFunction.Count) Export-ModuleMember -Function $DynamicFunction.Basename } Else { Write-Verbose 'No Credentials were passed with -ArgumentList. Loading module without any connection to Autotask Web Services. Use Connect-AtwsWebAPI to connect.' Export-ModuleMember -Function 'Connect-AtwsWebAPI' } # Backwards compatibility since we are now trying to use consistent naming Set-Alias -Scope Global -Name 'Connect-AutotaskWebAPI' -Value 'Connect-AtwsWebAPI' # Restore Previous preference If ($OldVerbosePreference -ne $VerbosePreference) { Write-Debug ('{0}: Restoring old Verbose preference' -F $MyInvocation.MyCommand.Name) $VerbosePreference = $OldVerbosePreference } If ($OldDebugPreference -ne $DebugPreference) { Write-Debug ('{0}: Restoring old Debug preference' -F $MyInvocation.MyCommand.Name) $DebugPreference = $OldDebugPreference } |