Monday, June 5, 2017

Everyday Powershell - Part 43 - Automatically Resume Failed HyperV Replication

Everyday Powershell, as useful as HyperV Replication.

So on our 2012R2 HyperV boxes we occasionally get problems with replication. Usually after a Windows Update related reboot.

So we could go through each of the VMs failed Replications, right click, resume replication but what are we? Barbarians?!?

We've scheduled the following script  to run on our hypervisors;

$hypervisor = "someserver"

$vms = Get-VMReplication -ComputerName $hypervisor | where health -eq "critical" | where state -ne replicating | where name -ne "someservertoexclude"

foreach($vm in $vms){
    while((Get-VM -ComputerName $hypervisor -VMName $ | where ReplicationState -ne "disabled" | get-vmReplication).state -ne "Replicating"){
        (get-VM -ComputerName $hypervisor -VMName $ | where ReplicationState -ne "disabled" | get-vmReplication).state
        if ((get-VM -ComputerName $hypervisor -VMName $ | where ReplicationState -ne "disabled" | get-vmReplication).state -ne "Resynchronizing"){
            get-vm $ -ComputerName $hypervisor | Resume-VMReplication -Resynchronize
            get-vm $ -ComputerName $hypervisor | Resume-VMReplication -Continue
            get-vm $ -ComputerName $hypervisor | Resume-VMReplication
            get-vm $ -ComputerName $hypervisor | get-VMReplication
        start-sleep -Seconds 10

get-vm -ComputerName $hypervisor | where health -eq "warning" | foreach-object {Reset-VMReplicationStatistics $}

So now when replication goes to hell because of a reboot, all the VMs just politley get back in line and do as they're told!

Friday, May 5, 2017

Everyday Powershell - Part 42 - Creating and populating Groups

Everyday Powershell, as useful as a loosely typed variable. In that sometime it's great others it can ruin your day!

So we're following on from last time where we learned the resolution of all the monitors we could talk to.

Now we're going to do something with that data.
import-csv C:\temp\monitoraudit.csv | where pcon -eq $true | where ScreenWidth -ne "" | ForEach-Object{
    $temp = "" | select pc, resolutionstring
    $temp.pc = $_.computername
    $temp.resolutionstring = ("PCs with screens at " + $_.ScreenWidth + "x" + $_.ScreenHeight)
    $test = $null
    $test = get-adgroup $temp.resolutionstring
    if($test -eq $null){
        New-ADGroup -GroupScope DomainLocal -Name $temp.resolutionstring
    Add-ADGroupMember $temp.resolutionstring -Members (get-adcomputer $temp.pc)
We use another foreach-object to jump over each row in our CSV
  • setup another temp object 
  • fill the temp object if useful information, PC name and a string with the resolution
  • we check if an AD group with the name of our string exists
  • if it doesn't we create the group
  • then we add the PC Name to the AD group
So what can we do with this? Well it's really useful to had AD groups with all your machines resolutions. You can;
  • See who management likes
  • Create interesting reports on which monitors should be replaced
  • Use the groups to apply policies to
The last one is what we're doing this for. We'll use these groups to target customised wallpapers, screen savers and login screens.

Friday, April 28, 2017

Everyday Powershell - Part 41 - Get Screen Resolution from remote PCs

Everyday powershell. It's not updated everyday, it's tools you could use daily.

You know sometimes you just need to know what resolution all your computers are running.
get-adcomputer -Filter {operatingsystem -like "Windows 7*"-Properties operatingsystem | ForEach-Object {
    $temp = "" | select computername, ScreenHeight, ScreenWidth, pcon
    $temp.pcon = Test-Connection $ -Count 1 -Quiet
    $temp.computername = $
        $resolution = Get-WmiObject -ComputerName $ -Class Win32_DesktopMonitor
        $temp.ScreenHeight = $resolution.ScreenHeight
        $temp.ScreenWidth  = $resolution.ScreenWidth
    $temp | export-csv C:\temp\monitoraudit.csv -Append

Check out the filter on the first line, that can be anything. We just needed Windows 7 machines.

It's a pretty easy foreach-object;

  • sets up a temp object in my favorite manner,
  • pings the machine to make sure it's up,
  • pulls the info we need from WMI
  • then bangs it out to the console and a CSV.
Hitting up each machine with a WMI query gets us fast results but it's not exactly complete. You could rejig this so that it ran as part of a login script or schedule it to run daily.

Why do we need this info? Well that's for next time when we'll do something useful with this data set we've created.

Thursday, November 24, 2016

Windows 10 Delivery Optimization Service

Ok so how the heck didn't I know this was a thing?

From that site

How is my PC used to send apps and updates to other PCs?
Delivery Optimization downloads the same updates and apps that you get through Windows Update and the Windows Store. Delivery Optimization creates a local cache, and stores files that it has downloaded in that cache for a short period of time. Depending on your settings, Windows then send parts of those files to other PCs on your local network or PCs on the Internet that are downloading the same files.

So I'm essentially seeding windows updates from my home PC? Which is great and all, a really efficient use of resources... For the people trying to distribute the updates.
Me I guess I've gotta suck up the rest of the month (22 days) with no download allowance. How generous of me.

Running with the powershell theme that we're all about here... Here's how you would stop that;

Get-Service DoSvc | Set-Service -StartupType Disabled

Sunday, April 17, 2016

Everyday Powershell - Part 40 - Get folder size

So my daughter (10 months) and I were hanging out on the couch listening to Pandora. I encourage her to play with the media center keyboard and she was doing that with gusto. When WHAM! Media Center PC hangs and when it reboots is unable to start the operating system.

We did a full power cycle and it came back fine, but reported low disk space. So it looks like my little girl hit her first problem with a full disk and windows hibernation. I'm so proud!

Her spamming had apparently asked the computer to hibernate. It tried but ran out of disk. So after getting back into the OS we needed to do a bit of a review and free up some space. At this point it dawned on us what our next part of Everyday Powershell was going to be about!

function get-foldersizes{
    param($startFolder )

    $report = @()

    $count = 0
    $colItems = ((Get-ChildItem $startFolder ) + (Get-ChildItem $startFolder -Hidden))
    foreach ($i in $colItems){
        write-progress -activity "Coutin Files" -Status $i.fullname -percentcomplete (($count / $colitems.count) * 100)
            $subFolderItems = (Get-ChildItem $i.FullName -File -Recurse | Measure-Object -property length -sum)
            $subFolderItems = $i.FullName | Measure-Object -property length -sum
        $temp = "" | select folder, size
        $temp.folder = $i.FullName
        $temp.size = [math]::round(($subFolderItems.sum / 1MB),2)
        $report += $temp
    $report | sort size

Super simple function that gets the size of all folders in $startfolder if that's null it just grabs the current folder.

So once the function was up and running my girl and I found an old copy of marvel heroes taking up 11gb. We deleted that and got back to the important business of playing with blocks!

Reference - We used this technet article as the basis for our script.

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{
    $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;

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{
    $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")
    $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.