Hello Fellow PowerShellers,
I'm not sure exactly when this started happening, but I have a script that moves locally archived event logs to network storage.
There are two functions in the script - Collect-Logs and 7zip-Logs. Each of these are recursively called from themselves, as well as at the bottom of the script that actually starts the process.
They kick off the first time through, but when they are called again, the script cannot find them. I've never had to before, but should I specify the function as global? If I open the script in notepad/notepad++ what have you, copy the text and paste it into a powershell console, it works as expected. It'll run from within ISE as well.
Edit: Here is the script =>
# Script to collect archived event logs from servers. When each job is started, an event is created to 'watch' for a change in job status.
# When a job completes, the next one in queue is automatically started.
Function Collect-Logs
{
if($Collectqueue.count -gt 0)
{
$item=$Collectqueue.dequeue()
$jobtype=$item[0]
$source=$item[1]
$destination=$item[2]
$server=$source.split('\')[2]
$jobname="$($server)_$($jobtype)"
if($jobtype -like "*Logs*")
{
$j=start-job -name $jobname -scriptblock {param($x,$y) robocopy $x $y /np /z /r:0 /w:0 /ndl /njh /njs /xx /s} -argumentlist $source,$destination
Write-host "Job $jobname started"
Register-ObjectEvent -InputObject $j -EventName StateChanged -Action {
Write-host ('Job#{0} ({1}) complete' -f $sender.id,$sender.name) -fore white -back red
Collect-Logs
Unregister-Event $eventsubscriber.SourceIdentifier
Remove-Job $eventsubscriber.SourceIdentifier }|out-null
}
else
{
$j=start-job -name $jobname -scriptblock {param($x,$y) robocopy $x $y /is /np /z /r:0 /w:0 /ndl /njh /njs /xx /mov /if archive*.*} -argumentlist $source,$destination
Write-host "Job $jobname started"
Register-ObjectEvent -InputObject $j -EventName StateChanged -Action {
Write-host ('Job#{0} ({1}) complete' -f $sender.id,$sender.name) -fore white -back red
Collect-Logs
Unregister-Event $eventsubscriber.SourceIdentifier
Remove-Job $eventsubscriber.SourceIdentifier }|out-null
}
}
}
#************************************************************************************************************************************
# This function compresses logs older than (today - 30 days) to .7z (7-zip) archives. When each job
# completes, the next is automatically loaded from the queue.
Function 7Zip-Logs
{
if($Zipqueue.count -gt 0)
{
$data=$Zipqueue.dequeue()
#$proc+=$data
$files=@($data.group|select -expandproperty fullname)
$datestring="{0}{1}{2}" -f $data.values[2..4]
$server=$data.values[0]
$log=$data.values[1]
$target="\\fileserver\eventlog_archive\archived\$($server)\$($server)-$($log)_$($datestring).7z"
$jobname="$($server)$($log)$($datestring)"
Write-Host "Starting job: $jobname"
$j=Start-Job -name $jobname -ScriptBlock {c:\7zip\7z.exe a -m0=PPMd -sdel -stl -mx9 -ms=off -mmt=on $args[0] @($args[1])} -argumentlist $target,$files
Register-ObjectEvent -InputObject $j -EventName StateChanged -Action {
Write-Host ('Job#{0} ({1}) complete' -f $sender.id,$sender.name) -fore white -back red
7zip-Logs
Unregister-Event $eventsubscriber.sourceidentifier
remove-job $eventsubscriber.sourceidentifier}|out-null
}
}
#************************************************************************************************************************************
# Generate a list of servers then build the queue
$list=@()
$searcher=[adsisearcher]"(&(objectcategory=computer)(operatingsystem=*windows server*))"
$searcher.findall()|sort {$_.properties.name}|%{
$list+=$_.properties
}
$2k3path="admin$\system32\config"
$2k8path="admin$\system32\winevt\logs"
$syslogs="admin$\system32\logfiles"
$Collectqueue=[system.collections.queue]::synchronized( (new-object system.collections.queue) )
$Zipqueue=[system.collections.queue]::synchronized( (new-object system.collections.queue) )
# Populate the queues
#
# Log collection
foreach($server in $list)
{
Write-host "$($server.name)"
$logdest="\\fileserver\eventlog_archive\$($server.name)"
if((get-item \\$($server.name)\$2k8path\archive* -erroraction silentlycontinue).count -gt 0){$Collectqueue.enqueue(@("Events","\\$($server.name)\$2k8path","$logdest\Events"))}
$Collectqueue.enqueue(@("SysLogs","\\$($server.name)\$syslogs","$logdest\SysLogs"))
if(test-path "\\$($server.name)\l$\*log*" -erroraction silentlycontinue)
{
gi \\$($server.name)\l$\*log* -erroraction silentlycontinue|select -expandproperty fullname|%{$Collectqueue.enqueue(@("LogFiles",$_,"$logdest\LogFiles"))}
}
}
# Archiving
# Collect and add items to queue
# Get a list of containers in the archive - Except the one containing the 'really archived' files. Then for each of those,
# collect all windows event log files whose 'lastwritetime' is less than [today] - 30 days. Group these by directory name, log type (security, application, etc),
# year, month, and day. Add each group to the queue.
gci \\fileserver\eventlog_archive -exclude archived|?{$_.psiscontainer}|%{
$server=$_.name
Write-Host "Loading files from $_"
#gci "$($_.fullname)\archive*" -recurse|?{$_.lastwritetime -le (get-date).adddays(-30)}|group-object {$server},{($_.name).split('-')[1]},{$_.lastwritetime.year.tostring()},`
#{$_.lastwritetime.month.tostring().padleft(2).replace(' ','0')},{$_.lastwritetime.day.tostring().padleft(2).replace(' ','0')}}|sort count -descending|%{$Zipqueue.enqueue($_)}
gci "$($_.fullname)\archive*" -recurse|
Where-object {[datetime]"$($_.name.split('-')[3,4,2]-join('/')) $($_.name.split('-')[5..7]-join(':'))" -lt (get-date).adddays(-30)}|
Group-Object {$server},{$_.name.split('-')[1]},{$_.name.split('-')[2]},{$_.name.split('-')[3]},{$_.name.split('-')[4]}}|sort count -descending|%{$zipqueue.enqueue($_)}
#*********************************************************************************************************
# Do the work
while(((get-job -state running).count -lt 8) -and (($collectqueue.count) + ($zipqueue.count)) -gt 0)
{
Collect-Logs
7Zip-Logs
}