In the PowerShell script writing series, we are working on some of the helpful areas to write powershell scripts. In this series we would continue covering some of the important topics on working with PowerShell read files, write files,folder,subfolders.
Another area where you should become very confident is working with files (read & write), as you will need to work with them very frequently.
First, we will take a look at the basics of working with files by retrieving and writing files and the content of the files. This can be achieved with the Get-Content and Set-Content/Out-File cmdlets.
First of all, we will take a dedicated look at how you can export content to a file:
There is a small difference between exporting content with the two aforementioned cmdlets. Set-Content will call the ToString() method of each object, whereas Out-File will call the Out-String method first and then write the result to file.
You will have a similar result when using Out-File or Set-Content in combination with Out-String:
Sometimes, it may also be necessary to export the content with a specified encoding. There is an additional flag available to accomplish this task, as shown in the following example:
Reading File content in powershell
Retrieving the content works very similarly to the Get-Content cmdlet. One downside of the cmdlet is that it will load the complete file into the cache. Depending on the file size, this may take very long and even become unstable. Here is an easy example to load the content into a variable:
Because of this issue, it may become necessary to only retrieve a dedicated number of lines. There are two flags available for this, as follows:
Improving performance of Get-content
In addition, you can also specify how many lines of content are sent through the pipeline at a time. The default value for the ReadCount flag is 0, and a value of 1 would send all content at once. This parameter directly affects the total time for the operation, and can decrease the time significantly for larger files:
Working with Files,Folder,Sub-folders
The next step when working with files and folders is searching for specific ones. This can be easily achieved with the Get-ChildItem command for the specific PSDrive:
As you can see, you can easily work with the -Directory and -File flags to define the outcome. But you will normally not use such simple queries, as you want to filter the result in a dedicated way.
The next, more complex, example shows a recursive search for *.txt files. We are taking four different approaches to search for those file types and will compare their runtimes:
All methods retrieved the same amount of line? $($countWhere -eq $countWhereObject -eq $countInclude -eq $countCmd)
The Slow Approach!
The first two approaches use Get-ChildItem with filtering afterwards, which is always the slowest approach.
The third approach uses filtering within the Get-ChildItem cmdlet, using the -Include flag. This is obviously much faster than the first two approaches.
You will also need to create new files and folders and combine paths very frequently, which is shown in the following snippet. The subdirectories of a folder are being gathered, and one archive folder will be created underneath each one:
Keep in mind that, due to the PSDrives, you can simply work with the basic cmdlets such as New-Item. We made use of the -WhatIf flag to just take a look at what would have been executed. If you're not sure that your construct is working as desired, just add the flag and execute it once to see its outcome.
A best practice to combine paths is to always use Join-Path to avoid problems on different OSes or with different PSDrives. Typical errors are that you forget to add the delimiter character or you add it twice. This approach will avoid any problems and always add one delimiter.
The next typical use case you will need to know is how to retrieve file and folder sizes.
The following example retrieves the size of a single folder, optionally displaying the size for each subfolder as well.
It is written as a function to be dynamically extendable. This might be good practice for you use, in order to understand and make use of the contents of previous chapters. You can try to extend this function with additional properties and by adding functionality to it.
.SYNOPSIS
Retrieves folder size.
.DESCRIPTION
Retrieves folder size of a dedicated path or all subfolders of the dedicated path.
.EXAMPLE
Get-FolderSize -Path c:\temp\ -ShowSubFolders | Format-List
.INPUTS
Path
.OUTPUTS
Path and Sizes
.NOTES
folder size example
#>
function Get-FolderSize {
Param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
$Path,
[ValidateSet("KB","MB","GB")]
$Units = "MB",
[Switch] $ShowSubFolders = $false
)
if((Test-Path $Path) -and (Get-Item $Path).PSIsContainer )
{
if ($ShowSubFolders)
{
$subFolders = Get-ChildItem $Path -Directory
foreach ($subFolder in $subFolders)
{
$Measure = Get-ChildItem $subFolder.FullName -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
$Sum = $Measure.Sum / "1$Units"
[PSCustomObject]@{
"Path" = $subFolder
"Size($Units)" = [Math]::Round($Sum,2)
}
}
}
else
{
$Measure = Get-ChildItem $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
$Sum = $Measure.Sum / "1$Units"
[PSCustomObject]@{
"Path" = $Path
"Size($Units)" = [Math]::Round($Sum,2)
}
}
}
}
Next, we will dive into specific file types, as they hold some benefits in storing, retrieving, and writing information to file.
Another area where you should become very confident is working with files (read & write), as you will need to work with them very frequently.
First, we will take a look at the basics of working with files by retrieving and writing files and the content of the files. This can be achieved with the Get-Content and Set-Content/Out-File cmdlets.
First of all, we will take a dedicated look at how you can export content to a file:
There is a small difference between exporting content with the two aforementioned cmdlets. Set-Content will call the ToString() method of each object, whereas Out-File will call the Out-String method first and then write the result to file.
You will have a similar result when using Out-File or Set-Content in combination with Out-String:
Sometimes, it may also be necessary to export the content with a specified encoding. There is an additional flag available to accomplish this task, as shown in the following example:
Reading File content in powershell
Retrieving the content works very similarly to the Get-Content cmdlet. One downside of the cmdlet is that it will load the complete file into the cache. Depending on the file size, this may take very long and even become unstable. Here is an easy example to load the content into a variable:
Because of this issue, it may become necessary to only retrieve a dedicated number of lines. There are two flags available for this, as follows:
Improving performance of Get-content
In addition, you can also specify how many lines of content are sent through the pipeline at a time. The default value for the ReadCount flag is 0, and a value of 1 would send all content at once. This parameter directly affects the total time for the operation, and can decrease the time significantly for larger files:
Working with Files,Folder,Sub-folders
The next step when working with files and folders is searching for specific ones. This can be easily achieved with the Get-ChildItem command for the specific PSDrive:
As you can see, you can easily work with the -Directory and -File flags to define the outcome. But you will normally not use such simple queries, as you want to filter the result in a dedicated way.
The next, more complex, example shows a recursive search for *.txt files. We are taking four different approaches to search for those file types and will compare their runtimes:
All methods retrieved the same amount of line? $($countWhere -eq $countWhereObject -eq $countInclude -eq $countCmd)
The Slow Approach!
The first two approaches use Get-ChildItem with filtering afterwards, which is always the slowest approach.
The third approach uses filtering within the Get-ChildItem cmdlet, using the -Include flag. This is obviously much faster than the first two approaches.
You will also need to create new files and folders and combine paths very frequently, which is shown in the following snippet. The subdirectories of a folder are being gathered, and one archive folder will be created underneath each one:
Keep in mind that, due to the PSDrives, you can simply work with the basic cmdlets such as New-Item. We made use of the -WhatIf flag to just take a look at what would have been executed. If you're not sure that your construct is working as desired, just add the flag and execute it once to see its outcome.
A best practice to combine paths is to always use Join-Path to avoid problems on different OSes or with different PSDrives. Typical errors are that you forget to add the delimiter character or you add it twice. This approach will avoid any problems and always add one delimiter.
The next typical use case you will need to know is how to retrieve file and folder sizes.
The following example retrieves the size of a single folder, optionally displaying the size for each subfolder as well.
It is written as a function to be dynamically extendable. This might be good practice for you use, in order to understand and make use of the contents of previous chapters. You can try to extend this function with additional properties and by adding functionality to it.
.SYNOPSIS
Retrieves folder size.
.DESCRIPTION
Retrieves folder size of a dedicated path or all subfolders of the dedicated path.
.EXAMPLE
Get-FolderSize -Path c:\temp\ -ShowSubFolders | Format-List
.INPUTS
Path
.OUTPUTS
Path and Sizes
.NOTES
folder size example
#>
function Get-FolderSize {
Param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
$Path,
[ValidateSet("KB","MB","GB")]
$Units = "MB",
[Switch] $ShowSubFolders = $false
)
if((Test-Path $Path) -and (Get-Item $Path).PSIsContainer )
{
if ($ShowSubFolders)
{
$subFolders = Get-ChildItem $Path -Directory
foreach ($subFolder in $subFolders)
{
$Measure = Get-ChildItem $subFolder.FullName -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
$Sum = $Measure.Sum / "1$Units"
[PSCustomObject]@{
"Path" = $subFolder
"Size($Units)" = [Math]::Round($Sum,2)
}
}
}
else
{
$Measure = Get-ChildItem $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
$Sum = $Measure.Sum / "1$Units"
[PSCustomObject]@{
"Path" = $Path
"Size($Units)" = [Math]::Round($Sum,2)
}
}
}
}
Next, we will dive into specific file types, as they hold some benefits in storing, retrieving, and writing information to file.
EmoticonEmoticon