31 December 2014

PowerShell 5.0 and the OneGet commandlets

Great new feature coming up in WMF 5.0: OneGet.
Most people are familiar with the package managers within the different Linux tastes.

Well OneGet is just like that but then for Windows.
Command line based software installation and un-installation.
It works with the Chocolatey as the software repository which currently holds up 2561 applications.

There are 2 more repository's, PSGallery and MSPSGallery but they hold none to little applications.

First let's see what we can do with OneGet:

Get-Command -Module OneGet | Select Name

Name
----
Find-Package
Get-Package
Get-PackageProvider
Get-PackageSource
Install-Package
Register-PackageSource
Save-Package
Set-PackageSource
Uninstall-Package
Unregister-PackageSource

If you want to start using OneGet, you first have to install "nuget":

Find-Package

The provider 'nuget v2.8.3.6' is not installed.
'nuget' may be manually downloaded from
'https://oneget.org/nuget-anycpu-2.8.3.6.exe' and copied to 'C:\Program
Files\OneGet\ProviderAssemblies'.
Would you like OneGet to automatically download and install 'nuget' now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"):

To view the installed repositories:
Get-PackageSource
To view the total number of packages in the repository:
Find-Package | Measure-Object
To show all the packages in the repository:
Find-Package | Sort-Object –Property Name | Out-GridView
Install a package:
install-package -Name imgburn
To uninstall a package:
uninstall-package -Name imgburn
Set the repository as trusted:
set-packagesource -name chocolatey -trusted
To unregister the Chocolatey repository:
Unregister-PackageSource –name Chocolatey

Source

16 December 2014

Schedule a PowerShell script with task scheduler

For all your status emails that you want to run every day the task scheduler is your friend, well sort of.
Sometimes i just can't understand why it throws errors at me.
I found a nice article about this over at Dmitry's blog.

1. Get your script ready
Surprising as it might sound, your script might actually not be ready to run in a scheduled task as is. This happens if it uses cmdlets from a particular PowerShell module or snapin, and it worked for you interactively because you used a specialized shell (e.g. Exchange Management Shell) or a tool like PowerGUI Script Editor which loads the modules for you.
If you indeed are using using any non-default cmdlets, simply add Add-PSSnapin or Import-Module to the beginning of the script. For example:

Add-PSSnapin Quest.ActiveRoles.ADManagement
2. Schedule the task
To schedule a task simply start Windows Task Scheduler and schedulepowershell.exe executable passing the script execution command as a parameter. The -File parameter is the default one so simply specifying the script path as the argument would work in a lot of cases:
You can find powershell.exe in your system32\WindowsPowerShell\v1.0 folder.
4. Report task success or failure
If you want your script to report success or failure (or some sort of other numerical result) simply use the exit keyword in the script to pass the value, e.g.:
exit 4
Then your Windows Task Scheduler will show the value in the Last Run Result (you might need to hit F5 to refresh the column in the task scheduler):
3. Passing parameters
If you need to pass parameters things get a little trickier. Say, you have a script which adds two numbers:
param($a=2, $b=2)
"Advanced calculations ahead"
exit $a + $b
To pass the numbers as parameters, you would want to use powershell.exe -Command instead of powershell.exe -File. This -Command argument will then have the script invocation operator &, path to the script, and the parameters. E.g.:
Program:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Add argument (optional)-Command "& c:\scripts\hello.ps1 -a 2 -b 3"
If you want to also get your exit code from the script, you would need to re-transmit that by adding exit $LASTEXITCODE to the command (I learnt this tip from MoW). E.g.
Program:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Add argument (optional)-Command "& c:\scripts\hello.ps1 -a 2 -b 3; exit $LASTEXITCODE"
5. Run x86 PowerShell on x64 Windows
On 64-bit versions of Windows you actually have both 64-bit and 32-bit versions of PowerShell. In most cases you don’t care but in some cases (e.g. specific COM objects being used) you might need specifically a 32-bit version. To get that to run, simply pick the proper executable when you schedule the task:
Regular PowerShell (64-bit version on 64-bit Windows):%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
32-bit PowerShell (x86):%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe
6. Other options
To learn about all parameters PowerShell executable has simply run it with /? option (from either cmd.exe or a PowerShell session).
I normally use -noprofile to make sure that nothing in the PowerShell profile interferes with the task.
Also, if your Execution Policy does not allow running scripts the -ExecutionPolicy parameter comes handy allowing you to make an exception just for this task. E.g.:
c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File c:\scripts\hello.ps1 -ExecutionPolicy RemoteSigned
Here are some other parameters provided by PowerShell:
-PSConsoleFile
    Loads the specified Windows PowerShell console file. To create a console
    file, use Export-Console in Windows PowerShell.
I guess you could use that is you want the exact environment you have in the predefined shell from Exchange, AD, or SQL. E.g.: PowerShell -PSConsoleFile SqlSnapIn.Psc1
-Version
    Starts the specified version of Windows PowerShell.
I don’t think this one actually works.
-NoLogo
Hides the copyright banner at startup.
Not really relevant for scheduled tasks, imho…
-NoExit
    Does not exit after running startup commands.
Might be useful for troubleshooting.
-Sta
    Start the shell using a single-threaded apartment.
If your script needs STA mode (if you don’t know what this is – most likely you don’t need this. ;))
-NonInteractive
    Does not present an interactive prompt to the user.
Not really relevant for scheduled tasks, imho…
-InputFormat
    Describes the format of data sent to Windows PowerShell. Valid values are
    "Text" (text strings) or "XML" (serialized CLIXML format).

-OutputFormat
    Determines how output from Windows PowerShell is formatted. Valid values
    are "Text" (text strings) or "XML" (serialized CLIXML format).
-WindowStyle
    Sets the window style to Normal, Minimized, Maximized or Hidden.
Unfortunately, I could not make this work. I tried to use -WindowStyle Hiddento avoid the PowerShell console window popping up during task execution but with no luck.
-EncodedCommand
    Accepts a base-64-encoded string version of a command. Use this parameter
    to submit commands to Windows PowerShell that require complex quotation
    marks or curly braces.

    # To use the -EncodedCommand parameter:
    $command = 'dir "c:\program files" '
    $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
    $encodedCommand = [Convert]::ToBase64String($bytes)
    powershell.exe -encodedCommand $encodedCommand
Can be useful when having to pass advanced expressions and getting issues with parser.

02 December 2014

Check WAN IP address at icanhazip.com and mail the results

Since my ISP had planned maintenance last week, i couldn't access my boxes at home from the internet. My WAN IP address had changed. This happens once a year maybe but it's annoying enough to make something for it.

I found a great script from Leon van Efferen, but it didn't do exactly what i needed so i modified it a bit.

First off the check against whatismyip.com didn't work anymore, so i modified that to check against icanhazip.com.

Which by the way you can also do from Powershell directly:
(Invoke-WebRequest icanhazip.com).Content.Trim()
Then i wanted to receive an email everyday just to know it's still working and to be able to check my IP address always, not only if it changes.

This is what i came up with:
###########################################################################
#
# NAME:  CheckWANIP 
#
# COMMENT: Check the WAN IP Address based on ifconfig.me Automation page
#   and e-mail a message .
#
###########################################################################

#Set Target Domain
$TargetDomain = "domain.com" #Enter your FQDN that is linked to your WAN ip address

Function SendMail {
$EmailFrom = "IPCheck@domain.com" #Enter the e-mail address it should send the message from.
$EmailTo = "user@domain.com" #Enter the e-mail address it should send the message to.
$Subject = "External IP Address at icanhazip.com is $current_WAN_IP" #Enter your subject the e-mail message should contain.
$Body = "Compare the IP addresses from domain.com $DNS_WAN_IP and DNS records from ifconfig.me $Current_WAN_IP"  #Enter the message that the e-mail should contain.
$SMTPServer = "smtp.gmail.com" #Enter the FQDN of your SMTP server eg. smtp.gmail.com
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25) #Enter your SMTP Port eg. 587
$SMTPClient.EnableSsl = $false # Change to $false if you don't want to use SSL
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
}

# Do not change anything below this line.
$DNS_WAN_IP = [System.Net.Dns]::GetHostAddresses("$TargetDomain") | select-object IPAddressToString -expandproperty  IPAddressToString
Write-host "Resolved IP Address of $TargetDomain = $DNS_WAN_IP" 
$Current_WAN_IP = (Invoke-WebRequest icanhazip.com).Content.Trim()
Write-host "Current WAN IP Address = $Current_WAN_IP"
SendMail
Write-host "Sending email"
exit

Then you can schedule it as a daily task:
Powershell.exe "& 'C:\path to script\CheckWANIP.ps1'"