Redirecting PowerShell command errors to a file

PowerShell has several redirection operators that can be used to redirect specific type of output to a file. For example, if you want to redirect all errors produced by different cmdlet in your script to a text file, you can use Error redirection to do so.

It is particularly helpful when you want to hide errors from appearing on the screen but need them to identify any possible issues and improving the script. Sometimes, when you have a script deployed in production, you can ask users (who are using your script) for the error redirection file to troubleshoot the script.

To send errors to specified file, use 2> file.name

To append errors to a specified file, use 2>> file.name

Following examples attempts to delete files from c:\temp folder and redirects any errors to c:\errors.txt file.


PS C:\> Get-ChildItem -Path c:\temp

Directory: C:\temp

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         4/24/2016   2:45 PM        972 errors.txt
-a---         4/24/2016   2:48 PM      21085 ex2.docx
-a---         4/24/2016   2:49 PM        274 test.txt
-a---         4/24/2016   2:47 PM       8008 test.xlsx
-a---         4/24/2016   2:49 PM        289 test2.ps1

PS C:\> Get-ChildItem -Path C:\temp | Remove-Item 2> C:\errors.txt
PS C:\>

If above command has not resulted in any error, you will not see c:\errors.txt or anything in the file. if the command produced any errors, it will be there in the error file. In example above, two documents were open and they were not deleted. notice how errors were not shown on the console but they were redirected to given error file:

PS C:\> get-content C:\errors.txt
Remove-Item : Cannot remove item C:\temp\ex2.docx: The process cannot access the file 'C:\temp\ex2.docx' because it is being used by another
process.
At line:1 char:31
+ Get-ChildItem -Path C:\temp | Remove-Item 2> c:\errors.txt
+                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (C:\temp\ex2.docx:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item C:\temp\test.xlsx: The process cannot access the file 'C:\temp\test.xlsx' because it is being used by
another process.
At line:1 char:31
+ Get-ChildItem -Path C:\temp | Remove-Item 2> c:\errors.txt
+                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (C:\temp\test.xlsx:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS C:\> Get-ChildItem C:\temp

Notice that the error message redirected to the file is same as you would see on the console when not handling (by means of  -ErrorAction, Try/Catch etc.). It shows line number that has thrown the error and helps in troubleshooting the script/code.

2> c:\errors.txt in Remove-Item cmdlet in the pipeline is used to direct the errors to given text file (here c:\errors.txt). If you need to append to a file instead of overwriting/creating a new one (2> c:\errors.txt creates the file if does not exist or overwrites it if it exist), use append operator (2>> c:\errors.txt):

PS C:\> Get-ChildItem -Path C:\temp | Remove-Item 2>> c:\errors.txt

One important point to note is, you shouldn’t always be just redirecting errors. There are times when you need to handle errors in a script and take appropriate action. In those cases, its better to use error handling (using try/catch, -ErrorAction parameter of supported cmdlets etc.) to handle the error appropriately.

 

Compute MD5, SHA and other hashes of a file in PowerShell

PowerShell 4.0 includes a nice cmdlet Get-FileHash that let you compute hash of a given file based on specified algorithm. This cmdlet supports MD5, SHA1, SHA256 etc. algorithms to compute file hash. For a list of all supported algorithms by this cmdlet, refer to Get-FileHash cmdlet details.

For example, to compute SHA1 hash of a file c:\temp\sample.iso, run following command:

PS C:\temp> Get-FileHash -Path C:\temp\sample.iso


Algorithm  Hash                                                             Path
---------  ----                                                             ----
SHA256     08966CE743AA1CBED0874933E104EF7B913188ECD8F0C679F7D8378516C51DA2 C:\temp\sample.iso

As you notice, by-default SHA256 algorithm is used to compute file hash if you don’t specify an algorithm.

You can specify -Algorithm parameter to use any of available algorithms with this cmdlet. For example, to compute a MD5 hash of a file, following command will help:


PS C:\temp> Get-FileHash -Path C:\temp\sample.iso -Algorithm MD5


Algorithm Hash                                  Path
---------   ----                                ----
MD5         520A6D1CBCC9CF642C625FE814C93C58    C:\temp\sample.iso

 

If you need to compute hash of multiple files, there are multiple methods available.. for example, to compute hash of all files in a folder, following command can be used:

Get-ChildItem $PSHOME | foreach { Get-FileHash -Path $_.FullName -Algorithm MD5 }

This command will compute MD5 hash of all files in PowerShell home directory.

 

 

Resize a disk partition using PowerShell

In Windows Server 2012, there is a ‘Storage’ module that provides lot of cmdlets to work with disk storage. You can get a list of available cmdlets by using following command:

Get-Command -Module Storage

Resize-Partition cmdlet, as the name suggests, let you resize a partition to specific size. Before you can resize a partition, you need to get the disk on which partition is created along with partition number.

Get-Disk cmdlet provides information about all available disks on the system:

PS C:\Windows\system32> get-disk
Number Friendly Name OperationalStatus Total Size Partition Style
------ ------------- ----------------- ---------- ---------------
0 Virtual HD ATA Device Online 20 GB MBR
1 Microsoft Virtual Disk Online 32 GB MBR
2 Microsoft Virtual Disk Online 15 GB MBR

Once the disk on which partition has to be resized, is identified, you can get the actual partition by using Get-Partition cmdlet. For example, to list all partitions on disk 1, use:

PS C:\Windows\system32> Get-Partition -DiskNumber 1

 Disk Number: 1
PartitionNumber DriveLetter Offset Size Type
--------------- ----------- ------ ---- ----
1 F 1048576 25 GB IFS
2 G 26844594176 7 GB IFS

Instead of using these two cmdlets to get desired disk partition, you could simply use Get-Partition cmdlet and it will display all partitions on all available disks:

PS C:\Windows\system32> Get-Partition

 Disk Number: 0

PartitionNumber DriveLetter Offset Size Type
--------------- ----------- ------ ---- ----
1 C 1048576 20 GB IFS

 Disk Number: 1

PartitionNumber DriveLetter Offset Size Type
--------------- ----------- ------ ---- ----
1 F 1048576 25 GB IFS
2 G 26844594176 7 GB IFS

 Disk Number: 2

PartitionNumber DriveLetter Offset Size Type
--------------- ----------- ------ ---- ----
1 H 1048576 15 GB IFS

Now, you can use Resize-Partition cmdlet to resize the selected partition. For this example, let’s resize partition 1 on disk 1 and set its size to 20GB:

PS C:\Windows\system32> Resize-Partition -DiskNumber 1 -PartitionNumber 1 -Size 20GB
PS C:\Windows\system32>

Now check the partitions to verify that it has been resized to mentioned size (20GB):

PS C:\Windows\system32> Get-Partition -DiskNumber 1

 Disk Number: 1

PartitionNumber DriveLetter Offset Size Type
--------------- ----------- ------ ---- ----
1 F 1048576 20 GB IFS
2 G 26844594176 7 GB IFS

Let’s try to resize it to lesser value, say 4GB:

PS C:\Windows\system32> Resize-Partition -DiskNumber 1 -PartitionNumber 1 -size 4gb

Resize-Partition : Size Not Supported
At line:1 char:1
+ Resize-Partition -DiskNumber 1 -PartitionNumber 1 -size 4gb
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+ CategoryInfo : NotSpecified: (StorageWMI:ROOT/Microsoft/.../MSFT_Partition) [Resize-Partition], CimExce ption 
+ FullyQualifiedErrorId : StorageWMI 4097,Resize-Partition

Not what we expected..PowerShell threw an error message saying the specified size is not supported. It means that we tried to set it to size lower than the current ‘used space’ on the partition.

Wouldn’t it be nice to know the minimum and maximum size of a partition that it can be resized to? PowerShell has cmdlets that will let you know this!

PS C:\Windows\system32> Get-PartitionSupportedSize -DiskNumber 1 -PartitionNumber 1

SizeMin SizeMax
 ------- -------
 5340622848 26843545600

This output is in bytes making it a bit difficult to identify what size it is.. let’s use computed properties to convert it into GB:

PS C:\Windows\system32> Get-PartitionSupportedSize -DiskNumber 1 -PartitionNumber 1 | select @{Name="Minimum Size (GB)";
Expression={$_.SizeMin/1GB}}, @{Name="Maximum Size (GB)";Expression={$_.SizeMax/1GB}}

Minimum Size (GB) Maximum Size (GB)
 ----------------- -----------------
 4.97384262084961 25

Cool, isn’t it? :)

Run powershell script when execution policy is set to Restricted

bydefault, Powershell execution policy is set to ‘Restricted’ and it prevents any Powershell script from running.

There are times when we just need to run a script (say, for just testing purpose) and does not want to change execution policy. In those cases, you can launch the script using Powershell.exe with -ExecutionPolicy parameter as shown below:

powershell.exe -ExecutionPolicy RemoteSigned -File c:\test.ps1

This command will simply launch the specified script with “RemoteSigned” execution policy. Please note that running a script in this way will not change the execution policy on the computer where it is running. You can check current execution policy on a computer using following command:

get-executionPolicy