Skip to the content.

PS: Custom File-Structures for Projects

Often, when working with projects, you’ll need to generate a file-structure. Why not automate this using PowerShell?

The standard way to create new files/directories in PowerShell is through the New-Item (ni) cmdlet. Why not customize it to create the whole file-structure for your project?

This example creates file-structure with blank files for a web project & opens them in your favourite editor:

<#
.SYNOPSIS
Creates custom project file-structure.
.EXAMPLE
New-ItemX -Web
nix -Web
#>
function New-ItemX{
    [cmdletBinding()]
    [Alias('nix')]
    param(
        [switch]$Web,
        [switch]$Notes,
        [switch]$Python,
        [switch]$PowerShell
    )
    $State = ""
    switch ($PSBoundParameters.keys){
        'Web' {
            $State = "vim -p index.html js/main.js css/style.css"
            New-Item -ItemType 'directory' -Path js,css,media,fonts,common
            New-Item -ItemType 'file' -Path index.html,js/main.js,css/style.css
            $State
        }
    }
}
OUTPUT

13-02-2021 (07:12 PM)

The next question is - What if you accidentally closed all your files? How would you open them all at once?

One way is to save the open-files command in a global variable ($State). However, this is lost upon closing the current session window.
We can export this variable into a XML file to solve this, and include an import statement in your user $PROFILE to ensure that it is available across all sessions.
Also, we can conditionally import this variable - ie, only if it exists.
We can even encrypt/decrypt storage of this variable, but this would be an overkill.

function New-ItemX{
    [cmdletBinding()]
    [Alias('nix')]
    param(
        [switch]$Web,
        [switch]$Notes,
        [switch]$Python,
        [switch]$PowerShell
    )
    $global:State = ""
    switch ($PSBoundParameters.keys){
        'Web' {
            $global:State = "vim -p index.html js/main.js css/style.css"
            New-Item -ItemType 'directory' -Path js,css,media,fonts,common
            New-Item -ItemType 'file' -Path index.html,js/main.js,css/style.css
	    $State | Export-CliXML ~\states.ps1xml
            Invoke-Expression $State
        }
    }
}
if ([System.IO.File]::Exists("$HOME\states.ps1xml")){
    $State = Import-CliXML "$HOME\states.ps1xml"
}

Now, opening your last project is easy - just use iex $State.

13-02-2021 (08:04 PM)

Did you try it out?

We accidentally left out a serious flaw with the code - we didn’t take into account that we’re using relative paths for opening up files. Hence, each iex $State call just creates new files.
Oh, the joys of software!
Thankfully, we can resolve this by listing & using the absolute paths of each file (using Get-ChildItem).
To ensure spaces in filepaths don’t become an issue (eg. C:\Users\Chaitanya Tejaswi\...), we’ll wrap them in "".

function New-ItemX{
    [cmdletBinding()]
    [Alias('nix')]
    param(
        [switch]$Web,
        [switch]$Notes,
        [switch]$Python,
        [switch]$PowerShell
    )
    $global:State = ""
    $Files = "" 
    switch ($PSBoundParameters.keys){
        'Web' {
            New-Item -ItemType 'directory' -Path js,css,media,fonts,common
            New-Item -ItemType 'file' -Path index.html,js/main.js,css/style.css
            (Get-ChildItem index.html,js/main.js,css/style.css).FullName | forEach {$Files += '"'+$_+'" '}
            $global:State = "vim -p $Files"
	    $State | Export-CliXML ~\states.ps1xml
            Invoke-Expression $State
        }
    }
}

This does it for now. Phew!

References