Visual Studio Code

For a long time I have been using PowerShell ISE for writing PowerShell scripts. But a few months ago I switched to Visual Studio Code.

The main reason for me was the built-in support for Git. This makes it so much easier for using Git. Specially if you just have started using Git. There is no need to remember commands for the Git command line or to use a separate Gui.

Another reason for me was that it not only supports PowerShell but also many other languages. Some have built-in support. For others you can install an extension. You can find many extension at the Visual Studio Code Marketplace. At my work we use Puppet for configuration management. And there is extension for Puppet. So I can use one editor for all my scripts.

Because Visual Studio Code supports extensions it is easy to customize the editor for you own needs. There are extension for themes, languages, keymaps, debuggers, linters etc.

To get started with VSCode I found the blog posts on the Hey Scripting Guy blog very helpful.

I you do not use Visual Studio Code I suggest you take a look at it. Ohhhhh, and it is free also!

Advertisements

Creating a zip file from a single file

In the last 2 posts I shared two PowerShell functions for extracting an archive and creating a new zip file from a folder. Today I will share a new function, New-ArchiveFromFile.

This function you can use when you want to compress a single file. This can be useful for log management. Instead of archiving log files in one big zip file I prefer archive log files in separate zip files. This way it is much easier and faster to remove older files that you don’t want to keep.

 

<#

.Synopsis

   Creates a new archive from a file

.DESCRIPTION

   Creates a new archive with the contents from a file. This function relies on the

   .NET Framework 4.5. On windwows Server 2012 R2 Core you can install it with

   Install-WindowsFeature Net-Framework-45-Core

.EXAMPLE

   New-ArchiveFromFile -Source c:\test\test.txt -Destination c:\test.zip

#>

function New-ArchiveFromFile

{

    [CmdletBinding()]

    [OutputType([int])]

    Param

    (

        # Param1 help description

        [Parameter(Mandatory=$true,

                   ValueFromPipelineByPropertyName=$false,

                   Position=0)]

        [string]

        $Source,

        # Param2 help description

        [Parameter(Mandatory=$true,

                   ValueFromPipelineByPropertyName=$false,

                   Position=1)]

        [string]

        $Destination

    )

    Begin

    {

        [System.Reflection.Assembly]::LoadWithPartialName(“System.IO.Compression.FileSystem”) | Out-Null

    }

    Process

    {

        try

        {

            Write-Verbose “Creating archive $Destination….”

            $zipEntry = $Source | Split-Path -Leaf

            $zipFile = [System.IO.Compression.ZipFile]::Open($Destination, ‘Update’)

            $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal

            [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipfile,$Source,$zipEntry,$compressionLevel)

            Write-Verbose “Created archive $destination.”

        }

        catch [System.IO.DirectoryNotFoundException]

        {

            Write-Host “ERROR: The source $source does not exist!” -ForegroundColor Red

        }

        catch [System.IO.IOException]

        {

            Write-Host “ERROR: The file $Source is in use or $destination already exists!” -ForegroundColor Red

        }

        catch [System.UnauthorizedAccessException]

        {

            Write-Host “ERROR: You are not authorized to access the source or destination” -ForegroundColor Red

        }

    }

    End

    {

        $zipFile.Dispose()

    }

}


 

This is just a basic version. It could use some improvements.

Creating zip files in Windows Server Core

In my last post I talked about extracting zip files in Windows Server Core and shared a PowerShell function that I made.

Today I decided to make a new function that you can use to create a new archive. The function uses the same ZipFile class.

<#
.Synopsis
 Creates a new archive from a directory
.DESCRIPTION
 Creates a new archive with the contents from a folder. This function relies on the
 .NET Framework 4.5. On windwows Server 2012 R2 Core you can install it with 
 Install-WindowsFeature Net-Framework-45-Core
.EXAMPLE
 New-ArchiveFromDirectory -SourceDirectory c:\test -Destination c:\test.zip
#>
function New-ArchiveFromDirectory
{
 [CmdletBinding()]
 [OutputType([int])]
 Param
 (
 # Param1 help description
 [Parameter(Mandatory=$true,
 ValueFromPipelineByPropertyName=$false,
 Position=0)]
 [string]
 $SourceDirectory,

 # Param2 help description
 [Parameter(Mandatory=$true,
 ValueFromPipelineByPropertyName=$false,
 Position=1)]
 [string]
 $Destination
 )

 Begin
 {
 [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
 }
 Process
 {
 try
 {
 Write-Verbose "Creating archive $Destination...."
 [System.IO.Compression.ZipFile]::CreateFromDirectory($SourceDirectory, $destination)
 Write-Verbose "Created archive $destination."
 }
 catch [System.IO.DirectoryNotFoundException]
 {
 Write-Host "ERROR: The source directory $SourceDirectory does not exist!" -ForegroundColor Red
 }
 catch [System.IO.IOException]
 {
 Write-Host "ERROR: The destination $destination already exist!" -ForegroundColor Red
 }
 catch [System.UnauthorizedAccessException]
 {
 Write-Host "ERROR: You are not authorized to access the source or destination" -ForegroundColor Red
 }
 finally
 {

 }
 }
 End
 {

 }
}

Extracting zip files in Windows Server Core

For a project I wanted to use Windows Server 2012R2 Core as a stand alone server. Using Windows Server Core as a stand alone server can be challenging. Lot of things can be done with powershell or other command line tools.

When it is not possible to use file shares you have to find other ways to get files to the server. One method you can use is to download it from the internet. In powershell you can use the Invoke-WebRequest CmdLet.

Invoke-WebRequest -Uri http://someserver.tld/software.exe -OutFile .\downloads\software.exe

Another challenge is extracting archives like zip files. Windows Server Core and PowerShell don’t have native commands for extracting these files. So you need to download tools like 7Zip to do that.

Or you can make your own PowerShell script or function for it. I already had a function that creates archives but for extracting. So I thought I could change it to extract archives. In my script I used the com object shell.application. As I found out this is not working in Windows Server Core. The com object shell.application depends on explorer.exe. Which does not exist on Windows Server Core.

Thanks to Google I found out that .NET 4.5 has the System.IO.Compression namespace wich includes the ZipFile class. This class can be used for creating and extracting archives. And luckily you can use .NET classes in PowerShell. See the example below.

[System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
[System.IO.Compression.ZipFile]::ExtractToDirectory($ZipFile, $Destination)

Before you use it make sure that the .NET Framework 4.5 Core is installed.

Get-WindowsFeature -name NET-Framework-45-Core

If it is not installed you can install it with the following command.

Install-WindowsFeature -name NET-Framework-45-Core

To make it a bit more easy for myself I made a function for extracting archives.

<#
.Synopsis
 Expands compressed files
.DESCRIPTION
 Expands the contents of a compressed file to a folder. This function relies on the
 .NET Framework 4.5. On windwows Server 2012 R2 Core you can install it with 
 Install-WindowsFeature Net-Framework-45-Core
.EXAMPLE
 Expand-Archive -File c:\test.zip -Destination c:\test\
#>
function Expand-Archive
{
 [CmdletBinding()]
 [OutputType([int])]
 Param
 (
 # Param1 help description
 [Parameter(Mandatory=$true,
 ValueFromPipelineByPropertyName=$false,
 Position=0)]
 [string]
 $File,

 # Param2 help description
 [Parameter(Mandatory=$true,
 ValueFromPipelineByPropertyName=$false,
 Position=1)]
 [string]
 $Destination
 )

 Begin
 {
 [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
 }
 Process
 {
 try
 {
 Write-Verbose "Extracting archive $file...."
 [System.IO.Compression.ZipFile]::ExtractToDirectory($file, $destination)
 Write-Verbose "Extracted archive $file to $destination."
 }
 catch [System.IO.FileNotFoundException]
 {
 Write-Host "ERROR: Archive $file does not exist!" -ForegroundColor Red
 }
 catch [System.IO.DirectoryNotFoundException]
 {
 Write-Host "ERROR: Destination $destination does not exist!" -ForegroundColor Red
 }
 catch [System.IO.PathTooLongException]
 {
 Write-Host "ERROR: The path specified for -File or -Destination is too long" -ForegroundColor Red
 }
 catch [System.UnauthorizedAccessException]
 {
 Write-Host "ERROR: You are not authorized to access the archive or destination" -ForegroundColor Red
 }
 finally
 {

 }
 }
 End
 {

 }
}

Let’s see what the next challenge will be.