Some time ago I’ve written a little tool called “PS2EXE” that creates .EXE files from PowerShell script files. As mentioned in earlier posts this is no conversation of PS to EXE! The PS2EXE script creates an EXE by using the C# compiler and stores the script as Base64 encoded string inside a tiny PowerShell host application.
Today I’ve updated the PS2EXE script to version 0.3.0.0. Now it supports PowerShell 3.0 and PowerShell 2.0.
On Windows 8 or Windows Server 2012 there is PowerShell 3.0 installed by default. On Windows 7 or Windows Server 2008 R2 you can install it using Windows Management Framework 3.0.
With PowerShell 3.0 installed you will always start the 3.0 enviroment by using:
the Start Menu (or Screen)
the “Run” dialog:
the command line:
Execution PS2EXE reports PowerShell version 3.0:
You can start a PowerShell 2.0 enviroment by using this parameter: -version 2.0 for POWERSHELL.EXE
Execution PS2EXE reports PowerShell version 2.0:
Now lets use to create an EXE file using the PS2EXE script…
1. Sample: PowerShell 3.0 without parameters –runtime20 and –runtime30
2. Sample: PowerShell 3.0 with parameter –runtime20
(Behind the scene this starts PowerShell.exe using parameter –version 2.0.)
3. Sample: PowerShell 2.0 without parameters –runtime20 and –runtime30
4. Sample: PowerShell 2.0 with parameter –runtime20
Last Thursday I wrote about “Exporting SharePoint 2013 Design Packages with PowerShell”. Today I’d like to show you the import function. This functions can be used to handle with SharePoint 2013 Design Packages with PowerShell, e.g. in deployment scenarios. Therefore it should by very useful. (I hope so 😉 ) FEEDBACK WELCOME!!!
The first sample shows you how to import one design package to a dedicated site. By using the “Apply” parameter the design package will be applied to the site immediately.
The second sample shows you hot to import two different packages to two different site collections. In the sample I use a hashtable for input parameters. They are assigned to the function parameters by “property name binding”. See “http://technet.microsoft.com/en-us/library/hh847743.aspx”: Section “ValueFromPipelineByPropertyName”:
[…]
For example, if the function has a ComputerName parameter, and the
piped object has a ComputerName property, the value of the ComputerName
property is assigned to the ComputerName parameter of the function.
The following example declares a ComputerName parameter that is
mandatory and accepts input from the ComputerName property of the
object that is passed to the function through the pipeline.
[…]
Some more details about that. Skip it if you are not interested…
<begin/>
This “property name binding” does not work with hashtables. Therefore I created a helper function “New-ObjectFromHashtable” that creates a PowerShell object (“PSObject”). This function is generic. (It’s also included in the script files.)
On the one hand with “new-object System.Management.Automation.PSObject” you can create a new “empty” PowerShell object that can be used in your script as every other object, e.g. a SharePoint object like an instance of class SPSite. With cmdlet “Add-Member” you can add new members to the object. – On the other hand you have a hashtable with named values. You can access the collection of names = keys and with each key you can access the value. – Let’s combine it: You can iterate through the keys collection and create a new member in an empty PSObject instance.
functionNew-ObjectFromHashtable {
#written by Ingo Karstein (https://blog.kenaro.com)# v1.0#Use this function to convert a hashtable to a PowerShell object ("PSObject"), e.g. for using hashtables for property name binding in# PowerShell pipelines
[CmdletBinding()]
param(
[parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
[Hashtable]
$Hashtable
)
begin {
$results= @()
}
process {
$r=new-objectSystem.Management.Automation.PSObject$Hashtable.Keys | % {
$key=$_$value=$Hashtable[$key]
$r | Add-Member-MemberTypeNoteProperty-Name$key-Value$value-Force
}
$results+=$r
}
end {
$results
}
}
The resulting object can be passed to each “property name binding” enabled cmdlet. – The PowerShell engine tries to match input object property names and cmdlet parameter names. If there is a match the input object property value gets assigned to the cmdlets input parameter.
The cmdlet can also convert a list of hashtables to a list of objects. That is used in the “Import-SPDesignPackage” script.
<end/>
Parameters
Parameter Name
Parameter Set Name
Mandatory?
Position
Description
SiteUrl
Default
Yes
0
Site Url for import
Site
Site
Yes
0
SPSite object for import
ImportFileName
DefaultSite
Yes
1
Filename and path of the design package for import
Apply
DefaultSite
Yes
2
$true = Apply the design package after import$false = Only install the design package for later activation
PackageName
DefaultSite
No
3
Package name. If not specified it uses the file name without extension. The package name will be used for naming the imported file in the solution gallery of the site collection
MajorVersion
DefaultSite
No
–
Version number of the design package. If not specified it uses “1” for the major version.
MinorVersion
DefaultSite
No
–
Version number of the design package. If not specified it uses “0” for the minor version.
The function returns an object for each processed (or not processed) site collection:
Object Property
Description
SiteUrl
Url of the processed site
Success
$true = Import and “Apply” (if specified) was successful
InputFileFound
$true = File found$false = File not found
InputFileExtensionValid
$true = Input file has extension “.wsp”$false = Input file hat not extension “.wsp”
SiteFound
$true = The specified site was found
SolutionFileName
The name of the solution is auto generated from package name or file name and major and minor version number. This is the name of the package in the site collections solution gallery.
PackageAlreadyExsits
$true = the solution does already exist in the solution gallery.
Some additions
The import process requires the package to be stored inside the site collection before the the last input step. Therefore the function creates a folder named “tmp_importspdesignpackage_15494B80-89A0-44FF-BA6C-208CB6A053D0” in the site collections root web root folder. In this folder the package gets uploaded. From the location the package is imported. The folder will be deleted after successful or not failed import.
To install the project just by deploying the solution. The SharePoint feature will automatically be activated in the Central Administration Web Application without need of further actions.
In the “System Settings” section of the CA you’ll find a new link:
Just click it and you will get this:
The SharePoint PowerShell SnapIn is loaded automatically so that you can start immediately to execute SharePoint Cmdlets!
Here is an example:
“Get-SPSite”
Or this one:
Request for value for missing parameter “Path” of Cmdlet “Backup-SPSite”
Final output:
The project is “BETA”. I need your help to improve the project. Please feel free to test it or to extend it. But if you do so please send me your results!
Starting at 12th of September 2011 I’ll be freelancer. – In August I had some vacation days to spend. – So I created a new project for me – and for you.
I call it “Web based PowerShell Console” or “WebPSConsole”.
It is a full featured Browser based PowerShell console that enables you to work on a server machine remotely. It’s like PowerShell remoting but it’s not the same. While PowerShell remoting uses “WinRM” the tool that I’ve created uses a “normal” PowerShell host that will be executed in an IIS environment. (Please see my comment related to “PowerGUI Pro Mobile Shell” at the end of this article.)
That means: With my tool you will have a ASP.NET 4.0 based Web Application that can be accessed by a browser. The ASP.NET web app has a .ASPX site and some code behind. On the server in the ASP.NET context a PowerShell Host developed by me is running that accepts commands send by the clients Browser. If a command is send it will be executed by the PowerShell Host. All output is send back to the clients Browser.
It’s on Codeplex: http://webpsconsole.codeplex.com with all source code! – It’s ALPHA. I’ve done lots of testing but I’m a single developer with a single machine… I’d be happy to get your improvements or experiences!
Lets have a look at the app:
That is the “GUI”. The black frame will contain the output of the server side PowerShell session.
Let’s enter a command.
get-childitem c:windows | select -first 5
After clicking “Send” the command is send to the server. The server executes the command and returns the PowerShell output.
Let’s try this:
get-credential
You see the blue colored input box for the credential information input.
Here you see the implemented “session timeout”:
After 15 minutes of inactivity you’ll get a warning. After 20 minutes the session will be terminated. After termination you are not able to access the old session including session history!
Let’s try this:
a$ = read-host
Here you get an input field for a single line of text. The output is stored in variable $a. Let’s check the content of variable $a after sending the input:
Now let’s test the functionality of completing missing cmdlet parameters:
get-content
Leave the last line empty and click “Send”.
You get:
Now let’s test the “choice” functionality:
After “Send” you get:
You see here the blue colored choice input field. If you choose “Halt Command” in this case the “Hello Ingo” command will not be executed:
If you select “Cancel” in such cases the complete PowerShell pipeline will be stopped! Not only the current command!
You can set colors a you need to:
Than “Send” and test it with:
You’ll get:
Now let’s have a look at the function “Download console as RTF”. You’ll find the link above the console frame.
Click “Open”.
This is a Rich Text Format copy of the complete console output! – A “Clear-Host” will not clear this output! – This file can only be downloaded while the current session running. After the session ends you will not be able to access the information anymore!
Let’s try “Show current buffer”. This command is above the console frame too.
Here you get the “real” PowerShell buffer as HTML. This page can be save.
Let’s try:
clear-host
Open “Show current buffer” again:
(It’s empty now because clear-host did clear the PowerShell buffer!)
A word to the keyboard usability:
In the command input field you can use ESCAPE to clear the input field.
You can use CTRL+ENTER to send the command.
In other input fields (choice, credential, read-line,…) except “Read-Key” (see below) you can use ESCAPE to cancel the current operation and pipeline.
You can use there ENTER to send your entered data.
You can use TAB and SHIFT+TAB to navigate inside the input frame: input field, Send button and Cancel button.
The “Trace log” is an optional frame that maybe shows more information about your server connection and the “work behind”. Just click the line and the frame will be shown:
(“Send buffer as HTML” is caused by the “Show current buffer” function.)
You can close the PowerShell session by clicking the “x” in the dialog title (beside “v0.1.0.0”):
Now you can close the Browser or click “Ok” to start a new session. Or reload the Browser page to create a new session.
Setup
Now I want to tell you how to install the project.
First of all you need IIS. This can be installed on Windows 7 too.
You need a user account for executing PowerShell at server side. This account is used by every user of WebPSConsole: Each user of WebPSConsole will be impersonated at the server with the “execution account”. Here you should choose the account very carefully.
1.
Create a directory on the server where you store the binaries. You create a folder “c:inetputwebpsconsole”.
2.
Copy the binaries there.
3.
Open IIS Manager.
Create a new Application Pool for the “execution account”. This account need to execute ASP.NET 4.0 code.
Select “Classical Mode” for the application pool! – Please check the settings. In my case the settings were not used. After creating the app pool I had to edit it and set “Pipeline Mode” and “Framework Version” again!!!
4.
Create a new web application “WebPSConsole” using the previously created application pool.
Right click the “Sites” node in IIS Manager.
You get this dialog. Fill in your specific informations. Here is my sample. I’ll use “ikWebPSConsole” as host header name in this setup demo because the host header “webpsconsole” already exists for development purpose.
Click the “Select” button beside “Application pool:
“OK”.
My sample data:
(In order to get this working on my machine I have to edit c:windowssystem32driveretchosts and insert “ikWebPSConsole” as new local DNS entry.)
5.
Change the Authentication settings. Disable “Anonymous Access” and enable “Windows Authentication”.
Select the web app in the treeview. On the right side double click “Authentication”.
You get:
First double click “Anonymous Authentication” and deactivate it!
Now enable “Windows Authentication” the same way!
6.
You should restrict the usage of the web app by setting access restrictions.
There you can grant or deny access to the web app for specific users, e.g. administrators.
As an example: Here only “DOMAINAdministrator” will have access to WebPSConsole.
You should enable SSL.
I’ve done this already in the setup example above while creating the web app.
You could use “SSL client certificates” to protect the web app.
7. Test the app.
Security
I’ts as secure as you configure it!
You can restrict the rights of the console on the server by selecting a carefully configured user account as application pool account. You don’t have to configure this user to be “local admin” 😉
You can use SSL! (As shown above)
You can use Client-SSL-Certificates!
You can restrict client IP addresses!
You can restrict access by secifying users (as shown above).
BUT be sure you know what you do – as always 😉
Limitations
It’s not as fast as a local PowerShell because of the client-server-interaction.
Currently it runs only under the user context of the application pool. There should be “real” impersonation of the logged in user. But this did not work.
It consumes memory on the server because of the data saved on the server in the session. Be sure to monitor the servers memory usage if you deploy it on live servers!
There is not “Progress” support at the moment!
Ideas for future features:
Command completion (like “Intellisence”)
Client side syntax check
“Color code”
Please help me to impove the app! – Please post comment of your experiences!
As I said I’ve developed this project in my last vacation. After finishing v0.1.0.0 I’ve seen PowerGUI Pro MobileShell by Quest Software . It’s based on the same idea as my project but is older and has more features I think. I only know a YouTube video of it because I do not know the commercial version of PowerGUI. – Beside this the free PowerGUI tool is my favorite PowerShell IDE. – For use on a live server you should think about using PowerGUI Pro MobileShell!
Version Update from 0.1.0.0 to 0.1.1.0 at 2011-08-22.
But: It does not convert the PowerShell script to an other language! It encapsulates the script with a lightweight PowerShell host written in C# and compiles the dynamically generated C# source code in memory to an EXE file. The resulting EXE is an .NET assembly that contains the source script encoded in Base64. The EXE includes all stuff that is needed to execute an PowerShell through the .NET object model. It is based on classes in the namespace System.Management.Automation that reperents the PowerShell engine. – Therefore the EXE file is not a real “standalone” EXE file. It needs PowerShell to be installed!!! And – of course – it needs .NET Framework v2.0. Furthermore “script execution” have to be allowed (see cmdlet: set-execultionpolicy). – The resulting EXE is “MSIL” and is able to execute as x64 or x86.
The tool “PS2EXE” itself is a PowerShell script! – It does the in-memory compilation and generates the EXE file. It uses the CSharpCodeProvider class of namespace Microsoft.CSharp.
The script is really simple. I contains a multiline string that represents the PowerShell host I’ve written. This is much more interesting than the PS2EXE.ps1 script itself. – Have a look into it!
Usage:
Call the script with this parameters:
-inputFile
PowerShell script file
-outputFile
file name (with path) for the destination EXE file
-debug
(switch) generate debug info in the destination EXE file. The dynamically generated .CS file will stored beside the output EXE file. Furthermore a .PDB file will be generated for the EXE file
-verbose
(switch) shows also verbose informations – if any.
Sample:
This creates “test.exe” out of the PowerShell source file “test.ps1”
Limitations: It’s not easy to create a fully functional PowerShell host such as “Console host” (powershell.exe) or “ISE” (powershell_ise.exe). So there may be functionality that does not work properly.
The generated EXE can also be calls using command line options. There are 4 options that are used by the PowerShell host:
-debug
Forces the EXE to be debugged. It calls “System.Diagnostics.Debugger.Break()”.
-extract:”Filename”
Extracts the PowerShell script inside the EXE and saves it as “Filename”. The script will not be executed.
-wait
At the end of the script execution it writes “Press a key…” and waits for a key to be pressed.
-end
All following options will be passed to the script inside the EXE. All preceding options are used by the EXE and will not be passed to the script.
Sample:
I create a script file containing this line of code:
$args | Write-Host
I save it as “c:test2.ps1” and convert it as EXE by using PS2EXE:
Sample 1.: “-wait” forces the “Hit any key…” message. All options following “-end” will be passed to the script.
Sample 2., 3. : The script will not get options preceding to “-end”.
Sample 4: “-wait” follows to “-end” and so it’s passed to the script. No message “Hit any key…”.
So. That’s it for the moment. Please feel free to modify the script and let me know.
Possible tasks:
Sign the script inside the EXE with code signature
There are some mysterios errors on my SharePoint farm. After reading tons of log files I found some hints to problems with the “Session State Service” of SharePoint 2010.
I found this Cmdlets in PowerShell for controlling this service:
I tried to enable the service with the first Cmdlet. – This was the resulting error:
Error message: “Microsoft SharePoint Server session state could not find the Session State Service. Contact your farm administrator.”
There is no information about this error in the internet. (Till now )
MY SOLUTION FOR MY PROBLEM (may be it does not help you in your special situation. It’s “experimental”!!!):
I created a PowerShell script for re-creating the Session State Service and its Service Application.
Before you go on: Make sure, the Windows service “ASP.NET State Service” is running. (I set it to start automatically during system startup.)
This is the resulting script:
#region Check x64 host
if( [System.IntPtr]::Size-ne8) {
Write-Error"Please use a x64 PowerShell host!"return
}
#endregion#region Load SharePoint SnapIn and DLL
Remove-PSSnapinMicrosoft.SharePoint.PowerShell-ErrorActionSilentlyContinueAdd-PSSnapinMicrosoft.SharePoint.PowerShell-ErrorActionSilentlyContinue#Check available SharePoint Cmdletsif( (Get-Command-Noun SPWeb*) -eq$null ) {
Write-Error"SharePoint SnapIn not loaded. SharePoint cmdlets missing!"return
}
#endregioncls$farm= [Microsoft.SharePoint.Administration.SPFarm]::Local$services=$farm.get_Services() #get all SharePoint services$sessionStateService= ($services | ? { $_.TypeName -like"*session state*" } ) #find the existing Session State Service -> it was "NULL" for me!if( $sessionStateService-eq$null ) {
#Recreate the Service$newSessionStateService=New-ObjectMicrosoft.Office.Server.Administration.SessionStateService ("", $farm)
$newSessionStateService.Id= [System.Guid]::NewGuid()
$newSessionStateService.Name=[String]::Empty$newSessionStateService.Update()
$farm.Update()
$newSessionStateService.Provision()
$newSessionStateService.Name=[String]::Empty$newSessionStateService.Update()
}
$services=$farm.get_Services()
$sessionStateService= ($services | ? { $_.TypeName -like"*session state*" } )
$servers=(Get-SPServer)
#Create service instances on all application servers of the SharePoint farm$servers | % {
if( $_.Role -eq"Application" ) {
$currentSessionStateSvcOnServer= ($_.ServiceInstances | ? { $_.TypeName -like"*session state*" } )
if( $currentSessionStateSvcOnServer-eq$null ) {
#write-host $_.Name $server.Role $_.gettype().fullname#To create a service instance you must use a "protected" constructor [type]$t="Microsoft.SharePoint.Administration.SPServiceInstance"-as"Type"$p= @( ("string"-as [Type]), ("Microsoft.SharePoint.Administration.SPServer"-as [Type]),
("Microsoft.SharePoint.Administration.SPService"-as [Type]) )
$c=$t.GetConstructor([System.Reflection.BindingFlags]::NonPublic-bor [System.Reflection.BindingFlags]::Instance,$null, $p, $null)
#these are the parameters for creating a service instance by using the protected constructor [Object[]]$params= @([Object]"Session State Service Instance",
[Object]([Microsoft.SharePoint.Administration.SPFarm]::Local.Servers[$_.Name]),
[Object]([Microsoft.SharePoint.Administration.SPFarm]::Local.Services[$sessionStateService.Id]))
$newSvcInstance=$c.Invoke($params)
#update & provisioning$newSvcInstance.Update()
$newSvcInstance.Provision()
}
}
}
if( (Get-SPSessionStateService-ErrorActionSilentlyContinue) -ne$null ) {
Write-Host"Successfull :-)"-ForegroundColorGreen
} else {
Write-Host"Failed :-("-ForegroundColorRed
}
After that, the “Enable-SPSessionStateService” works:
(Spend me 1 1/2 days.)
You can use this script to delete the Session State Service, e.g. if some script parts does not work as expected. ONCE MORE: USE IT CAREFULLY AND AT YOUR OWN RISK!!!
If you want to set the SharePoint 2010 Enterprise Search Service Application "Default Content Access Account" by using PowerShell you can use this script:
$searchapp= Get-SPEnterpriseSearchServiceApplication "Search Service Application" $c=New-ObjectMicrosoft.Office.Server.Search.Administration.Content($searchapp) $c.SetDefaultGatheringAccount($crawlUser, (ConvertTo-SecureString$crawlPwd-AsPlainText-force))
($crawlUser is – of cause – the login of the account and $crawlPwd is the password in plain text)