Wednesday, January 29, 2014

What I learned at the Winter Scripting Games - Part 2

Our scripts for event 1 have been uploaded but they were far from finished. I blame Australia Day for eating our last Saturday of free time. There's a reason it's called National Drunk Day... It's the day we're Drunk all Day.

Our team "Awesome" has 4 members, 2 complete newbies, 1 observer and Me. We've taken on a bit of work trying to learn as we go but it's been really illuminating even if we're not getting all the way through the events.

We're learning to collaborate on distributed software projects

We're learning about setting up functions to run with pipe lined input

We're learning about all that help stuff that's at the top of everyone's scripts

We're learning to teach each other about the fundamentals of computer programming

Just deciding to be in the event and have a go puts us ahead of the majority. We're not expecting to take gold in any events, that's not what this is about. We get interesting problems that have been hand picked to teach us something. We have to work together and come up with working solutions and that experience has been invaluable already!

Wednesday, January 22, 2014

Everyday Powershell - Part 15 - Reading event logs with specific date ranges

Last post we were talking about using specific dates in our event log checker... So here's how;

$ComputerName = "SOMESERVER"
[String[]]$EventLogNames=@("Application","System")#Main eventlogs
$EventStartDate = get-date -date "18/12/2013 7:00pm" #(Get-Date).addhours(-1)
$EventEndTime = get-date -date "18/12/2013 9:00pm" #(Get-Date).addhours(-0)

$EventCritea = @{logname = $EventLogNames; StartTime=$EventStartDate; EndTime=$EventEndTime}

Get-WinEvent -ComputerName $ComputerName -FilterHashTable $EventCritea  -ErrorAction SilentlyContinue | fl

Pretty simple really.

Friday, January 17, 2014

Change Storage Location of Smart Paging File and Snapshot location for HyperV VMs

So when you provision a big HyperV machine and forget to change the default location for "Virtual Machines" it won't take long till the system volume of your Hyper visor starts to run out of disk.

After you punish the admin that didn't change the default Virtual Machine Location you can use this script to move the paths to same folder as the first VHD of each VM.

$vms = get-vm -ComputerName SOMEHYPERVBOX | where {$_.smartpagingfilepath -like "c:\*"} | select Name, SmartPagingfilepath

foreach ($vm in $vms)
{
    [string]$newpath = [system.io.path]::getdirectoryname((Get-VM -ComputerName 
SOMEHYPERVBOX -Name $vm.name | Get-VMHardDiskDrive|select -first 1).path)
    [string]$name = $vm.name
    Move-VMStorage -ComputerName 
SOMEHYPERVBOX -VMName $name -SmartPagingFilePath "$newpath" -SnapshotFilePath "$newpath"
}
This works for us, you may need to tweak it to comply with the particular requirements of your environment.

Good luck and make sure that Admin never rolls servers into prod with default settings again!

Wednesday, January 15, 2014

What I learnt at the Winter Scripting Games - Part 1 - Subnet Scanner

We're done with the practice event for the winter scripting games and one of the first requirements was a subnet scanner! I've always wanted one of those! So we wrote one and it's here for you to use;
$MaxThreads = 20
$network = "192.168.92."
#$subnet = "24" #TODO... set $rangestart and $rangeend to the appropriate values based of subnet... Anyone know how to achieve that algorithmically? We'll just leave it as a manual setting for now
$rangestart = 1
$rangeend = 254
$counter = $rangestart

$scriptblock = {param($ip)
    $temp ="" | Select-Object IP, Status
    $temp.status = "Fail"
    $test = $null
    $temp.ip = $ip 
    $test = test-connection $ip -count 1
    if ($test -ne $null)
    {
        $temp.Status = "Success"
    }
    write-output $temp -NoEnumerate
}

while ($counter -le $rangeend)
{ 
    Write-Progress  -Activity "Pinging $ip" -Status "Waiting for threads to close" -CurrentOperation ("" + $counter + " threads created - " + ((Get-Job -state running).count) + " threads open") -PercentComplete $prog
    $prog = ($counter / $rangeend) * 100  
    $ip = $network + $counter.ToString()
    While ($(Get-Job -state running).count -ge $MaxThreads)
    {
         Write-Progress  -Activity "Pinging $ip" -Status "Waiting for threads to close" -CurrentOperation ("" + $counter + " threads created - " + ((Get-Job -state running).count) + " threads open") -PercentComplete $prog
    }
    Start-job -ArgumentList $ip, $outputpath -scriptblock $scriptblock -Name ("subnetscans"+$ip) | out-null
    $counter++
    start-sleep -Milliseconds 200
}
$report = Get-Job -Filter "name -like 'subnetscans*'" | Receive-Job -wait
$report | select IP, Status
This is a neat example of using start-job to create a multi-threaded script.

Thursday, January 2, 2014

Everyday Powershell - Part 14 - Working with event logs at specific times

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems

Missed a week over Christmas and a day late with this post. We trust you'll forgive us, holidays is holidays. For us that means no computer.

Today's script is a simple one for looking at all the events in an event log within a certain time frame.

It's the kind of script you need when the boss reports odd behavior on his or her PC. You ask "what time was this boss?" bang in the time frames the boss reports into this script and you'll get a list of events in that time frame! Oh powershell you're so useful!

[String]$ComputerName = "someserver"
[String[]]$EventLogNames=@("Application","System")#Main eventlogs
$EventStartDate = (Get-Date).addhours(-6)
$EventEndTime = (Get-Date).addhours(-4)

$EventCritea = @{logname = $EventLogNames; StartTime=$EventStartDate; EndTime=$EventEndTime}
Get-WinEvent -ComputerName $ComputerName -FilterHashTable $EventCritea  -ErrorAction SilentlyContinue

$eventstatdate and $eventstarttime don't have to be relative to the current time. Bonus points if you can figure out the correct syntax for inputting an arbitrary time.

Wednesday, December 18, 2013

Everyday Powershell - Part 13 - Working with SQL Server in powershell

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems


Today's script isn't very long. It's difficult to write SQL that will work on generic servers. This line will list the all the Databases on a given SQL server.


invoke-sqlcmd -ServerInstance "SOMESQLSERVER" -Query "SELECT * FROM [master].[dbo].[sysdatabases]"

Yes that's right you can send a SQL query off to your DB server and get the results back as a powershell object! This is freaking amazing! You'll have to use a bit of imagination and think up ways to make SQL queries in your environment, but once you start coming up with scenarios you won't stop! There are any number of powerful combinations possible when you can pull SQL data into powershell. 

We've just implemented a monitoring script that checks a table for new rows and if there aren't any new rows within the last ten minutes it emails us.


Add-PSSnapin SqlServerCmdletSnapin100
$test = invoke-sqlcmd -ServerInstance "
SOMESQLSERVER" -Query "SELECT top 1 *
  FROM [SOMEDATABASE].[dbo].[SOMETABLE]
  order by [CreationDate] desc"

$tenminutesago = (get-date).addminutes(-10)
foreach ($item in $test)
{
    if ($item.creationdate -lt $
tenminutesago)
    {
        Send-MailMessage -SmtpServer SOMEMAILSERVER -from SOMEONE@SOMEDOMAIN.COM -to 
SOMEONE@SOMEDOMAIN.COM -subject "No data since $today" -Body $item
    }
}

To make this invoke-sqlcmd work we need to install the SQL management tools. We've done this by running the SQL 2012 installer wizard and making sure Management tools are ticked. Also in some OS configuration we've had to load the snapin manually.

Add-PSSnapin SqlServerCmdletSnapin100

Jay Querido has a great write-up over on his blog on what to do if invoke-sqlcmd doesn't work.

We'll see what other SQL scripts we can come up with over the next few weeks. We want to give examples that will work anywhere so if you think of anything let us know.

Wednesday, December 11, 2013

Everyday Powershell - Part 12 - Change the owner of all files in a folder

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems

This one was another request. We love requests please send more!

The reader wanted a script that would recursively set  the owner of all files in a folder.

As usual the scripting guys are all over this kind of thing.
http://blogs.technet.com/b/heyscriptingguy/archive/2008/04/15/how-can-i-use-windows-powershell-to-determine-the-owner-of-a-file.aspx

Our contribution was putting it in a loop and adding a progress indicator. Vital sanity proofing if you are going to watch this thing as it runs over thousands of files...
$path = c:\test
$objUser = New-Object System.Security.Principal.NTAccount("SOMEDOMAIN", "SOMEUSER")

$list = get-childitem $path -recurse
$count = $list.count
$i = 0

foreach ($file in $list)
{
    $i++
    $prog = ($i/$count) * 100
    Write-Progress -Activity "Processing" -percentcomplete $prog -Status $file.fullname
    $objFile = Get-Acl $file.fullname
    $objFile.SetOwner($objUser)
    Set-Acl -aclobject $objFile -path $file.fullname
}

Working with Access Control Lists is a bit funny. We can't just add things to the ACL we've got make a copy of it;
$objFile = Get-Acl $file.fullname

Perform the modification;
$objFile.SetOwner($objUser)

and then apply it to the file as a new ACL.
Set-Acl -aclobject $objFile -path $file.fullname