Quantcast
Channel: Windows PowerShell - SAPIEN Blog
Viewing all 308 articles
Browse latest View live

Using a ModuleSpecification Object

$
0
0

With the advent of side-by-side module versions in Windows PowerShell 5.0, the lovely, but obscure ModuleSpecification object has become your new best friend. Use it to make sure that the commands and module that you use are the ones that you intend.

Using ModuleSpecification

Let’s start with an example. I want to get the Expand-Archive command in the Microsoft.PowerShell.Archive cmdlet. I can use Get-Command, of course, but when I surround the command name with wildcard characters to make sure it searches, it returns this:

PS C:\ > Get-Command *Expand-Archive*

CommandType   Name             Version   Source
-----------   ----             -------   ------
Function      Expand-Archive   1.0.0.0   PowerShellLogging
Function      Expand-Archive   1.0.0.0   PowerShellLogging
Function      Expand-Archive   1.0.0.0   Microsoft.PowerShell.Archive
Function      Expand-Archive   0.8.0.0   Microsoft.PowerShell.Archive
Cmdlet        Expand-Archive   3.2.1.0   Pscx

[Tip: To detect name conflicts in your installed modules, use Group-Object.]

When I run ‘Get-Command Expand-Archive,’ PowerShell gets the command that actually runs when I type ‘Expand-Archive.’ That command is determined by command precedence and by the order in which PowerShell finds modules, which is, in turn, determined by the order of paths in the $PSModulePath environment variable. That’s complex enough on my own system, but if I’m running shared code in an arbitrary environment, I better make sure that I’m running the correct command.

If I wanted the Expand-Archive command in the PSCX module, I could use a module-qualified name, such as:

Get-Command PSCX\Expand-Archive

But, I need to specify both the module name and the version. That’s where the ModuleSpecification object comes in. This command gets the Expand-Archive function in the 1.0.0.0 version of Microsoft.PowerShell.Archive.

Get-Command -Name Expand-Archive `
-FullyQualifiedModule @{ModuleName = 'Microsoft.PowerShell.Archive';
                       RequiredVersion = '1.0.0.0'}

And, if I need to distinguish between two different modules with the same name and version (I created this conflict, but it could happen), you can add a GUID value to get the right module.

Get-Command -Name Expand-Archive `
-FullyQualifiedModule @{ModuleName = 'PowerShellLogging';
                        RequiredVersion = '1.0.0.0';
                        GUID='abc0b34-02de-453a-9726-6bb7b716a63f'}

I can even use the invoke/call operator (&) to run a command in a specific version of a specific module.

$myCommand = Get-Command -Name Expand-Archive `
-FullyQualifiedModule @{ModuleName = 'Microsoft.PowerShell.Archive';
                        RequiredVersion = '1.0.0.0'}
 
& $myCommand -Path .\Myzip.zip -DestinationPath .\Unzipped

Where can I use ModuleSpecification?

One of the most important places to use a ModuleSpecification object is the value of the #Requires -Module parameter.

#Requires -Module @{ModuleName='Pester'; ModuleVersion='3.4.0'}

Also, several cmdlets and functions in PowerShell 5.0 have parameters that take a ModuleSpecification object.

PS C:\ > .\Get-ParameterType.ps1 -ParameterType ModuleSpecification

CmdletName         Parameter
----------         ---------
Export-PSSession   FullyQualifiedModule
Get-Command        FullyQualifiedModule
Get-Module         FullyQualifiedName
Import-Module      FullyQualifiedName
Import-PSSession   FullyQualifiedModule
Remove-Module      FullyQualifiedName
Save-Help          FullyQualifiedModule
Update-Help        FullyQualifiedModule

(See Get-ParameterType.ps1 on GitHub.)

While Import-Module has a FullyQualifiedName parameter that takes a ModuleSpecification object, it also has version parameters that have the same effect, except for the GUID.

PS C:\> (Get-Command Import-Module).ParameterSets.Parameters | where Name -like "*Version" | Sort Name | Select -Property Name, ParameterType -Unique

Name             ParameterType
----             -------------
MaximumVersion   System.String
MinimumVersion   System.Version
RequiredVersion  System.Version

Also, several commands, including the functions in the PowerShellGet module, have version parameters, even though they don’t have parameter that takes a ModuleSpecification object.

Import-Module -Name Pester -RequiredVersion 3.4.0

Be aware that Version and ModuleVersion parameters often behave like MinimumVersion, not RequiredVersion. To verify for any given command, check the help.

PS C:\> C:\ps-test\Get-ParameterName.ps1 -ParameterName "*Version"

CmdletName          Parameter      Type
----------          ---------      ----
Find-DscResource    MinimumVersion System.Version
Find-Module         MinimumVersion System.Version
Find-Script         MinimumVersion System.Version
Get-InstalledModule MinimumVersion System.Version
...

Syntax of a ModuleSpecification Object

You can create a ModuleSpecification object from a hash table using particular keys. PowerShell converts the hash table to the correct object type.

Here are the hash table keys. ModuleName is required and you must include exactly one of the version keys. GUID key is optional.

  • ModuleName <string> (required): Specifies one module name. Enter only one name string. Wildcard characters are not suppored.

Select one of the following keys (required):

  • ModuleVersion <String or System.Version>: Specifies the minimum acceptable version.
    @{ModuleName = 'Pester'; ModuleVersion = '3.4.0'}
  • MaximumVersion <String or System.Version>: Specifies the maximum acceptable version.
    @{ModuleName = 'Pester'; MaximumVersion = '3.3.10'}
  • RequiredVersion <String or System.Version>: Specifies the required version.
    @{ModuleName = 'Pester'; RequiredVersion = '3.3.9'}

The GUID key is optional:

  • GUID <String or System.Guid>: Specifies the module GUID.
    @{ModuleName = 'Pester'; ModuleVersion = '3.4.0'; GUID='a699dea5-2c73-4616-a270-1f7abb777e71'}

By the way, examining the Microsoft.PowerShell.Commands.ModuleSpecification class, separate from its PowerShell implementation is not very helpful.

For example, you can create a ModuleSpecification object with no arguments or with a Name argument, but if you do, all of the other fields are blank, because they are read-only (get, not set).

PS C:\> $ms = [Microsoft.PowerShell.Commands.ModuleSpecification]::New('PSScriptAnalyzer')

PS C:\> $ms | Get-Member

TypeName: Microsoft.PowerShell.Commands.ModuleSpecification

Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ToString         Method     string ToString()
Guid             Property   System.Nullable[guid] Guid {get;}
MaximumVersion   Property   string MaximumVersion {get;}
Name             Property   string Name {get;}
RequiredVersion  Property   version RequiredVersion {get;}
Version Property version    Version {get;}

PS C:\ps-test> $ms.Version = '1.0.0.0'
'Version' is a ReadOnly property.
At line:1 char:1
+ $ms.Version = '1.0.0.0'
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException

And, the properties don’t match the hash table key names.

PS C:\> $ms

Name : PSScriptAnalyzer
Guid :
Version :
MaximumVersion :
RequiredVersion :

So, forget the class and use the rules to create a hash table.

How does it work?

One word of caution. When the core commands use the ModuleSpecification object parameters, they don’t always return what you expect.

For example, in PowerShell 5.1.14352.1002, when you specify a minimum version, Import-Module doesn’t look for the earliest qualified version. Instead, it imports the first instance of that module that it encounters with a version greater than or equal to the minimum.

Also, Get-Command cannot get a command in a non-default version of a module unless that version is already imported into the current session.

image

We’ll look at these behaviors in a separate post.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  


PowerShell Studio 2016 – Service Release & High DPI Support

$
0
0

We released a new service build of PowerShell Studio 2016 (v5.2.124)!

PowerShell Studio High DPI

 

Here’s what’s new:

High DPI Support

We have added high DPI support to PowerShell Studio’s UI. Those of you who previously ran PowerShell Studio on a high DPI monitor (Windows 10 in particular) probably noticed that the application appeared fuzzy. The fuzzy appearance is caused by Windows’ scaling of non-DPI aware applications. The good news is that this no longer the case with PowerShell Studio 2016.

Not DPI Aware
Fuzzy Non DPI Aware
DPI Aware
DPI Aware

High DPI Layouts

With high DPI screens, you will require high DPI layouts. When PowerShell Studio detects a high DPI environment (DPI > 96) it will automatically load (if present) the high DPI version of the selected layout.

To create your own high DPI version of a custom layout, simply save the layout with the .HighDPI.layout extension:

Low DPI file: High DPI file:
(Layout Name).layout (Layout Name).HighDPI.layout

 

High DPI Designer

PowerShell Studio now ensures that your forms scale correctly in the designer. As a result, you can edit the same psf file in a low DPI environment and in a high DPI environment, while maintaining the form’s scale (as oppose to Visual Studio where it is recommended to design the GUI in a 96 DPI environment because the form will not scale correctly when editing between different DPI environments.)

Important: Older versions of PowerShell Studio will incorrectly scale forms created in high DPI environments. Therefore, psf files created or saved by this version of PowerShell Studio will not be backwards compatible.

 

High DPI Control Sets

Similar to the designer, Control Sets now support high DPI scaling and will scale correctly in low DPI settings.

Important: Due to scaling compatibility, Control Sets created with this version will not be backwards compatible with older versions of PowerShell Studio.

 

High DPI Scripts

It is important that the GUIs you create display correctly when executed in high DPI environments. To ensure this, we updated the script generator to include the necessary code to allow your GUIs to scale correctly. Saving the psf file in this build is all that is needed.

We will discuss how to design a GUI for high DPI environments in an upcoming article, because there are some design considerations you need to address in order for your controls to display correctly.

Note: Displaying the GUI in high DPI depends on the executing host. The host running the script must be DPI aware, otherwise the form may have a fuzzy look to it. PowerShell Studio’s internal hosts and the packager engines are all DPI aware.

 

Document Selector

When you press [Ctrl + Tab] to cycle between documents, the Document Selector appears. We added a new option to disable this feature, allowing you to directly cycle through the document tabs without opening the selector.

Document Selector

Note: The Document Selector displays the documents in activation order instead of the tab order.

You can modify the feature by checking/unchecking the Show the document selector when navigating tabs option in Options->General:

Options - Show Document Selector

 

Please continue providing your feedback. Many of the new features included in the service builds are suggestions from users like you. Therefore, if you have any suggestions or feature requests, please share them with us on our Wish List and Feature Requests forum.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

PrimalScript 2016 service build adds CPU and memory performance graphs

$
0
0

The latest service build of PrimalScript 2016 (7.2.91) adds performance graphs for your scripts.

image

To enable this feature you just need to make the “Performance” tab visible before you execute your script.

image

Performance data can be collected on any script run from within PrimalScript as long as you enabled output redirection. That means this applies to PowerShell, VBScript, Perl or any other script that you run from within PrimalScript.

The output window will also display the peak values during the execution of your script when it finishes.

image

Since collecting this data while executing your script obviously adds additional CPU and memory usage by itself, this feature is turned off by default. Just switch it on when you need help determining if your script has memory or CPU usage problems. This also means that this data is relative. You cannot directly compare data from a graph to another script that is executed without collecting performance data.

The graph in the docked Performance panel scales automatically as the script runs, but because of the generally small height of the docked window some details may not be visible in the graph. You can make the Performance panel a docked window to see the performance data in greater detail.

image

image

As you can see, this makes it a little bit easier to discern the variations in CPU usage and memory consumption.

As always, if you have any feedback or suggestion on a feature, please head over to our product support or wishlist forum and tell us what you like to see.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Introducing the SAPIEN Information Center

$
0
0

Over the years, the articles in this blog have grown extensively. There’s a lot of valuable information in here, but it’s become hard to find because it’s mixed in with various tour announcements, special offers, conference recaps, and the like. So, we have decided to pull the important articles and place them—along with information relevant to PowerShell and scripting—in a more organized and easily searchable venue.

We are proud to introduce the SAPIEN Information Center.

Recent-Articles

The most recent articles are always highlighted in a list on the left side of the window.

The SAPIEN Information Center currently has the following categories:

You can find the categories in the Contents menu.

Content-Menu

To list the articles in a category, click the category entry in the menu. Or, click the triangle to expand the category.

Expanded-Content-Menu

The SAPIEN Information Center has a Tag feature that helps you to search for articles. For example, to winnow the articles to just the ones marked “PrimalScript,” use the tag drop-down menu on the left-side of your browser window.

Tag-drop-down-menu

To find articles, use the search box in the top left corner.

For more detailed searches, click Advanced Search. You can search by author or category, too.

Advanced-Search

When you open an article, you get a list of related articles as well. Related articles share keywords with the article you are viewing.

Related-Articles

SAPIEN Blog subscribers, never fear – we will announce the arrival of new SAPIEN Information Center articles with blog posts. The blog will still be used
to announce our sales, tours, conferences and the like.

We will be constantly adding to this cornucopia of material about SAPIEN Technologies, Inc. products, PowerShell, and things you never knew you needed to know. So make the SAPIEN Information Center a place you frequent often for tips, tricks, advice and plain old ‘how-tos’.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Write a Multi-Form PowerShell GUI App

$
0
0

Tested on: PowerShell 2.0+, PowerShell Studio 2016

This step-by-step example shows you how to create a very simple multi-form PowerShell GUI app. The app consists of a parent form that gets data from a child form and displays it. When you finish, you’ll know how to use the basic multi-form features of PowerShell Studio.

image003

For details about how these features work under the covers, see How Do Multi-Form Projects Work?

For this task, we assume that you know how to create a single-form PowerShell GUI app or that you’ve participated in a Thinking in Events hands-on lab. Otherwise, start with the My First Form videos (Part 1: Build a Simple PowerShell GUI App and Part 2: Controls and Properties) and read the beginner blogs in PowerShell GUIs: Where do I start?

———————

I had a great time in Austin, Texas (yes, Austin is still in Texas) last week with the Austin PowerShell User Group (@ATXPowerShell). Founded by Thom Schumacher and now admirably led by Aditi Satam, this awesome group serves PowerShell folks in the whole Austin metro area. And, Austin is home to whole slew of computing powers, including Facebook, Dell, IBM, AMD, 3M, and the famous University of Texas at Austin.

Read the full post in the SAPIEN Information Center….

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Setting up PowerShell on your Mac (Update!)

$
0
0

Now that PowerShell is available on the Mac, we thought it would be useful to show how easy it is to setup a Mac terminal session that automatically opens into PowerShell. Figure 1 shows what we mean.

Figure 1 - PowerShell Terminal Session

Figure 1 – PowerShell Terminal Session

First you need to download the PowerShell macOS package from here (look for the Get PowerShell section in the README.md) and install it using the directions found here . Once PowerShell is installed and running on your system, follow the instructions below to set up your PowerShell terminal

Here are the steps to follow:

  1. Open Terminal on the Mac in whatever fashion you usually use
  2. In the Terminal menu, select Preferences…
  3. Select Profiles in the Preferences window toolbar
  4. Select a Profile in the left list
  5. Select the Gear icon at the bottom of the list
  6. Select Duplicate Profile from the drop down
  7. Rename the new profile to PowerShell
  8. In the Text tab on the right do the following:
    Figure 2 - Text Preferences

    Figure 2 – Text Preferences

    1. Click on Color & Effects and select a Dark Blue color from the color wheel
    2. Change the font to Menlo Regular 24 (or whatever works for you)
    3. Check all the attributes in the Text section
    4. Click on _Underline in the cursor section
  9. Click the Window Tab
    Figure 3 - Window preferences

    Figure 3 – Window preferences

    1. Set the title to whatever you want. We like Windows PowerShell
    2. Check or uncheck the other items you want or don’t want to see in the title bar
  10. Select the Tab tab
    Figure 3 - Tab preferences

    Figure 3 – Tab preferences

    1. check the options you want to see when you have PowerShell tabs
  11. Click the Shell tab
    Figure 4 - Shell preferences

    Figure 4 – Shell preferences

    1. Check Run Command and type in powershell (lowercase)
    2. Click on Run inside shell
    3. Click Never in the Ask before closing section

You now have a PowerShell profile. To open a terminal window right to PowerShell, select the Shell Menu from the Terminal menu bar. Then select New Window / PowerShell. Viola! Up comes your PowerShell terminal window.

If you ONLY want to use PowerShell as your terminal window, you can set your startup preference to your PowerShell profile:

Figure 5 - New window with profile

Figure 5 – New window with profile

or set PowerShell as your default profile.

Figure 6 - Set default profile

Figure 6 – Set default profile

There you have it! Happy PowerShelling on your Mac!

UPDATE:

Want PowerShell on your dock for immediate access? In the Terminal Preferences pane, select the PowerShell profile you created. At the bottom of the list click on the gear icon and select Export. This will create a .terminal file. Dragged the terminal file to the right side of your dock (right of the dividing line where your folders and documents live). You now have a Dock icon that immediately starts a PowerShell Terminal!

Figure 7 - Create a .terminal file

Figure 7 – Create a .terminal file

 

Figure 8 - PowerShell on the Dock

Figure 8 – PowerShell on the Dock

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

How Do Multi-Form Projects Work?

$
0
0

Applies to: PowerShell Studio 2016, Windows PowerShell 3.0+

I recently wrote an article with step-by-step instructions for creating a very simple multi-form PowerShell GUI application. In our sample app, we use PowerShell Studio features that make it very easy to open a child form from the main form and gets the text in the textbox on the child form.

In this article, I’ll explain what goes on in the background to make these features work. You might not care — just so they work — and that’s fine. But if you’re wondering how this happens, or you need to debug a problem, or you’d like to customize these features for your environment, this information will help.

image003

It’s One Script

One of the first things to know about GUI apps is that PowerShell Studio combines the code in the form or form project — all of it — into a single PowerShell script, a .PS1 file.
Read the full post in the SAPIEN Information Center….

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Writing Help for Dynamic Parameters

$
0
0

Because dynamic parameters can be added to a command from multiple sources, the command author (who writes the help) cannot predict the dynamic parameters that might be available at runtime. Therefore, Get-Help expects dynamic parameters to be documented in the help file for the code that adds the dynamic parameters; not the code that has the dynamic parameters.

This makes sense in theory, but, in practice, it’s not discoverable and it’s very confusing for users.

To write help for the dynamic parameters that you add to cmdlets and functions, you need to sneak it into the description. I’ll show you how. The article ends with suggestions for making this process easier. I welcome your suggestions, too.

Read the full post in the SAPIEN Information Center.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  


HelpUri v. HelpInfoUri

$
0
0

Although the names are similar and often confused, these properties are different. If you confuse them, the help for your PowerShell commands and modules won’t work.

The HelpUri property stores the URL (http or https) of online help for a command. It’s a property of commands (cmdlets, functions, workflows). When a user runs Get-Help -Online, Get-Help opens the default browser to the HelpUri property value.

The HelpInfoUri property of modules stores the URL of the online location of the HelpInfo XML file that enables updatable help for the module.

In fact, a non-null value of HelpInfoUri indicates that the module supports updatable help. The updatable help CAB files can be stored in the same location (or any online location specified by the HelpContentUri element in the HelpInfo XML file), but the HelpInfoUri URL always points to the HelpInfo XML file.

Read the full article in the SAPIEN Information Center…

 

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

SAPIEN Script Packager updates and new features.

$
0
0

The Script Packager in PrimalScript 2016 gets an update with the next service build (7.2.95). Since this service build changes the locations where your executable files are generated and some new options are available, we thought we’d let you know about these changes before they are actually released.

Based on your feedback, the script engine selection in the Packager settings was too confusing. So we updated the user interface to minimize the number of selections and provide you with a preview of what this selection will do.

image

Furthermore, as many of you indicated that you still need to support 32 bit machines, this new packager version supports building 32 and 64 bit executables at the same time. Additionally, we added a native Windows platform option, which will always execute the correct version, depending on the current platform. This means you have four options:

1. Microsoft Windows 32 bit, which will generate a 32 bit executable.
2. Microsoft Windows 64 bit, which will generate a 64 bit executable.
3. Microsoft Windows 32 and 64 bit, which will generate a 32 bit and a 64 bit executable.
4. Microsoft Windows Native, which does the same as above (with different naming) but also creates a starter executable, which will launch the correct version for you.

 

image

Since the packager can now generate multiple targets with the same name, it can no longer place these files side-by-side with your script. Instead, the executable files are generated in a platform specific folder under a common folder. The common folder can be specified in the packager options and defaults to “bin”. We suggest you stick to that name to keep things uniform, but you can, of course, change it if necessary.

Let’s assume we package a file called “CoolApp.ps1”. Where will the executable file end up?

image
Depending on your choice, the file CoolApp.exe will be in bin\x86 for 32 bit and bin\x64 for 64 bit. If you selected 32 and 64 bit, well, you will get both files generated in their respective folders.

But what about the last option? The native platform option?

image

Choosing this build target will put all the files in a folder called bin\Any platform. You will get a CoolApp.exe, CoolAppx86.exe and CoolAppx64.exe. Additionally, .config files are generated for each of them if you checked that option.
The CoolAppx86 and CoolAppx64 files are your actual packaged script. The CoolApp.exe file is a starter application that will execute the right package for the current platform. For your application to work, you must install or deploy all three files together. The starter application receives the same icon, digital signature and manifest as the packaged files, so a shortcut to that file will create the same experience.

 

We have also added Windows 10 as a target restriction to PrimalScript. All newly generated executables using the default templates are now marked as Windows 10 applications. Additionally, when restricted to a specific version, the executables display the expected and encountered versions in the error message.

image

 

The option for auto-incrementing the file version was moved to the Version Information tab.

image

 

Oh, and one more thing.

A great many users indicated that they dot source files with common functions. Since these are external to a packaged script, they needed to be deployed with the executable. That created the need to create an installer for an otherwise simple application, required a review or change of script execution policies and, last but not least, opened the application up for user intervention by editing the external script files.

This is why we added an option to resolve dot sourced files while packaging. If the option is enabled, the code of the external scripts gets injected into the packaged script when building the executable.

 

image

 

  • Files specified with or without single and double quotes are supported. Files that do not exist will issue a warning. If you have a dot source statement inside a comment block, the file will be inserted into the comment block.
  • Using a line comment will prevent a file from being resolved.
  • If you need to resolve only some but not all external files, you can use a different case for the file extension.
    . ./include/lib.ps1 will be resolved by the packager,
    . ./include/lib.PS1 will not be resolved.

To make this clear, the statement is case sensitive, the actual filename’s case is not relevant.

As always, questions and comments are welcome. And yes, all these changes will come to PowerShell Studio as well very soon.

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Friday Puzzle: What does a Catch block catch?

$
0
0

On Friday, January 6, 2017, I posted the following puzzle on Twitter and Facebook (here, too!).

It shows a Try block that encloses an expression with an intentional error and a Catch block that writes an error. But, when you run it, the error doesn’t appear as designed.

The error is supposed to say ‘Cannot multiply by apple.’ But, it doesn’t. What went wrong here?

I marked this week’s puzzle “beginner” not because it’s easy or obvious, but because almost everyone who’s written error handling for a PowerShell script has already run into this and is familiar with it.

The Solution: Catch catches the error

The answer is that the Catch block catches terminating errors. In a Catch block, $_ represents the error or exception that it caught. It does not contain any of the objects in the (now terminated) pipeline.

Let’s run the code and see what happens.

An error occurs when PowerShell tries to multiply a string (‘car’) by another string (‘apple’). It’s a terminating error, that is, a serious error that stops the pipeline, so it falls into the Catch block, as designed. So far, so good.

But, the error that the Catch block generates does not say ‘Cannot multiply by apple’. Instead, it says (color added for emphasis):

Cannot multiply by Cannot convert value "apple" to type "System.Int32". Error: "Input string was not in a correct format.".

The Cannot multiply by comes from the Write-Error message string. The next part of the message string is $_, the current object in the pipeline. But, the value of $_ is not ‘apple’. Instead, its value is:

Cannot convert value "apple" to type "System.Int32". Error: "Input string was not in a correct format.".

And, the type of the current object is not a string, like ‘apple’. It’s an ErrorRecord. To figure this out, I comment-out the Write-Error command and replace it with strings that write the value of the current object and its type.

These diagnostic strings — the ones that write out values and types — are one of my favorite tools. I use them whenever I get unexpected output.

What happened here is now a bit clearer.

We started with an array of objects:

1, 2, 'apple', 3

And piped them to the ForEach-Object cmdlet.

1, 2, 'apple', 3 | ForEach-Object { <expression> }

ForEach-Object gets the items in the array one at a time and includes them in the expression. So, in the ForEach-Object expression, the value of $_ is the current array item.

PS C:\> 1, 2, 'apple', 3 | ForEach-Object { "The current object: $_" }
The current object: 1
The current object: 2
The current object: apple
The current object: 3

The expression multiples a string (‘car’) by the current object. When the current object is an integer, the multiplication works.

PS C:\> 'car' * 3
carcarcar

NOTE: In PowerShell, multiplication is not commutative: (‘car’ * 3) -ne (3 * ‘car’). For more information, see about_arithmetic_operators.

But, PowerShell won’t let you multiply a string by another string.

PS C:\> 'car' * 'apple'
Cannot convert value "apple" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:1
+ 'car' * 'apple'
+ ~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger

When you try to multiply two strings, PowerShell declares a terminating error, an error so serious that it terminates or stops the pipeline. If the terminating error occurs in a Try block, as in this case, control falls to the Catch block. The $_ still works, but the current object ($_) in the Catch block is not an item in the array of the now-terminated pipeline. It is the terminating error or exception that stopped the pipeline in the Try block.

In this case, the terminating error, the value of $_, is:

Cannot convert value "apple" to type "System.Int32". Error: "Input string was not in a correct format.".

The Fix

Once you’ve figured out what went wrong, it’s easy to come up with several different solutions. The simplest solution is to add an expression to the ForEach-Object script block that assigns the current object to a variable (in this case, $x). Each time an object in the pipeline goes through the ForEach-Object script block, its value is assigned to $x, replacing the previous value. Then, if a terminating error occurs, you can use the $x variable in the error message.

When I first tried this solution many years ago, I was worried that the Try and Catch script blocks might have different scopes, requiring us to define the variable outside of the Try-Catch, but fortunately, they’re in the same scope. And terminating the pipeline doesn’t delete variables created in the pipeline.

Someone suggested using the PipelineVariable common parameter to create the variable that saves the current object, but the pipeline variable is valid only as long as the pipeline is active.

You might notice that, in the fix, I replaced the Write-Error cmdlet with the Throw statement. Write-Error works, too, but I usually omit it from Catch blocks because some folks think that it converts a terminating error to a non-terminating error, allowing the pipeline to continue. It doesn’t and I don’t want to confuse people, so, in my code, I use Throw.

Summary

The moral of the story is to test everything in your scripts, including the errors. If the errors don’t print as you expected, throw some debugging code in there.

Thanks to everyone on Facebook and Twitter who tried the puzzle. Thanks to those who submitted guesses (they were terrific!) and those who refrained to give beginners a chance.

For more information about error handling in PowerShell, including the difference between terminating and non-terminating errors, see Dave Wyatt‘s awesome: The Big Book of PowerShell Error Handling. For help with the Try-Catch block, see about_Try_Catch_Finally. For help with PowerShell arithmetic, see about_arithmetic_operators.

And, for some truly fun stuff with PowerShell arithmetic, see Fun Formatting Ones, Part 1: The Task and Fun Formatting Ones, Part 2: The Method, where we examine some really clever code by Doug Finke.

Like this Friday PowerShell Puzzle? Find more puzzles here. If you have a PowerShell puzzle suggestion, post it here or ping me on Twitter at @juneb_get_help.

June Blender is a technology evangelist at SAPIEN Technologies, Inc and a Microsoft Cloud & Datacenter MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

Friday Puzzle: Why doesn’t Include include?

$
0
0

On Friday, January 20, 2017, I posted the following puzzle on Twitter and Facebook (and here!).

It shows a Get-ChildItem command where the value of the Path parameter is $PSHome, the Windows PowerShell installation directory, and the value of the Include parameter is ‘*ps1xml.’ The command returns nothing — not a single file — even though the next command shows that there are 14 *.ps1xml files in the root of the $PSHome directory.

What happened here? Why didn’t the Get-ChildItem -Include command work?

This might enlighten you. Or, confuse you even more. In this command, we add ‘\*’ to the path, which indicates its immediate subfolders. When you add ‘\*’, Get-ChildItem gets the .ps1xml files in its root folder.

And, adding -Recurse works, too, although it gets all .ps1xml files in all subdirectories of $PSHome recursively. And, sadly the Depth parameter (new in PowerShell 5.0) seems to have no effect on Get-ChildItem when -Include or -Exclude are used (not documented).

PS C:\> Get-ChildItem -Path $PSHome -Include '*ps1xml' -Recurse

What’s going on here?

 

About the Include Parameter

To solve the mystery, look at help for the Include parameter. I worked really hard to get this parameter description right, so I remember it well.

As we’ve found, the Include parameter works only when the path includes “\*” or the command includes the Recurse parameter.

The coolest thing about the Include and Exclude parameters are that they take an array of values, and include or exclude all items in the array.

PS C:\ > Get-ChildItem -Path $PSHOME\* -Include "*.xml", "*.txt"

TIP: Exclude does not require -Recurse or ‘\*’

 

Include is critical in PowerShell 2.0, because the Recurse parameter doesn’t work on items that have no child-items.

# This fails
PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml -Recurse

In Windows PowerShell 2.0, you need to do this:

# This works
PS C:\> Get-ChildItem -Path $PSHome\* -Recurse -Include '*ps1xml'

Which parameters can you use?

To get .psm1xml files in a directory, you can specify the file name extension on the Path parameter.

PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml

 

Beginning in PowerShell 3.0, you can use the Recurse parameter even when the Path value is an item without child-items (a “leaf”).

PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml -Recurse

 

You can also use the Filter parameter. But neither take an array.

PS C:\> Get-ChildItem -Path $PSHome -Filter "*.ps1xml"

You can also use the Exclude parameter, which works without the ‘\*’ and Recurse, although it has the opposite effect. And, like Include, when you use the Recurse parameter with Exclude, the Depth parameter has no effect.

PS C:\> Get-ChildItem -Path $PSHome -Exclude "*.ps1xml"

 

And, you can pipe the result to Where-Object or the Where method, although those options are significantly slower.

PS C:\> Get-ChildItem -Path $PSHOME | Where-Object {$_.Extension -eq '.ps1xml' -or $_.Extension -eq '.dll'}
PS C:\> (Get-ChildItem -Path $PSHOME).where({$_.Extension -eq '.ps1xml' -or $_.Extension -eq '.dll'})

 

Read the help!

So, the moral of the story is to read the help. And, when the help is missing or wrong, file an issue on UserVoice or in the PowerShell-Docs repo on GitHub. The cool folks on the PowerShell team, and their open-source helpers, respond very quickly.

Like this Friday PowerShell Puzzle? Find more puzzles here. If you have a PowerShell puzzle suggestion, post it here or ping me on Twitter at @juneb_get_help.

June Blender is a technology evangelist at SAPIEN Technologies, Inc and a Microsoft Cloud & Datacenter MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

Friday Puzzle Solution: What does Return keyword return?

$
0
0

On Friday, February 3, we posted a Friday Puzzle that shows a PowerShell function and a PowerShell class method that contain the same command sequence, including a statement with the Return keyword.

The puzzle asks: What does the function return? What does the class method return? And, of course, we want to understand why.

To solve this puzzle, I posted a video: What does the PowerShell Return keyword return? It’s a video explainer that examines the effect of using Return in a function and in classes, and it dives deep into the rules for using Return in a class method.

For more information, see:

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Microsoft Cloud & Datacenter MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

Enabling deep script block logging

$
0
0

As of the KB3000850 update and PowerShell 5.0, PowerShell has included script block logging so that admins would have more tools for the blue team side of pen testing. If you’re unfamiliar or have never heard of it before, I recommend giving this blog post a read.

Not only does the post describe what script block logging is, but it outlines two separate ways to enable it. For example, you can edit your group policy and enable the “Turn on PowerShell Script Block Logging feature” through Windows Components -> Administrative Templates -> Windows PowerShell.

Of course, this being PowerShell, the other way to enable it is a change to a registry key that can be done with a custom function or cmdlet. The blog article even goes as far as providing you with a custom function that will do just this.

What does this have to do with SAPIEN?

While the function provided will enable script block logging, it doesn’t modify the registry in the same way the policy editor does. If you make the modification using the function from the mentioned blog post, the key becomes an REG_SZ with the value of 1.

This technically will work with PowerShell, and the logs will be created as expected. The problem is, if any other application or script relies on that value to determine if logging is enabled, they must account for it being a String instead of an int or their app won’t crash. Which is exactly what happened recently when we were testing the new features around script block logging that were added to PrimalScript and PowerShell Studio.

With that being said, I’ve written a script that contains the same 4 functions from the blog post except they’ve been slightly modified. Each enable-function checks to see if the key exists, if it does and is of the right data type, nothing is done. If it exists and is of the wrong data type, it is removed and the correct type is added.

Manage_PSScript_Block_Logging

PowerShell Studio 2017: Service Release v5.4.137

$
0
0

Today we released a new build of PowerShell Studio 2017 (v5.4.137). In this build we added a number of new features, including some user requests, and made some improvements on existing features.

 

New Features

Git Ignore Filter for Projects

For those of you who use Git, we added a new option to project creation that includes a .gitignore file prefilled with filters for PowerShell Studio’s temporary files.

New Project Ignore Git

If you have an existing project, you can insert a .gitignore file using the Project panel context menu.

Add Git Ignore

If the project file already contains a .gitignore file, it will automatically append the project temporary file filters to the existing file.

Create Project from Existing Module

Do you have an existing module that you wish to edit in PowerShell Studio, but don’t have a project? No problem, the new Create Project from Existing Module command will create a PowerShell Studio Module Project to use for your existing script module.

Create Project For Existing Module

When you use the command, it will ask you to select the module’s psm1 or psd1 file.

Select Module

You are then presented with the following dialog.

New Project From Module

The New Project From Module dialog provides the following options:

Copy the module to a separate project directory

The project will be created in a separate project folder and the module’s contents will be copied over to the new project’s folder. This folder location is determined by the Location field.

It is recommended to make a copy of the module for the project, especially if the module is located in My Documents\WindowsPowerShell\Modules folder. The project will build and export the module to My Documents\WindowsPowerShell\Modules folder for you.

Create the module in the module’s directory

When selected, the project will be created in the same directory as the module. If the module is located in the My Documents\WindowsPowerShell\Modules folder, PowerShell Studio will not allow you to export the module in order to prevent accidental overwriting of existing files.

Create project folder

When checked, PowerShell Studio will create a subfolder using the module’s name in the Location path.

Include Git ignore file for temporary project files

When checked, PowerShell Studio will create a .gitingore file, for Git source control, that filters out any temporary project files.

 

After selecting your options, press the Create Project button and PowerShell Studio will create the project for your existing module.

Note: If the project doesn’t contain an existing manifest psd1 or a psm1 file, PowerShell Studio will automatically create one for you.

 

Set Manifest’s Module Version via the Properties Panel

With this build, you can now modify a module manifest’s ModuleVersion directly from the Properties panel. You can do this by selecting the psd1 file in the Project panel and then use the Properties panel to edit the version.

ModuleVersion via Properties Panel

With this feature, you no longer need to open the manifest to edit the module’s version.

 

Collapsing Strings

We added another requested feature, which is the ability to collapse multi-line strings in the editor.

Collapsable Strings

You can also choose to include strings when using the Collapse All and Expand All commands.

Include Strings

 

Find / Replace Dialog History

As per your request, we included a history for the Find / Replace dialog. You can now access your find history via a dropdown list within the Find What field.

Find Replace History

Add Save Commands to Document Tab Context Menu

As per your request, we added the save commands to the document tab context menu.

Save in Document ContextMenu

 

Updated Features

Improved Splatting Support

Last service release we introduced the new Splat Command feature.

Splat Command

We improved the Splat Command so that it takes into account commands that are part of an existing statement, such as an assignment or piping, without breaking the structure of the statement.

Splatted Commands

The parameters hashtable name now incorporates the command’s name in order to help prevent conflicts when splatting multiple commands within a single pipe statement.

 

PrimalSense and Environmental variables

PowerShell Studio will now evaluate environmental variables in order to provide PrimalSense for folders and file paths.

Path PrimalSense with Environmental Variables

 

 

Please continue providing your feedback. Many of the new features included in the service builds are suggestions from users like you. Therefore, if you have any suggestions or feature requests, please share them with us on our Wish List and Feature Requests forum.


iPowerShell Now Available on Android

$
0
0

SAPIEN technologies, Inc. is proud to announce that we’ve officially released iPowerShell on the Play Store!  In this blog post, we will outline the two biggest features available.

SSH/PSWA Servers

Just as in the iOS version, there is a console capable of managing your servers using SSH or PowerShell Web Access. We worked with /n Software again using their PowerShell Server software which allows connecting over SSH using PowerShell.

Adding either type of server works the same way; simply tap the Server tile from the main page, click the plus in the bottom right corner (Image 1), and fill out your server info (Image 2):

Image 1

Image 2

Once you’ve added the server, you can select it from the list and begin running commands as if you were using a console at the machine (Image 3). The console also comes with the Cmdlet Builder and history feature from iOS as well. Use the Builder to make complex cmdlets easier to form or History to find the cmdlet you ran last night but can’t recall the name (Image4).

Image 3

Image 4

Help File Reference

When you first install the app, you’re prompted to download the reference data which is roughly 60MB in size and contains all the default Microsoft PowerShell help files. They’re fully searchable and sortable by module, verb, or even noun. This way, if you’re looking for something that you’re certain starts with Wai, you don’t have to waste your time digging (Image 5).

Image 5

Perhaps you use a custom module that you can’t live without (such as DBA Tools) and the help files aren’t added to iPowerShell, yet. Well, as long as the help files follow the specifications from Microsoft, you can add them to the app by simply going to Tools → Data → Update (Image 6) and selecting the help files (Image 7):

Image 6

Image 7

Currently, iPowerShell is available for Android KitKat (4.4) or later. If you have any feedback or bug reports, please direct them to our forums: https://www.sapien.com/forums/viewforum.php?f=17

 

Designing GUIs for High DPI Displays

$
0
0

I posted a new article on how to design a GUI for high DPI displays on our SAPIEN Information Center:

 

2Sapien_Blog

Designing GUIs for High DPI Displays

In this article, I will cover techniques on how to make your PowerShell GUI compatible with high DPI (Dots per inch) displays. The article will also cover a few caveats to be aware of.

To get a better understanding of what different DPI settings mean, let’s look at standard screen resolutions. A typical 1080p screen will a have 96 DPI (Font scale: 100%). Higher resolution monitors, such as 4K monitors can have a DPI of 192 or higher (Font scale: >=200%).

DPI is determined by the font scale of the OS. If you would try to maintain a DPI of 96 on a 4K monitor, everything will appear to be tiny. Increasing the font scale, will decrease the DPI, which in turn will make icons and text appear larger and easier to see.

New Script engines for Windows PowerShell

$
0
0

One of the more common tasks for an administrator is to write a script for a helpdesk employee or a fellow admin who is maybe not so PowerShell savvy (yet). Many of you like to package that script as an executable file to prevent the user from “experimenting” with your code and messing things up in the process.
From what we hear, it is quite common for these users to come back and say they only see a flashing window when they try to run your script. Now you have to go and explain that this is a console window flashing and they need to open a console to run that exe or script from there.
After wasting this perfectly good explanation you most likely have to go in person and set up a shortcut for the user to do all you just explained.
Let’s face it, PowerShell is a console language, but not everyone is familiar or comfortable with using a console.

So here you are, trying to make your life easier by writing a script only to have to go into either development mode and make that script a GUI application or to go into teaching mode and lecture helpdesk employees on the use of consoles.
If only there was an easier way …

I did what many do today, I searched the internet for a script and modified it to suit my purpose. So here is my shoutout to Martin Pugh at https://thesurlyadmin.com/, thanks for the network speed script!

image

Here is what it looks like when you run the script. Pretty simple. The seasoned admins among you know that it gets squirrely when there are many more servers and content scrolls. Consoles have buffer limits and, for some reason, those more inclined to use a mouse, have an inexplicable dislike for anything in a console.
But wait, Notepad, everyone knows how to use Notepad, right?

 

image

Now lets package that script with the Windows Application engine and see what happens.

image

Much better. Anyone familiar with Notepad can handle that.

SNAGHTML1f7e73f9

The File and Edit menus provide the usual functions, you can save the output of your script as a text file, the edit menu can find and copy specific text, so if things go wrong it is quite easy for the user to provide you with actual feedback and error messages.
Additionally, there is an automatically generated About box in the Help menu which contains all the information you specified in the version resource while packaging.

image

Now you can actually determine what version your users run by asking them to simply go to the about box.

 

It took about ten minutes and some minor modifications to make a simple command line script into a Windows Notepad style application.
There are some limitations of course but we here at SAPIEN think you will find this very useful in enabling others to use your scripts.

As always, if you have any ideas, comments, feedback, please use our feedback forum and reference this post.
https://www.sapien.com/forums/viewforum.php?f=23

Creating a system tray application with PowerShell

$
0
0

One of the great benefits of PowerShell is the ability to very quickly retrieve system information and metrics. We have added three new packager engines to PowerShell Studio and PrimalScript to make it easier to present or log that information in a standard way. I have already discussed the new Windows Application engine here:
https://www.sapien.com/blog/2017/06/14/new-script-engines-for-windows-powershell/

This time around I will show you how easy it is to create a Windows System Tray Application with PowerShell and the new packager engine.
Just like last time we start with a script I found on the internet:
https://gallery.technet.microsoft.com/scriptcenter/Powershell-Script-for-13a551b3

 

Here is a shout out to Sravan Kumar for sharing his script to check website availability and response times. His script produces an HTML report that we will not use. We want a tray application that checks a list of web sites in intervals and alerts us if one is not available or slow with a tray message.
The list of sites the application checks must come from a text file that is loaded for each iteration, so that there is no need to stop and start the application to pick up new URLs.
The goal for this engine was to allow you to convert a simple script to a system tray application while only using Write-Host, Write-Output etc. You should not have to know much about how tray applications actually work.

 

image
Don’t worry, the source for this script is attached to this post.

The file containing the URLs to be checked has to be here: C:\ProgramData\URICheck\URLList.txt
and it contains one URL per line.

There are a few simple things you need to do when making a script into system tray application:
1. It needs to be a loop. As you can see, this script has a while($true) loop. If you do not do that, your tray app will do things just once and then sit there.

2. Sleep when you are not doing anything. The example sleeps a minute after checking the list. Realistically, it could check only every ten minutes and still be fine. If you omit that, you will be using up way more CPU cycles than you need.
Your script runs on its own thread, so exiting the tray application is not dependent on your script sleeping or not.

3. Set $progressPreference = ‘silentlyContinue’, unless you really, really need progress windows. Since the System Tray App engine is a Windows Application, it will display progress notifications as a popup window. Cmdlets like Invoke-WebRequest will display progress, no matter how quick. This can result in flashing progress popups from your applications. We did not generally disable progress display, because you may need to use it for some lengthy operation.

4. Limit your output. Every time a tray app uses any PowerShell output method, a notification in the lower right corner will pop up and the associated system sound will be played. So only produce output if there is something that requires the user’s attention.

5. Supply a meaningful icon. The icon of your application will be display in the system tray. You want to have a distinguishable icon in case you have more than one PowerShell based tray application.

6. Fill out your version resources. A tray application package has an automatic about box, which displays the information in your version resources.
image

image

Last but not least, here is how you do all that. It is pretty simple. After running and debugging your script just as you always would, package it using the new Windows Tray App engine:
image

That’s it.

You can download the script and the packaged executables from here: https://sapien.s3.amazonaws.com/Blog_Post_Files/CheckURI.zip

 

As always, if you have any ideas, comments, feedback, please use our feedback forum and reference this post.
https://www.sapien.com/forums/viewforum.php?f=23

Write a Windows Service in PowerShell

$
0
0

Previously I showed you the new Windows Application engine (https://www.sapien.com/blog/2017/06/14/new-script-engines-for-windows-powershell/) and the Windows System Tray engine https://www.sapien.com/blog/2017/07/10/creating-a-system-tray-application-with-powershell/.
Today I will show you the last of the three new engines, the Windows Service engine.

Writing a Windows Service can be a challenging experience, even for a programmer. Generally, unless you do that exact thing for a living, nobody writes a Windows Service very often. So most folks don’t have a lot of experience with this particular task.
You do what most programmers do, you Google the task at hand. If you google “write a windows service in powershell” the first hit points to an MSDN magazine article: https://msdn.microsoft.com/en-us/magazine/mt703436.aspx
My compliments to the author, Jean-Francois Larvoire, who did a great job explaining the intricate details of building a service in Windows PowerShell.
If you do this very often, you should definitely read that article.

But, for most of us, this is not a very frequent task. So I will show you a way of doing this without knowing much about services or C#. All you need is PowerShell. Instead of using a script from somewhere on the internet we use a one-liner today.

Get-Process solitaire -ErrorAction SilentlyContinue | Stop-Process –PassThru

I am assuming you can see that this will simply terminate any process named ‘Solitaire’. We will call our service “SolitaireKiller”
Just as previously with the System Tray Application in the last post, the script needs a loop, so it executes the code inside again and again. Also like the tray app, we need to sleep in between iterations so we don’t hog a CPU core for no reason.
For terminating a solitaire game it is not necessary to do that within a second of startup anyway, so we just go with a minute. I don’t think many folks will finish a game in that time.

while($true) {
Get-Process solitaire -ErrorAction SilentlyContinue | Stop-Process –PassThru
Start-Sleep –Seconds 60
}

Run that as a script and it will just kill any Solitaire game you are playing within a minute. We do want to get a notification when a process was terminated, so we make a little adjustment to our script

while($true) {
$ProcessList = Get-Process solitaire -ErrorAction SilentlyContinue
if($ProcessList) {
Write-Host “Terminating Windows Solitaire process”
$ProcessList | Stop-Process –Force | Out-Null
}
Start-Sleep –Seconds 60
}

That’s all. So now we make that a service. Package your script with the Windows Service engine and the PowerShell version most appropriate for your script.

image

Make sure you enter all pertinent information in the Version settings.

image

 

Services need to be installed on a system. To make your life easer, all that is also already build in. All you need to do is run the service executable from an elevated command prompt with /i (as in install)
image

Now you can look at your service control panel and you will see the Solitaire Killer service. Remember the items you wrote in the ‘Product name’ and ‘Description’ fields for the version information? They are automatically used for the service name and description.

image

So now go ahead and start that service. Launch a game of Solitaire and wait. Within a minute it will be gone.
Now look at your event log. What you wrote there with Write-Host (or any other PowerShell output mechanism) will show up here in the Application Event Log.

image

 

image

To remove the service from your system, simply stop the service and use the /u parameter (as in uninstall) and it will be gone. Please note that it may take a few seconds to exit and that you may need to restart the services control panel to see that.

 

You can download the script and the packaged executables from here: https://sapien.s3.amazonaws.com/Blog_Post_Files/SolitaireKiller.zip

As always, if you have any ideas, comments, feedback, please use our feedback forum and reference this post.
https://www.sapien.com/forums/viewforum.php?f=23

Viewing all 308 articles
Browse latest View live