Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Out-CompressedFile

Posted on December 6, 2010

I'm not sure where this idea came from, but I thought it might be nice to redirect output to a compressed text file. I know disk space is cheap these days but perhaps you're running PowerShell 2.0 on an older platform and you want to save output from a command that will generate a ton of data. Using NTFS compression might buy you a little breathing room. My function, Out-CompressedFile, can be used in place of Out-File.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

My function doesn't have all the features of Out-File and assumes you are using most of the defaults.
[cc lang="PowerShell"]
Function Out-CompressedFile {

[cmdletBinding(SupportsShouldProcess=$True)]

Param(
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a file path and name",
ValueFromPipeline=$False)]
[ValidateNotNullorEmpty()]
[string]$FilePath,
[Parameter(Position=1,Mandatory=$False,ValueFromPipeline=$True)]
[psobject]$InputObject,
[switch]$Append
)

Begin {
Write-Verbose -Message "$(Get-Date) Starting $($myinvocation.mycommand)"
#get file if -append was specified
if ($Append -AND (Test-Path $FilePath))
{
Write-Verbose -Message "$(Get-Date) Appending to $Filepath"
#get full path
if (-Not $FilePath.Contains("\"))
{
$FilePath=(Get-Item $filePath).fullname
}
}
elseif (-Not $Append)
{
#otherwise, create an empty file
Write-Verbose -Message "$(Get-Date) Creating $FilePath"
#if just a file name, then use the current working directory"
if (-not $FilePath.Contains("\"))
{
Write-Verbose -Message "$(Get-Date) Using current working directory $PWD"
$FilePath=Join-Path -Path (Get-item $pwd).FullName -ChildPath $FilePath
}
if ($pscmdlet.ShouldProcess($filepath))
{
Try
{
#Create the file
$f=[System.IO.File]::Create($filepath)
$f.Close()
#get the full file name
$FilePath=$f.Name
} #close Try
Catch
{
Write-Warning "Failed to create $Filepath"
Write-Error $_
Exit
} #close Catch
} #close if should process
} #close elseif not $append
else
{
Write-Error "Failed to find $filepath. You can only append to an existing file."
Exit
}

Write-Verbose -Message "$(Get-Date) Full path is $FilePath"
#replace \ with \\ for WMI
$wmipath=$filePath.Replace("\","\\")
Write-Verbose -Message "$(Get-Date) Getting $wmipath"
#check and see if file is already compressed
$CIMFile=Get-WmiObject -Class CIM_DATAFILE -filter "Name='$wmipath'"
if (-Not $CIMFile.Compressed)
{
#if not, compress it
if ($pscmdlet.ShouldProcess("$Filepath"))
{
Write-Verbose -Message "$(Get-Date) Compressing $Filepath"
$rc=$CIMFile.Compress()
if ($rc.ReturnValue -ne 0)
{
Write-Warning "Failed to compress $Filepath. Continuing without it."
}
}
} #close if not compressed

#initialize a variable to hold all the input
Write-Verbose -Message "$(Get-Date) Initializing data variable"
$data=@()
} #close Begin

Process {
Foreach ($item in $InputObject) {
$data+=$item
}#close Foreach

} #close process

End {
Write-Verbose -Message "$(Get-Date) Sending output to $FilePath"
#data will always be appended because the file always exists, even it is empty
$data | Out-File -FilePath $Filepath -append
Write-Verbose -Message "$(Get-Date) Ending $($myinvocation.mycommand)"
} #close End

} #end Function

[/cc]
My function has comment-based help but I've omitted from the listing here.

You use the function just as you would Out-File with some subtle differences. First, if you use -Append, the function verifies the file exists. This is because I want to check and see if the file exists so I can enable compression if necessary. If you don't specify -Append, then I create an empty file.
[cc lang="PowerShell"]
Try
{
#Create the file
$f=[System.IO.File]::Create($filepath)
$f.Close()
#get the full file name
$FilePath=$f.Name
} #close Try
[/cc]
I also compress the file ahead of time if it is not already compressed using WMI. WMI needs \\ in a path for each \ so I fix the path accordingly.
[cc lang="PowerShell"]
#replace \ with \\ for WMI
$wmipath=$filePath.Replace("\","\\")
Write-Verbose -Message "$(Get-Date) Getting $wmipath"
#check and see if file is already compressed
$CIMFile=Get-WmiObject -Class CIM_DATAFILE -filter "Name='$wmipath'"
if (-Not $CIMFile.Compressed)
{
#if not, compress it
if ($pscmdlet.ShouldProcess("$Filepath"))
{
Write-Verbose -Message "$(Get-Date) Compressing $Filepath"
$rc=$CIMFile.Compress()
if ($rc.ReturnValue -ne 0)
{
Write-Warning "Failed to compress $Filepath. Continuing without it."
}
}
} #close if not compressed
[/cc]
Once I have the file ready, I take all input and store it in a buffer variable. To be honest, I'm not sure what the effect will be for extremely large data sets. But I expect this to work for 99% percent of you.
[cc lang="PowerShell"]
Process {
Foreach ($item in $InputObject) {
$data+=$item
}#close Foreach

} #close process
[/cc]
The last part of the function simply passes the data to Out-File, using the compressed file. Because the file has already been verified or created, I need to use -Append.
[cc lang="PowerShell"]
End {
Write-Verbose -Message "$(Get-Date) Sending output to $FilePath"
#data will always be appended because the file always exists, even it is empty
$data | Out-File -FilePath $Filepath -append
Write-Verbose -Message "$(Get-Date) Ending $($myinvocation.mycommand)"
} #close End
[/cc]
Use the function once it is loaded into your PowerShell session, just as you would Out-File.

Download Out-CompressedFile.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

4 thoughts on “Out-CompressedFile”

  1. Pingback: Tweets that mention Out-CompressedFile | The Lonely Administrator -- Topsy.com
  2. JV says:
    December 6, 2010 at 2:18 pm

    Shortcut syggestiuon:

    $file="E:\projects\scripts\14193132471.txt"
    dir $file |select mode,attributes |fl
    [System.IO.File]::SetAttributes($file,[System.IO.FileAttributes]::Compressed)
    dir $file |select mode,attributes |fl

    1. Jeffery Hicks says:
      December 6, 2010 at 2:28 pm

      That would certainly work. I’m so used to using WMI. Thanks for the tip.

  3. JV says:
    December 6, 2010 at 3:37 pm

    I have to appologize for that. It dowsn;t wotk as I thought. You need to use IO-CONTROL API to do the compression. IOCTL is not exposed through NET classes. so my idea won’t work for the ‘Compressed’ attribute but will work for all others I have tried.

    WMI would be the easied way to access the IOCTL function as far as I can tell.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d