1

I have the following code which is parsing an XML file in PowerShell, and then iterating through the entries in the config file (which are backup jobs) and performing backups (by calling functions).

if ($xmlfile.configuration.DBAndFilesBackup.item("MSSQL").haschildnodes) {
    $xmlfile.configuration.DBAndFilesBackup.MSSQL.backup | 
        Start-RSJob -Name {$_.Name} -Throttle 2  -ScriptBlock {
            # Begin the Backup
            BeginBackup $_.Name $log

            # Backup the mssql database
            MSSQLBackup $_.Name $_.DBPath $Using:backupdir $Using:backuptempdir

            # Backup the files
            FilesBackup $_.Name $_.FolderName $_.FilesPath $Using:backupdir $Using:backuptempdir

            # End the Backup
            EndBackup $_.FolderName $_.Name $log $Using:emailTo $Using:backupdir $Using:backuptempdir
        } -FunctionsToLoad BeginBackup,MSSQLBackup,FilesBackup,EndBackup,Mailer,PrintHeader |
        Wait-RSJob |
        Receive-RSJob |
        Out-file "$ScriptDir\logs\corebackup\$ScriptName $($xmlfile.configuration.DBAndFilesBackup.MSSQL.backup.Name) $DateStamp.log"
}

Start-RSJob is a custom PowerShell module similar to the Start-Job cmdlet that handles kicking off parallel jobs.

Both RSJob and the native PowerShell Start-Job cmdlet don't seem to handle PowerShell transcription (logging). Thus I'm utilizing Write-Output, in addition to Out-File to capture the output of the jobs.

The problem I've run into is that in the Write-Output portion of the script I want to include the name of the backup in the log file name. In other words I end up with a file named "corebackup 2015-08-24.log" instead of "corebackup backupname 2015-08-24.log".

The issue is how do I pass $_.Name to Out-File. Right now a log is written, but without the job name.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Brad
  • 1,979
  • 7
  • 35
  • 47

3 Answers3

2

Then wrap it in the other For-EachObject block and assign $_.Name to a variable accessible outside the pipeline. I've looked at the Start-RsJob docs and it should work:

if ($xmlfile.Configuration.DBAndFilesBackup.Item('MSSQL').HasChildNodes) {

    $xmlfile.Configuration.DBAndFilesBackup.MSSQL.Backup | ForEach-Object {
        $BackupName = $_.Name
        $_ | Start-RSJob -Name $BackupName -Throttle 2  -ScriptBlock {

                # Begin the Backup
                BeginBackup $_.Name $log

                # Backup the mssql database
                MSSQLBackup $_.Name $_.DBPath $Using:backupdir $Using:backuptempdir

                # Backup the files
                FilesBackup $_.Name $_.FolderName $_.FilesPath $Using:backupdir $Using:backuptempdir

                # End the Backup
                EndBackup $_.FolderName $_.Name $log $Using:emailTo $Using:backupdir $Using:backuptempdir

            } -FunctionsToLoad BeginBackup,MSSQLBackup,FilesBackup,EndBackup,Mailer,PrintHeader |
                Wait-RSJob |
                    Receive-RSJob |
                        Out-File "$ScriptDir\logs\corebackup\$ScriptName $BackupName $DateStamp.log"
    }
}

P.S. I'm using this module for logging, it captures any output from PS console: Enhanced Script Logging module:

Automatically copy PowerShell console output to a log file (from Output, Error, Warning, Verbose and Debug streams), while still displaying the output at the console. Log file output is prepended with date/time and an indicator of which stream originated the line.

beatcracker
  • 6,714
  • 1
  • 18
  • 41
  • 1
    Not sure if that will work since `$Name` won't be define within the scritpblock when its executed by the job. I recommend using `-ArgumentList` instead and setting it using the `$args` array. – Carlos Nunez Aug 25 '15 at 04:28
  • @CarlosNunez Yep, scriptblocks are tricky, but I'm still not sure where other variables in scriptblock come from (`$_.FolderName`, `$_.FilesPath`, etc) – beatcracker Aug 25 '15 at 09:53
  • The other variables in the script block are coming from the xml config file. So the xml looks something like this: – Brad Aug 25 '15 at 11:31
  • Setting $Name = $_.Name outside of the scriptblock won't work because its not defined at that point. $_.Name is actually $xmlfile.configuration.DBAndFilesBackup.MSSQL.backup.Name. So the above attempts to define it before its defined. – Brad Aug 25 '15 at 11:41
  • Also $xmlfile.configuration.DBAndFilesBackup.MSSQL.backup.Name isn't a single item as far as I know. Its several xml entries from the config file. – Brad Aug 25 '15 at 11:41
  • @Brad Check updated code, I think it should work now. – beatcracker Aug 25 '15 at 12:11
  • The above code seems to resolve the log file naming issue BUT i think it's broken the throttling. The xml file contains for example three entries and when i set the throttle to 1 - i see two log files created simultaneously. – Brad Aug 25 '15 at 16:14
  • Actually its interesting - the log files are all created simultaneously - but the backup directories are only created one at at a time - regardless of weather I set throttle to 1 or 2. – Brad Aug 25 '15 at 16:34
2

Try this:

Start-RSJob -ArgumentList @($Name) -Throttle 2 -ScriptBlock {
    $Name = $args[0]
    ...
}
Carlos Nunez
  • 2,047
  • 1
  • 18
  • 20
  • @That'll fix the scriptblock, but it still wouldn't get `$_.Name` to the `Out-File` cmdlet. But if we combine your code with mine, that should work: assign variable beforehand, pass it to the scriptblock in `ArgumentList` and then use it in `Out-File`. – beatcracker Aug 25 '15 at 09:48
0

I wasn't able to get any of the above working with throttling. In other words I could get output but then throttling broke, or i could make throttling work but not get output.

The solution I ended up using was to add a bunch of "Write-Output | Out-file $log -Append" to my script every time I want to output something.

Kinda ugly hack - but by using that inside of the scriptblock I can capture the output.

Thanks to everyone for their help and advise.

Brad
  • 1,979
  • 7
  • 35
  • 47