Clearing the Archive Attribute Bit

I use a whole set of PowerShell scripts to create my lab environment when I’m working on a book or article. The master scripts all reside in a Build directory on my labhost. The problem is that when something goes wonky, or I need to tweak a script to do something a bit different, I’m usually working from the lab client, not the host. What I don’t want to do is lose any changes I’ve made if I blow away a client (which happens fairly often in a lab!) So I try to remember to copy the change up to the master Build directory. But that’s not 100%, so I wanted a quick way to copy only the changed files back up to the host. The easy way to do it should be using the filesystem’s Archive attribute bit, but it turns out Windows PowerShell is just plain brain-dead about how it handles file attributes. You have to resort to binary ANDs and binary XORs to manipulate them. Well, that’s just not fun. So, having spent the time to get it working, I thought I’d just share the script I use to clear the Archive attribute for one or many files. Enjoy.

<# 
.Synopsis 
Clears the archive bit on a set of files 
.Description 
Clear-myArchiveBit returns a list of files whose archive bit is set to on, and resets 
them to off. This is command supports the -Recurse parameter. 
.Example 
Clear-myArchiveBit *.ps1 
This command clears the archive bits of all ps1 files in the current directory

.Example 
Clear-myArchiveBit *.ps1 -Path $home\psbin -recurse 
This command clears the archive bit of all PS1 files in the $home\psbin directory, 
and all subdirectories of $home\psbin.

.Parameter Filter 
The filename filter to use. Aliases are Name and Filename. Default is *. 
.Parameter Path 
The path to the files to be changed. Default is ".". 
.Parameter Recurse 
If specified, the change is made to the Path and all subdirectories of the Path. 
.Inputs 
[string] 
[string] 
[switch] 
.Notes 
    Author: Charlie Russel 
 Copyright: 2016 by Charlie Russel 
          : Permission to use is granted but attribution is appreciated 
   Initial: 16 May, 2016 (cpr) 
   ModHist: 
          : 
#> 
[CmdletBinding()] 
Param( 
     [Parameter(Mandatory=$False,ValueFromPipeline=$True,Position=0)] 
     [alias("Name","Filename")] 
     [string]$Filter = "*", 
     [Parameter(Mandatory=$false,ValueFromPipeline=$false,Position=1)] 
     [string]$Path = ".", 
     [Parameter(Mandatory=$false,ValueFromPipeline=$false)] 
     [switch]$Recurse 
     ) 
Write-Verbose "Clearing the Archive bit on $filter in $path" 
# This is how we'll XOR the bit when we get to that. 
$Archive = [io.fileattributes]::Archive

# First, get all the files whose Archive bit is currently set. 
if ($Recurse) { 
   $chgdFiles = Get-ChildItem -Filter $Filter -Path $path -Recurse ` 
                  | Where {$_.mode -match "a" } 
} else { 
   $chgdFiles = Get-ChildItem -Filter $Filter -Path $path ` 
                  | Where {$_.mode -match "a" } 
}

# Now, we clear the bit on those files using a binary XOR. 
ForEach ($file in $chgdFiles ) { 
   Set-ItemProperty -Path $file.FullName ` 
                    -Name Attributes ` 
                    -Value ((Get-ItemProperty $file.FullName).Attributes ` 
                            -bXOR $Archive ) 
} 
Write-Verbose "The following files have had their Archive attribute cleared: " 
Write-Verbose "" 
$chgdFiles | Write-Verbose

2 Responses to Clearing the Archive Attribute Bit

  • David Mans says:

    I have to agree with you about PS file attribute manipulation. Before version 5 it was complicated and buggy. For instance, you could set the attributes to ‘Normal’ (which clears all bits) but then it wouldn’t let you reset any flag outside of A,S,H and R. PS shouldn’t let you clear bits you can’t then reset!! But it did.
    With version 5, the syntax is simple:
    (ls $fileName).attributes -= ‘Archive’ # clears A bit (R,S,H not set)
    (ls $fileName).attributes -= ‘Archive’ # strangely enough, sets it back on
    Not useful if the target system is running <ver5

    • Charlie Russel says:

      A useful change in V5+. And long overdue. But your second line already shows the problem even with this new version — it toggles the attribute on if it’s off. I needed a way to ensure that it was OFF, and bXOR was the “solution”. Not a pretty one, but sometimes you just need a hammer!

Leave a Reply

Your email address will not be published. Required fields are marked *