My Technical Notes

Wednesday, 30 December 2015

PowerShell ImportObject Script

re-write this


Param([string]$dataFileName, [string]$destinationTableName, [string]$typeDefinitionFileName, [string]$columnsDefinitionFileName, [bool]$useDefaultFieldNames = $false, [bool]$identifySplitLines = $false, [int]$thousandSleepInMs = 1000, [string]$jobName = "ImportJob")

$ErrorActionPreference = 'Stop'

$Global:importLogDir = & "$PSScriptRoot\Get-LogPath.ps1" $dataFileName $destinationTableName
$infoLogPath = "$importLogDir\info_log.txt"
$errorLogPath = "$importLogDir\error_log.txt"

$infoLogPath,$errorLogPath | % { if (Test-Path $_) { Remove-Item $_ } }

# $Global:importProcess = Start-Process powershell.exe -ArgumentList @("'$PSScriptRoot\Import.ps1'", $dataFileName, $destinationTableName, $typeDefinitionFileName, $columnsDefinitionFileName, $useDefaultFieldNames, $identifySplitLines, $thousandSleepInMs, $jobName) -PassThru

Function ParamArgSpec([string]$variableName) {
    $value = (Get-Variable $variableName).Value
    
    if (($value -eq $null) -or ($value -is [string] -and [string]::IsNullOrWhiteSpace($value))) {
        # return nothing
    } elseif ($value -is [string]) {
        return "-$variableName '$value'"
    } elseif ($value -is [bool]) {
        return "-$variableName  `$$value"
    } else {
        return "-$variableName $value"
    }
}
# http://stackoverflow.com/a/17869001/288393
# could use $PSBoundParameters instead
[string[]]$paramsList = & {
    "&"
    "'$PSScriptRoot\Import.ps1'"
    'dataFileName','destinationTableName','typeDefinitionFileName','columnsDefinitionFileName','useDefaultFieldNames','identifySplitLines','thousandSleepInMs','jobName' | % { ParamArgSpec($_) }
};

$scriptParameter = '"' + [string]::Join(" ", $paramsList) + '"';

$importProcess = Start-Process powershell.exe -ArgumentList '-Command',$scriptParameter -PassThru

$import = New-Object PSObject 

$import | Add-Member NoteProperty Invocation $MyInvocation.Line

$import | Add-Member NoteProperty InfoLogPath $infoLogPath
$import | Add-Member NoteProperty ErrorLogPath $errorLogPath

$import | Add-Member Process $importProcess

$import | Add-Member ScriptMethod TailWaitInfoLog {
    Tail -Wait $this.InfoLogPath;
}

$import | Add-Member ScriptMethod TailWaitErrorPath {
    Tail -Wait $this.ErrorLogPath;
}

$import | Add-Member ScriptMethod KillProcess {
    Stop-Process -Id $this.Process.Id -Force
}

return $import;

Param([string]$dataFileName, [string]$destinationTableName, [string]$typeDefinitionFileName, [string]$columnsDefinitionFileName, [bool]$useDefaultFieldNames = $false, [bool]$identifySplitLines = $false, [int]$thousandSleepInMs = 1000, [string]$jobName = "ImportJob") 
# note that the $identifySplitLines is false in this script, but the default argument to PamisArchive.DataImport.PamisArchive_DataImporter.ImportFile is true

# make this ErrorActionPreference variable globally to stop?
$ErrorActionPreference = 'Stop'

$root = if ($PSScriptRoot) { $PSScriptRoot } else { "." }

$ErrorActionPreference = 'Stop'

# print out parameter values:
# $m -split ',' | str-trim | Str-From '$' | Str-To-F '=' | str-trim | % { "Write-Host `"$_`: `$$_`"" } | cb
# $m -split ',' | str-trim | Str-From '$' | Str-To-F '=' | str-trim | % { "`"$_`: `$$_`" | Out-File `"C:\Temp\log.txt`" -Append" } | cb

$dataImportConfigPath = "C:\_svn\PamisArchive\PamisArchive.DataImport.ConsoleApp\App.config"

$logDir = & "$root\Get-LogPath.ps1" $dataFileName $destinationTableName
$binDir = "C:\_svn\PamisArchive\PamisArchive.DataImport.ConsoleApp\bin\Debug";

$nlogXmlConfigTemplate = '<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd">
        <variable name="logDir" value="LOG_DIR_PLACEHOLDER"/>
        <variable name="layout" value="${longdate}|${level:uppercase=true}|${callsite}|${message}"/>
        <targets>
            <target xsi:type="Debugger" name="debugger" layout="${layout}" />
            <target xsi:type="File" name="infoLog" fileName="${logDir}\info_log.txt" layout="${layout}" deleteOldFileOnStartup="false"/>
            <target xsi:type="File" name="errorLog" fileName="${logDir}\error_log.txt" layout="${layout}" deleteOldFileOnStartup="false"/>
            <target xsi:type="File" name="recordErrorLog" fileName="${logDir}\recordError_log.txt" layout="${longdate}|${level:uppercase=true}|${callsite}|${message} ${exception:format=Type,Message,StackTrace}" deleteOldFileOnStartup="false"/>
        </targets>

        <rules>
            <logger name="*" minlevel="Trace" writeTo="debugger" />
            <logger name="recordErrorLogger" final="true" writeTo="recordErrorLog" />
            <logger name="*" minlevel="Debug" maxlevel="Warn" writeTo="infoLog" />
            <logger name="*" minlevel="Error" writeTo="errorLog" />
        </rules>
    </nlog>'

Add-Type -AssemblyName System.Configuration
Add-Type -Path "$binDir\NLog.dll"
Add-Type -Path "$binDir\PamisArchive.DataImport.dll"

Function StrVal([string]$x) {
    if ([string]::IsNullOrWhiteSpace($x)) {
        return [System.Management.Automation.Language.NullString]::Value;
    } else {
        return $x.Trim();
    }
}

Function SetAppConfig([string]$Path) {
    [AppDomain]::CurrentDomain.SetData('APP_CONFIG_FILE', $Path)

    [Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
    [Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
    ([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"})[0].GetField("s_current", "NonPublic, Static").SetValue($null, $null)
}

# START create empty log folder with default log file
if (-not (Test-Path $logDir)) {
    mkdir $logDir | Out-Null
} else {
    Remove-Item "$logDir\*" -Recurse -Force
}

New-Item -ItemType File "$logDir\info_log.txt" | Out-Null

# Touch-File "$logDir\info_log.txt" | Out-Null # because touch-file is a dependency
# END create empty log folder with default log file

SetAppConfig -Path $dataImportConfigPath # set the script to read from app.config
    
# START set up the NLog configuration using code
$nlogXmlConfig =  $nlogXmlConfigTemplate -replace "LOG_DIR_PLACEHOLDER",$logDir

[NLog.LogManager]::Configuration = New-Object NLog.Config.XmlLoggingConfiguration @( [System.Xml.XmlReader](New-Object System.Xml.XmlNodeReader ([xml]$nlogXmlConfig)), ".")

$logger = [NLog.LogManager]::GetLogger('PsLogger');
$logger.Info("PS: Starting Import for $dataFileName, $destinationTableName, $( if ($useDefaultFieldNames) { "using default names" } elseif ($typeDefinitionFileName) { $typeDefinitionFileName } else { $columnsDefinitionFileName })");
[NLog.LogManager]::Flush();

# END set up the NLog configuration using code

$config = [System.Configuration.ConfigurationManager]

$dataImporter = New-Object PamisArchive.DataImport.PamisArchive_DataImporter @(<# cn #> $config::ConnectionStrings["PamisArchiveConnectionString"].ConnectionString, 
    <#data dir #> $config::AppSettings["PAMIS.Data"], 
    <# column DefinitionsDir #> $config::AppSettings["PAMIS.ColumnDefinitions"], 
    <# typeDefinitionsDir #> $config::AppSettings["PAMIS.TypeDefinitions"])
    
$dataImporter.ImportFile(
    <# dataFileName #> $dataFileName,
    <# tableName #> $destinationTableName,
    <# columnsFileName = null #> (StrVal $columnsDefinitionFileName),
    <# typeDefinitionFileName = null #> (StrVal $typeDefinitionFileName),
    <# useDefaultFieldNames = false #> $useDefaultFieldNames,
    <# identifySplitLines = true #> $identifySplitLines,
    <# thousandSleepInMs = 0 #> $thousandSleepInMs)

To be redone:

  • http://tahirhassan.blogspot.co.uk/2015/12/start-process-powershellexe-with.html
  • http://tahirhassan.blogspot.co.uk/2015/12/powershell-start-script-and-then-kill-it.html

No comments: