are begin block variables not global?

This topic contains 7 replies, has 2 voices, and was last updated by  Vern Anderson 3 years, 4 months ago.

  • Author
    Posts
  • #16544

    Vern Anderson
    Participant

    I'm having a problem in one of my scripts and a variable is not being seen after the end block closes. I had assumed that all my variables I setup in the begin block were global. Is this not the case?

    -VERN

  • #16545

    Dave Wyatt
    Moderator

    They're set in the scope of whatever script block contains the Begin block, by default. This could be a script, function, or anonymous script block. The only way that scope would be Global is if you had dot-sourced that script, function or scriptblock.

    Incidentally, this is what happens when you run something in the ISE by pressing F5. It's the same as if you'd dot-sourced your script at a console, so your "script" scope becomes global in that case, and any variables set are left behind after the script finishes.

  • #16557

    Vern Anderson
    Participant

    Thanks Dave,

    My script is here if you want to look it over. [url]http://vernanderson.wordpress.com/2014/04/28/zip-old-iis-log-files-based-on-age/[/url]

    The problem with it is that it was creating empty ZIPs so I was trying to use the $tempFolder variable in an if loop so that if the folder had no child items it would just exit. I wound up having to move the variable out of the begin block and further up to the top of the file below the help.

    Replacing line 73:
    [blockquote][System.IO.Compression.ZipFile]::CreateFromDirectory($tempFolder,$Destination,$compressionLevel,$includeBaseDirectory)[/blockquote]

    With this code:
    [blockquote] if ((Get-ChildItem $tempFolder).Length -lt 1) {Remove-Item $tempFolder -Recurse -Force -ErrorAction SilentlyContinue ; exit}
    else
    {
    [System.IO.Compression.ZipFile]::CreateFromDirectory($tempFolder,$Destination,$compressionLevel,$includeBaseDirectory)
    Remove-Item $tempFolder -Recurse -Force -ErrorAction SilentlyContinue
    } [/blockquote]

  • #16558

    Vern Anderson
    Participant

    I will be updating the script soon so that people don't use the buggy one.

  • #16559

    Dave Wyatt
    Moderator

    Can you attach a copy of the script here? Copying and pasting from the page you linked results in all of the code on a single line, for some reason.

  • #16574

    Vern Anderson
    Participant
    < #
    .Synopsis
       Compresses IIS logs based on provided age in days
    .DESCRIPTION
       Creates ZIP Archives in the default IIS log file path with a date code based on log file age adds those logs to the ZIP then removes the aged logs, also removes ZIP Archives based on a second parameter for ZIP file age in days.
       If you plan to run from a scheduled task un-remark the last line of the file and change the values to the desired number of days
    .EXAMPLE
       Zip-IISLogs -LogFileDays 30 -ZipFileDays 90
    .EXAMPLE
       Zip-IISLogs -LogFileDays  -ZipFileDays 
    .EXAMPLE
       If calling from the command line change the default values at the bottom of this script
    #>
    function Zip-IISLogs
    {
        [CmdletBinding()]    
        Param
        (
            # LogFileDays number of days old to archive and then delete
            [Parameter(Mandatory=$false,
                       ValueFromPipelineByPropertyName=$true,
                       Position=0)]
            $LogFileDays,
     
            # ZipFileDays number of days old to delete and remove the old ZIP files that are no longer needed
            [Parameter(Mandatory=$false,
                       ValueFromPipelineByPropertyName=$true,
                       Position=1)]
            $ZipFileDays
        )
     
        Begin
        {
        $LogFileDays = (Get-Date).AddDays(-$LogFileDays)
     
        # Setup some global variables
        $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
        $includeBaseDirectory = $false # if true creates a folder within a folder
        $defaultLogPath = Get-WebConfiguration -Filter system.applicationhost/sites/sitedefaults/logfile | Select-Object -ExpandProperty directory
     
        # TEMP foldername and filename variable
        $tempName = "IISLogs"+(Get-Date).ToShortDateString().Replace("/","-")
        $Destination = $defaultLogPath.Replace("%SystemDrive%",$env:SystemDrive)+"\"+$tempName+".zip"
        [System.IO.FileInfo]$tempFolder = $env:TEMP+"\"+$tempName
        New-Item -Path $tempFolder -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
     
        function Get-IISLogFilePath
        {
        # Load the PowerShell Module for IIS
        Import-Module WebAdministration
     
        $Sites = Get-ItemProperty 'IIS:\Sites\*'
        foreach ($Site in $Sites)
            {
            $SiteID = $Site.ID
            $LogPath = $Site.logFile.directory
            $Logpath = $LogPath.Replace("%SystemDrive%",$env:SystemDrive)
            "$LogPath"+'\W3SVC'+"$SiteID"
            }
        }
        }
        Process
        {
        $iisLogFolders = Get-IISLogFilePath
        foreach ($folder in $iisLogFolders)
            {
            Get-ChildItem $folder -Recurse -Include *.log | Where-Object {$_.LastWriteTime -le $LogFileDays} | Move-Item -Destination $tempFolder -Force
            }
     
        # Now create the zip file
        # Load the built in ZIP Assembly from Windows
        [Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )# Load the built in ZIP Assembly from Windows
        [System.IO.Compression.ZipFile]::CreateFromDirectory($tempFolder,$Destination,$compressionLevel,$includeBaseDirectory)
        Remove-Item $tempFolder -Recurse -Force -ErrorAction SilentlyContinue
     
        # Remove old ZIPs
        if ($ZipFileDays)
            {
            Get-ChildItem -Path $defaultLogPath.Replace("%SystemDrive%",$env:SystemDrive) -Include *.zip -Recurse | Where-Object {$_.LastWriteTime -le (Get-Date).AddDays(-$ZipFileDays)} | ForEach-Object {Remove-Item $_.FullName -Force}
            }
        }
        End
        {
        Clear-Host
        (Get-ChildItem $Destination).FullName
        }
    }
    # Remember to set your defaults below replace the variables with your numbers if you plan to run from a scheduled task then REMOVE the "#" from the last line
    # HINT: ZipFileDays 0 will NOT delete old ZIP files 
    Zip-IISLogs -LogFileDays 30 -ZipFileDays 120
  • #16575

    Dave Wyatt
    Moderator

    I don't see any problem with the scope of the $tempFolder variable. It should be usable right to the end of the function.

    It is a little bit odd that you have $LogFileDays listed as able to be passed via the pipeline, but you're using it in your Begin block. The function is also written in such a way that you could only ever really process one input record on the pipeline, so you should probably make that explicit and throw an error if two or more objects are encountered. These aren't really related to the problem you had with $tempFolder, but it's all that really jumped out at me.

    Here's a way that you could revise your code and not need to rely on $tempFolder in that particular step. Since you're already moving files in a loop anyway, I just added -Passthru to the Move-Item command, assigned the results to a variable and checked its count:

    
    function Zip-IISLogs
    {
        [CmdletBinding()]    
        Param
        (
            # LogFileDays number of days old to archive and then delete
            [Parameter(Mandatory=$false,
                       ValueFromPipelineByPropertyName=$true,
                       Position=0)]
            [UInt32] $LogFileDays = 0,
            
            # ZipFileDays number of days old to delete and remove the old ZIP files that are no longer needed
            [Parameter(Mandatory=$false,
                       ValueFromPipelineByPropertyName=$true,
                       Position=1)]
            [UInt32]
            $ZipFileDays = 0
        )
        
        Begin
        {
            # Setup some global variables
            $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
            $includeBaseDirectory = $false # if true creates a folder within a folder
            $defaultLogPath = Get-WebConfiguration -Filter system.applicationhost/sites/sitedefaults/logfile | Select-Object -ExpandProperty directory
            
            # TEMP foldername and filename variable
            $tempName = "IISLogs"+(Get-Date).ToShortDateString().Replace("/","-")
            $Destination = $defaultLogPath.Replace("%SystemDrive%",$env:SystemDrive)+"\"+$tempName+".zip"
            [System.IO.FileInfo]$tempFolder = $env:TEMP+"\"+$tempName
            New-Item -Path $tempFolder -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
            
            function Get-IISLogFilePath
            {
                # Load the PowerShell Module for IIS
                Import-Module WebAdministration
                
                $Sites = Get-ItemProperty 'IIS:\Sites\*'
                foreach ($Site in $Sites)
                {
                    $SiteID = $Site.ID
                    $LogPath = $Site.logFile.directory
                    $Logpath = $LogPath.Replace("%SystemDrive%",$env:SystemDrive)
                    "$LogPath"+'\W3SVC'+"$SiteID"
                }
            }
    
            $alreadyExecutedProcessBlock = $false
        }
        Process
        {
            if ($alreadyExecutedProcessBlock)
            {
                throw 'Only one object may be piped to Zip-IISLogs.'
            }
            else
            {
                $alreadyExecutedProcessBlock = $true
            }
    
            $oldestLogDate = (Get-Date).AddDays(-$LogFileDays)
            $iisLogFolders = Get-IISLogFilePath
    
            $movedLogs = @(
                foreach ($folder in $iisLogFolders)
                {
                    Get-ChildItem $folder -Recurse -Include *.log |
                    Where-Object { $_.LastWriteTime -le $oldestLogDate } |
                    Move-Item -Destination $tempFolder -Force -PassThru
                }
            )
    
            if ($movedLogs.Count -gt 0)
            {
                # Now create the zip file
                # Load the built in ZIP Assembly from Windows
                [Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )# Load the built in ZIP Assembly from Windows
                [System.IO.Compression.ZipFile]::CreateFromDirectory($tempFolder,$Destination,$compressionLevel,$includeBaseDirectory)
            }
    
            Remove-Item $tempFolder -Recurse -Force -ErrorAction SilentlyContinue
    
            # Remove old ZIPs
            if ($ZipFileDays)
            {   
                Get-ChildItem -Path ([Environment]::ExpandEnvironmentVariables($defaultLogPath)) -Include *.zip -Recurse |
                Where-Object {$_.LastWriteTime -le (Get-Date).AddDays(-$ZipFileDays)} |
                ForEach-Object {Remove-Item $_.FullName -Force}
            }
        }
        End
        {
            Clear-Host
            (Get-ChildItem $Destination).FullName
        }
    }
    
    # Remember to set your defaults below replace the variables with your numbers if you plan to run from a scheduled task then REMOVE the "#" from the last line
    # HINT: ZipFileDays 0 will NOT delete old ZIP files 
    Zip-IISLogs -LogFileDays 30 -ZipFileDays 120
    
  • #16577

    Vern Anderson
    Participant

    Thank you for catching the ValueFromPipelineByPropertyName param property I forgot to clean that up after using the Ctrl+J Snippet. I will just clean that up rather than handle errors for it because it was unintentional.

    I appreciate your time thanks Dave!

    -VERN

You must be logged in to reply to this topic.