Get the daily forecast in your console, with PowerShell

October 20, 2014 FoxDeploy

Today I saw a post on reddit about scraping a webpage for weather information. Reading over the comments, I had an idea, and I quickly looked away wanting to try this myself before seeing what someone else posted.

http://www.reddit.com/r/PowerShell/comments/2jitvn/help_with_screen_scraping_or_interpreting_web/

If you don’t care about how this is done, skip to the bottom for the code, here is a preview of the finished product:

Reading the OP’s question, he basically wanted to get a weather alert if it was going to rain. I thought this a nice goal, but expanded further to wanting to get certain weather information like the temp, forecast and wind speed, right in the console when I started it up.

Knowing that PowerShell has exceptional WebService and Remote API capabilities, I started my search trying to locate a web service out there somewhere with a nice REST or JSON API available to get my weather info from.  I read about ForeCast.IO, an open API made for weather applications, with a very reasonable price (free for up to 1,000 queries a day!) and quickly signed up.

A note on APIs

One thing to keep in mind when setting up a tool like this is that you’ll need to generally register for an account to use most APIs. Many places will provide these services free for the first 1,000 or 10,000 queries, but then charge you a pittance beyond that. Keep this in mind when sharing code about things like this. If someone has your API Key, they are effectively you. If they leave your script running on a loop constantly hammering an API somewhere, you can be on the hook for $100’s.

Don’t give people your API key unless you’d feel safe giving them your physical or digital wallet.

weather_01 Make note of your API Key on this page.

If you’re OK with all of this,

Go to ForeCast.IO and sign up for an account then make note of the API key

Great, copy down your API and then hide it!

If we take a look at the documentation, we’ll see that to make a call, we simply need to run a web request, subbing in certain values, and in response we’ll get something back…

https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE

As stated above, we need to replace our API Key for the word APIKEY anywhere found in docs. We’ll also need to substitute in the latitude and longitude. If you look at the example on the site, they give the following to get the weather in Alcatraz. I’m hiding my API Key in $API_key

https://api.forecast.io/forecast/$API_key/37.8267,-122.423

If you run Invoke-WebRequest, then convert From JSON, you’ll have a nice PowerShell object.

weather_02 Um, the weather looks to be very bad in Alkatraz. Let’s cancel our vacation!

Now, if you want to look up your own city, you can get your latitude and longitude here.

This all all well and good, except the time comes back in Unix time format, which measures ticks on the clock since January 1st, 1970, so you can convert that with the following PowerShell code.  I got this approach from this answer from Keith Hill on StackOverflow.

[TimeZone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($weather.currently.time)) 

So, after pulling out a little bit of data, I have the following code. This will get the current temp, weekly summary, and also play an alert sound if any weather alerts are encountered! Hope you enjoy it!

A preview picture of the finished product:

weather_03

function Get-Weather{
param($city = "33.9533,-84.5406")
$API_key = "****PUT YOUR APIKEY HERE******"
$url = "https://api.forecast.io/forecast/$APIkey/$city"
 
If
 
$weather = Invoke-WebRequest $url | ConvertFrom-Json
 
$ForeCastTime = [TimeZone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($weather.currently.time))
 
("The weather is generally " + $weather.currently.summary + " and currently " + $weather.currently.temperature + " degrees Fahrenheit at " + $ForeCastTime.DateTime)
("wind is gusting up to " + $weather.currently.windspeed + " m/PH with a chance of precipitation at " +  $weather.currently.precipProbability)
#it is currently 54.9 degrees Fahrenheit at Monday, October 20, 2014 10:23:11 AM
 
("The weekly forecast is " + (($weather.daily.summary) -creplace '\?',"").ToLower())
 
("The following Weather alerts were found for the requested area")
$weather.Alerts | % {write-host `a;
        Write-host -ForegroundColor YELLOW $_.Title
        Write-host -ForegroundColor Red $_.Description}
 
#return a Global weather object for us to play with
$Global:weather = $weather
}

Continue Reading...

Download all the PowerShell summit videos...with PowerShell

October 16, 2014 FoxDeploy

This is just a rehash of a previous post of using YoutubeDL to parse playlists and download stuff, but here is doing it to download the European PowerShell Summit Videos.

$url = "https://www.youtube.com/playlist?list=PLfeA8kIs7Coehjg9cB6foPjBojLHYQGb\_"

$playlisturl = $url

$VideoUrls= (invoke-WebRequest -uri $Playlisturl).Links | ? {$\_.HREF -like "/watch\*"} | \` ? innerText -notmatch ".\[0-9\]:\[0-9\]." | ? {$\_.innerText.Length -gt 3} | Select innerText, \` @{Name="URL";Expression={'http://www.youtube.com' + $\_.href}} | ? innerText -notlike "\*Play all\*" | ? innerText -notlike "\*Play\*"

ForEach ($video in $VideoUrls){ Write-Host ("Downloading " + $video.innerText) .\\youtube-dl.exe $video.URL } 
Continue Reading...

Useful PowerShell ISE Snippets

October 15, 2014 FoxDeploy

Hi guys,

One of the best features of the PowerShell ISE is the presence of Snippets, a great engine to fill in code-snippets for common tasks.  I pretty much use this every single day!

Hit Control+J to display the snippet menu. You can hover over for more info and detailed syntax.

 

Making a new Snippet is kind of difficult though.  I found this wonderful little snippet that allows you to easily create more snippets.  I know.  Snippets in Snippets?  Not sure if it is more Ludacris or Inception though…

Rob the PowerShell DBA had this awesome snippet on his blog.

$snippet1 = @{
    Title = "New-Snippet";
    Description = "Create a New Snippet";
    Text = @"
`$snippet = @{
    Title = `"Put Title Here`";
    Description = `"Description Here`";
    Text = @`"
    Code in Here 
`"@
}
New-IseSnippet @snippet
"@
}
New-IseSnippet @snippet1 Force

From <http://sqldbawithabeard.com/2014/09/09/powershell-snippets-a-great-learning-tool/>

What does it do? Well, after running this in the ISE, you can hit Control+J and bam, an easy to fill in form to create a nice new Snippet.

[]Snippets00 You’ll use this on a weekly basis!

Fill in the values and hit F5 to create the snippet.

I love this so much, here are a bunch of snippets I use everywhere.

Custom Objects using Try/Catch

I made a whole blog post about doing this. It’s now my go-to standard when making information gathering tools.

$snippet = @{
    Title = "Try/Catch/Custom Objects";
    Description = "A great way to get good streamlined output while Try/Catching";
    Text = @"
        try {`$a=Get-WmiObject -Class Win32_ComputerSystem -ErrorAction Stop -ComputerName $name} 
   catch{`$a= [pscustomobject]@{Name=`$name;Domain="Access Denied"}}
   [pscustomobject]@{RUM_Name=`$name;ReplyName=`$a.Name;Domain=`$a.Domain} 
"@
}
New-IseSnippet @snippet

Quick PS Custom Object

Sometimes you just need to grab a bunch of info about a thing and make it a single object. Here’s how:

$snippet = @{
    Title = "Custom Object";
    Description = "I always forget how to do this!";
    Text = @"
       #Add more columns to the object by adding extra key/values
      [pscustomobject]@{Name=$name;Domain="Access Denied"}
"@
}
 
New-IseSnippet @snippet

Progress Bar within ForEach Loop

This looks easy but I would forget how to do it constantly.

$snippet = @{
    Title = "Write Progress Sample";
    Description = "Progress and how to do it";
    Text = @"
    #sample range of numbers
    `$users = (1..13000)
 
    #setting up base number
    `$i=0
     
    ForEach (`$user in `$users){
        #increment
        `$i++ 
 
        #Round the numbers up for a nice output and then Write-Progress
        Write-Progress -Activity "Processing `$user" -PercentComplete ((`$i/`$users.Count) * 100) -Status ("`$i out of " + `$users.Count +" completed "+[math]::Round(((`$i/`$users.Count) * 100),2) +" %")
        }
"@
}
New-IseSnippet @snippet

PowerShell V1 Custom Object Format

Sometimes you have to work on ancient systems and forget how to make old-school custom objects. Never again! This example is based on capturing the output of Get-MailboxStatistics within $mbx.

$snippet = @{
       Title = "PS 2.0 Custom Objects";
       Description = "Old Fashioned Custom Objects";
       Text = @"
       `$ObjectProperties = @{
Name = `$user
RecipientType=`$mbx.RecipientType
LastLoggedOnUserAccount=`$mbxstat.LastLoggedOnUserAccount
LastLogOffTime=`$mbxstat.LastLogOffTime
LastLogonTime=`$mbxstat.LastLogonTime
}
`$obj = New-Object PSObject -Property `$ObjectProperties
 
"@
   }
  New-IseSnippet @snippet6

Old-School Custom Objects using Try/Catch

A repeat of my first Custom Object loop, this time with Pre-V2 objects

$snippet = @{
    Title = "Old School try/catch custom object ";
    Description = "Using try/catch to create custom objects is a great way to capture information succinctly.  However, the [PSCustomObject] Accelerator/casting only work on PS 3 and up.  This example uses old school Items to get around that";
    Text = @"
    `$users | ForEach-Object { 
    `$name = `$_
    try {`$a=Get-mailbox `$name -erroraction Stop} 
   catch{   `$ObjectProperties = @{
        Name = `$name
        HiddenFromAddressListsEnabled="MBX Not Found"
        }
        `$a = New-Object PSObject -Property `$ObjectProperties}
 
 
       `$ObjectProperties = @{
            Name = `$name
            HiddenFromAddressListsEnabled=`$a.HiddenFromAddressListsEnabled
            }
        New-Object PSObject -Property `$ObjectProperties
   }
"@
}
New-IseSnippet @snippet

Display a Popup Prompt

This is a shorty, but a useful one!

$snippet = @{
    Title = "Popup Message";
    Description = "Add a simple pop-up message";
    Text = @"
    `$msg = New-Object -ComObject WScript.Shell
    `$msg.Popup("Hi Chris", 5, "DeadMau5", 48)
 
"@
}
New-IseSnippet @snippet
Continue Reading...

Upcoming Event - Using PowerShell for Active Directory October 29th 2014 8:00 AM PST

October 08, 2014 FoxDeploy

Hi all,

Wanted to draw attention to this nice remote event coming up at the end of the month.

Using PowerShell for Active Directory October 29th 2014 8:00 AM PST

Continue Reading...

Great new ISE Features in PowerShell 5.0 and Windows 10

October 07, 2014 FoxDeploy

This will be a quick post, but I want to highlight some of the great new features in the ISE for Windows 10 / WMF 5 and PowerShell 5.0. Currently you can use these features on Windows 8.1 and up if you install the WMF 5.0 September preview (found here) or find them natively installed on Windows 10 if you’ve had a chance to try the Tech preview.

Jump into Debugger from ISE

I LOVE this feature.  Previously to hop into Debugger you had to either apply [CmdletBinding] to your script or Function and litter your code with Write-Debug statements, or manually set $DebugPreference = $true to skirt [CmdletBinding].  With PowerShell v 5 this is no more!

Take the following code:

1..100000 | ForEach-Object {get-date; $\_ } 

Simple enough, iterate from 1 to 100000 and ForEach-Object, Get-Date and then write the current value.

Now, imagine if the math were a little different, something like this

1..100000 | ForEach-Object {get-date; 100 / ($\_ % 100) } 

Because we’re taking the remainder of 100 divided by our current number, when our number is perfectly divisble by 100 we’ll end up with a DIV/0 error state. If we wanted to debug or troubleshoot this code or other code from within the loop, we’d previously have needed to go through all sorts of hoops to add Debug statements.

New to PowerShell ISE v5 is the ability to hit Ctrl+B (yes, B, not C!) to jump into debug mode at any time.

It’s easy to miss in the ISE. When you launch any code, the status bar on the bottom of the window of the ISE will change from ‘Stopped’ or ‘Ready’ to the below

Running script / selection. Press Ctrl+Break to Stop. Press Ctrl+B to break into debugger.

Hitting Ctrl+B while our code is running changes our prompt too. We get a standard Write-Debug style display of which line the code was processing when we interuppted, and our prompt shifts into ‘[DBG]»’ mode, signaling that we are paused within execution of a script, and can access the variables available within script execution.

v5ISEchanges02

It now becomes very easy to access the current variable, making it very easy to troubleshoot why code fails in a particular situation.

v5ISEchanges03 Officially no excuse not to debug our code now!

This is a killer feature, in my opinion, and one I’ll highlight in my PowerShell teaching from now on.

AutoCompletion of DSC Resources

DSC support for the ISE started off a little rockily.  The ISE kind of knew what DSC was, but we Desired State Configuration fans didn’t get much love, and practically no autocomplete either!

I always found it hard to remember what the names or properties were of various resources (especially early on when things were not exactly 100% consistent between providers), and would have to reference my own blog post on the topic from time to time!

Now, there’s no forgetting.  When within a Configuration Scriptblock in the ISE, simply hit Ctrl+Space to display AutoComplete hints for the various resources available.

v5ISEchanges04

You can even select one and hit Ctrl+Space again to see a reminder of which properties are available for that Configuration Resource.

v5ISEchanges05

These great new features to the ISE contribute to make it an even better place to code.

Continue Reading...

Working back in the past: making OCS 2007 PowerShell tools in a Version 1.0 World

October 03, 2014 FoxDeploy

Recently, I had to work on an environment with PowerShell v. 1.0 (and I couldn’t upgrade it!) and Microsoft Office Communications Server 2007 (or OCS for those of us in the know).

Unfortunately for me, this became a journey of pain and discovery as I dove deep back into the dark annals of PowerShell history.

Here is a short list of things that did not work:

  • My modern day approach to tool writing includes throwing in Confirm and WhatIf as a matter of course, especially with potentially harmful actions like stripping OCS attributes from an account. WhatIf and $PSCmdlett don’t exist!
  • I like to set my tools up to do one of the following actions: create, set, process, report on particular types of objects. This means that I make liberal use of [Parameter] declarations relating to Pipeline input and aliases, all standard advanced functions nowadays. Advanced functions weren’t added until PS version 2.0!
  • I think it is due dilligence to make help and documentation for our tools, especially if they may outlive you in an environment. So for each of my functions, I added Comment-Based help. Guess what? Comment-based help wasn’t supported until PS version 2.0!
  • Comment blocks? Nope, Version 2.0, so I hope you like Batch style walls of hash signs.
  • [CmdletBinding] for -Debug or -Whatif? Nope, 2.0.
  • Running remotely? Nah! Version 2.0 introduced this feature, so enjoy running these commands locally, or tunneled through PSExec.

In the end, the functions I was left with worked, but felt very…very basic. In any case, here are a set of tools to help you enable, process and disable OCS users with PowerShell.

Note that you need to run these commands from an OCS server itself if you’re running PS 1.0. If you’re on a newer version, feel free to adapt these to work with you.

Big credit to this blog post for showing me the original WMI class to query for OCS info - http://blog.insideocs.com/2009/01/16/189/

####################################################################
#     ----Name : OCS 2007 Account Manipulation tools
#     ---Author: Stephen Owen, 10/3/2014
#     ----Ver 1: Release Version, all basic features provided but unfortunately advanced features like true whatif and true pipeline support won't work due to PowerShell limitations
#     Function : A set of tools based on this blog post to speed up Enabling and Disabling OCS accounts en masse - http://blog.insideocs.com/2009/01/16/189/
#     ---Usage : Use Get-OCSUser to obtain a list of all user accounts in OCS, filter this using Where-Object commands or comparisons and pipe into Disable or Enable-OCSuser Cmdlettes
##########################################
 
 
Function Get-OcsUser{
 
#.Synopsis
#   A simpler wrapper for Get-WMIObject on the Microsoft SIPEUser Class
#.DESCRIPTION
#   Long description
#.EXAMPLE
#   To obtain a list of all OCS Users
#
#   Get-OCSUser -Fi;;
#.EXAMPLE
#   To obtain only the users from OCS which match those found in a text file
#
#   Get-OCSUser | Where { (Get-Content C:\temp\DisableOCS.txt) -contains $_.DisplayName}
 
    param([switch]$Full)
    if ($Full){
        Get-WmiObject -class MSFT_SIPESUserSetting 
    }
    else{
        Get-WmiObject -class MSFT_SIPESUserSetting -Property DisplayName,Enabled,EnabledForEnhancedPresence,EnabledForFederation,UserCategory,PrimaryURI,InstanceID | Select DisplayName,Enabled,EnabledForEnhancedPresence,EnabledForFederation,UserCategory,PrimaryURI,InstanceID 
    }
}
 
 
 
Function Enable-OcsUser{
##
#.Synopsis
#   A wrapper for cretain WMI calls using Get-WMIObject on the Microsoft SIPEUser Class to enable users
##.DESCRIPTION
##Use this wrapper to ease the enablement of OCS Users using PowerShell.  Be sure to see the Examples for usage notes, as #PowerShell v1 limitations force some peculiar usage steps.
#.EXAMPLE 
##   Step 1 Obtain a list of all OCS Users and store in $OCS or a similar string
##
##   $OCS = (Get-OcsUser)
##
##   Step 2 Verify user to enable
##
##   $OCS | Where-Object {$_.PrimaryURI -eq "sip:Testy.McDelete@foxDeploy.com"} 
##
##   Step 3 ENABLE
##
   ##$OCS | Where-Object {$_.PrimaryURI -eq "sip:Testy.McDelete@foxDeploy.com"} | ForEach-Object {Enable-OCSUser -PrimaryURI $_.DisplayName} 
#.EXAMPLE
##   To obtain only the users from OCS which match those found in a text file, then enable them.  NOTE the usage of -WhatIf. 
##
##   Get-OCSUser | Where { (Get-Content C:\temp\DisableOCS.txt) -contains $_.DisplayName} | ForEach-Object {Enable-OCSUser -PrimaryURI $_.DisplayName -WhatIf} 
##
Param($PrimaryURI,[switch]$WhatIf)
        ForEach ($SIP in $PrimaryURI) {
            #get-wmiobject -class MSFT_SIPESUserSetting | where-object { $_.PrimaryURI -eq “sip:userid@SIPDomain” } | % { $_.Enabled = $True; $_.put() | out-null }
        if ($WhatIf){
            "Safety enablied, Would be enabling $PrimaryURI"
        }
        ELSE{
            "Safety released, actually enabling $SIP"
             Get-WmiObject -class MSFT_SIPESUserSetting | Where-Object { $_.DisplayName -eq $SIP } | ForEach-Object { $_.Enabled = $False; $_.put()
             Get-OcsUser | Where-Object {$_.DisplayName -eq $SIP}}
        }
 
         
         
        }
}
 
 
Function Disable-OcsUser{
##
#.Synopsis
#   A wrapper for cretain WMI calls using Get-WMIObject on the Microsoft SIPEUser Class to disable users
##.DESCRIPTION
   ##Use this wrapper to ease the deletion of OCS Users using PowerShell.  Be sure to see the Examples for usage notes, as #PowerShell v1 limitations force some peculiar usage steps.
#.EXAMPLE 
##   Step 1 Obtain a list of all OCS Users and store in $OCS or a similar string
##
##   $OCS = (Get-OcsUser)
##
##   Step 2 Verify user to disable
   ##
##   $OCS | Where-Object {$_.PrimaryURI -eq "sip:Testy.McDelete@foxDeploy.com"} 
##
##   Step 3 DELETE
##
   ##$OCS | Where-Object {$_.PrimaryURI -eq "sip:Testy.McDelete@foxDeploy.com"} | ForEach-Object {Disable-OCSUser -PrimaryURI $_.DisplayName} 
#.EXAMPLE
##   To obtain only the users from OCS which match those found in a text file, then disable them.  NOTE the usage of -WhatIf. 
##
##   Get-OCSUser | Where { (Get-Content C:\temp\DisableOCS.txt) -contains $_.DisplayName} | ForEach-Object {Disable-OCSUser -PrimaryURI $_.DisplayName -WhatIf} 
##>
Param($PrimaryURI,[switch]$WhatIf)
        ForEach ($SIP in $PrimaryURI) {
            if ($WhatIf){
                "Would be Disabling $PrimaryURI"
            }
            ELSE{
                "Safety released, disabling $SIP"
                Get-WmiObject -Class MSFT_SIPESUserSetting | Where-Object { $_.DisplayName -eq $SIP } | ForEach-Object { $_.Enabled = $False; $_.put()              
                    Get-OcsUser | Where-Object {$_.DisplayName -eq $SIP}
                    }
            }
 
        }
}
Continue Reading...

Microsoft MVP

Five time Microsoft MVP, and now I work for the mothership


Need Help?

Get help much faster on our new dedicated Subreddit!

depicts a crowd of people in a night club with colored lights and says 'join the foxdeploy subrreddit today'


Blog Series
series_sml_IntroToDsc
series_sml_PowerShellGUI series_sml_IntroToRaspberryPi Programming series_sml_IntroToWindows Remote Management Series The Logo for System Center Configuration Manager is displayed here Depicts a road sign saying 'Learning PowerShell Autocomplete'




Blog Stats