Use PowerShell to Toggle the Archive Bit on Files

Use PowerShell to Toggle the Archive Bit on Files

  • Comments 7
  • Likes

 

Summary: Learn how to use Windows PowerShell to toggle file attributes such as the archive bit.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a number of files that have had the archive bit flipped. Unfortunately, our backup program relies on the archive bit to determine if it has backed up a file recently or if a file has changed and is in need of backup again. What I need is a way to flip all of the archive bits in a folder.

-- BW

Hey, Scripting Guy! Answer Hello BW,

Microsoft Scripting Guy Ed Wilson here. Backup programs. Hmmm, I used to know a person who claimed he had an ideal business model. He said he would advertise extremely low-cost backup tape storage. The backup tapes would be stored in a big hole in the ground. When someone requested a tape from “storage,” they would be given a blank tape. This model would work, he said, because no one ever tests backup tapes, and no one ever practices a file restore. Luckily, this person never went into business, and never implemented the “low-cost storage” solution.

BW, I have seen the problem you mention occur when someone runs a scheduled daily backup to perform a custom ad hoc backup, instead of creating a custom on-demand job that does not flip archive bits. When this happens, backups get out of sequence, and it can be a real mess.

In yesterday’s Hey, Scripting Guy! Blog post, I began a discussion of using the Set-ItemProperty Windows PowerShell cmdlet to work with archive bits on a file.

The FSO library on my laptop contains a mixture of files. Some have the archive bit set and others do not. Some are compressed, others encrypted, and still others read-only. The folder is shown in the following image.

Image of FSO library on Ed's laptop

The Get-FilesWithArchiveBitSet.ps1 script will go through a folder and report files that have the archive bit set. It does not matter if there are additional file attributes; the script will detect the presence of the archive bit. The use of the io.fileattributes enumeration was discussed in yesterday’s Hey, Scripting Guy! Blog post.

The key to the script is the use of the If statement to perform a bitwise AND operation on the file attributes:

If((Get-ItemProperty -Path $file.fullname).attributes -band $attribute)

If the attribute is present, it is reported in green. If the attribute is not present, it is reported in blue:

{ Write-Host -ForegroundColor green `

    "$file.fullname has the $attribute bit set" }

 ELSE

  { Write-host -ForegroundColor blue `

    "$file.fullname does not have the $attribute bit set"}

The complete script is shown here.

Get-FilesWithArchiveBitSet.ps1

$path = "C:\fso"

$files = Get-ChildItem -Path $path -Recurse

$attribute = [io.fileattributes]::archive

 

Foreach($file in $files)

{

 If((Get-ItemProperty -Path $file.fullname).attributes -band $attribute)

  { Write-Host -ForegroundColor green `

    "$file.fullname has the $attribute bit set" }

 ELSE

  { Write-host -ForegroundColor blue `

    "$file.fullname does not have the $attribute bit set"}

} #end Foreach

When the Get-FilesWithArchiveBitSet.ps1 script runs, the output appears that is shown in the following image:

Image of script output

Now that we understand the basic process, let’s add one additional concept. To toggle the archive bit, I need to use a Bitwise Exclusive Or (BXOR) operator.

In the table that appears here, the first row is the decimal value of the position. In the second row is the binary representation of the number 33 that I obtained by using the convert class. In the second row, notice there is a 1 in the 32 column, and a 1 in the 1 column. The third row is the binary value of the number 1 (the value of the read-only enumeration). The fourth row represents the results of performing a bitwise Exclusive OR (BXOR) operation. When performing a BXOR operation, the rules are thus:

1 –BXOR 1 = 0, 1 –BXOR 0 = 1, 0 –BXOR 0 = 0.

128

64

32

16

8

4

2

1

0

0

1

0

0

0

0

1

0

0

0

0

0

0

0

1

0

0

1

0

0

0

0

0

I can use this information to determine the attributes other than the archive bit of a file. This is illustrated here. Notice that when I use –bxor on the file attributes, and –bxor with the archive bit, what remains is the ReadOnly attribute.

PS C:\> (Get-ItemProperty C:\fso\a.txt).attributes

ReadOnly, Archive

PS C:\> (Get-ItemProperty C:\fso\a.txt).attributes -bxor [io.fileattributes]::Archive

1

PS C:\>

Armed with this information, I create a script that will toggle the archive bit of a file. If the archive bit exists, it is removed; if it does not exist, it is added to the file. The Set-FilesWithArchiveBit.ps1 script is shown here.

Set-FilesWithArchiveBit.ps1

$path = "C:\fso"

$files = Get-ChildItem -Path $path -Recurse

$attribute = [io.fileattributes]::archive

 

Foreach($file in $files)

{

 If((Get-ItemProperty -Path $file.fullname).attributes -band $attribute)

  {

   "$file.fullname has the $attribute bit set, removing the bit."

   Set-ItemProperty -Path $file.fullname -Name attributes `

     -Value ((Get-ItemProperty $file.fullname).attributes -BXOR $attribute)

   "New value of $file.Fullname attributes"

   (Get-ItemProperty -Path $file.fullname).attributes

  }

 ELSE

  {

    Write-host -ForegroundColor blue `

    "$file.fullname does not have the $attribute bit set, setting the bit."

    Set-ItemProperty -Path $file.fullname -Name attributes `

      -Value ((Get-ItemProperty $file.fullname).attributes -BXOR $attribute)

    "New value of $file.Fullname attributes"

   (Get-ItemProperty -Path $file.fullname).attributes

    }

} #end Foreach

The Set-FilesWithArchiveBit.ps1 script is similar to the earlier script except that the Set-ItemProperty Windows PowerShell cmdlet is used to change the value of the attributes of the file. To do this, I use Get-ItemProperty to retrieve the file attributes, and then I use BXOR to perform a bitwise exclusive OR operation with my chosen attribute. This portion of the code is shown here:

Set-ItemProperty -Path $file.fullname -Name attributes `

     -Value ((Get-ItemProperty $file.fullname).attributes -BXOR $attribute)

When the Set-FilesWithArchiveBit.ps1 script runs, the output appears that is shown in the following image:

Image of script output

One thing to keep in mind about using the Set-ItemProperty cmdlet to work with file attributes through the FileSystem provider is that it is limited to working with the following attributes: Archive, Hidden, Normal, ReadOnly, or System. An error will be generated, and the attributes will not be modified if a file is compressed or encrypted.

BW, that is all there is to using the Set-ItemProperty cmdlet to toggle the archive bit.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hello,

    How can I reset the archive bit of files in UNC path?

    Thanx

  • Thank you for this article. It is well-written and educational. References to boolean algebra helped me understand the -BAND and -BXOR operations.

  • @William Tang Thank you for your comment -- it made my day! I am glad you liked the article, and found it helpful.

  • Thanks a lot for your detailed comments, greatly appreciated but I'm just wondering: The PowerShell is such a powerful product which allows very elegant solutions but what is the improvement here when I just want to change the let's say archive or hidden attributes on a few files and I need lots of code, when the 'old fashioned' way with attrib +H * would make my day quickly? I can't be simpler, can it? Thanks for a hint.

  • Hey Ed, I came here looking to set the Compressed attribute and was disappointed to read at the end of your article that set-itemproperty can not handle compressed or encrypted. Is there a powershell cmdlet that can flip the compress attribute? I am currently using the compress method in the CIM_DataFile WMI class, but would prefer to use native commands if possible. (GWMI -Query "Select * FROM CIM_DataFile WHERE Name='$FileName'").compress() Thanks for all the great articles!

  • For those enquiring on resetting (clearing) a bit:

    $attribute = [system.io.fileattributes]::Hidden.Value__
    ... -value ((get-itemproperty $file.fullname).attributes -band -bnot $attribute)

    1. Invert the attribute with -bnot (1's complement. e.g. 0001 becomes 1110)
    2. Bitwise And the value in 1. with the current attributes, thus clearing the required bit

  • OK, seems like it's a little more complicated, since only certain bits can be modified.
    When I tried it on a folder, I was limited to setting/resetting only certain attribute bits, so I was forced to add:

    $arc = [system.io.fileattributes]::Archive.Value__
    $hid = [system.io.fileattributes]::Hidden.Value__
    $nor = [system.io.fileattributes]::Normal.Value__
    $ro = [system.io.fileattributes]::ReadOnly.Value__
    $sys = [system.io.fileattributes]::System.Value__

    $canmod = $arc -BOR $hid -BOR $nor -BOR $ro -BOR $sys

    $folder = "c:\test\"

    $catts = (Get-ItemProperty "$folder").attributes # current attributes

    $reset = [system.io.fileattributes]::Hidden.Value__ # the attribute we want to reset

    Set-ItemProperty -Path "$folder" -Name attributes `
    -Value ($catts -BAND -BNOT $reset -BAND $canmod)

    The additional step is to mask out all but the attribute bits that we are allowed to modify, according to the error message that is generated when you attempt to do otherwise.