Nice PowerShell prompt

Been playing around with PowerShell the last days, and with nothing else better to do I did a nice looking prompt. :-)

This prompt will give you a marker if you run it as Administrator and another mark if you are outside the filesystem.

How to:
First you need to edit your profile so it autoload the new prompt.

notepad $profile

Then paste this code, save and start a new PowerShell command line.

function prompt
{
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        #                                                                              Rikard Ronnkvist / snowland.se
        # Multicolored prompt with marker for windows started as Admin and marker for providers outside filesystem
        # Examples
        #    C:\Windows\System32>
        #    [Admin] C:\Windows\System32>
        #    [Registry] HKLM:\SOFTWARE\Microsoft\Windows>
        #    [Admin] [Registry] HKLM:\SOFTWARE\Microsoft\Windows>
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        # New nice WindowTitle
        $Host.UI.RawUI.WindowTitle = "PowerShell v" + (get-host).Version.Major + "." + (get-host).Version.Minor + " (" + $pwd.Provider.Name + ") " + $pwd.Path

        # Admin ?
        if( (
                New-Object Security.Principal.WindowsPrincipal (
                        [Security.Principal.WindowsIdentity]::GetCurrent())
                ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
        {
                # Admin-mark in WindowTitle
                $Host.UI.RawUI.WindowTitle = "[Admin] " + $Host.UI.RawUI.WindowTitle

                # Admin-mark on prompt
                Write-Host "[" -nonewline -foregroundcolor DarkGray
                Write-Host "Admin" -nonewline -foregroundcolor Red
                Write-Host "] " -nonewline -foregroundcolor DarkGray
        }

        # Show providername if you are outside FileSystem
        if ($pwd.Provider.Name -ne "FileSystem") {
                Write-Host "[" -nonewline -foregroundcolor DarkGray
                Write-Host $pwd.Provider.Name -nonewline -foregroundcolor Gray
                Write-Host "] " -nonewline -foregroundcolor DarkGray
        }

        # Split path and write \ in a gray
        $pwd.Path.Split("\") | foreach {
            Write-Host $_ -nonewline -foregroundcolor Yellow
            Write-Host "\" -nonewline -foregroundcolor Gray
        }

        # Backspace last \ and write >
        Write-Host "`b>" -nonewline -foregroundcolor Gray

    return " "
}

Read MSI information with PowerShell

I tried to search for some way to read MSI-information with PowerShell, that wasn’t to easy to find.

Anyway, here is a function that helps you read the “Property” view from one MSI-file, the result is stored in a hash table.

# Load some TypeData
$SavedEA = $Global:ErrorActionPreference
$Global:ErrorActionPreference = "SilentlyContinue"
Update-TypeData -AppendPath ((Split-Path -Parent $MyInvocation.MyCommand.Path) + "\comObject.types.ps1xml")
$Global:ErrorActionPreference = $SavedEA

function global:get-msiproperties {
        PARAM (
                [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="MSI Database Filename",ValueFromPipeline=$true)]
                [Alias("Filename","Path","Database","Msi")]
                $msiDbName
        )

        # A quick check to see if the file exist
        if(!(Test-Path $msiDbName)){
                throw "Could not find " + $msiDbName
        }

        # Create an empty hashtable to store properties in
        $msiProps = @{}

        # Creating WI object and load MSI database
        $wiObject = New-Object -com WindowsInstaller.Installer
        $wiDatabase = $wiObject.InvokeMethod("OpenDatabase", (Resolve-Path $msiDbName).Path, 0)

        # Open the Property-view
        $view = $wiDatabase.InvokeMethod("OpenView", "SELECT * FROM Property")
        $view.InvokeMethod("Execute")

        # Loop thru the table
        $r = $view.InvokeMethod("Fetch")
        while($r -ne $null) {
                # Add property and value to hash table
                $msiProps[$r.InvokeParamProperty("StringData",1)] = $r.InvokeParamProperty("StringData",2)

                # Fetch the next row
                $r = $view.InvokeMethod("Fetch")
        }

        $view.InvokeMethod("Close")

        # Return the hash table
        return $msiProps
}

You need to expand your type configuration with this file, saved as comObject.types.ps1xml in the same directory as the script above.



        
                System.__ComObject
                
                        
                                GetProperty
                                
                        
                        
                                SetProperty
                                
                        
                        
                                InvokeParamProperty
                                
                        
                        
                                InvokeMethod
                                
                        
                
        


Off topic: Powershell to rename pictures

I’m trying hard to convert myself from VBScript to Powershell… so in the need of a powerfull filerenamer I wrote one in Powershell.

You need to download the Powershell Pack from http://code.msdn.microsoft.com/PowerShellPack

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                           Rikard Ronnkvist / snowland.se
#  Will rename JPG and AVI files, uses EXIF-tag on JPG-images and filedate on AVI-files.
#
#  Files will be named:
#    \some path\YYYYMM\YYYYMMDD_HHMMSS_00.JPG
#               ^^^^^^ - Optional, if you have createSubdir set to True
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$basePath = "F:\Pictures\Import dir"
$createSubdir = $True
$testMode = $False
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Download from:  http://code.msdn.microsoft.com/PowerShellPack
Import-Module PowerShellPack

# Add \* to use when searching
$searchPath = $basePath + "\*"

# Search for files
Write-Host "           Searching: " -ForegroundColor DarkGray -NoNewline
Write-Host $basePath -ForegroundColor Yellow

$allFiles  = Get-ChildItem -Path $searchPath -Include *.AVI,*.JPG -Exclude folder.jpg

Write-Host "               Found: " -ForegroundColor DarkGray -NoNewline
Write-Host $allFiles.Count -ForegroundColor Yellow -NoNewline
Write-Host " files" -ForegroundColor DarkGray

$fNum = 0
# Loop thru all files
foreach ($file in $allFiles )
{
        $fNum++
        # If it is an jpg use the exif-data, otherwise use date on file
        if ($file.Extension -eq ".JPG") {
                $imgInfo = $file | Get-Image | Get-ImageProperty
                $fileDate = $imgInfo.dt
        } else {
                $fileDate = $file.LastWriteTime
        }

        if ($createSubdir -eq $True) {
                # Set new filepath
                $fileDir = $basePath + "\" + $fileDate.ToString("yyyyMM")

                # Check directory
                if (!(Test-Path($fileDir))) {
                        # Create a new subdirectory
                        if ($testMode -ne $True) {
                                $newDir = New-Item -Type directory -Path $fileDir
                                Write-Host "            Creating: " -ForegroundColor DarkGray -NoNewline
                                Write-Host $fileDir -ForegroundColor Red
                        }
                }
        } else {
                # Use current directory
                $fileDir = $basePath
        }

        # Set new name to current to get "False" on first while
        $newPath = $file.Fullname

        $i = 0
        while (Test-Path $newPath) {
                # Set new filename
                $newPath = $fileDir + "\" + $fileDate.ToString("yyyyMMdd_HHmmss") + "_" + $i.ToString("00") + $file.Extension
                $i++
        }

        # Write som info
        Write-Host $fNum.ToString().PadLeft(4) -ForegroundColor DarkYellow -NoNewline
        Write-Host " / " -ForegroundColor DarkGray -NoNewline
        Write-Host $allFiles.Count.ToString().PadRight(4) -ForegroundColor Yellow -NoNewline
        Write-Host "   Moving: " -ForegroundColor DarkGray -NoNewline
        Write-Host $file.Name -ForegroundColor Cyan -NoNewline
        Write-Host " -> " -ForegroundColor DarkGray -NoNewline
        Write-Host $newPath -ForegroundColor Green

        # Move and rename the file
        if ($testMode -ne $True) {
                Move-Item $file.Fullname $newPath
        }
}

Ending up with something like this:

Oh, and you can add -Recurse on the Get-ChildItem row…