For outlook 2010 we had the outlook profiles set under:- HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles.
Similar location for outlook 2013 is:- HKCU\\Software\\Microsoft\\Office\\15.0\\Outlook\\Profiles.
In my program, I first look for 2013 profiles, getting an exception I look for 2010 profile location.
But this would fail if outlook is downgraded to 2010. As the registry key for outlook 2013 would still be at same place.
Any suggestions on this. Probably, if I can first get the correct version of outlook installed and then search the right key rather than using the try....except....block?
Majorly I want to list all the pst files attached to Outlook.
The PST file locations are stored in the profile sections in the registry. The officially supported API designed to access and manipulate the profile data is the IProfAdmin interface (you can play with it in OutlookSpy (I am its author) if you click the IProfAdmin button). PST path is stored in the PR_PST_PATH property. Extended MAPI can only be accessed from C++ or Delphi.
If Extended MAPI in C++ or Delphi is not an option, you can use ProfMan (it comes with the distributable version of Redemption - I am also its author); ProfMan can be used from any language. The following script (VB) retrieves PST files names from all local profiles:
'Print the path to all the PST files in all profiles
PR_PST_PATH = &H6700001E
set Profiles=CreateObject("ProfMan.Profiles")
for i = 1 to Profiles.Count
set Profile = Profiles.Item(i)
set Services = Profile.Services
Debug.Print "------ Profile: " & Profile.Name & " ------"
for j = 1 to Services.Count
set Service = Services.Item(j)
If (Service.ServiceName = "MSPST MS") or (Service.ServiceName = "MSUPST MS") Then
MsgBox Service.Providers.Item(1).ProfSect.Item(PR_PST_PATH)
End If
next
next
You can also retrieve PST file names from PST stores using the Outlook Object Model (but that requires Outlook to be running, and you can only do that for the currently used profile) - use the Store.FilePath property:
set vApp = CreateObject("Outlook.Application")
for each vStore in vApp.Session.Stores
MsgBox vStore.DisplayName & " - " & vStore.FilePath
next
There is a record of attached PSTs in the registry but it appears that it is more a record of PST files that are indexed by Outlook's search, so I'm not sure if clearing out the indexing cache would remove the entries from the registry or not at one point but here are two locations that I have used:
Office 2007
HKCU:\software\Microsoft\Office\12.0\Outlook\Catalog
Office 2013
HKCU:\software\Microsoft\Office\15.0\Outlook\Catalog
Also note that this seems to be a history of attached archives instead of a list of actively attached archives. To get at the actively attached archives the only method I had found was using the COM object (Outlook.Application) but this isn't very nice because initializing the COM object of course starts Outlook so if you are pulling information in the background it might upset end users.
That being said here is a little PowerShell script that will both dump the attached archives and search the registry for a history of attached archives and place the results on the desktop.
'****************************Currently attached archives' | Out-File
$Env:UserProfile\Desktop\ArchiveHistory.txt -append
#NOTE: This launches Outlook if it is not already running.
$Outlook = New-Object -Comobject Outlook.Application
$Namespace = $Outlook.GetNamespace('MAPI')
$Mailboxes = $Namespace.Stores | where {$_.ExchangeStoreType -eq 1} | Select-Object DisplayName
$AttachedArchives = $Namespace.Stores | where {$_.ExchangeStoreType -eq 3} | Select-Object DisplayName,FilePath
$MailBoxes | Out-File -FilePath $Env:UserProfile\Desktop\OutlookMailboxes.txt
$AttachedArchives | Out-File -FilePath $Env:UserProfile\Desktop\OutlookAttachedArchives.txt
'****************************Archive History for Office 2007' | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
get-item HKCU:\software\Microsoft\Office\12.0\Outlook\Catalog | select -expandProperty property | where {$_ -match '.pst$'} | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt
'****************************Archive History for Office 2010' | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
get-item HKCU:\software\Microsoft\Office\14.0\Outlook\Catalog | select -expandProperty property | where {$_ -match '.pst$'} | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt
'****************************Archive History for Office 2013' | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
get-item HKCU:\software\Microsoft\Office\15.0\Outlook\Search\Catalog | select -expandProperty property | where {$_ -match '.pst$'} | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
'****************************Archive History for Office 2016' | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
get-item HKCU:\software\Microsoft\Office\16.0\Outlook\Search\Catalog | select -expandProperty property | where {$_ -match '.pst$'} | Out-File $Env:UserProfile\Desktop\ArchiveHistory.txt -append
Related
I'm starting to work with Powershell and I've been doing some courses online. At this moment I'm stuck in a Challenge, I hope some good soul can help me with the instructions from the course.
Instructions are:
1-Find out what Windows features are installed on the server machine. (I'm remoting command to a computer named "Server")
2-Select only the data stored in the Name and InstallState columns.
3-Sort the data by the Name property in ascending (alphabetical) order.
4-Make sure the output format is set to table
5-Save the final output into a file called C:\features.txt on your desktop machine.
What I have come up with is this:
Invoke-Command -ComputerName Server -ScriptBlock{
>> Get-WindowsFeature | Select-Object -Property Name, InstallState | Sort-Object -Property Name | Format-Table
>> } | Out-File C:\features.txt
I have tried both with and without the select-object command since I know the format-table command works almost the same in this case. Thank u!
When ever I invoke a scriptblock on a remote computer i assign it to a variable and then handle the results this:
$myResults= Invoke-Command -ComputerName Server -ScriptBlock{…}
Foreach ($item in $myResults){
Write-host” $item.name /
$item.nstallState”
}
You use the pipeline rather excessively which is not wrong but for me personally still a beginner my self it is not easy to totally comprehend what each of them is exactly returning and forwarding to the next. Dont try to write a perfect line with several pips in the first attempt. Start with the smallest fastest fraction of the task. In this case yust get them all out without filter and pipelines. Then work your way from there, make little changes, use write-host to display the results and trail and error yourself to a deeper understanding of each of them. And then in the end u can chain them up.
As per my comment for example.
# 1-Find out what Windows features are installed on the server machine.
Get-WindowsFeature
# Results
<#
#>
# 2-Select only the data stored in the Name and InstallState columns.
Get-WindowsFeature |
Select-Object -Property Name, InstallState
# Results
<#
#>
# 3 - Sort the data by the Name property in ascending (alphabetical) order.
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name
# Results
<#
#>
# 4-Make sure the output format is set to table
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Format-Table # though this is not needed, since table is the default for less than 5 properties.
# Results
<#
#>
<#
# 5-Save the final output into a file called C:\features.txt on your desktop
machine.
#>
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Export-Csv -Path 'SomePathName' -NoTypeInformation -Append
# (I'm remoting command to a computer named "Server")
$Computers |
ForEach-Object {
Invoke-Command -ComputerName $PSItem.ComputerName -ScriptBlock{
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Export-Csv -Path 'SomePathName' -NoTypeInformation -Append
}
}
I need to get all installed applications and its details in a Windows device using shell commands. I tried using
Get-appxpackage
Get-WmiObject
wmic
Apps that were installed manually seems to be missing in the list. Please help by providing a better method.
An alternative can be to query the registry like this for example:
# HKLM - Local Machine
$InstalledSoftware = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}
# HKCU - Current User
InstalledSoftware = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}
Check this page out for more:
https://www.codetwo.com/admins-blog/how-to-check-installed-software-version/
Tip! Browse these locations in the registry manually before you dig in as it will help you see the structure and understand what properties are available. If the information you're seeking is not there, you might just ditch this suggestion.
For Windows 64-bit and 32-bit apps use
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table > C:\ws\apps.txt
the C:\ws\apps.txt need to be adjusted by you, to your output path.
I found the idea here, Social MS
I would like to check whether Slack is installed on a system or not.
Even though it was installed both of the below two commands giving me blank, why is this?
System details are: Windows 10 64 bit.
$slack32 = Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Select-Object DisplayName |
Select-String "Slack" |
Out-String
$slack64 = Get-ItemProperty 'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Select-Object DisplayName |
Select-String "Slack" |
Out-String
Slack by default installs under the User's directory, not Program Files, probably does the same in the registry hives.
Try HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
I'm trying to create a very simple script which would check if the a specific program is installed and if so return the version number for that program.
I've been able to get to the point where I'm running the script and able to return a binary value if a program is installed or not but not sure how to return the version number for that installed program.
What I will post will be just what I'm doing to return if program is installed, and need help in then attaining the version number.
function Check_Program_Installed {
$my_check = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName, DisplayVersion, InstallDate |
Format-Table -AutoSize |
Out-String
# Check if Google Chrome is installed
$my_check -Match "Google Chrome"
}
Check_Program_Installed
If you want that function to look for a specific installed program instead of returning a (table) formatted string, then you could simply do:
function Check_Program_Installed {
[CmdletBinding()]
Param(
[Parameter(Position = 0, Mandatory=$true, ValueFromPipeline = $true)]
$Name
)
$app = Get-ItemProperty -Path "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Where-Object { $_.DisplayName -match $Name } |
Select-Object DisplayName, DisplayVersion, InstallDate, Version
if ($app) {
return $app.DisplayVersion
}
}
Check_Program_Installed "Google Chrome"
This will return $null when not found, or the version as string like 70.0.3538.67
Instead of doing the match after formatting the table, you could add a where to select the result you need beforehand and then obtain the DisplayVersion directly from that object. You could clean this up more to do exactly what you need, but here is your code modified to retrieve and display the number if the application is found. Try switching to a bad name to see the else result:
function Get-ApplicationVersion {
$applicationName = "Google Chrome"
$my_check = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallDate | Where -Property DisplayName -Match $applicationName
$versionNumber = $my_check.DisplayVersion
if ($my_check) {
$versionNumber
}
else {
write-warning "Application not found"
}
}
Get-ApplicationVersion
EDITED: Renamed function name from Check_Program_Installed to use PS common verb Get, per suggestion.
function Get-InstalledProgram {
Param (
$ProgramName
)
$UninstallKeys = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
if ( $ProgramName )
{
$UninstallKeys | Where-Object -Property DisplayName -Match -Value $ProgramName | Select-Object DisplayName, DisplayVersion, InstallDate
}
else
{
$UninstallKeys | Select-Object DisplayName, DisplayVersion, InstallDate
}
}
If you wanted to see all the programs, then you don't have to add a parameter. Just pipe its output to Format-Table. Format-Table does some weird just where the items are no longer the objects you're expecting, but table objects. Here is how I would handle that:
Get-InstalledProgram | Format-Table -Autosize
If you want to search for a program, add a parameter. You'll see above I added a parameter for ProgramName. It will match this term to the registry key's DisplayName.
PS C:\> Get-InstalledProgram -ProgramName Java
DisplayName DisplayVersion InstallDate
----------- -------------- -----------
Java 8 Update 181 8.0.1810.25 20180725
Java Auto Updater 2.8.181.13 20180925
If you wanted to just get the version, I would recommend just piping your output to Select-Object -ExpandProperty DisplayVersion
PS C:\> Get-InstalledProgram -ProgramName 'Java 8' | Select-Object -ExpandProperty DisplayVersion
8.0.1810.25
tl;dr
In Windows PowerShell[1] v5.1+, use the following (searches among both 32-bit and 64-bit installed programs, as shown in Control Panel):
Get-Package -ProviderName Programs -IncludeWindowsInstaller '*Google Chrome*' |
ForEach-Object Version
Note: The 32-bit-only HKEY_LOCAL_MACHINE:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall registry key may have more specific entries than what Control Panel shows - I'm unclear on why, but perhaps the composite view in Control Panel is sufficient.
Applied to your example:
PS> (Get-Package -ProviderName Programs -IncludeWindowsInstaller '*Google Chrome*').Version
70.0.3538.67
As for what you tried:
Since you're checking the Wow6432Node registry key branch specifically, you're checking installed 32-bit programs only.
As such, a better name for your function would be Check_32BitProgram_Installed or, more in line with with the function's intent, using an approved PowerShell verb, Get-32BitProgramVersion.
Alternatively, name, the function Get-ProgramVersion and look in both the 32-bit and 64-bit locations and process the results as shown in Theo's and Kevin M. Lapio's and Shawn Esterman's helpful answers:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*,
HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
In line with the generic title of your question, the above is a solution that essentially searches the list of installed applications you would see in Control Panel > Programs > Programs and Features (appwiz.cpl), which covers both 32-bit and 64-bit applications:
Windows PowerShell v5.1 comes with the PackageManagement module and a Programs package provider[1] that allows inspecting installed programs via the Get-Package cmdlet; in PSv3 and PSv4, it is possible to manually install it.
To list installed programs (shown with abridged sample output):
PS> Get-Package -ProviderName Programs -IncludeWindowsInstaller
Name Version Source ProviderName
---- ------- ------ ------------
Git version 2.18.0 2.18.0 Programs
Microsoft Azure Compute Emu... 2.9.8699.20 Programs
Microsoft Azure Authoring T... 2.9.8699.20 Programs
# ...
The output objects are of type [Microsoft.PackageManagement.Packaging.SoftwareIdentity], which have .Name and .Version properties, which enables the solutions above.
The Programs package provider supports two dynamic options (options specific to that provider):
-IncludeWindowsInstaller is needed to make the list of programs reported match what Control Panel shows.
-IncludeSystemComponent, by contrast, reports components that do not show in Control Panel.
[1] Unfortunately, the underlying Programs package provider is not available in PowerShell Core on Windows as of v7.0 - and I'm unclear on whether that is a not-yet situation or whether it will never be - see GitHub issue #13225.
I print outputs like this in my code, but I was told that my outputs needs to be in text(not object). Can somebody explain to me what it means and whats wrong in my code? Thanks.
Write-Output "ALL INSTALLED WINDOWS FEATURES:"
Write-Verbose -Message "Searching installed features..." -Verbose
$obj=Get-WindowsFeature | Where-Object {$_.Installed} | Select-Object Name, InstallState | Format-Table -AutoSize
Write-Output $obj
Write-Output "OPERATING SYSTEM INFO:"
Write-Verbose -Message "Searching operating system info..." -Verbose
$opInfo=Get-CimInstance Win32_OperatingSystem | Select-Object Version, Caption, InstallDate, LastBootUpTime, TotalVirtualMemorySize , SystemDirectory | FL
Write-Output $opInfo
There's nothing technically wrong with your code but personally I would change Write-Output "OPERATING SYSTEM INFO:" to a Write-Verbose, having that header in the output will make working with the results of your function in other parts of the code. However returning the object opInfo rather than a collection of strings is absolutely correct and the only reason someone would be telling you not to is if the code they intend what you are creating to interact with is either written incorrectly or written in an older scripting language like VBS, or if they are just not aware the preference for objects in Powershell development.