Check if registry key is present before Get-ItemProperty [duplicate] - powershell

This question already has answers here:
Check if a Registry Path Exists in Remote Machine
(4 answers)
Test if registry value exists
(13 answers)
Closed 3 months ago.
I've been trying to create a script that checks which applications are installed on a remote server. So far I've been able to get it working to do the job when everything is in place.
However, one of my servers are a bit broken and the "uninstall" registry key is missing from the registry.
So before doing Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" and Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" I want to check if the registry key is present and if that isn't the case, I wish to run Get-WmiObject -Query "select * from win32_product"
Currently when I run it on the machine that is missing the "Uninstall" registry key I get
Cannot find path 'HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' because it does not exist.
+ CategoryInfo : ObjectNotFound: (HKEY_LOCAL_MACH...rsion\Uninstall:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : ServerName001
Current script:
# Change to computer you wish to search.
$ComputerName = "ServerName001"
$ScriptPath = Get-Location
$GetWmiObject_Win32Product = $ScriptPath.ToString() + $ComputerName + "_Get-WmiObject-win32_Product.csv"
$GetItemProperty = $ScriptPath.ToString() + $ComputerName + "_Get-ItemProperty.csv"
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
$directoryInfo64bit = Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Measure-Object
$directoryInfo32bit = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Measure-Object
$Apps = #()
if($directoryInfo64bit.count -eq 0){
Write-Output "No 64bit Uninstall folder"
}else{
$Apps += Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
}
if($directoryInfo32bit.count -eq 0){
Write-Output "No 32bit Uninstall folder"
}else{
$Apps += Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
}
$Apps | Select-Object -Property DisplayName, Publisher, DisplayVersion, InstallDate, InstallLocation, PSComputerName
} | Export-Csv -Path $GetItemProperty -NoTypeInformation -Encoding utf8
Get-WmiObject -Query "select * from win32_product" -ComputerName $ComputerName | Select-Object -Property Name, Vendor, Version, PSComputerName | Export-Csv -Path $GetWmiObject_Win32Product -NoTypeInformation -Encoding utf8

Related

Powershell local repository Get-WindowsAutoPilotInfo

I have downloaded Get-WindowsAutoPilotInfo and placed on network share. I am trying to use it as a repository to run the script on mulitple pcs remote. But I canĀ“t get it to work it says my reposity doesnt exist, but if I do Get-PsRepository I get the Installation Policy "Trusted" and the correct Source Location.
So I most get the SerialNumber which works, then hardwarehash (not working), and also GroupTag (working on this later when I've dealt with Hardware hash problem).
"Warning: Unable to find repository and therefor says Get-WindowsAutoPilotInfot is not reconginsed as name of cmdlet,function,script ...
Do you have any ideas what I do wrong?
Get-PSRepository
Install-Script -Repository \\Networkshare\--\---\Scripts\GetHardWareHash -Name "Get-WindowsAutoPilotInfo" -Scope AllUsers -Force
$Info = Get-WindowsAutoPilotInfo | Select-Object -ExpandProperty 'Hardware Hash'
$SerialNumber = Get-WmiObject win32_bios | Select-Object -ExpandProperty SerialNumber
$Model = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model
$addInfo = #(
$Info,
$Model,
$env:COMPUTERNAME
$SerialNumber
)
# Concert $addInfo to a PSObject for easier exporting to CSV.
$addInfoObject = [PSCustomObject]#{
Info = $Info
Model = $Model
ComputerName = $env:COMPUTERNAME
SerialNumber = $SerialNumber
}
$addInfo | Add-Content \\MyPath\AutoPilot $SerialNumber.log
# Define CSV names
$csvNameInfo = "HashFilesCollected" + ".csv"
$csvNameAddInfo = "AutoPilot " + $SerialNumber + ".csv"
# Export to CSV
$Info | Add-Content \\MyPath\$csvNameInfo
$addInfoObject | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Select-Object -Skip 1 | Add-Content \\MyPath\$csvNameAddInfo

Get-ChildItem not detecting the existing drives

I have a powershell script below which should logically work but throws below error saying "A drive with the name 'E" does not exist." But in fact it exists. This error comes when I input the drive using a variable, but if I input the drive that is path manually like "E:" it will work ok. Do no know what I am doing wrong.
Get-ChildItem : Cannot find drive. A drive with the name 'E' does not exist.
At line:24 char:10
+ $list = Get-ChildItem -path $CDDriveLetterToText
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (E:String) [Get-ChildItem], DriveNotFoundExcepti
on
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
My code is as below.
Function Image-Windows10 () {
$CDDrives = Get-WmiObject win32_volume | where {$_.DriveType -eq '5'} | Select-Object -Property name
$FlashDrives = get-wmiobject win32_diskdrive | where {$_.InterfaceType -eq 'SCSI'} | select-object -property index, size
[int]$NumberOfFlashDrives=$FlashDrives.Count
[int]$NumberOfCDDrives=$CDDrives.Count
$CDDriveLetterToText = Out-String -inputObject $CDDrives.Get($NumberOfCDDrives-1)
$CDDriveLetterToText = $CDDriveLetterToText.Replace("name","").Replace("----","").Replace("`n","").Replace(" ","")
$list = Get-ChildItem -Path $CDDriveLetterToText
}
Image-Windows10
instead of selecting the name you might want to go for the property DriveLetter. the parameter -ExpandProperty will return an array of the specified value - thus no need to manipulate the string'
# get all drive letters from devices of type 'CDRom'
$driveArray = Get-WmiObject win32_volume | where {$_.DriveType -eq '5'} | Select-Object -ExpandProperty DriveLetter
# this array can then be iterated like
foreach($drive in $driveArray) {
$list = Get-ChildItem -Path $drive
}

Use powershell on remote machine for Edge Version

I have a script that returns Version numbers for 3rd Party software running on our Domain. Java, chrome, etc to ensure we are up to date.
This is all working OK.
However, I am trying to use:
Get-AppxPackage -Name Microsoft.MicrosoftEdge | select-object Version
within a remote Powershell session or 'invoke-command' but it is returning no results,
the command works fine if locally, and also when RDP'd onto the remote machine.
How can i use this cmdlet remotely to check Edge is version compliant?
Many Thanks.
EDIT:
import-module activedirectory
$workstations = Get-ADComputer -Filter "OperatingSystem -like 'Windows 10 *'" -Property * | select name -ExpandProperty Name
foreach ($workstation in $workstations)
{
$session = New-PSSession -Computername $workstation
$resultofsession = Invoke-Command -Session $Session -ScriptBlock{
$Path="HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
$path2 = "HKLM:\SOFTWARE\Microsoft\Internet Explorer\"
$java = Get-ItemProperty $Path | Select-Object DisplayName, DisplayVersion | where displayname -like "java*"
$chrome = Get-ItemProperty $path | Select-Object DisplayName, DisplayVersion | where displayname -ceq "Google Chrome"
$adobe = Get-ItemProperty $path | Select-Object DisplayName, DisplayVersion | where displayname -ceq "Adobe Acrobat Reader DC"
$edge = Get-AppxPackage -Name Microsoft.MicrosoftEdge | select-object Version
$ie = get-itemProperty $path2
$Object = New-Object PSObject -property #{
'chrome' = "CHROME: " + $chrome.displayversion + ","
'edge' = "EDGE: " + $edge + ","
'ie' = "IE: " + $ie.svcVersion + ","
'java' = "JAVA: " + $java.Displayversion + ","
'adobe' = "ADOBE: " + $adobe.displayversion + ","
'hostname' = hostname
}
Write-output $object
}
remove-pssession $session
write-output $resultofsession | format-table -HideTableHeaders -autosize -force | Out-File "C:\web\Version.txt" -append
}
Get-AppxPackage will return only information for the current users profile (in this case, the account running the script). You likely need to add the -AllUsers switch, but note this will return a result for each user logged in (and they may have different versions). You can use the -user parameter to specify a specific user.
AppX packages are only updated for the user profile when they log in, hence why different users can have different versions of an app on the same workstation. Assuming everything works as expected, the app should be updated when the user next logs in.
Try the following to return the version number for each user ID:
$edge = Get-AppxPackage -AllUsers -Name Microsoft.MicrosoftEdge | select-object #{N="User"; E={$_.packageUserInformation.UserSecurityId.Username}},Version
Example output:
User Version
---- -------
test 42.17127.1.0
S-1-5-18 44.17763.1.0
jacob 44.18252.1000.0

PowerShell Get-Winevent by Keywords and Provider Name issues

I'm new to powershell and have been learning quite a bit. But still more to go. So my code isn't the tightest.
I've created an Event-log search tool. It allows me to search via ID, error level, key word, etc. For the most part, it works, with the exception of the keywords and provider name.
Currently, when trying to search the logs for a keyword or set of keywords, the script prompts the error message:
Get-WinEvent : The specified image file did not contain a resource section
At C:\Users\Rob\Google Drive\Powershell\Get-logs.ps1:65 char:9
+ Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The specified image file did not contain a resource section,Microsoft.PowerShell.Commands.GetWinEventCommand
Problem is, I am not understanding the ps1.65 char:9 bit. The script then continues on and get's me old irrelevant data from the logs.
Here is the code for the two area's i'm having issue. Full code at the end.
Keyword Search:
elseif ($Kwrd -gt "a"){
foreach ($Kwrd in $Kwrd)
{
Get-WinEvent -FilterHashtable #{logname=$Log} -ComputerName $Computer | where-object { $_.Message -like "*$Kwrd*" } | Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum | Format-List
}
}
Provider Name Search:
elseif ($Prov.Length -gt 1){
Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | Where-Object {($_.ProviderName -like "*$Prov*")} | Sort-Object TimeGenerated -Descending|Select-Object -First $Maxnum | Format-List
}
So for example, if i wanted to search the application log for the provider name System Restore, (Which I have a few in there from the Revo application i ran recently) this is what the script does.
Enter Computer or EXIT to quit: office
Enter log set to retrieve: application
Enter Instance ID or leave blank:
Enter number of logs to retrieve: 10
Enter error level or leave blank:
Search logs by keyword or leave blank:
Search by Provider or leave blank: System Restore
Get-WinEvent : The specified image file did not contain a resource section
At C:\Users\Rob\Google Drive\Powershell\Get-logs.ps1:65 char:9
+ Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The specified image file did not contain a resource section,Microsoft.PowerShell.Commands.GetWinEventCommand
PS C:\Users\Rob>
It's the same issue for the keyword search,. Same error message. Only difference is the line number changes from 65 to 61, since the code is on line 61.
It's not perfect, but i'm learning as I go. Here's the full script. Any idea's how I can get the information from the logs without the error?
Clear-Host
while (1 -ne 2){
$Computer = $Null
$IDNum = $Null
$Lvl = $Null
$Kwrd = $Null
$Prov = $Null
Write-Host ''
$Computer = Read-Host "Enter Computer or EXIT to quit"
if ($Computer -eq "EXIT") {exit;}
$Log = Read-Host "Enter log set to retrieve"
$IDNum = Read-Host "Enter Instance ID or leave blank"
$IDNum = $IDNum.Split(',')
$MaxNum = $MaxNum = Read-Host "Enter number of logs to retrieve"
$Lvl = Read-Host "Enter error level or leave blank"
$Lvl = $Lvl.Split(',')
$Kwrd = Read-Host "Search logs by keyword or leave blank"
$Kwrd = $Kwrd.Split(',')
$Prov = Read-Host "Search by Provider or leave blank"
if ($IDNum.Length -gt 1){
foreach ($IDNum in $IDNum)
{
Get-WinEvent -FilterHashTable #{LogName=$Log; ID=$IDNum} -ComputerName $Computer | Where-Object { ($_.ID -eq "*$IDNum*")} |Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum| Format-List
}
}
elseif ($Lvl -gt 1 ){
foreach ($Lvl in $Lvl)
{
Get-WinEvent -FilterHashTable #{LogName=$Log;Level=$lvl} -ComputerName $Computer -MaxEvents $MaxNum |Select-Object -First $MaxNum | Sort-Object TimeGenerated -Descending | Format-List
}
}
elseif ($Kwrd -gt "a"){
foreach ($Kwrd in $Kwrd)
{
Get-WinEvent -FilterHashtable #{logname=$Log} -ComputerName $Computer | where-object { $_.Message -like "*$Kwrd*" } | Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum | Format-List
}
}
elseif ($Prov.Length -gt 1){
Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | Where-Object {($_.ProviderName -like "*$Prov*")} | Sort-Object TimeGenerated -Descending|Select-Object -First $Maxnum | Format-List
}
else {
Get-WinEvent -LogName $Log -ComputerName $Computer | Sort-Object TimeGenerated -Descending| Select-Object -First $MaxNum | Format-List
}
} else{
Clear-Host
$log = $IDNum = $MaxNum = $Lvl = $Kwrd = $Prov = $Null
continue
Write-Host ''
Write-Host ''
}
Thanks.
Note: I'm Running ISE as admin.
Couple of comments
1) I can't recreate the error (your script ran fine on my machine) but it's behaving as though its trying to open/read an image file (very odd).
2) I tried running get-winevent with no parameters and I got many get-winevent : The data is invalid errors. When I researched this error, I learned thatget-winevent seems to be a buggy/problematic/fussy cmdlet. So, I suggest you try get-eventlog instead
3) You're invoking Get-WinEvent inside a loop which makes the program take much longer to run then necessary. I suggest you execute Get-EventLog (see comment #2 above) one time and pipe the output to out-gridview. For example:
Get-EventLog -LogName application | out-gridview -Title "App log events"
Then, use the out-gridview filters to display only the output you want to see.
Example output for the command above:

Getting Installed Programs via Registry

So I've been over at
https://blogs.technet.microsoft.com/heyscriptingguy/2013/11/15/use-powershell-to-find-installed-software/
trying to use this to get a list of installed programs on a remote machine. I already started the WinRM remotely via PS, and am using the command
Invoke-Command -cn MC-PKS-MCARDH-L -ScriptBlock {
Get-ItemProperty HKLM:\Software\Wow6432Node\* |
select PSPath, PSParentPath, PSChildName
}
The primary use of this is to get the Adobe versions of programs on the client's PC, but for some reason this doesn't return many of the folders. It just returns HP, ESRI, Malwarebytes, and a few others:
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\ESRI
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node
PSChildName : ESRI
PSComputerName : mc-pks-mcardh-l
RunspaceId : 76050648-eec5-4e90-960d-872264a894d4
PSShowComputerName : True
Any reason this is? I tried using the one from the page I linked:
HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
but Adobe Reader doesn't even show up on that list.
I'm an AD Admin on the domain so why is it not showing all the folders? I'm looking via regedit now on the test machin and theres a folder called Adobe.
I'd recommend using, or at least trying, WMI:
Get-WmiObject -Class Win32_Product | Select-Object -Property Name, Vendor, Version | Format-Table;
You can also specify -ComputerName to query a remote machine.
To list all properties for dev. purposes, try:
Get-WmiObject -Class Win32_Product | Format-List -Property *;
Good luck!
--- ALTERNATIVELY, please try:
[String] $strKey = '';
[String] $strSubKey = '';
[PSCustomObject] $objData = $null;
#( 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall' ) | Foreach-Object {
$strKey = $_;
Get-ChildItem -Path $strKey | Select-Object -ExpandProperty PSChildName | Foreach-Object {
$strSubKey = $_;
$objData = Get-ItemProperty -LiteralPath (Join-Path -Path $strKey -ChildPath $strSubKey) | Select-Object -Property DisplayName, DisplayVersion;
if ( $objData.DisplayName -ne $null ) {
Write-Output -InputObject $objData;
} #if
} #Foreach-Object
} #Foreach-Object