Powershell On Windows Server 2008 vs. Windows XP? - powershell

I'm writing a PowerShell script for a particular client. I tested the script on several of our desktop machines, and the tried the script on the client's system. I ran into the following issues:
Issue #1
As a good little Do Bee, I defined a bunch of help text, so when you run Get-Help on my script, it would give you detailed help. I used the following syntax:
<#
Get-Help
.SYNOPSIS
C> FileWatcher.ps1 -FilePath <FileName> -SenderEmail Bob#Foo.com ^
-ToEmail Joe#Bar.com -SmtpServer smtp.foo.com
.DESCRIPTION
Blah, blah, blah...
#>
On my machine, it works, and this is recognized as comment. However, on the client's machine, this produced an error as soon as it saw the C> which it thought was a redirect. Getting rid of the #> and <# and putting # in front of each line got rid of this problem, and brought us Issue #2.
Issue #2
I defined a bunch of parameters like this:
Param (
[ValidateScript({Test-Path $_ -PathType 'Leaf'})]
[Parameter(
Position=0,
HelpMessage="File you want to watch")]
$FilePath = "\\rke032\QuickCon\wincommlog.000",
[String]
[Parameter(
blah, blah, blah
PowerShell coughed on [ValidateScript({Test-Path $_ -PathType 'Leaf'})] saying it wasn't a valid type.
As I said, we tested this on a wide variety of Windows machines. I have a Windows XP machine. It's PowerShell version # 6.0.6002.1811. On another machine that's running Windows 7, the PowerShell version is 6.1.7600.
On the client's machine (a Windows 2008 Server) which is giving us these errors, the version is 6.0.6001.18000.
We ran the Powershell scripts by bringing up a PowerShell window, and then typing in the script's name. The ExecutionPolicy is set to Unrestricted. The script has a *.ps1 suffix on the end. I can't believe there's that big a difference between revision 6.0.6002 and 6.0.6001 to have a problem with unrecognized syntax. Is there something else going on?

Compare the output of $PSVersionTable and not the build version. In particular the PSVersion property is interesting. I guess you have PS1 on one machine and PS2 on another. The extension is .ps1 regardless of the PowerShell version.
This guess is reinforced by noticing that block comments don't work and neither do parameter attributes.

Related

Powershell - run .MSI installation with arguments but Windows Installer pops up and nothing happens

I am using Powershell 7 to install .MSI application with some arguments (same installation with same arguments passed well when using for example Ansible tool).
Every time I try to run script I am getting Windows Installer pop up window which someone mentioned ( someone wrote "This pop up is the msiexec help pop up. It’s telling you it doesn’t like your command line"). I tried several different orders but always getting this failure.
I saw there was similar issue but it was completely different issue with Accepting License Terms, I do not have issue with that.
My arguments are:
$webDeployInstallerFilePath = "C:\fa_components\PRIME\SUN TEST 2020.1 (x64).msi"
$switch2 = #(
"i `"$webDeployInstallerFilePath`""
"/quiet"
"passive"
"/l* C:\tmp_installation\logs\Prime_log.txt"
"INSTALLDIR=C:\"
"FRONTINIDIR=C:\ProgramData\Front\64bit\ini\"
"FRONTINILOG=C:\ProgramData\Front\64bit\log\"
"PRIME=C:\TEST Arena\"
"ProgramMenuFolder=C:\ProgramData\"
"COMMONAPPDATA_FRONTDIR=C:\ProgramData\Front\"
"COMMONAPPDATA_FRONT64BITDIR=C:\ProgramData\Front\64bit\"
"CommonAppDataFolder=C:\ProgramData\"
)
Program requires some of it needed argumets.
I try to execute it with:
Start-Process msiexec.exe -ArgumentList $switch2 -Wait
I try to run my .ps1 script but as I mentioned I am getting only picture with windows installer and nothing happens (you can see that on following link)
windows installer picture
Thanks in advance!
Yes, a few problems.
"i" should be "/i" (note the forward slash)
"passive" should be "/passive" (note the forward slash)
Because it has a space in the path, "PRIME=C:\TEST Arena\" should be "PRIME="C:\TEST Arena\""
Examples here: https://www.alkanesolutions.co.uk/2018/07/18/install-and-uninstall-msi-using-powershell/
$switch2 = #(
"/i `"$webDeployInstallerFilePath`""
"/quiet"
"/passive"
"/l* C:\tmp_installation\logs\Prime_log.txt"
"INSTALLDIR=C:\"
"FRONTINIDIR=C:\ProgramData\Front\64bit\ini\"
"FRONTINILOG=C:\ProgramData\Front\64bit\log\"
"PRIME=`"C:\TEST Arena\`""
"ProgramMenuFolder=C:\ProgramData\"
"COMMONAPPDATA_FRONTDIR=C:\ProgramData\Front\"
"COMMONAPPDATA_FRONT64BITDIR=C:\ProgramData\Front\64bit\"
"CommonAppDataFolder=C:\ProgramData\"
)

Powershell running a cmdlet from a called script

I have a script that calls another script (with arguments). The called script contains the Install-WindowsFeature cmdlet. When I run the script, the called script runs, but returns the following error:
Install-WindowsFeature : The term 'Install-WindowsFeature' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path
Of course, I can run the cmdlet just fine from a PowerShell console. I can also run the called script from a PowerShell console and Install-WindowsFeature works fine. So, is it something to do with calling a script from a script that runs a cmdlet? Here is my calling code:
$script = "C:\Path\script.ps1"
$argumentList = #()
$argumentlist += ("-Arg1", "value")
$argumentlist += ("-Arg2", "value")
$argumentlist += ("-Arg3", "value")
Invoke-Expression "$script $argumentList"
In the called script, I called Install-WindowsFeature as below:
if ($someValue) { Invoke-Command -ScriptBlock {Install-WindowsFeature -Name RSAT-AD-Tools} }
I've also tried it as below:
if ($someValue) { Install-WindowsFeature -Name RSAT-AD-Tools }
12/16/16 EDIT: This script is running in a GUI built with Sapien PowerShell Studio. When I change the build type to "Native" it works. I have to reset my lab to check, but I suspect it will also run if I just run it in the x64 context. This article explains why I think this matters.
Running on Windows Server 2012 R2
Unless you've got a compelling reason for it, let's see if we can clean up your calling pattern a bit - and hopefully make your other issues go away by avoiding the contortionism.
Rather than creating your parameter list as a string, take advantage of parameter splatting. It's good to get out of the habit of treating PowerShell like other scripting languages that don't work with objects.
$splat = #{
Arg1 = "value1";
Arg2 = "value2";
Arg3 = "value3"
}
& c:\path\script.ps1 #splat
Using that on a script.ps1 something like this:
param(
$Arg1,
$Arg2,
$Arg3
)
Write-Host "Arg1 = $Arg1, Arg2 = $Arg2, Arg3 = $Arg3
You'll get an expected output of:
Arg1 = value1, Arg2 = value2, Arg3 = value3
Once you've got that, there's probably no reason to use Invoke-Command on the call to Install-WindowsFeature, unless you're leaving out details like invoking remotely to a server. Invoke-Command { Install-WindowsFeature } still works fine for me on Server 2012R2 with PowerShell 5, and there's no reason it shouldn't.
This assumes you're running this script on a Server that support Install-WindowsFeature, as the other comments point out. Client Windows doesn't support Install-WindowsFeature, and the RSAT tools are installed via a stand-alone RSAT .MSU package, which you manage differently.
Install-WindowsFeature is natively provided with Server Manager on Server 2012R2 - there's no need to Import-Module... unless you've done something to your profile or fouled up your modules folders. One of the earlier versions of Windows Server needed it - but that was a couple versions back. Likewise, Add-WindowsFeature was the old name - and it's still available as an alias for Install-WindowsFeature.
I'm assuming you've tried Install-WindowsFeature directly from the command line to ensure it's in working order, and Get-Module Install-WindowsFeature looks reasonable.
PS C:\Windows\system32> get-module ServerManager
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.0.0.0 ServerManager {Get-WindowsFeature, Install-WindowsFeature, Uninstall-Win...
While we're on the topic, there's very little reason to drop to DISM on Server that supports Install-WindowsFeature, and a number of reasons not to.
Server Manager and several other tools (including Win32_ServerFeature) rely on the feature states parsed and understood by the WMI provider used by Install-WindowsFeature. It's possible to enable the right set of features using DISM, but needs attention and detail. Enabling only "part" of a role and feature may get the functionality you want for specific cases, but the role or feature may not show up as installed in Get-WindowsFeature, may not be uninstallable via Remove-WindowsFeature, and may not offer relevant UI features in Server Manager like monitoring health of the role, viewing relevant events, or offering tools for administering it.
Install-WindowsFeature integrates with additional code from the role & features you're installing, and may run additional health and pre-requisite checks to ensure your correctly configured.
DISM featurenames tend to change more often than the role & feature name of Server Manager, so your script portability will be better.
There are other points, but I won't go into them since DISM was primarily a comment fork.
You are probably right, it seems like the script gets executed with x86 PowerShell. I want to share a snippet with you which I use for scripts that needs to run in a specific environment (e. g. x64 PowerShell).
The script restarts itself in a x64 PowerShell if its started as x86 process. Just put this at the top of your script:
# Reinvoke the script as x64 if its called from a x86 process.
if ($env:Processor_Architecture -eq "x86")
{
&"$env:windir\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -file $myinvocation.Mycommand.path -executionpolicy bypass
exit
}
Also note that the Install-WindowsFeature cmdlet doesn't work on all windows versions so consider to use dism instead:
$featuresToInstall = #('RSAT-AD-Tools')
$dismParameter = #('/online', '/Enable-Feature', ($featuresToInstall | % { '/FeatureName:{0}' -f $_ }), '/NoRestart')
dism #dismParameter
The running environment determines what modules you have access to. When I created this project in PowerShell Studio, it took the default of x86 (a 32 bit environment). This worked but because I was running it on Windows Server 2012 R2 (a 64-bit environment) I did not have access to the powershell modules such as Import-Module and Install-WindowsFeature. Changing this to a x64 project resolved my issue.
In order to avoid this scenario, it is important to make sure you run PowerShell scripts and modules in the architecture that is native to the OS. You can do this by setting the project correctly (if using a tool like PowerShell Studio) or by verifying that you are running in the native mode for that OS with the code Martin Brandl provided.

How do I get PowerShell 4 cmdlets such as Test-NetConnection to work on Windows 7?

The situation. On a Windows 7 SP1 machine, I have updated with Windows6.1-KB2819745-x64-MultiPkg.msu. Furthermore, in PowerShell $PSVersionTable now reports ‘PSVersion 4.0’.
At present, my conclusion is that many PowerShell 4 cmdlets such Test-NetConnection, will only work on Windows 8.1. However, I was wondering if there was a work-around whereby I could import PowerShell 4 modules on my Windows 7 machine.
You cannot. They rely on the underlying features of the newer OS (8.0 or 8.1) and cannot be ported back to Windows 7 . The alternative is to write your own functions / modules to replicate the new cmdlets using .NET framework methods.
For instance, the Get-FileHash cmdlet is a one-liner in PowerShell 4.0, but to replicate in 2.0 we have to use .NET.
PowerShell v4
Get-FileHash -Algorithm SHA1 "C:\Windows\explorer.exe"
PowerShell v2
$SHA1 = new-object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider
$file = [System.IO.File]::Open("C:\Windows\explorer.exe",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
[System.BitConverter]::ToString($SHA1.ComputeHash($file)) -replace "-",""
$file.Close()
At least Test-NetConnection can be ported back to Windows 7. Just copy folders NetTCPIP, DnsClient, and NetSecurity from the supported Windows machine with the same PowerShell version (Windows 8.1, Windows 10, etc). Folder - C:\Windows\System32\WindowsPowerShell\v1.0\Modules. Then Import-Module -Name C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetTCPIP -Verbose
Alternatively, you can import a module from a remote machine (say win2012):
$rsession = New-PSSession -ComputerName win2012
Import-Module NetTCPIP -PSSession $rsession
I have had the same problem on my Windows 7 x64 and both solutions worked for me as of PowerShell 5.1.
Adding to Anton Krouglov's answer. PowerShell modules are cross-platform compatible. So a module copied from Windows Server 2012 R2 x64 can be imported to Windows 7 x86, and even if you are running as standard user without rights to copy them to C:\Windows\System32\WindowsPowerShell\v1.0\Modules you can copy it to any local folder, and run.
Assuming you copied the NetTCPIP, DnsClient, and NetSecurity modules from a Windows Server 2012 or higher machine, and save them to a folder you can import them using
Get-ChildItem -Directory .\psmodules | foreach { Import-Module -Name $_.FullName -Verbose}
Test-NetConnection -InformationLevel "Detailed"
As far as I know, Windows Server 2008 R2/Windows 7 simply doesn't have the counters that the .NET methods use to implement get-netstuff.
A new PowerShell version can implement hash compare, etc. since this is not related to anything, just a piece of code. But if you want to use, for example, Get-NetTCPConnection there is nothing to show.
I see several responses which assert portability, and my testing confirms their assertions:
Import all of the required modules, either from file, or via a PSSession to a host which has the required modules.
The architecture of PowerShell Console (x86 or x64) you run will determine which module architecture you import.
For those who are:
still unable to make this work
AND
do need a reliable TCP test, but may not need everything else provided by Test-NetConnection
AND
Need it all to work even on PowerShell v2.0
You may wish to try this.
# Create a TCP Client using .Net & attempt connection to target
$TCPClient = New-Object .net.sockets.tcpclient("[IP address or hostname]",[port])
# At the above point you may see familiar-looking Windows error messages in
# red text. (You may want to use "try/catch" if you intend to loop).
# Otherwise, check your new object's status to see if it worked
$TCPClient.Connected
# The response is either "True" or False"
# Now to avoid leaving idle connections, run:
$TCPClient.Close()
Naturally, it should be possible to create a loop which tests multiple connections, and outputs the results by selecting the properties of the $TCPClient.
My initial testing shows you would want to Select these properties
The address you tested
$TCPClient.Client.RemoteEndPoint.Address.IPAddressToString
The port you tested
$TCPClient.Client.RemoteEndPoint.Port
The result
$TCPClient.Connected
HIH
While PowerShell 4.0 is available on Windows 7, as Knuckle-Dragger states certain features rely on newer operating system functionality. Unfortunately Test-NetConnection is not available in Windows 7 as stated in the documentation.
Test-Connection, which is present, is basically ping. Test-NetConnection offers much more functionality, allowing a choice of things such as TCP ports, protocols, route tracing, and information levels.
There is a Send-Ping script available from the ScriptCenter in the TechNet gallery, but I think this is only really useful if you are stuck on PowerShell 3.0 for some reason.
I can only assume you installed the wrong package. Make sure you download the proper package from here.
Below you will see in running Windows 7 Service Pack 1 with PowerShell 4 using Test-Connection and Get-FileHash:

Why won't this powershell script accept parameters?

myscript.ps1
Param(
[Parameter(Mandatory=$true,Position=1)]
[string]$computerName
)
echo "arg0: " $computerName
CMD.exe
C:\> myscript.ps1 -computerName hey
Output:
cmdlet myscript.ps1 at command pipeline position 1
Supply values for the following parameters:
computerName: ddd
arg0:
ddd
I'm simply trying to work with Powershell parameters in CMD, and I can't seem to get a script to take one. I see sites saying to precede the script with .\ but that doesn't help. I added the mandatory line to see if Powershell was reading a parameter or not, and it's clearly not. The parameter computerName is obviously the word "hey". The Param block is the very first thing in the script. Powershell appears to recognize a parameter computerName, but no matter how I enter the command, it never thinks I'm actually entering parameter.
What the heck's wrong with my syntax?
By default, Powershell will not run scripts that it just happens to find in your current directory. This is intended by Microsoft as a security feature, and I believe that it mimics behavior found in unix shells.
Powershell will run scripts that it finds in your search path. Your search path is stored in $env:path.
I suspect that you have a script named "myscript.ps1" in some other directory that is on your search path.
I have had this happen to me before. The symptom I saw was that the parameter list seemed different than what I had defined. Each script had a different parameter list, so the script bombed when I fed it a parameter list intended for the other script. My habit is to not rely on parameter position, so this problem was easy to find.
The addition of ".\" to the script ".\myscript.ps1" should force the shell to use the .ps1 file in your current directory. As a test, I would specify the full path to the file you are trying to execute (If there are spaces in the path, be sure to wrap the path in "quotes") or change it to some totally crazy name that won't be duplicated by some other file (like "crazyfishpants.ps1") and see if the shell still finds the file.
You can get into similar problems if you have a function ("Get-Foo") that is loaded out of a module or profile with the same name as a script file ("Get-Foo.ps1"). You may wind up running something other than what you intend.
Position values should be 0-based (0 for the first parameter). That said, I can't duplicate what you're seeing on either PowerShell 2.0 or 3.0.
Thank you all for your very informative responses. It looks like my question was slightly edited before I submitted it, in that the text leads you to believe that I was entering this command directly in Powershell.
I was actually running the command for the script in CMD, which totally explains why it was not passing parameters to the Powershell script. Whoever green-lighted my question probably changed C:\> to PS> thinking that I made a typo.
I assumed that if I could run the script straight from CMD, I could send parameters to it on CMD's command line, but apparently that's not the case. If I run the script in Powershell, it indeed works just fine, I'm now seeing.
My ultimate goal was to allow users to run the Powershell script from CMD. It's looking like I can make a batch file that accepts parameters, and then start powershell and send those parameters to the PS script. And so, in the batch file, I should do something like:
powershell -File C:\myscript.ps -computerName %1
This enigma was probably solved 100 times over on this site, and I apologize for the confusion. Thank you again, for your responses.

Creating an executable .exe file from a PowerShell Script?

Is it possible to create an executable file.exe file from a PowerShell Script?
No. At least, not yet, and after 5 versions of PowerShell, it seems unlikely ever.
I wish I could just leave it at that, but other people have provided a bunch of "workaround" type answers I feel compelled to address:
You can wrap your .ps1 script in another script type to make it double-clickable, and you can even generate an executable with the script embedded (see the other answers on this thread) ... but those "executables" require the right version of PowerShell to be already present on the system, so you're not gaining anything by doing that, and you loose a lot of the features of PowerShell (like streaming object output, help documentation, and automatic parameter handling with tab completion for users).
Here is a simple .cmd batch file wrapper (you could extend this to allow parameters):
REM <#
copy %0 %0.ps1
PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Command "&{Set-Alias REM Write-Host; .\%0.ps1}"
del %0.ps1
exit
REM #>
### Your PowerShell script goes below here.
### I've put a couple of lines as an example ...
ls | sort length -desc | select -first 5 | ft
ps | sort ws -desc | select -first 10 | ft
I know ...
With Portable PowerShell, it would probably be possible to package up a sort of self-extracting zip that would contain the right version of PowerShell and a script and would work. That's not an executable in any normal sense of the word -- it's a bit like if Valve had decided to just ship a vmware image on a thumbdrive as their solution to letting Linux users play Half Life. However, the product seems abandoned.
With PrimalScript (or PowerShell Studio) or PowerGui or pShellExec, your script can be encrypted, so it's slightly secured against prying eyes ... but this is basically just obfuscation, and essentially no different than the batch file, and in some ways worse.
Out of the box - no. However I have built a PowerShell script that can take a script and create an EXE wrapper around it. I created this script a while ago but decided to blog it here for folks to check out.
Use PowerGUI's Script Editor (it is free and works). Open your script in the PowerGUI Script Editor > Tools > Compile script > Choose whatever options you would like for your .exe (password protect source code, automatically close console after .exe runs, etc.).
Yes, there is a option with PS2EXE to create such *.exe Files.
Usage
The whole thing is really simple and well explained nevertheless
here is a snippet of it:
C:\Scripts\PS2EXE\PS2EXE_0.5.0.0.0\ps2exe.ps1
-inputFile C:\Scripts\ExampleEXE\example.ps1
-outputFile C:\Scripts\ExampleEXE\example.exe -sta -noConsole -runtime40 -verbose -x64
The only bad thing is that the project is depreciated. No Updates or new Versions since 2015.
EDIT:
This projected has been picked up and is being maintained by a new person now. You can find the updated code here, last updated 01/04/2018 as of this edit.
https://gallery.technet.microsoft.com/scriptcenter/PS2EXE-GUI-Convert-e7cb69d5
Version Information
For adding and editing the version information use something like VERPATCH.
UPDATE 2019
Shout out to a git-repo which is called PythonEXE.
It demonstrates how to create an executable from a Python project and also provides a YouTube Step-By-Step Guide.
I understood your question as "Can my PowerShell script generate an executable?" That is what I was trying to do when I found this post. That is possible using the Add-Type command.
Add-Type -TypeDefinition #"
using System;
class Program {
public static void Main(string[] args) {
Console.WriteLine("Hello World!");
}
}
"# -CompilerParameters #{
"GenerateExecutable" = $true
"OutputAssembly" = "test2.exe"
}
PrimalScript from Sapien will generate an exe from a PowerShell script. The machine one which the executable is run must have PowerShell installed.
The solution I found best to distribute a PowerShell script as exe was to wrap it in a NSIS executable.
I write a .nsi script like this:
Name "Maintenance task"
OutFile "maintenance.exe"
ShowInstDetails show
Section "Main"
;Executes the "script-to-run.ps1" PowerShell script
InitPluginsDir
SetOutPath "$pluginsdir\MyOrg" ;It is better to put stuff in $pluginsdir, $temp is shared
;extract the .ps1 and run it, collecting output into details.
File script-to-run.ps1
nsExec::ExecToLog 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$pluginsdir\MyOrg\script-to-run.ps1" '
SetOutPath $exedir
SectionEnd
I just have to compile the script to an exe with the NSIS toolchain, and it will run on any OS that has PowerShell, no matter what is the execution policy.
This was inspired by this question How to call PowerShell in NSIS.
There's a project called Portable PowerShell that is still in beta after a couple of years ... might be worth looking at for your needs.
http://shelltools.wik.is/Portable_PowerShell