Saturday, March 23, 2013

Creating Desktop Shortcuts using Powershell

If you've been wanting to create shortcuts using Powershell and all the examples on the web don't work then you've come to the right spot.

Aside from the code provided here, you can also download my free tool at:

http://download.cnet.com/Powershell-Shortcut-Builder/3000-2344_4-76168548.html

For Access:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Access.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "C:\Program Files (x86)\Microsoft Office\Office15\MSAccess.exe"
$Sc.Description = "Access Link"
$Sc.Save()

For the Calculator:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Calc.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "Calc"
$Sc.Save()

For Disk Management:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "diskmgmt.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "diskmgmt.msc"
$Sc.Description = "Disk Management Link"
$Sc.Save()

For Excel:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Excel.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "C:\Program Files (x86)\Microsoft Office\Office15\Excel.exe"
$Sc.Description = "Excel Link"
$Sc.Save()

For MSPaint:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "MSPaint.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "MSPaint.exe"
$Sc.Description = "MSPaint Link"
$Sc.Save()

For Notepad:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Notepad.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "Notepad.exe"
$Sc.Description = "Notepad Link"
$Sc.Save()

For Word:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Word.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "C:\Program Files (x86)\Microsoft Office\Office15\winword.exe"
$Sc.Description = "Winword Link"
$Sc.Save()

For Wordpad:

$ws = New-Object -com WScript.Shell
$Dt = $ws.SpecialFolders.Item("Desktop")
$Scp = Join-Path -Path $Dt -ChildPath "Wordpad.lnk"
$Sc = $ws.CreateShortcut($Scp)
$Sc.TargetPath = "C:\Program Files (x86)\Windows NT\Accessories\Wordpad.exe"
$Sc.Description = "Wordpad Link"
$Sc.Save()

Also, if you want to add a link to this blog:

$ws = New-Object -comObject WScript.Shell
$Dt = $ws.SpecialFolders.item("Desktop")
$URL = $ws.CreateShortcut($Dt + "\Powershell Pain Relief.url")
$URL.TargetPath = "http://powershellpainrelief.blogspot.com"
$URL.Save()

Getting the local machine's IP Address

If you haven't seen this before, that's okay because I hadn't either:

[System.Net.Dns]::GetHostbyAddress($IP).HostName

The problem I have with this call is that it is mentally deprived. First, how can this be called without already knowing the IP address? It can't meaning, you already have a method to obtain the IP Address.  Why would you want to bother getting the HostName?

[System.Net.Dns]::GetHostbyName("WIN-SEN3DGN4RRM").HostName

This returns my FQDN:   WIN-SEN3DGN4RRM.Mary.Local

Same call but with a different property:

[System.Net.Dns]::GetHostbyName("WIN-SEN3DGN4RRM").AddressList[0].IPAddressToString

Returns: 10.1.10.14

ADSI getting the current domain


Really easy to get the active domain:

$iret = [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices")
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain

ManagementClass For Each

Here's an example of using the ManagementClass and enumerating with for each:

[System.Management.ManagementClass]$mc = New-Object System.Management.ManagementClass
$mc.Path.NamespacePath = "root\cimv2"
$mc.Path.Classname = "Win32_Process"
$mc.Scope.Options.Authentication = 6
$mc.Scope.Options.Imersponation = 3
$moc = $mc.GetInstances
foreach($mm in $moc)
{
    foreach($prop in $mo.Properties)
    {   
        $v = 30
        #$v = $v - $prop.Name.ToString().Length
        write-host $prop.Name.PadRight($v, " ") : $prop.Value
    }
   
}

Do Until Example

If your like me, Do until can dive you nuts.  Why? Becuase its the opposite of what you think the logic should be.  Here's an example.

$mos = new-object System.Management.ManagementObjectSearcher("Select * From Win32_Process")
$mos.Scope.Path.NamespacePath = "root\cimv2"
$mos.Scope.Path.Classname = "Win32_Process"
[System.Management.ManagementObjectCollection]$moc = $mos.Get()
$mocEnum = $moc.GetEnumerator()
$iret = $mocEnum.MoveNext()
do{
    [System.Management.ManagementBaseObject]$mo = $mocEnum.Current
    [System.Management.PropertyDataCollection]$propset = $mo.Properties
    $propEnum = $propset.GetEnumerator()
    $iret = $propEnum.MoveNext()
    do{
         [System.Management.PropertyData] $prop = $propEnum.Current
         [System.String]$s = $prop.Name
         write-host $s.PadRight(30, " ") : $prop.Value   
    }
    until($propEnum.MoveNext() -eq $False)
    write-host
}

until($mocEnum.MoveNext() -eq $False)

The MoveNext returns true until there is nothing left to enumerate through. So what is being said here is while MoveNext equals true allow the routine to loop. Here's the same thing with Do While:

$mos = new-object System.Management.ManagementObjectSearcher("Select * From Win32_Process")
$mos.Scope.Path.NamespacePath = "root\cimv2"
[System.Management.ManagementObjectCollection]$moc = $mos.Get()
$mocEnum = $moc.GetEnumerator()
$iret = $mocEnum.MoveNext()
do{
[System.Management.ManagementBaseObject]$mo = $mocEnum.Current
[System.Management.PropertyDataCollection]$propset = $mo.Properties
$propEnum = $propset.GetEnumerator()
$iret = $propEnum.MoveNext()
do{
[System.Management.PropertyData] $prop = $propEnum.Current
[System.String]$s = $prop.Name
write-host $s.PadRight(30, " ") : $prop.Value
}
    while($propEnum.MoveNext())
    write-host
}

while($mocEnum.MoveNext() )


Registry Identity Check

Excuse me, mister computer, just who in hades are you?

Kind of helps to answer that question with identity keys that are created in the registry and then discovered

                       function Check-machine-registry
                     {
                             try
                            {
                                [System.Boolean]$rt = $false
                                $Name = "KeyValueName"
                                $Path = "HKLM:\SOFTWARE\Some registry key path"
                                $key = Get-Item $Path  -ErrorAction SilentlyContinue
                                $value = $key.GetValue($Name)
                                if ($Value -ne "KeyValue")
                                {
                                    return $rt
                                }
                                $Name1 = "KeyValueName"
                                $Path1 = "HKLM:\SOFTWARE\Some registry key path"
                                $key1 = Get-Item $Path  -ErrorAction SilentlyContinue
                                $Value1 = $key1.GetValue($Name1)
                                if ($Value1 -ne "KeyValue")
                                {
                                    return $rt
                                }
                                $rt = $true
                                return $rt 
                            }
                            catch
                            {
                                return $rt
                            }
                    }

From net user with love

   function get-service-account-information
                        {
                            for($c=0;$c -lt 3;$c++)
                            {
                                $d = net user $UserNames[$c] /DOMAIN
                                Foreach($a in $d)
                                {
                                    if($a.contains("Account active") -eq $true)
                                    {
                                        $Active = $a.Replace("Account active","")
                                        $Active = $Active.Trim()
                                        if($Active.contains("Yes") -eq $true)
                                        {           
                                            $strActive[$c] = "Yes"
                                        }
                                    }
                                    else
                                    {
                                        $strActive[$c[ = "No"
                                    }
                                    if($a.contains("Account expires") -eq $true)
                                    {
                                        $AExpires = $a.Replace("Account expires","")
                                        $AExpires = $AExpires.Trim()
                                        if($AExpires.contains("Never") -eq $false)
                                        {
                                     $AExpires = $a.Replace("Account expires","")
                                            $AExpires = $AExpires.Trim()   
                                            $dt = [DateTime]$AExpires
                                            $f = $([DateTime]::Now - $dt)
                                            [System.String]$g = $f.TotalMilliSeconds/86400000
                                            $pos = $g.IndexOf(".")
                                            $g = $g.Substring(0, $pos)
                                            $strAccountExpires[$c] = $g
                                        }
                                    }
                                    if($a.contains("Password expires") -eq $true)
                                    {
                                        $PExpires = $a.Replace("Password expires","")
                                        $PExpires = $PExpires.Trim()   
                                        $dt = [DateTime]$PExpires
                                        $strPasswordExpiresDate[$c] = "Password is set to expire on: " + $PExpires
                                        $f = $($dt - [DateTime]::Now)
                                        [System.String]$g = $f.TotalMilliSeconds/86400000
                                        $pos = $g.IndexOf(".")
                                        $g = $g.Substring(0, $pos)
                                        $g = $g.Trim()
                                        $strPasswordExpires[$c] = $g
                                    }
                                    if($a.contains("Password last set") -eq $true)
                                    {
                                        $PLastSet = $a.Replace("Password last set","")
                                        $PLastSet = $PLastSet.Trim()   
                                        $dt = [DateTime]$PLastSet
                                        $strPasswordLastSet[$c] = $dt
                                    }
                                    if($a.contains("User may change password") -eq $true)
                                    {
                                        $PChangeable = $a.Replace("User may change password","")
                                        $PChangeable = $PChangeable.Trim()
                                        if($PChangeable.contains("Yes") -eq $true)
                                        {           
                                            $strPasswordChangeable[$c] = "true"
                                        }
                                        else
                                        {
                                            $strPasswordChangeable[$c] = "false"
                                        }
                                    }
                                }
                            }
                        }  

Using WMI WbemScripting.SWbemLocator


More code, less talking.

$Locator = new-Object -comObject WbemScripting.SWbemLocator
$svc = $Locator.ConnectServer(".", "root\cimv2")
$ob = $svc.Get("Win32_Process")
$objs = $ob.Instances_(0)

for($x=0;$x -lt $objs.Count;$x++)
{

        $mo = $objs.ItemIndex($x)
        $propEnum = $mo.Properties_.GetType().InvokeMember("_NewEnum", [System.Reflection.BindingFlags]::InvokeMethod, $Null, $mo.Properties_, $Null)
        $ret = $propEnum.MoveNext()
        do
        {
            $prop = $propEnum.Current
            [System.String]$s = $prop.Name
            write-host $s.PadRight(30, " ") : $prop.Value
        }
        Until($propEnum.MoveNext() -eq $False)
     write-host
    }

Multi Dimantional Arrays Framework Style

I know the standard Powershell array creation looks like this: $myArray = @(), but I wanted something more. Something with some teeth.

One Dimensional Array:
$myarray = [Array]::CreateInstance([String], 10)

Two Dimensional Array:
$myarray = [Array]::CreateInstance([Object], 10, 10)

Three Dimensional Array:
$myarray = [Array]::CreateInstance([Boolean], 10, 10, 10)

Not sure why anyone would want to create a 10 x 3 matrix but I wanted to show that the type of object you want to use goes first. followed by the amount of dimensions and their 1 based amount.

One based?

Yep. Try doing 10. 9 is the limit minus 1 for 0 equals 10

$UserNames = [Array]::CreateInstance([String], 3)
$UserNames[0] = "First User"
$UserNames[1] = "Second User"
$UserNames[2] = "Third User"


An additioanl advantage here is that you can use GetLength

for($c=0;$c -lt $UserNames.GetLength(0);$c++)
{

write-host $UserNames.GetValue($c)
}

Fun with the .Net Framework

Okay, admittedly, there are a slew of blogs and web pages that cover exactly the same thing.

I just do it a bit differently.

Here's an example of what I mean:

Someone makes a big deal about the below information:

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Hello World")


I do this:

#This line creates a WScript.Shell COM object I will use to set the current directory. 
$ws = new-object -comobject WScript.Shell

#This line loads SCOM 2007 SDK Operations Manager Framework
$iret =[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager")
#This line creates a pointer to a specific ManagementPack I want to unseal
$mp = new-object Microsoft.EnterpriseManagement.Configuration.ManagementPack("C:\Program Files\System Center Operations Manager 2007\System.Library.mp")

#This line creates a pointer to the XmlWriter I will use to write out the XML with
$xmlWriter = new-object Microsoft.EnterpriseManagement.Configuration.IO.ManagementPackXmlWriter($ws.CurrentDirectory)

#This line writes the ManagementPack out in xml Format and tells me where the file is
$filename = $xmlWriter.WriteManagementPack($mp)

#This line displays a messagebox with the newly created filename and path
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show($filename)


I could have just as easily used: Write-Host $filename and been done with it.

But what is really going on here with: [System.Windows.Forms.MessageBox]::Show($filename)?

Well, for one thing, take a look at the image below:


The object, System.Windows.Forms.MessageBox, is created and is told to invoke a method called show.

Since this method takes many optional parameters, we use the one which enables us to use just one.