Archive | April 2014

Get all (non-default) scheduled tasks

I tried querying the scheduled tasks to give me a list of all (non-default) scheduled tasks. I also wanted to have its schedule information, which appeared to be a pretty hard task in the get-service command. After several unsuccessful attempts, I tried something else with great and immediate results. It appeared that the schtasks did give me all the info I need, so I query the tasks by using the schtasks dos tool and saving that information into variables.

Since all default tasks either have no computername, no author, next run time as N/A, or contains the author Microsoft. So first I will query for all scheduled tasks and then filter out those that I don’t need; thus leaving me with the tasks I need for my automatic documentation purposes.

I haven’t tested the script on Windows 2008, but I assume that it uses the same naming as Windows 2012; the commands itself are all Powershell 2 compatible, so should work on 2008 as they also work on Windows 2003.

In this script I don’t remove disabled tasks from the list, because I need to list those myself as well, but I did supply the line that you can add to the where-object part of the $ScheduledTasks to filter those out as well.

The text for every schedule was returned over several properties, of which I make a readable (pretty plain English) text at both Switch parts of the script (one for Windows 2003, the other for 2012 (and presumably 2008)). Beware of the spaces after Daily and Hourly, which schtasks appears to return!

 

#Get all scheduled tasks on the system in a Csv format
$Tasks = schtasks /query /v /fo csv | ConvertFrom-Csv
#Filtering out all Windows tasks for Windows 2k3 and 2k12 (and 2k8?)
$ScheduledTasks = $Tasks | Where-Object { $_.HostName -eq $env:COMPUTERNAME -and $_.Author -ne "N/A" -and $_.'Next Run Time' -ne "N/A" -and $_.Author -notmatch "Microsoft" -and $_.TaskName -notmatch "User_Feed_Synchronization" }
# -and $_.'Scheduled Task State' -ne "Disabled" # <-- Add this to the where-object selection in the line above to filter out disabled tasks as well

Foreach($ScheduledTask in $ScheduledTasks)
{
$Tasktext = ""
$ScheduledTask.'TaskName'.Substring($ScheduledTask.'TaskName'.IndexOf("\")+1)
$ScheduledTask.'Start In'
$ScheduledTask.'Task To Run'
#In case of W2k12 (and W2k8?)
If($ScheduledTask.'Schedule Type')
{
Switch($ScheduledTask.'Schedule Type')
{
"Hourly " { $Tasktext = $ScheduledTask.'Schedule Type' + "at " + $ScheduledTask.'Start Time' }
"Daily " { $Tasktext = $ScheduledTask.'Schedule Type' + "at " + $ScheduledTask.'Start Time' }
"Weekly" { $Tasktext = $ScheduledTask.'Schedule Type' + " on every " + $ScheduledTask.Days + " at " + $ScheduledTask.'Start Time' }
"Monthly"
{
If($ScheduledTask.Months -eq "Every month") { $Tasktext = $ScheduledTask.'Schedule Type' + " on day " + $ScheduledTask.Days + " at " + $ScheduledTask.'Start Time'}
Else { $Tasktext = "Yearly on day " + $ScheduledTask.Days + " of " + $ScheduledTask.Months + " at " + $ScheduledTask.'Start Time' }
}
}
}
#In case of W2k3
If($ScheduledTask.'Scheduled Type')
{
Switch($ScheduledTask.'Scheduled Type')
{
"Hourly " { $Tasktext = $ScheduledTask.'Scheduled Type' + "at " + $ScheduledTask.'Start Time' }
"Daily " { $Tasktext = $ScheduledTask.'Scheduled Type' + "at " + $ScheduledTask.'Start Time' }
"Weekly" { $Tasktext = $ScheduledTask.'Scheduled Type' + " on every " + $ScheduledTask.Days + " at " + $ScheduledTask.'Start Time' }
"Monthly"
{
If($ScheduledTask.Months -eq "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC") { $Tasktext = $ScheduledTask.'Scheduled Type' + " on day " + $ScheduledTask.Days + " at " + $ScheduledTask.'Start Time' }
Else { $Tasktext = "Yearly on day " + $ScheduledTask.Days + " of " + $ScheduledTask.Months + " at " + $ScheduledTask.'Start Time' }
}
}
}
#This line can be removed if the filter excludes disabled tasks
If($ScheduledTask.'Scheduled Task State' -eq "Disabled") { $Tasktext = "Disabled" }
$Tasktext
}

This leave you with the following 4 variables, which you can use for exporting or other purposes

$ScheduledTask.'TaskName'.Substring($ScheduledTask.'TaskName'.IndexOf("\")+1)
$ScheduledTask.'Start In'
$ScheduledTask.'Task To Run'
$Tasktext

You can download a copy of this script from my skydrive

Get all non-default Windows services

Getting a list of all services isn’t that hard. This can be achieved with Get-Service or with Get-WmiObject win32_service. It seems that Get-Service doesn’t leave me with enough properties to query and/or filter out, and this time the Get-WmiObject queries work quick enough; thus I’ll use this for my code.

I wanted a list of all non-default Windows services in Windows 2012… This I will use in a script that will automatically write documentation for the application servers which I manage.

I couldn’t find somethins like this, so decided to share my work and how I got to the result once I completed it.

It seems that if I filter out most MS services where its caption doesn’t contain ‘Windows’ or it’s path contains the text ‘Windows’

#Get all services where its caption or its pathname doesn't contain Windows
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" }

It seems the Microsoft Policy Platform service and the Local Session Manager services don’t have ‘Windows’ mentioned, so I will filter these out by path/name
The Windows 2012 R2 server I query also contains Microsoft Office and System Center Endpoint Security, thus I need to filter these out as well

#Adding exclusion for "policyhost.exe" removes Microsoft Policy Platform service
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and $_.PathName -notmatch "policyhost.exe" }

#Adding exclusion for service name "LSM" removes the Local Session Manager service
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and $_.PathName -notmatch "policyhost.exe" -and $_.Name -ne "LSM" }

#Adding exclusion for "OSE.EXE" removes the Office Source Engine Service
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and $_.PathName -notmatch "policyhost.exe" -and $_.Name -ne "LSM" -and $_.PathName -notmatch "OSE.EXE" }

#Adding exclusion for "OSPPSVC.EXE" removes the Office Software Protection Platform Service
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and $_.PathName -notmatch "policyhost.exe" -and $_.Name -ne "LSM" -and $_.PathName -notmatch "OSE.EXE" -and $_.PathName -notmatch "OSPPSVC.EXE" }

#Adding exclusion for "Microsoft Security Client" removes Microsoft Security Client (SCEP)
#This leaves us with all non-default services on a Windows 2012 R2 server!
Get-WmiObject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and $_.PathName -notmatch "policyhost.exe" -and $_.Name -ne "LSM" -and $_.PathName -notmatch "OSE.EXE" -and $_.PathName -notmatch "OSPPSVC.EXE" -and $_.PathName -notmatch "Microsoft Security Client" }

Conclusion

This returns all non-default services which I need for my automatic documentation (parts of this script will be posted on this blog, in posts like this one). Now I can put them in an object and query their specific items. I listed several properties in the example script below; using $NonDefaultServices | gm will give you all usable properties of your NonDefaultServices object.

$NonDefaultServices = Get-wmiobject win32_service | where { $_.Caption -notmatch "Windows" -and $_.PathName -notmatch "Windows" -and

$_.PathName -notmatch "policyhost.exe" -and $_.Name -ne "LSM" -and $_.PathName -notmatch "OSE.EXE" -and $_.PathName -notmatch
"OSPPSVC.EXE" -and $_.PathName -notmatch "Microsoft Security Client" }

$NonDefaultServices.DisplayName # Service Display Name (full name)
$NonDefaultServices.PathName # Service Executable
$NonDefaultServices.StartMode # Service Startup mode
$NonDefaultServices.StartName # Service RunAs Account
$NonDefaultServices.State # Service State (running/stopped etc)
$NonDefaultServices.Status # Service Status
$NonDefaultServices.Started # Service Started status
$NonDefaultServices.Description # Service Description

Offline servicing of a VHD or WIM file

I came across a nifty PowerShell module today. The Module can be found here: http://windowsitpro.com/windows/add-updates-offline-vhd-or-wim-file

It’s an automation of the offline servicing of a VHD(X) or WIM file.

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$Arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $Arguments
Break
}

Import-Module C:\Install-Patch.psm1
Install-Patch <Path/share to vhdx file> "<Path/Share to SCCM/WSUS Windows 2012 updates>"

This script I put in my task scheduler to run weekly, specifying the location of my VHDX file which I use to deploy servers from… This way my main VHD file always contains the latest updates when I deploy a new server from this VHD.

The script will first check if it has been ran as administrator, if not, it’ll restart the script and execute and apply all updates the system doesn’t contain (yet) and uses your SCCM/WSUS share (thus automatically uses its settings and rules for update deployment)

Weird get-process behaviour

Today I encountered some weird behaviour by the get-process command. I was working on a tool to get a list of open programs on a remote computer when I encountered some strange behaviour/inconsistencies, even within the host itself (without remotely connecting and querying).

Once I use the get-process -name command to get the session ID for each instance, it works fine on the local machine, if I run it like this:

(get-process -Name Explorer).SessionId

But one I run this ‘remote’ by specifying a computername (or even localhost on host itself), it returns session 0 for all instances

(get-process -Name Explorer -ComputerName "LOCALHOST").SessionId

Once I use Invoke-Command to ‘remotely’ run the first command, It again works like expected.

Invoke-Command {(get-Process -Name "Explorer").SessionId} -ComputerName 'LOCALHOST'

These are the commands and their output:

Get-Process strange behaviour

Does anyone know why it would lose the session information once I specify the computer name?

It appears that if I would like to check for CPU usage, the first and the third command again work fine, but the 2nd command doesn’t return anything at all!

Running .SQL scripts with Powershell

Today I came across a great script by Andy Mishechkin on MS Technet.


The PowerShell script for execution of T-SQL batch files

It’s a great script for .SQL file execution against a SQL server. It can also run .SQL files which contains GO commands. In short: works like a charm!

Add-WindowsFeature Error: 0x800f0902 – The operation cannot be completed because Windows is currently performing another servicing operation

Today I encountered a problem, for which I couldn’t find a solution (which is pretty rare), so thought I’d post a blog about it and maybe someone can help me.

I sometimes have a problem with the Add-WindowsFeature. In powershell, overall it works fine, but sometimes it gives me the following error:

Add-WindowsFeature: The request to add or remove features on the specified server failed.

Installation of one or more roles, role services, or features failed.

The operation cannot be completed because Windows is currently performing another servicing operation.

Wait a few minutes and try running the command again. Error: 0x800f0902

At line:1 char:1

+ Add-WindowsFeature NET-Framework-Features,NET-Framework-Core,NET-Framework-45-Fe…

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: (@{Vhd=;Credent…Name=localhost}:PSObject) [Install-WindowsFeature],    Exception

    + FullyQualifiedErrorId : DISMAPI_Error__Failed_To_Enable_Updates,Microsoft.Windows.ServerManager.Commands.AddWindowsFeatureCommand

It seems that either the System Center Endpoint Protection (update and/or scan) or the Automatic Maintenance (in the Action center) causes the Add-WindowsFeature to fail (not sure which of the two yet).

Edit: I could localize the problem to be the Automatic Maintenance (in the Action Center). Is there a way to pause or disable this during the running of my Powershell script? Or at least is there a check if it is active or not? So I can check that and wait with installing the Windows Feature until automatic maintenance is finished.


Edit: I found the solution by checking the information MS has about the Automatic Maintenance as described at MSDN on Microsoft.com , which led me to the task scheduler.

Get-ScheduledTask | Where TaskPath -like "*TaskScheduler*"
Led me to show all possible automatic maintenance tasks. Since I don’t want to disable or delete the task, I got several options. Two of which will follow.

– I can stop all running instances by using the following code:
Get-ScheduledTask | Where TaskPath -like "*TaskScheduler*" | Stop-ScheduledTask

– I can wait until maintenance tasks are finished and then continue with my code:

$CheckIfMaintenanceIsRunning = $true
While($CheckIfMaintenanceIsRunning)
{
$RunningTasks = Get-ScheduledTask | Where TaskPath -like "*TaskScheduler*" | Where State -eq "Running"
If($RunningTasks)
{
Start-Sleep -Seconds 5
$CheckIfMaintenanceIsRunning = $True
}
Else
{
$CheckIfMaintenanceIsRunning = $false
}
}

Since in my case the probability of maintenance running while I execute my script is pretty low and also shouldn’t take too long to finish and the fact that I will run my code on systems owned and maintained by other system administrators, I will choose the wait option.

 

Edit: as _Emin_ stated in the comments, it is better to use

Get-ScheduledTask -TaskPath *TaskScheduler*

Thus the corresponding code above would become:

Get-ScheduledTask -TaskPath *TaskScheduler* | Stop-ScheduledTask

and

$RunningTasks = Get-ScheduledTask -TaskPath *TaskScheduler*| Where State -eq "Running"