I have a PowerShell script named myscript.ps1 on a remote server.
I would like to know what is the version of this file.
Unfortunately this command gives me nothing :
(Get-Item "C:\myscript.ps1").VersionInfo.FileVersion
My question is : is there a way to add some information regarding the version of the script or else ? If yes, how please ?
My end goal is to check if the running script is the latest version otherwise download latest version on remote server and execute.
Thank you all.
I'm not sure you're going to find that information there unless it was set. I usually see that info in things like DLLs.
If it were me, and I was looking to see if a file was different (a script or otherwise) I would use the Get-FileHash commandlet instead.
You can not set FileVersionInfo in .Net, so you will always get a null value when you check the FileVersionInfo on your PowerShell script. What you may want to do instead is to check the LastWriteTime property to see if the file on the server is newer than what you have locally.
Related
I have a need to check to see if a program is installed by looking at an EXE file. Some goofy programs don't behave nicely and put rational info in the registry. I have Get-Command $path working, and it allows me to get version info as a property which is also nice. However, I want to do some validation, making sure the file is a valid file. So I tried taking a TXT file and just changing the extension to EXE, and kind of expected Get-Command to throw an exception. But no, it works fine and just reports a version number of 0.0.0.0. When I manually look at the properties of a real EXE and my fake EXE I see that File version and Product version both exist as properties, but are empty. I'm not casting the version value to [version] or anything, so it seems like Windows itself inserts a value of 0.0.0.0 when it's null, which... sucks. Is this something I can actually depend on; that no REAL executable will ever have a value of 0.0.0.0 for Version, and report that as a bad file accordingly? Or is 0.0.0.0 a valid version number that someone might actually use?
0.0.0.0 is technically a valid version number, but I'd say it's quite unlikely that an executable uses it explicitly.
Pragmatically speaking, you can therefore infer from the presence of this version number that a given executable contains no embedded version resource.
$hasVersionResource = (Get-Command some.exe).Version.ToString() -ne '0.0.0.0'
However, this aspect is separate from whether a given file is a valid (binary) executable, i.e. whether it can actually run: binaries do not require this resource in order to execute.
When I call the following code:
Start-Process Firefox
Then the PowerShell opens the browser. I can do that with several other programs and it works. My question is: How does the PowerShell know which program to open if I type Firefox? I mean, Im not using a concrete Path or something ...
I though it has something to do with the environment variables ... But I cannot find any variable there which is called Firefox ... How can he know?
I traced two halves of it, but I can't make them meet in the middle.
Process Monitor shows it checks the PATHs, and eventually checks HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe so that's my answer to how it finds the install location, and then runs it.
That registry key is for Application Registration which says:
When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey.
The file is sought in the following locations:
The current working directory.
The Windows directory only (no subdirectories are searched).
The Windows\System32 directory.
Directories listed in the PATH environment variable.
Recommended: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
That implies PowerShell calls the Windows ShellExecuteEx function, which finds FireFox as a registered application, or it tries the same kind of searching itself internally.
Going the other way to try and confirm that, the Start-Process cmdlet has a parameter set called UseShellExecute. The 'Notes' of that help says:
This cmdlet is implemented by using the Start method of the System.Diagnostics.Process class. For more information about this method, see Process.Start Method
Trying to trace through the source code on GitHub:
Here is the PowerShell source code for Start-Process.
Here, at this line it tries to look up the $FilePath parameter with CommandDiscovery.LookupCommandInfo.
Here it checks else if (ParameterSetName.Equals("UseShellExecute"))
Then Here is the .Start() function which either starts it with ShellExecute or Process.Start()
OK, not sure if ShellExecute and ShellExecuteEx behave the same, but it could be PS calling Windows, which is doing the search for "FireFox".
That CommandSearcher.LookupCommandInfo comes in here and follows to TryNormalSearch() which is implemented here and immediately starts a CommandSearcher which has a state machine for the things it will search
SearchState.SearchingAliases
Functions
CmdLets
SearchingBuiltinScripts
StartSearchingForExternalCommands
PowerShellPathResolution
QualifiedFileSystemPath
and there I get lost. I can't follow it any further right now.
Either it shortcuts straight to Windows doing the lookup
Or the PowerShell CommandSearcher does the same search somehow
Or the PowerShell CommandSearcher in some way runs out of searching, and the whole thing falls back to asking Windows search.
The fact that Process Monitor only logs one query in each PATH folder for "firefox.*" and then goes to the registry key suggests it's not doing this one, or I'd expect many more lookups.
The fact that it logs one query for "get-firefox.*" in each PATH folder suggests it is PowerShell's command searcher doing the lookup and not Windows.
Hmm.
Using Process Monitor I was able to trace the PowerShell.
It first searches the $env:path variable, then the $profile variable.
In my case firefox wasn't found and then it searches through a whole lot in the Registry and somehow finds it.
It might have something to do with how firefox is installed on the system.
I am using Windows 7 as well as windows 2008 r2, I am trying to write a powershell script to find all the software installed on all the machines on my network. I have done research and see the cmdlets I need to do this task but I get some many unrecognized cmdlts. I am new to powershell and the other admins only use GUI's and I am trying to show them how powerful the command line can be. Is there something I need to run to update my machine with the latest cmdlets?
$PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
3 0 -1 -1
currently the command that is failing is Get-RemoteProgram
I am using 64-bit machines
Assuming that you are using thisGet-RemoteProgram, you need to "dot source" it before you can use the command. This tells your script to read the file and include the functions it contains in your script.
. .\Get-RemoteProgram.ps1
Load the function into memory by dot-sourcing the script file this makes the Get-RemoteProgram function available in your current session of PowerShell
So your script would need to include
. .\Get-RemoteProgram.ps1
prior to any call to Get-RemoteProgram
As far as the version of PowerShell, 3.0 is certinaly not the latest. You can always find the latest version at Microsoft. Currently, https://msdn.microsoft.com/powershell is a good place to reference, or even check Wikipedia--lots of places are kept updated with the latest info on PowerShell.
All,
Note: I have updated the question after some feedback.
Thanks to #jisaak for his help so far.
I have the need to run a PowerShell script that adds TCP bindings and some other stuff when I deploy my Cloud Service.
Here is my Cloud Service Project:
Here is my Cloud Service Project and Webrole project:
Here is my task in ServiceDefinition.csdef:
And here is the PowerShell script I want to run:
here is my attempt at the Startup.cmd:
When I deploy I get this in the Azure log:
And this in the powershell log:
Any help would be very much appreciated.
I think I am nearly there but following other people syntax on the web doesn't seem to get me there.
thanks
Russ
I think the issue is that the working directory of the batch command interpreter when it runs Startup.cmd runs is not as expected.
The Startup.cmd is located in the \approot\bin\Startup directory but the working directory is \approot\bin.
Therefore the command .\RoleStartup.ps1 is not able to find the RoleStartup.ps1 as it is looking in the bin directory not in the bin\Startup directory.
Solutions I know to this are:
Solution 1:
Use ..\Startup\RoleStartup.ps1 to call the RoleStartup.ps1 from Startup.cmd.
Soltuion 2:
Change the current working directory in Startup.cmd so that the relative path .\RoleStartup.ps1 is found. I do this by CHDIR %~dp0 (see here) to change into the directory that contains Startup.cmd.
Solution 3:
As Don Lockhart's answer suggested, do not copy the Startup directory to the output, instead leave it set as "Content" in the Visual Studio project. This means the files within it will exist in the \approot\Startup directory on the Azure instance. (You would then want to make sure that the Startup folder is not publically accessible via IIS!). Then update the reference to Startup.cmd in ServiceDefinition.csdef to ..\Startup\Startup.cmd, and update the reference to RoleStartup.ps1 in Startup.cmd to ..\Startup\RoleStartup.ps1. This works on the fact that the working directory is bin and uses ..\Startup to always locate the Startup directory relative to it.
You don't need to set the executionpolicy within your cmd - just call the script. Also, you should use a relative path because you can't rely that there is C disk.
Change your batch to:
powershell -executionpolicy unrestricted -file .\RoleStartup.ps1
Right click on the RoleStartup.ps1 and Startup.cmdin Visual Studio and ensure that the Copy to Output directory is set to copy always.
If this still doesn't work, remove the startup call in your csdef, deploy the service, rdp into it and try to invoke the script by yourself to retrieve any errors.
Edit:
Try to adopt your script as below:
Import-Module WebAdministration
$site = $null
do # gets the first website until the result is not $null
{
$site = Get-WebSite | select -first 1
Sleep 1
}
until ($site)
# get the appcmd path
$appcmd = Join-Path ([System.Environment]::GetFolderPath('System')) 'inetsrv\appcmd.exe'
# ensure the appcmd.exe is present
if (-not (Test-Path $appcmd))
{
throw "appcmd.exe not found in '$appcmd'"
}
# The rest of your script ....
I've found it easier in the past to not copy the content to the output directory. I have approot\bin as the working directory. My startUp task element's commandLine attribute uses a relative reference to the .cmd file like so:
The .cmd file references the PowerShell script relatively from the working directory as well:
PowerShell -ExecutionPolicy Unrestricted -f ..\StartUp\RoleStartup.ps1
Ok,
So I am coming back to this after many different attempts to make it work.
I have tried using:
Startup config in the ServiceDefinition.csdef
I have tried registering a scheduled task on the server that scans the Windows Azure log looking for [System[Provider[#Name='Windows Azure Runtime 2.6.0.0'] and EventID=10004]]
Nothing worked either due to security or the timing of events and IIS not being fully setup yet.
So I finally bit the bullet and used my Webrole.cs => public override bool OnStart() method:
Combined with this in the ServiceDefinition.csdef:
Now it all works. This was not the most satisfying result as some of the other ways to do it felt more elegant. Also, many others posted that they got the other ways of doing it to work. Maybe I would have got there eventually but my time was restricted.
thanks
Russ
I am currently working on a powershell script. The objective of this script is to import data from a .csv file from which new users are created if that username does not already exist in the Active Directory.
My question is how can I make this script run from any location so all I have to do is type the name of the script and it will run. I have been able to do this in BASH but can't figure out how to do this in power shell. So far google has been little help.
If it makes any difference i'm using Windows Server 2008 R2
The basic idea is to create Powershell Function which will do the work (or will call other script placed in other location) and put this method to Profile.ps1 script (the script which is loaded everytime you start powershell) - Look at Windows PowerShell Profiles for further details.
The link above for Powershell Function from Tomas Panik is not there anymore so I want to add to the answer here.
Short version:
You can create your function by using Powershell Function. However, this will only last for that session only.
In order for you to use your function regularly, you need to generate/add your function to your own PowerShell profile. Quick tutorials are here and here. Tomas Panik's link to Windows PowerShell Profiles also has very good info.
Update: thanks Hussein Al-Mosawi for reporting the old broken link!