For some reason, when I run Get-Service in powershell, it throws an error. If I run Set-Service first however, Get-Service will work until I open powershell again. I can't seem to find this issue anywhere online. Has anyone experienced this and if so, is there a solution?
Error: "Program 'Get-Service' failed to run: No application is associated with the specified file for this operationAt line:1 char:1"
tl;dr
Remove file C:\Windows\System32\Get-Service from your system - it shouldn't be there.
After that, Get-Service will start working again.
PowerShell tries to open the perhaps accidentally created, extension-less C:\Windows\System32\Get-Service file on your system first, if you haven't imported module Microsoft.PowerShell.Management yet in the session.
That PowerShell tries to open a non-executable file - one without a filename extension - that it locates via $env:PATH is in itself problematic - see this answer.
The Microsoft.PowerShell.Management module, which contains the Get-Service and Set-Service cmdlets (among other commands), is normally imported on demand the first time you try to execute one of its commands in a session.
Technically, since the module is located in a known location, it is subject to module auto-loading.
However, if the module isn't imported yet, an external program / document file of the same name located in one of the directories listed in environment variable $env:PATH takes precedence, and it is executed / opened by default.
Since the file in your case was had no filename extension, the Windows shell did not know how to open it, resulting in the error message you saw (if you double-clicked the file in File Explorer, you'd get "How do you want to open this file?" dialog instead).
As a result, trying to execute a command named Get-Service by itself does not trigger import of the Microsoft.PowerShell.Management module - the external file keeps getting called.
By contrast, since the Set-Service cmdlet is not shadowed by an external file, calling it does implicitly import the module.
Once the module has been imported, submitting command Get-Service calls the cmdlet rather than the external file, because PowerShell's regular command precedence then kicks in, where cmdlets take precedence over external programs with the same name.
While this situational distinction makes the execution behavior hard to predict, consistently giving precedence to known cmdlets, irrespective of whether their module happens to have been imported into the current session yet or not, is not an option for performance reasons: see the discussion in since-closed GitHub issue #10853.
To unambiguously invoke a command from a given module, prefix the command name with the module name followed by \:
That is, even without the module imported, you could have invoked the Get-Service cmdlet as follows:
Microsoft.PowerShell.Management\Get-Service
Related
If I open a new Powershell 7 session and run get-command Get-Website
the response I get is
Get-Command: The term 'Get-Website' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
If I then run import-Module WebAdministration and again run get-command Get-Website, this time I get the expectefd output of
CommandType Name Version Source
----------- ---- ------- ------
Function Get-Website 1.0 WebAdministration
If I close the Powershell 7 session, open a new one and run get-command Get-Website, the new session does not recognise the command.
If I run a session of Windows Powershell, I do not have to import the module, the command is already there.
Anyone able to explain what is going on?
Thanks
You are not the only person having this problem. Unfortunately, I can't speak to whether any of the solutions there work, as neither the asker or anyone else has confirmed them.
Note: I had originally suspected this might be a problem with automatic importing through the WindowsCompatibility module, but it appears that it does not interfere with auto-importing of modules. In addition, as of PowerShell 7 the WindowsCompatibility module features are baked into PowerShell itself.
For whatever reason, WebAdministration may not be able to be automatically imported in PowerShell Core. There are a few reasons for this but they are mostly on the module side, and you can't change the behavior without modifying the module.
You can try setting $PSModuleAutoLoadingPreference = 'All' in your current PowerShell session, but generally that doesn't need to be changed from the default value of ModuleQualified. More information on $PSModuleAutoLoadingPreference can be found here.
If that doesn't work, you'll have to manually import the module in every session.
Fortunately, manually importing modules isn't required for the vast majority of them. For the ones which can't be automatically imported, you must use Import-Module MODULENAME in each new session. You can simplify this by adding the Import-Module cmdlet to one of the following profile locations:
$profile.CurrentUserCurrentHost
$profile.CurrentUserAllHosts
$profile.AllUsersCurrentHost
$profile.AllUsersAllHosts
For scripts, Import-Module should generally be done inside the script to prevent needing profiles in scenarios where profile loading is desired to be disabled such as when PowerShell is invoked in the following way: powershell.exe -NoProfile ....
In your case, it would like like so:
Import-Module WebAdministration
Here is some additional information about the $profile variable.
I have a machine i would like to install a module on, specifically SwisPowerShell for working with SolarWinds. Internet is disabled on it so i cant use install-module, so i manually downloaded the .nupkg from another machine and went through the steps of unpacking the files into the correct folders. https://learn.microsoft.com/en-us/powershell/scripting/gallery/how-to/working-with-packages/manual-download?view=powershell-7.2. all the .dll files and the windows powershell datafile i have tried in both directories "C:\Program Files\WindowsPowerShell\Modules\SwisPowerShell\3.1.0.343" and "C:\Users\username\Documents\WindowsPowerShell\Modules\SwisPowerShell\3.1.0.343". Importing the module with "import-module -name SwisPowerShell -Global -force -Verbose" shows that everything loads correctly, but then running "get-module SwisPowerShell -Verbose" returns nothing. even loading each dll individually with "add-type -path "C:...\somefile.dll" shows nothing. running "get-module -ListAvailable" shows the module in both (or either) directories as they should be. using "get-help cmdletname" and "get-command cmdletname" shows the correct cmdlet definitions. trying to run any of the cmdlets returns "The term 'connect-swis' is not recognized as the name of a cmdlet, function... yada yadda" for all of the cmdlets. its like powershell sees the files but refuses to use them. Am i missing a step that tells powershell that this is a valid module to use? could it be blocked somehow? what extra steps does install-module do that a manual install does not that i could try?
Try running process monitor while installing on another machine. You might find out it's doing some registry changes too.
I wrote a script to build all .net projects in a folder.
Issue
The issue is I am getting a missing function error when I call Build-Sollution.
What I tried
I made sure that function was declared before I used it so I am not really sure why it saids that it is not defined.
I am new to powershell but I would think a function calling another functions should work like this?
Thanks in advance!
Please see below for the error message and code.
Error Message
Line |
3 | Build-Sollution $_
| ~~~~~~~~~~~~~~~
The term 'Build-Sollution' 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 is correct and try again.
Build-Sollution:
Code
param (
#[Parameter(Mandatory=$true)][string]$plugin_path,
[string]$depth = 5
)
$plugin_path = 'path/to/sollutions/'
function Get-Sollutions {
Get-ChildItem -File -Path $plugin_path -Include *.sln -Recurse
}
function Build-Sollution($solution) {
dotnet build $solution.fullname
}
function Build-Sollutions($solutions) {
$solutions | ForEach-Object -Parallel {
Build-Sollution $_
}
}
$solutions_temp = Get-Sollutions
Build-Sollutions $solutions_temp
From PowerShell ForEach-Object Parallel Feature | PowerShell
Script blocks run in a context called a PowerShell runspace. The runspace context contains all of the defined variables, functions and loaded modules.
...
And each runspace must load whatever module is needed and have any variable be explicitly passed in from the calling script.
So in this case, the easiest solution is to define Build-Sollution inside Build-Sollutions
As for this...
I am new to powershell but I would think a function calling another
functions should work like this?
... you cannot use the functions until you load your code into memory. You need to run the code before the functions are available.
If you are in the ISE or VSCode, if the script is not saved, Select All and hit use the key to run. In the ISE use F8 Selected, F5 run all. In VSCode, F8 run selected, crtl+F5 run all. YOu can just click the menu options as well.
If you are doing this from the consolehost, the run the script using dot sourcing.
. .\UncToYourScript.ps1
It's ok to be new, we all started somewhere, but it's vital that you get ramped up first. so, beyond what I address here, be sure to spend time on Youtube and search for Beginning, Intermediate, Advanced PowerShell for videos to consume. There are tons of free training resources all over the web and using the built-in help files would have given you the answer as well.
about_Scripts
SCRIPT SCOPE AND DOT SOURCING Each script runs in its own scope. The
functions, variables, aliases, and drives that are created in the
script exist only in the script scope. You cannot access these items
or their values in the scope in which the script runs.
To run a script in a different scope, you can specify a scope, such as
Global or Local, or you can dot source the script.
The dot sourcing feature lets you run a script in the current scope
instead of in the script scope. When you run a script that is dot
sourced, the commands in the script run as though you had typed them
at the command prompt. The functions, variables, aliases, and drives
that the script creates are created in the scope in which you are
working. After the script runs, you can use the created items and
access their values in your session.
To dot source a script, type a dot (.) and a space before the script
path.
See also:
'powershell .net projects build run scripts'
'powershell build all .net projects in a folder'
Simple build script using Power Shell
Update
As per your comments below:
Sure the script should be saved, using whatever editor you choose.
The ISE does not use PSv7 by design, it uses WPSv5x and earlier.
The editor for PSv7 is VSCode. If you run a function that contains another function, you have explicitly loaded everything in that call, and as such it's available.
However, you are saying, you are using PSv7, so, you need to run your code in the PSv7 consolehost or VSCode, not the ISE.
Windows PowerShell (powershell.exe and powershell_ise.exe) and PowerShell Core (pwsh.exe) are two different environments, with two different executables, designed to run side-by-side on Windows, but you do have to explicitly choose which to use or write your code to branch to a code segment to execute relative to the host you started.
For example, let's say I wanted to run a console command and I am in the ISE, but I need to run that in Pwsh. I use a function like this that I have in a custom module autoloaded via my PowerShell profiles:
# Call code by console executable
Function Start-ConsoleCommand
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('scc')]
Param
(
[string]$ConsoleCommand,
[switch]$PoSHCore
)
If ($PoSHCore)
{Start-Process pwsh -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
Else {Start-Process powershell -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
}
All this code is doing is taking whatever command I send it and if I use the PoSHCore switch...
scc -ConsoleCommand 'SomeCommand' -PoSHCore
... it will shell out to PSCore, run the code, otherwise, it just runs from the ISE>
If you want to use the ISE with PSv7 adn not do the shell out thing, you need to force the ISE to use PSv7 to run code. See:
Using PowerShell Core 6 and 7 in the Windows PowerShell ISE
I have a custom PowerShell module with two cmdlets. I have it successfully, but manually, deployed on my machine. However, I deployed it by placing the binary file and module manifest in a location, and then registering the module. I also had to manually write an Import-Module command into my 'all users' profile.
Now I am sure I can deploy this module with Publish-Module, but how do I get the Install-Module to write the Import-Module statement to the profile file?
As of PowerShell 3.0, a module is automatically imported when a command from the module is invoked. This was a brilliant on Microsoft's part; however, it did require that modules are located in a location where PowerShell looks for modules by default. Makes sense. You can see those locations by running the following command:
$env:PSModulePath -split ';'
Is there a reason you'd rather not use one of the paths stored in the above environmental variable? That said, I'd keep your code out of the "C:\Windows\System32..." path. The other options are better: "C:\Program Files\PowerShell\Modules" (AllUsers) and "C:\Users\tommymaynard\Documents\PowerShell\Modules" (CurrentUser). Depending on your PowerShell version/OS, those path could be different. You won't need to write an Import-Module command into a $PROFILE script if you get the module into a preferred location. Maybe you already know this, but maybe not.
You're not going to get Install-Module to write to any of the $PROFILE scripts.
$PROFILE | Select-Object -Property *
Well, not by default anyway. You could write your own Install-Module function, that runs PowerShellGet's Install-Module function, and includes writing to various $PROFILE scripts. The problem is that you'll need to include logic so you don't blow away the contents of someone's $PROFILE script if it's not empty, and only append to it.
Seriously though, this is turning into a lot of work, when you could drop the module into a location where PowerShell can find it on its own.
Edit: It just occurred to me, you can add a value/path to the $env:PSModulePath environmental variable. It's a single string with semi-colon delimiters:
$env:PSModulePath.GetType().Name
Therefore, it'd look like this:
$env:PSModulePath += ';C:\Another\Path'
That's great and all, but again how might you stage this, right? It takes you back to the write-to-all-the-$PROFILE-scripts problem,... although you may be able to update the variable via Group Policy Preferences. Again, probably better to just relocate your module.
I'm writing a powershell cmdlet. From inside of my cmdlet BeginProcessing() method, I want to be able to retrieve the the directory that was the default directory at the time the cmdlet was invoked.
Example:
If the user does this:
cd \myDirectory
invoke-mycmdlet
I want for my code to know that the default shell directory was c:\myDirectory.
When I access Environment.CurrentDirectory, it's always c:\windows\system32
I've seen a similar post on SO where the poster needed to set Environment::Current directory from inside the shell using get-location. That won't work for me.
Basically, my cmdlet does some file system stuff, and I want the user to be able to just cd\ into a directory, and execute my cmdlet, with it operating on the directory that they switched into -- just like you would expect it to work from the old Command Console.
You might want to try this instead, CurrentLocation.Path could also point to other provider paths, such as the registery.
this.SessionState.Path.CurrentFileSystemLocation.Path
You know, I always seem to find it right after I post -- regardless of how long I spent looking before reaching for SO!
So, my cmdlet inherits from PsCmdlet. I found that I could get the path I wanted from
this.SessionState.Path.CurrentLocation.Path
(where "this" is a cmdlet class that inherits from PsCmdlet)
Try the Get-Location cmdlet. It should be the script's current executing location, rather than the powershell host startup folder.