Tag Archive | Powershell

Find text (string) in text file(s)

If you want to find a certain text (string) in a text file or multiple text files, the quickest way to do so, is by using the select-string option.

First you’d need to get a list of the files you want to search trough:

$FileList = Get-ChildItem -Path "D:\temp\"
or you can use it on a single file as well
$FileList = Get-ChildItem -Path "D:\temp\file.txt"

After that, you can use select-string to find all files which contains the string you like to search for (in this case I’m searching for the text ‘success’):
$Success = $FileList | Select-String -Pattern 'success'

The variable $Success now has the following properties:
Context
Filename
IgnoreCase
Line
LineNumber
Matches
Path
Pattern

Out of which these are usually the most interesting ones in this kind of search:
Line (the text in the line select-string found the text you’re searching for)
Path (path & file name to the file)

Searching through a directory with about 50 files, which have a total size of 12,6MB and over 200.000 matches, only took 2 seconds this way. As far as I know, this is the quickest way to search through files with PowerShell.

Instead of a simple text search, you can also direct the select-string cmdlet to detect multiple matches per line, display text before and after the match, or display only a Boolean value (True or False) that indicates whether a match is found. Select-String uses regular expression matching, but it can also perform a simple match that searches the input for the text that you specify; like in my example above.

Have fun using this great and quick cmdlet. If you know of any quicker and easier ways to find text or patterns in files, let me know in the comments below and maybe my next blog post will be about that.

Remember that those who forget to script, are doomed to repeat their work!

Get-Date

The Get-Date cmdlet is pretty nifty and gives you a lot of date/time formats you’d want to use in your script.

Like if you were to save files with a unique stamp, you’d want a date/time format like <year><month><day><hour><minute><second>

Here are some examples to achieve this goal, with outputs

Get-Date -Format s
2015-11-19T20:22:35

(Get-Date -Format s).Replace("-","").Replace(":","").Replace("T","")
20151119202235


"{0}{1}{2}{3}{4}{5}" -f (Get-Date).Year,(Get-Date).Month,(Get-Date).Day,(Get-Date).Hour,(Get-Date).Minute,(Get-Date).Second
20151119202235

$Date = Get-Date
"{0}{1}{2}{3}{4}{5}" -f $Date.Year,$Date.Month,$Date.Day,$Date.Hour,$Date.Minute,$Date.Second
20151119202235


Get-Date -Format yyyyMMddHHmmss
20151119202235

Get-Date -UFormat %Y%m%d%H%M%S
20151119202235

As you can see, all the given examples have the same output.

The first example doesn’t completely live up to the task as I described in my format, thus I need to remove several characters (by replacing them with a blank), which is the second example.

The third and fourth example will do a format-string and get all different get-date attributes. The fourth example is the same as the third, but in this case I fist put the output of the Get-Date cmdlet into a variable called $Date, this already makes the code a little bit less, but still longer than the Second example.

The fifth and sixth example use the formatting parameters Format and Uformat. Format is the .Net format and UFormat is the Unix format. Those are the shortest ones to use.

I myself like the switches for formatting a lot, for cases where you need to get the date the way you want it, without changing the localization settings of a server/computer.

Like for example in the EU, most (or maybe all) countries work with dates in the <day>-<month>-<year> pattern and time in the 24H format; while in the US dates are worked with in the <month>/<day>/<year> pattern and time in 12h format with AM and PM. But once working with files and sorting dates, the format as used in the example in usually used.

The PowerShell help tells us all the options for Uformat (each is preceded by a % sign):

  • c Date and time – abbreviated (Fri Jun 16 10:31:27 2006)

Date:

  • D Date in mm/dd/yy format (06/14/06)
  • x Date in standard format for locale (09/12/07 for English-US)

Year:

  • C Century (20 for 2006)
  • Y Year in 4-digit format (2006)
  • y Year in 2-digit format (06)
  • G Same as ‘Y’
  • g Same as ‘y’

Month:

  • b Month name – abbreviated (Jan)
  • B Month name – full (January)
  • h Same as ‘b’
  • m Month number (06)

Week:

  • W Week of the year (00-52)
  • V Week of the year (01-53)
  • U Same as ‘W’

Day:

  • a Day of the week – abbreviated name (Mon)
  • A Day of the week – full name (Monday)
  • u Day of the week – number (Monday = 1)
  • d Day of the month – 2 digits (05)
  • e Day of the month – digit preceded by a space ( 5)
  • j Day of the year – (1-366)
  • w Same as ‘u’

Time:

  • p AM or PM
  • r Time in 12-hour format (09:15:36 AM)
  • R Time in 24-hour format – no seconds (17:45)
  • T Time in 24 hour format (17:45:52)
  • X Same as ‘T’
  • Z Time zone offset from Universal Time Coordinate (UTC) (-07)

Hour:

  • H Hour in 24-hour format (17)
  • I Hour in 12 hour format (05)
  • k Same as ‘H’
  • l Same as ‘I’ (Upper-case I = Lower-case L)

Minutes & Seconds:

  • M Minutes (35)
  • S Seconds (05)
  • s Seconds elapsed since January 1, 1970 00:00:00 (1150451174.95705)

Special Characters:

  • n newline character (\n)
  • t Tab character (\t)

The help tells us that the settings for the Format switch can be found here. This is the information which is currently (when writing this blog) available on the site:

Format pattern Associated Property/Description
d ShortDatePattern
D LongDatePattern
f Full date and time (long date and short time)
F FullDateTimePattern (long date and long time)
g General (short date and short time)
G General (short date and long time)
m, M MonthDayPattern
o, O Round-trip date/time pattern; with this format pattern, the formatting or parsing operation always uses the invariant culture
r, R RFC1123Pattern; with this format pattern, the formatting or parsing operation always uses the invariant culture
s SortableDateTimePattern (based on ISO 8601) using local time; with this format pattern, the formatting or parsing operation always uses the invariant culture
t ShortTimePattern
T LongTimePattern
u UniversalSortableDateTimePattern using the format for universal time display; with this format pattern, the formatting or parsing operation always uses the invariant culture
U Full date and time (long date and long time) using universal time
y, Y YearMonthPattern

The following table lists the custom DateTime format patterns and their behavior. For more information, see Custom DateTime Format Strings.

Format pattern Description
d, %d The day of the month. Single-digit days do not have a leading zero. The application specifies “%d” if the format pattern is not combined with other format patterns.
dd The day of the month. Single-digit days have a leading zero.
ddd The abbreviated name of the day of the week, as defined in AbbreviatedDayNames.
dddd The full name of the day of the week, as defined in DayNames.
f, %f The fraction of a second in single-digit precision. The remaining digits are truncated. The application specifies “%f” if the format pattern is not combined with other format patterns.
ff The fraction of a second in double-digit precision. The remaining digits are truncated.
fff The fraction of a second in three-digit precision. The remaining digits are truncated.
ffff The fraction of a second in four-digit precision. The remaining digits are truncated.
fffff The fraction of a second in five-digit precision. The remaining digits are truncated.
ffffff The fraction of a second in six-digit precision. The remaining digits are truncated.
fffffff The fraction of a second in seven-digit precision. The remaining digits are truncated.
F, %F Displays the most significant digit of the seconds fraction. Nothing is displayed if the digit is zero. The application specifies “%F” if the format pattern is not combined with other format patterns.
FF Displays the two most significant digits of the seconds fraction. However, trailing zeros, or two zero digits, are not displayed.
FFF Displays the three most significant digits of the seconds fraction. However, trailing zeros, or three zero digits, are not displayed.
FFFF Displays the four most significant digits of the seconds fraction. However, trailing zeros, or four zero digits, are not displayed.
FFFFF Displays the five most significant digits of the seconds fraction. However, trailing zeros, or five zero digits, are not displayed.
FFFFFF Displays the six most significant digits of the seconds fraction. However, trailing zeros, or six zero digits, are not displayed.
FFFFFFF Displays the seven most significant digits of the seconds fraction. However, trailing zeros, or seven zero digits, are not displayed.
gg The period or era. This pattern is ignored if the date to be formatted does not have an associated period or era string.
h, %h The hour in a 12-hour clock. Single-digit hours do not have a leading zero. The application specifies “%h” if the format pattern is not combined with other format patterns.
hh The hour in a 12-hour clock. Single-digit hours have a leading zero.
H, %H The hour in a 24-hour clock. Single-digit hours do not have a leading zero. The application specifies “%H” if the format pattern is not combined with other format patterns.
HH The hour in a 24-hour clock. Single-digit hours have a leading zero.
K Different values of the Kind property, that is, Local, Utc, or Unspecified.
m, %m The minute. Single-digit minutes do not have a leading zero. The application specifies “%m” if the format pattern is not combined with other format patterns.
mm The minute. Single-digit minutes have a leading zero.
M, %M The numeric month. Single-digit months do not have a leading zero. The application specifies “%M” if the format pattern is not combined with other format patterns.
MM The numeric month. Single-digit months have a leading zero.
MMM The abbreviated name of the month, as defined in AbbreviatedMonthNames.
MMMM The full name of the month, as defined in MonthNames.
s, %s The second. Single-digit seconds do not have a leading zero. The application specifies “%s” if the format pattern is not combined with other format patterns.
ss The second. Single-digit seconds have a leading zero.
t, %t The first character in the AM/PM designator defined in AMDesignator or PMDesignator, if any. The application specifies “%t” if the format pattern is not combined with other format patterns.
tt The AM/PM designator defined in AMDesignator or PMDesignator, if any. Your application should use this format pattern for languages for which it is necessary to maintain the distinction between AM and PM. An example is Japanese, for which the AM and PM designators differ in the second character instead of the first character.
y, %y The year without the century. If the year without the century is less than 10, the year is displayed with no leading zero. The application specifies “%y” if the format pattern is not combined with other format patterns.
yy The year without the century. If the year without the century is less than 10, the year is displayed with a leading zero.
yyy The year in three digits. If the year is less than 100, the year is displayed with a leading zero.
yyyy The year in four or five digits (depending on the calendar used), including the century. Pads with leading zeros to get four digits. Thai Buddhist and Korean calendars have five-digit years. Users selecting the “yyyy” pattern see all five digits without leading zeros for calendars that have five digits. Exception: the Japanese and Taiwan calendars always behave as if “yy” is selected.
yyyyy The year in five digits. Pads with leading zeros to get five digits. Exception: the Japanese and Taiwan calendars always behave as if “yy” is selected.
yyyyyy The year in six digits. Pads with leading zeros to get six digits. Exception: the Japanese and Taiwan calendars always behave as if “yy” is selected. The pattern can be continued with a longer string of “y”s padding with more leading zeros.
z, %z The time zone offset (“+” or “-” followed by the hour only). Single-digit hours do not have a leading zero. For example, Pacific Standard Time is “-8”. The application specifies “%z” if the format pattern is not combined with other format patterns.
zz The time zone offset (“+” or “-” followed by the hour only). Single-digit hours have a leading zero. For example, Pacific Standard Time is “-08”.
zzz The full time zone offset (“+” or “-” followed by the hour and minutes). Single-digit hours and minutes have leading zeros. For example, Pacific Standard Time is “-08:00”.
: The default time separator defined in TimeSeparator.
/ The default date separator defined in DateSeparator.
% c Where c is a format pattern if used alone. To use format pattern “d”, “f”, “F”, “h”, “m”, “s”, “t”, “y”, “z”, “H”, or “M” by itself, the application specifies “%d”, “%f”, “%F”, “%h”, “%m”, “%s”, “%t”, “%y”, “%z”, “%H”, or “%M”.

The “%” character can be omitted if the format pattern is combined with literal characters or other format patterns.

\ c Where c is any character. Displays the character literally. To display the backslash character, the application should use “\\”.

Have fun with getting the date in your format.

Notepad++ downloader and updater

I love to use Notepad++ (npp), but I also have npp installed on servers on which users can log on, but don’t have administrative privileges. They also love to use npp, but with the updater enabled, they get popup messages for the updates, but cannot install them. I don’t want to have to check all servers that I manage if they need a new version of npp, but if there’s a new version I do want to like that one to be rolled out on all servers.

There are many ways to do this job, but next to wsus, we don’t use other tooling, so I decided to create two little tools.

  1. NppDownloader
  2. NppUpdater

The first tool will check if the npp website if there’s a newer version available then the one that’s already on the disk in a certain folder or on a certain share (this one I schedule on my file server). The second tool is one that I schedule on each server with npp, it’ll check a certain folder or share for npp installers. The latest one found, will be installed on the system, if it’s newer than the current version that’s installed (I assume the default installtion location is used).

Both scripts will create a log file which is overwritten each time the script is ran. These scripts were made before I did my loop and fire write speed tests (as you can read in my previous blog post), thus still contains the [io.file]::WriteAllLines commands instead of the [io.file]::WriteLine command. It only writes a couple of lines in the file, so should be about as quick I guess.

I’ve zipped them both, and added cmd files with some options so it can be ran as administrator with the script starting in the correct path (normally a cmd that’s ran as administrator will start in C:\windows\system32). There is an option to enable the localextentions and go to the path the cmd file is started from. This is achieved by these lines in the cmd file:

setlocal enableextensions
cd /d "%~dp0"

The zipped powershell scripts and cmd files can be found here: NppDownloaderAndUpdater.zip

 

Edit: If you also want to automatically schedule the NppDownloader file, you might be interested in my follow-up post: Create windows scheduled task for the nppupdater script

Powershell application – Get information from a webpage, parse it and show the results

Today I created a nice little ‘application’ in Powershell.

In The Netherlands we have a site called Marktplaats (www.marktplaats.nl) which is some sort of combination between e-bay and craiglist. This is one of the biggest sites in The Netherlands, but I was missing some search options on this site and thought they started to show to many ads. Thus I decided to try something in Powershell to help make my life somewhat easier and while I’m at it, also implement the things that I think the site is missing.

One of the main important things I was missing, was a wide search pattern which I could fine-grain down to the things I’d like it to return. (ie. searching for all free items, but excluding sand, cats, yellow stones etc).

Second thing I’m missing is and alert function. I’d like to receive an alert if something I search for gets placed on the site (and if it also complies with the from and to price I’m searching the item for.

Third thing as mentioned before: They started loading the site with Ads. At the moment it’s about 1 ad for each 2 items on the site. This is way too much and decreases the fun I have of browsing trough secondhand items.

Fourth thing: It appears that the site has restrictions on the distance radius I can set. Apparently their search function itself isn’t limited by those distance radiuses; Thus I can start to offer an app which can search any distance.

 

As you can see in the screen shot, there’s no more Ads 🙂

I still need to program the 2nd feature which I want (it’s harder than I thought it would be), but I did already style the app in the same template style as the site and its logo. It nicely filters out all Ads; It also filters out the items I don’t want in my search results.

 

Things I stumbled upon:

When resizing the form, the objects on the form didn’t resize accordingly and stayed on the same place.

This could be solved by using a splitcontainer on my form (something that splits the form in 2 parts); the splitcontainer already contains features for resizing. By setting its anchor, I was able to do the same with all the objects on the form and have them resize when I resize my form! 🙂

$SplitContainer1=New-ObjectSystem.Windows.Forms.SplitContainer
$SplitContainer1.Anchor = ([System.Windows.Forms.AnchorStyles]([System.Windows.Forms.AnchorStyles]::Top -bor[System.Windows.Forms.AnchorStyles]::Bottom -bor[System.Windows.Forms.AnchorStyles]::Left -bor[System.Windows.Forms.AnchorStyles]::Right))

Getting the search result was pretty easy; parsing the info a little bit harder

$WebUrl = "http://www.marktplaats.nl/z.html?
$page = Invoke-WebRequest $WebUrl
$html.getElementsByTagName('tr') | ? { (($_.className -eq 'search-result defaultSnippet group-0') -or ($_.className -eq 'search-result defaultSnippet group-1')) } | % {

After which I could do the ‘magic’ with everything it returned. Thanks to their programmers being a little bit lazy, my work was made easier with parsing the text and even changing it, so I would have to write less code (one of the things I added is an ‘open in new window’ for each hyperlink, so It would open the default browser on the system when I want to watch the product itself and I’m not stuck with the browser object in my tool (which I don’t need to extend now to support more features and/or show buttons etc).

In the beginning the script didn’t perform that well. Once I changed the replacement texts into a regex replacement, this sped up the process somewhat, but after I changed the function that changes the returned text (and checks it for certain values) to a select-string, this sped up the entire process a lot. Right now it takes me about 9-11 seconds (depending on the type of system and hardware) to get a 3,5MB result from the website, parse it, and show the parsed results (which is saved into a temp file, which is about 100KB still). All with all I’m pretty happy with how it turned out and its overall look and feel; same goes for the speed and ease; thus another great app/script to add to my collection 🙂

Next feature that’ll be added will be to check for new items and alert me when one is added inside my search criteria.

How simple some things can be – Powershell indent

In the past few years, I’ve been using tools to indent my code… Today by accident found out that in Powershell ISE, if you select multiple lines and press tab it’ll indent all selected lines… and of course shift+tab will do the reverse.

Amazing how simple some things can be without any tool… And how I’ve never before thought about trying this and automatically went looking to create my own or find an external solution once I couldn’t find it in any menu.

Analyze Robocopy log files and mail the result

A long, long time ago (back in 2008) I created a VBS script which would analyze a folder filled with Robocopy logs and once done analyzing and creating a summary, it would mail the result to me.

A couple of days ago I decided it was time to update this script to Powershell. Once I was finished, I still wasn’t satisfied with its speed (neither was I with the VBS version of the script, but since it ran nightly I didn’t bother changing it). Since I was working on it, I thought I’d completely rewrite it and increase its speed some, together with making it more diverse, so I can use it in more situations and depending on the needed notification settings for each specific situation. Since Microsoft decided to default add Robocopy to the OS, I’ll be using it a lot more myself. I also checked the internet if others created something similar, I found some, but none could compete with what I just created and/or had the diversity I needed; thus thought I’d share it.

I tested this script on Powershell 2.0 and 4.0, so should also work with 3.0. If not, please contact me and I can update/change it. (also include the error please)

Ok, so what does this script? It will read the contents of all robocopy log files in the specified path. If you add -recurse, it’ll also include subfolders. Depending on your settings, it’ll create a summary file with either a summary of all found log files, only the ones with errors and warnings or only the ones with errors. Depending if you want warnings and/or errors, it’ll add detailed information about the errors it found in all the log files. The detailed information for errors will be placed in the top of the summary file. The output file will be placed in the directory the script is started from. Depending on your settings it’ll send an e-mail report with a summary of the analyzed logs and the summary file (with detailed error and/or warning info) will be attached to this mail.

After I finished creating the script, I also added detailed help information and tested its speed.

Reading of 110 files (95,8MB), which consist of 7 errors in 4 files and 402924 warnings in 4 files;
Running time: 2m8s
Tested with option SummaryAll (maximum output) and a MaxLinesPerFile of 500 (thus 2007 lines (500 per warnings file) to write)

Same conditions as above, but tested with SummaryAllWithoutWarnings (thus only 7 lines to write)
Running time: 20s

The Robocopy settings I use (I also use this to make copties of files that can be open by users in their desktop session, that’s why I excluded the ~$ temporary excel files in this script, otherwise you’d get false-positive errors)

robocopy "<source>" "<target>" /XD "<folder>" /XF "~$*.xls" "~$*.xlsx" "~$*.xlsm" /E /V /NP /LOG:"<Path\Logfile>" /R:2 /W:2

Getting eager to try it out yourself? The complete powershell script can be found here: AnalyzeRobocopyLogs.ps1

Use Get-Help .\AnalyzeRobocopylogs.ps1 to get default help information about the script and

Use Get-Help .\AnalyzeRobocopylogs.ps1 -full to get detailed information about the script

If you use this script change it or provide it to / share it with others, please comment me and/or link to my blog.

The E-mail message will look something like this:

AnalyzeRobocopyLogs MailMessage


 

Edit: Updated the script. It appeared that Powershell v2 had an issue with the summary text. This has been updated in the AnalyzeRobocopyLogs v2.1 script.

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

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"

Creating an ODBC connection

With Powershell 4 on Windows 8 and 2012, they’ve improve the support for ODBC connections. You just need to import the Wdac module to be able to use the different ODBC functions.

Get-Command *ODBC* shows the following functions:

Add-OdbcDsn
Disable-OdbcPerfCounter
Enable-OdbcPerfCounter
Get-OdbcDriver
Get-OdbcDsn
Get-OdbcPerfCounter
Remove-OdbcDsn
Set-OdbcDriver
Set-OdbcDsn

For instance, if you were to create a System ODBC connection, with a 32 bit SQL driver, use the following code:

Import-Module Wdac
$OdbcDriver = Get-OdbcDriver -Name *SQL* -Platform 32-bit
If(!$OdbcDriver.Count) # Only continue if 1 SQL ODBC driver is installed
{ Add-OdbcDsn -Name "ODBC Connection Name" -DriverName $OdbcDriver.Name -Platform 32-bit -DsnType System -SetPropertyValue @("Server=SQL ServerName\SQL Server Instance", "Trusted_Connection=Yes","Database=SQL DatabaseName") }