Private/Import-AtwsCmdLet.ps1


Function Import-AtwsCmdLet
{
  [CmdLetBinding(
      SupportsShouldProcess = $True,
      ConfirmImpact = 'Medium'
  )]
  Param
  (
    [Parameter(Mandatory = $True)]
    [String]    
    $ModuleName,
    
    [Switch]
    $NoDiskCache,
    
    [Switch]
    $RefreshCache,
    
    [String]
    $Prefix = 'Atws'
  )
  
  Begin
  { 
    If (-not($global:AtwsConnection[$Prefix].Url))
    {
      Throw [ApplicationException] 'Not connected to Autotask WebAPI. Run Connect-AutotaskWebAPI first.'
    }
    Else
    {
      $local:Atws = $global:AtwsConnection[$Prefix]
    }
    
    Write-Verbose -Message ('{0}: Calling API.EntityInfo() to get list over available entities.' -F $MyInvocation.MyCommand.Name)
    
    $Caption = $MyInvocation.MyCommand.Name
    $VerboseDescrition = '{0}: Calling API.EntityInfo()' -F $Caption
    $VerboseWarning = '{0}: About to call API.EntityInfo(). Do you want to continue?' -F $Caption

    If ($PSCmdlet.ShouldProcess($VerboseDescrition, $VerboseWarning, $Caption))
    {
      $Entities = $Atws.getEntityInfo()
    }
    Else
    {
      $Entities = @()
    }
    
    # A hashtable to keep track of fieldinfo pr entity. Keep it in the script and called functions
    $Script:FieldTable = @{}
    
    # An array to contain text that will be converted to a scriptblock
    $ModuleFunctions = @()
    
    $CacheInfo = Get-AtwsCacheInfo -Prefix $Prefix 
  } 
  
  Process
  {

    If ($CacheInfo.CacheDirty -or $NoDiskCache.IsPresent -or $RefreshCache.IsPresent)
    { 
      Write-Verbose -Message ('{0}: Generating new functions (CacheDirty: {1}, NoDiskCache: {2}, RefreshCache: {3}) ' -F $MyInvocation.MyCommand.Name,$CacheInfo.CacheDirty.ToString(), $NoDiskCache.IsPresent.ToString(), $RefreshCache.IsPresent.ToString())
      
      $Activity = 'Downloading detailed information about all Autotask entity types'
      $ParentId = 1
      
      

      Foreach ($Entity in $Entities)
      { 
        Write-Verbose -Message ('{0}: Importing detailed information about Entity {1}' -F $MyInvocation.MyCommand.Name, $Entity.Name) 
        
        $FieldTable[$Entity.Name] = Get-AtwsFieldInfo -Entity $Entity.Name

        # Calculating progress percentage and displaying it
        $Index = $Entities.IndexOf($Entity) +1
        $PercentComplete = $Index / $Entities.Count * 100
        $Status = 'Entity {0}/{1} ({2:n0}%)' -F $Index, $Entities.Count, $PercentComplete
        $CurrentOperation = "GetFieldInfo('{0}')" -F $Entity.Name
        Write-Progress -ParentId $ParentId -Activity $Activity -Status $Status -PercentComplete $PercentComplete -CurrentOperation $CurrentOperation
      
        $VerboseDescrition = '{0}: Creating and Invoking functions for entity {1}' -F $Caption, $Entity.Name
        $VerboseWarning = '{0}: About to create and Invoke functions for entity {1}. Do you want to continue?' -F $Caption, $Entity.Name
      }
      
      $Activity = 'Creating and importing functions for all Autotask entities.'
            
      Foreach ($Entity in $Entities)
      {
        Write-Verbose -Message ('{0}: Creating functions for entity {1}' -F $MyInvocation.MyCommand.Name, $Entity.Name) 
      
        # Calculating progress percentage and displaying it
        $Index = $Entities.IndexOf($Entity) +1
        $PercentComplete = $Index / $Entities.Count * 100
        $Status = 'Entity {0}/{1} ({2:n0}%)' -F $Index, $Entities.Count, $PercentComplete
        $CurrentOperation = 'Importing {0}' -F $Entity.Name
        
        Write-Progress -ParentId $ParentId -Activity $Activity -Status $Status -PercentComplete $PercentComplete -CurrentOperation $CurrentOperation
      
        $VerboseDescrition = '{0}: Creating and Invoking functions for entity {1}' -F $Caption, $Entity.Name
        $VerboseWarning = '{0}: About to create and Invoke functions for entity {1}. Do you want to continue?' -F $Caption, $Entity.Name
       
        $FunctionDefinition = Get-AtwsFunctionDefinition -Entity $Entity -Prefix $Prefix -FieldInfo $FieldTable[$Entity.Name] 
        
        If ($PSCmdlet.ShouldProcess($VerboseDescrition, $VerboseWarning, $Caption))
        { 
          Foreach ($Function in $FunctionDefinition.GetEnumerator())
          {
  
            If (-Not $NoDiskCache.IsPresent)
            {
              Write-Verbose -Message ('{0}: Writing file for function {1}' -F $MyInvocation.MyCommand.Name, $Function.Key)
                        
              $FilePath = '{0}\{1}.ps1' -F $CacheInfo.CacheDir, $Function.Key
          
              $VerboseDescrition = '{0}: Overwriting {1}' -F $Caption, $FilePath
              $VerboseWarning = '{0}: About to overwrite {1}. Do you want to continue?' -F $Caption, $FilePath

              If ($PSCmdlet.ShouldProcess($VerboseDescrition, $VerboseWarning, $Caption))
              {
                Set-Content -Path $FilePath -Value $Function.Value -Force -Encoding UTF8
              }
            }
                 
            $ModuleFunctions += $Function.Value
          }
          
        }
      }        
      
                
      Write-Verbose -Message ('{0}: Writing Moduleversion info to {1}' -F $MyInvocation.MyCommand.Name, $CacheInfo.CachePath)
                
      $ModuleVersionInfo = New-Object -TypeName PSObject -Property @{
        APIversion = $CacheInfo.APIversion
        ModuleVersion = $CacheInfo.ModuleVersion
        CI = $CacheInfo.CI
      }
                    
      Export-Clixml -InputObject $ModuleVersionInfo -Path $CacheInfo.CachePath -Encoding UTF8
      Write-Progress -ParentId $ParentId -Activity $Activity -Completed

    }
    Else
    {
      Write-Verbose -Message ('{0}: Reading function definitions from {1}' -F $MyInvocation.MyCommand.Name, $CacheInfo.CachePath)
      $CacheFiles = '{0}\*.ps1' -F $CacheInfo.CacheDir
      Foreach ($File in Get-ChildItem -Path $CacheFiles)
      { 
        $ModuleFunctions += Get-Content -Path $File.FullName -Encoding UTF8 -Raw
      }
    }
    
    Write-Verbose -Message ('{0}: Including private functions in dynamic module' -F $MyInvocation.MyCommand.Name)   
    
    $PrivateFunctions = @(
      'Get-AtwsInvoiceInfo',
      'Get-CallerPreference',
      'ConvertTo-PSObject',
      'Get-AtwsFieldInfo'
    ) 

    Foreach ($FunctionName in $PrivateFunctions) {
    
      # Prepare a new function name with current prefix
      $NewFunctionName = $FunctionName -replace '-Atws', "-$Prefix"
      
      # Get Command info
      $Command = Get-Command -Name $FunctionName -Module Autotask

      #
      $ModuleFunctions += $Command.ScriptBlock.Ast -replace '#Prefix', $Prefix -replace $FunctionName,$NewFunctionName
    }

  }
  End
  {
    Write-Verbose -Message ('{0}: Importing Autotask Dynamic Module' -F $MyInvocation.MyCommand.Name)
    
    # Have PowerShell convert all of our dynamically generated code to a scriptblock
    # (no error checks! Well, you probably notice if something goes wrong...)
    $FunctionScriptBlock = [ScriptBlock]::Create($($ModuleFunctions))
        
    # Simply import the scriptblock as a module. Simple as that. I cannot decide if this is
    # awesome or scary as h...!
    New-Module -Name $ModuleName -ScriptBlock $FunctionScriptBlock  | Import-Module -Global         
    
  }
}