Monday, March 7, 2016

Everyday Powershell - Part 39 - Scheduling a Powershell Script in powershell

We've covered this ground before back in the early parts of everyday powershell. But now if you've got at least windows 8 or server 2012 there's actually really good support in the shell for scheduled tasks now.

We powershell enthusiasts spend a lot of time scheduling jobs to run scripts of various sorts. That's a lot of repetitive work. You know what? If you are doing a job manually a lot, might be a good idea to script it.

Here's a quick function that wraps up the new-scheduled task commands and makes it quick and easy to schedule a powershell script.

function new-scheduledscript{
    param(
        [Parameter(Mandatory=$true)]
        $scriptpath,
        [Parameter(Mandatory=$true)]
        $user,
        [Parameter(Mandatory=$true)]
        $password,
        [Parameter(Mandatory=$true)]
        $time,
        [Parameter(Mandatory=$true)]
        $taskname
    )
    $A = New-ScheduledTaskAction –Execute C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -Argument "-file `"$scriptpath`""
    $T = New-ScheduledTaskTrigger -Daily -At $time
    $S = New-ScheduledTaskSettingsSet
    $D = New-ScheduledTask -Action $A -Trigger $T -Settings $S
    Register-ScheduledTask $taskname -InputObject $D -User $user -Password $password
}

Pulled  the syntax for this from the documentation over here; https://technet.microsoft.com/en-us/library/jj649810(v=wps.630).aspx


Wednesday, February 24, 2016

Everyday Powershell - Part 38 - Get-WindowsUpdateStatus

Got annoyed this week with some windows update configuration issues, so wrote this powershell to pull the relevant configuration information from the windows registry;

function get-windowsupdatestatus{
    param(
        $COMPUTERNAME
    )
    $report = invoke-command -ComputerName $COMPUTERNAME -ScriptBlock {
            $days = "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
            $auoptions = "Notify before download","Automatically download and notify of installation","Automatically download and schedule installation","Automatic Updates is required and users can configure it"
            $temp= "" | select UpdateServer, UpdateDay, UpdateTime, NoAutoRebootWithLoggedOnUsers, NoAutoUpdate, UpdateOptions
            $temp.updateserver = (get-itemproperty HKLM:\\Software\Policies\Microsoft\Windows\WindowsUpdate).wuserver
            $schedule = get-itemproperty HKLM:\\Software\Policies\Microsoft\Windows\WindowsUpdate\AU
            $temp.NoAutoRebootWithLoggedOnUsers = $schedule.NoAutoRebootWithLoggedOnUsers
            $temp.NoAutoUpdate = $schedule.NoAutoUpdate
            $temp.UpdateOptions = $auoptions[$schedule.AUOptions -2]
            $temp.updateday = $days[$schedule.ScheduledInstallDay -1]
            $temp.updatetime = (get-date -Hour ($schedule.ScheduledInstallTime).tostring().padleft(2,'0') -Minute 00 -Second 00 -Format "HH:mm")
            $temp
    }
    $report | select PScomputername, NoAutoRebootWithLoggedOnUsers,NoAutoUpdate,UpdateDay, UpdateTime,UpdateServer, UpdateOptions
}

This allowed us to see at a glance where the issues were across all our servers.

The script only runs in a single thread so it's slow. But it wouldn't be hard to multi-thread. In our case there were less than 100 servers to be reviewed so it wasn't a priority. If there's demand for a faster version we'll make it happen. Might be a good demo of how to take a single threaded powershell function and make it multi-threaded.


Monday, February 15, 2016

Everyday Powershell - Part 37 - Powershell Subnet Scanner

So we had a need to run a subnet scan this morning on a host where installing a subnet scanner would be a hassle. So powershell to the rescue!

Turns out there's a really easy but slow way to do this...
1..254 | ForEach-Object {test-connection ("192.168.6." + $_)}
Then there's a tricky way that's much quicker.
function start-subnetscan{
    param(
        $addressspace = "192.168.6.",
        $startip = 1,
        $endip = 254,
        $concurrentthreads = 30
    )
    $report = @()
    $startip..$endip | ForEach-Object {
        Write-Progress -Activity "Pinging Computers" -Status ("Pinging " + $addressspace + $_.tostring().padleft(3,"0") + " Starting Jobs. Started " + (get-job).count) -PercentComplete (($_ / $endip) * 100)
        start-job -scriptblock {
            $temp = "" | select IP, Online
            $temp.ip = ($args[0] + $args[1].tostring().padleft(3,"0"))
            $temp.online = test-connection $temp.ip -Quiet -Count 1
            $temp
        } -ArgumentList $addressspace, $_  
        while((get-job).count -ge $concurrentthreads){
            Write-Progress -Activity "Pinging Computers" -Status ("Waiting for resources. " + (get-job).count + " jobs running") -PercentComplete (($_ / $endip) * 100)
            $report += Get-Job | where state -eq 'completed' | Receive-Job
            Get-job | where state -eq 'completed' | Remove-Job
        }                           
    }
    $report += get-job | wait-job | Receive-Job
    $report | select IP, Online | sort IP | ft
    Get-job | wait-job  | Remove-Job
}

So to give you an idea of the power of multi threading we setup both commands so we could run them through measure-command and then we raced them!
Measure-Command -Expression {start-subnetscan} 
Days              : 0
Hours             : 0
Minutes           : 2
Seconds           : 55
Milliseconds      : 951
Ticks             : 1759513835
TotalDays         : 0.00203647434606481
TotalHours        : 0.0488753843055556
TotalMinutes      : 2.93252305833333
TotalSeconds      : 175.9513835
TotalMilliseconds : 175951.3835

Measure-Command -Expression {1..254 | ForEach-Object {test-connection ("192.168.6." + $_) -count 1}} 
Days              : 0
Hours             : 0
Minutes           : 11
Seconds           : 26
Milliseconds      : 940
Ticks             : 6869401183
TotalDays         : 0.00795069581365741
TotalHours        : 0.190816699527778
TotalMinutes      : 11.4490019716667
TotalSeconds      : 686.9401183
TotalMilliseconds : 686940.1183
 
Have a look at that! Running it multi-threaded made it 3 times faster.

Sunday, February 14, 2016

50000 Page Views

We just clocked over 50000 page views.


To celebrate lets review our most popular posts;
Looks like it's quick simple functionality that people are after. Well that's great because that's what we're all about with the everyday powershell series. Quick (and sometimes dirty) shell scripts that just get the job done.

We'll keep posting if you guys keep reading! Thanks for your attention and support over the years. If you've got any requests tweet them or google+ them at me @benhaslett 

Tuesday, December 15, 2015

Everyday Powershell - Part 36 - Check-EliteDangerous

So as this is typed the game Elite Dangerous is being patched to version 1.5 when the patch is done we'll be able to land our ships on planets!!! PLANETS!

We're all pretty excited by this and want to know as soon as the game is ready to play again. Well here's where powershell can help!

$issuesstring = (ConvertFrom-Json (invoke-webrequest http://hosting.zaonce.net/launcher-status/status.json).content).text
while ((ConvertFrom-Json (invoke-webrequest http://hosting.zaonce.net/launcher-status/status.json).content).text -eq $issuesstring){
    Write-host ((get-date).tostring() + " " + $issuesstring)
    Start-Sleep -Seconds 300
}
Write-Warning "We're on!"
[Reflection.Assembly]::LoadWithPartialName('System.Speech') | Out-Null
(New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak("Go get em commander!")

Simple loop that'll tell you when then status changes.

Tuesday, November 24, 2015

Everyday Powershell - Part 35 - Check for eDellRoot certificate

So Dell, bless their wee hearts, have been shipping their own root cert with new laptops. Problem is the private key is available to everyone who's got a copy of this cert! Which means any halfwit could sign ANYTHING and if this cert is in your root certs that halfwits stuff is going to be trusted on your computer.

Better check if that cert is there;
Get-ChildItem -path cert:\LocalMachine\root | where Thumbprint -eq 02c2d931062d7b1dc2a5c7f5f0685064081fb221
Get-ChildItem -path cert:\LocalMachine\root | where Thumbprint -eq 98a04e4163357790c4a79e6d713ff0af51fe6927

There's two of them, check for both. If they're there just delete them. It might break some of the Dell bloatware that ships with the laptops. But better to live without bloatware than have some dodgy root cert that every man and his dog has the private key for.

Sunday, September 13, 2015

Everyday Powershell - Part 34 - Browse the internet in private

Everyday Powershell. Getting you into the shell by providing little doses of utility that you could use everyday!

Does your Countries Government spy on it's citizens internet activity?

Do you think that's maybe a bit of a overreach?

Lot's of other people think that too!

One of the things the technically minded of us do to keep prying eyes from our private lives is run VPNs. If you've setup a VPN and have a dialler in windows you want to trigger you can use this script to fire up the VPN then kick off Chrome in Incognito Mode.


001
002
003
004
005
006
007
008
009
010
011
$connections = rasdial.exe
if ($connections -contains "No Connections"){
    rasdial.exe "SOME DIALER NAME", "SOMEUSER", "SOMEPASSWORD"
}

Start-Process "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -ArgumentList "-incognito"


#Create a desktop Shortcut with this;
#C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "& 'c:\scripts\dial-vpn.ps1'"